Skip to content

Commit 8c4015f

Browse files
committed
Add targeted tests to improve coverage for low-coverage files
- ApeTagItem: 80.7% → 98.3% (ReadOnly flags, BinaryValue, equality) - ApeTagHeader: 83.7% → 94.2% (Create with isReadOnly, inequality) - DsfDataChunk: 82.7% → 100% (AudioDataSize edge cases, Create) - OggFlacFile: Now visible at 87.8% (error paths, Dispose) - MusepackFile: Now visible at 92.2% (SV7 versions, sample rates) 55 new tests targeting edge cases and result type operators.
1 parent 7c15f90 commit 8c4015f

4 files changed

Lines changed: 584 additions & 0 deletions

File tree

tests/TagLibSharp2.Tests/Ape/ApeTagTests.cs

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,258 @@ private static byte[] CreateCompleteTag (Dictionary<string, string> items)
721721

722722
#endregion
723723

724+
#region ApeTagItem Coverage Tests
725+
726+
[TestMethod]
727+
public void ApeTagItem_CreateText_WithReadOnly_SetsFlag ()
728+
{
729+
var item = ApeTagItem.CreateText ("Title", "Test", isReadOnly: true);
730+
Assert.IsTrue (item.IsReadOnly);
731+
Assert.AreEqual (ApeItemType.Text, item.ItemType);
732+
}
733+
734+
[TestMethod]
735+
public void ApeTagItem_CreateBinary_WithReadOnly_SetsFlag ()
736+
{
737+
var item = ApeTagItem.CreateBinary ("Cover", "cover.jpg", [0xFF, 0xD8], isReadOnly: true);
738+
Assert.IsTrue (item.IsReadOnly);
739+
Assert.AreEqual (ApeItemType.Binary, item.ItemType);
740+
}
741+
742+
[TestMethod]
743+
public void ApeTagItem_CreateExternalLocator_WithReadOnly_SetsFlag ()
744+
{
745+
var item = ApeTagItem.CreateExternalLocator ("Link", "http://example.com", isReadOnly: true);
746+
Assert.IsTrue (item.IsReadOnly);
747+
Assert.AreEqual (ApeItemType.ExternalLocator, item.ItemType);
748+
}
749+
750+
[TestMethod]
751+
public void ApeTagItem_Render_RoundTrips ()
752+
{
753+
var original = ApeTagItem.CreateText ("Title", "Test Value");
754+
var rendered = original.Render ();
755+
var reparsed = ApeTagItem.Parse (rendered);
756+
757+
Assert.IsTrue (reparsed.IsSuccess);
758+
Assert.AreEqual ("Title", reparsed.Item!.Key);
759+
Assert.AreEqual ("Test Value", reparsed.Item.ValueAsString);
760+
}
761+
762+
[TestMethod]
763+
public void ApeTagItem_BinaryValue_NoFilename_ReturnsDataOnly ()
764+
{
765+
// Create binary item where the value has no null separator (no filename)
766+
var keyBytes = "Cover"u8.ToArray ();
767+
var binaryData = new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 };
768+
var itemData = new byte[8 + keyBytes.Length + 1 + binaryData.Length];
769+
770+
BitConverter.GetBytes ((uint)binaryData.Length).CopyTo (itemData, 0);
771+
BitConverter.GetBytes (2u).CopyTo (itemData, 4); // Flags = 2 (binary type)
772+
keyBytes.CopyTo (itemData, 8);
773+
binaryData.CopyTo (itemData, 8 + keyBytes.Length + 1);
774+
775+
var result = ApeTagItem.Parse (itemData);
776+
777+
Assert.IsTrue (result.IsSuccess);
778+
Assert.AreEqual (ApeItemType.Binary, result.Item!.ItemType);
779+
var bv = result.Item.BinaryValue;
780+
Assert.IsNotNull (bv);
781+
Assert.AreEqual ("", bv.Filename);
782+
CollectionAssert.AreEqual (binaryData, bv.Data);
783+
}
784+
785+
[TestMethod]
786+
public void ApeTagItem_ValueAsString_ForBinary_ReturnsNull ()
787+
{
788+
var item = ApeTagItem.CreateBinary ("Cover", "cover.jpg", [0x89, 0x50]);
789+
Assert.IsNull (item.ValueAsString);
790+
}
791+
792+
[TestMethod]
793+
public void ApeTagItem_BinaryValue_ForText_ReturnsNull ()
794+
{
795+
var item = ApeTagItem.CreateText ("Title", "Test");
796+
Assert.IsNull (item.BinaryValue);
797+
}
798+
799+
[TestMethod]
800+
public void ApeTagItem_Parse_SingleCharKey_Fails ()
801+
{
802+
var data = CreateTextItem ("X", "value");
803+
var result = ApeTagItem.Parse (data);
804+
Assert.IsFalse (result.IsSuccess);
805+
Assert.IsTrue (result.Error!.Contains ("short"));
806+
}
807+
808+
[TestMethod]
809+
public void ApeTagItem_Parse_TwoCharKey_Succeeds ()
810+
{
811+
var data = CreateTextItem ("XY", "value");
812+
var result = ApeTagItem.Parse (data);
813+
Assert.IsTrue (result.IsSuccess);
814+
Assert.AreEqual ("XY", result.Item!.Key);
815+
}
816+
817+
[TestMethod]
818+
public void ApeTagItem_Parse_InvalidFlagsAreMasked ()
819+
{
820+
var keyBytes = "Title"u8.ToArray ();
821+
var valueBytes = "Test"u8.ToArray ();
822+
var data = new byte[8 + keyBytes.Length + 1 + valueBytes.Length];
823+
824+
BitConverter.GetBytes ((uint)valueBytes.Length).CopyTo (data, 0);
825+
BitConverter.GetBytes (0xF8u).CopyTo (data, 4); // Invalid flag bits
826+
keyBytes.CopyTo (data, 8);
827+
valueBytes.CopyTo (data, 8 + keyBytes.Length + 1);
828+
829+
var result = ApeTagItem.Parse (data);
830+
831+
Assert.IsTrue (result.IsSuccess);
832+
Assert.AreEqual (ApeItemType.Text, result.Item!.ItemType);
833+
}
834+
835+
[TestMethod]
836+
public void ApeTagItem_Parse_ValueExtendsBeyondData_Fails ()
837+
{
838+
var keyBytes = "Title"u8.ToArray ();
839+
var data = new byte[8 + keyBytes.Length + 1 + 5];
840+
841+
BitConverter.GetBytes (100u).CopyTo (data, 0); // Claim 100 bytes
842+
keyBytes.CopyTo (data, 8);
843+
844+
var result = ApeTagItem.Parse (data);
845+
846+
Assert.IsFalse (result.IsSuccess);
847+
Assert.IsTrue (result.Error!.Contains ("extends") || result.Error.Contains ("beyond"));
848+
}
849+
850+
[TestMethod]
851+
public void ApeTagItem_CreateText_ShortKey_Throws ()
852+
{
853+
Assert.ThrowsExactly<ArgumentException> (() =>
854+
ApeTagItem.CreateText ("X", "value"));
855+
}
856+
857+
[TestMethod]
858+
public void ApeTagItem_CreateText_LongKey_Throws ()
859+
{
860+
var longKey = new string ('K', 256);
861+
Assert.ThrowsExactly<ArgumentException> (() =>
862+
ApeTagItem.CreateText (longKey, "value"));
863+
}
864+
865+
[TestMethod]
866+
public void ApeTagItem_CreateText_ReservedKey_Throws ()
867+
{
868+
Assert.ThrowsExactly<ArgumentException> (() =>
869+
ApeTagItem.CreateText ("ID3", "value"));
870+
Assert.ThrowsExactly<ArgumentException> (() =>
871+
ApeTagItem.CreateText ("TAG", "value"));
872+
Assert.ThrowsExactly<ArgumentException> (() =>
873+
ApeTagItem.CreateText ("OggS", "value"));
874+
Assert.ThrowsExactly<ArgumentException> (() =>
875+
ApeTagItem.CreateText ("MP+", "value"));
876+
}
877+
878+
[TestMethod]
879+
public void ApeTagItem_CreateText_ControlCharInKey_Throws ()
880+
{
881+
Assert.ThrowsExactly<ArgumentException> (() =>
882+
ApeTagItem.CreateText ("Title\x01", "value"));
883+
}
884+
885+
[TestMethod]
886+
public void ApeTagItemParseResult_OperatorEquals_Works ()
887+
{
888+
var failure1 = ApeTagItemParseResult.Failure ("Error A");
889+
var failure2 = ApeTagItemParseResult.Failure ("Error A");
890+
var failure3 = ApeTagItemParseResult.Failure ("Error B");
891+
892+
Assert.IsTrue (failure1 == failure2);
893+
Assert.IsFalse (failure1 == failure3);
894+
}
895+
896+
[TestMethod]
897+
public void ApeTagItemParseResult_OperatorNotEquals_Works ()
898+
{
899+
var failure1 = ApeTagItemParseResult.Failure ("Error A");
900+
var failure2 = ApeTagItemParseResult.Failure ("Error B");
901+
902+
Assert.IsTrue (failure1 != failure2);
903+
}
904+
905+
[TestMethod]
906+
public void ApeTagItem_Parse_NoKeyTerminator_Fails ()
907+
{
908+
var data = new byte[20];
909+
BitConverter.GetBytes (4u).CopyTo (data, 0);
910+
for (int i = 8; i < data.Length; i++)
911+
data[i] = (byte)'A';
912+
913+
var result = ApeTagItem.Parse (data);
914+
Assert.IsFalse (result.IsSuccess);
915+
Assert.IsTrue (result.Error!.Contains ("null"));
916+
}
917+
918+
#endregion
919+
920+
#region ApeTagHeader Coverage Tests
921+
922+
[TestMethod]
923+
public void ApeTagHeader_Create_ReadOnly_SetsFlag ()
924+
{
925+
var header = ApeTagHeader.Create (100, 5, isReadOnly: true);
926+
Assert.IsTrue (header.IsReadOnly);
927+
Assert.IsTrue (header.IsHeader);
928+
Assert.IsTrue (header.HasHeader);
929+
}
930+
931+
[TestMethod]
932+
public void ApeTagHeader_Render_RoundTrips ()
933+
{
934+
var original = ApeTagHeader.Create (200, 10);
935+
var rendered = original.Render ();
936+
var reparsed = ApeTagHeader.Parse (rendered);
937+
938+
Assert.IsTrue (reparsed.IsSuccess);
939+
Assert.AreEqual (original.TagSize, reparsed.Header!.TagSize);
940+
Assert.AreEqual (original.ItemCount, reparsed.Header.ItemCount);
941+
Assert.IsTrue (reparsed.Header.IsHeader);
942+
}
943+
944+
[TestMethod]
945+
public void ApeTagHeader_Parse_FooterData_Fails ()
946+
{
947+
var footer = ApeTagFooter.Create (100, 5, isHeader: false);
948+
var data = footer.Render ();
949+
950+
var result = ApeTagHeader.Parse (data);
951+
952+
Assert.IsFalse (result.IsSuccess);
953+
Assert.IsTrue (result.Error!.Contains ("header") || result.Error.Contains ("bit 29"));
954+
}
955+
956+
[TestMethod]
957+
public void ApeTagHeaderParseResult_OperatorEquals_Works ()
958+
{
959+
var failure1 = ApeTagHeaderParseResult.Failure ("Error A");
960+
var failure2 = ApeTagHeaderParseResult.Failure ("Error A");
961+
962+
Assert.IsTrue (failure1 == failure2);
963+
}
964+
965+
[TestMethod]
966+
public void ApeTagHeaderParseResult_OperatorNotEquals_Works ()
967+
{
968+
var failure1 = ApeTagHeaderParseResult.Failure ("Error A");
969+
var failure2 = ApeTagHeaderParseResult.Failure ("Error B");
970+
971+
Assert.IsTrue (failure1 != failure2);
972+
}
973+
974+
#endregion
975+
724976
#region Result Type Equality Tests
725977

726978
[TestMethod]

tests/TagLibSharp2.Tests/Dsf/DsfFileTests.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,77 @@ public void ParseDataChunk_InvalidMagic_ReturnsFailure ()
516516
Assert.IsFalse (result.IsSuccess);
517517
}
518518

519+
[TestMethod]
520+
public void DsfDataChunk_Create_SetsProperties ()
521+
{
522+
var chunk = DsfDataChunk.Create (1000);
523+
Assert.AreEqual (1000UL, chunk.ChunkSize);
524+
Assert.AreEqual ((ulong)(1000 - DsfDataChunk.HeaderSize), chunk.AudioDataSize);
525+
}
526+
527+
[TestMethod]
528+
public void DsfDataChunk_AudioDataSize_ChunkSizeLessThanHeader_ReturnsZero ()
529+
{
530+
var chunk = DsfDataChunk.Create (10); // Less than HeaderSize (12)
531+
Assert.AreEqual (0UL, chunk.AudioDataSize);
532+
}
533+
534+
[TestMethod]
535+
public void DsfDataChunk_AudioDataSize_ExactlyHeaderSize_ReturnsZero ()
536+
{
537+
var chunk = DsfDataChunk.Create (DsfDataChunk.HeaderSize);
538+
Assert.AreEqual (0UL, chunk.AudioDataSize);
539+
}
540+
541+
[TestMethod]
542+
public void DsfDataChunk_HeaderSizeValue_Returns12 ()
543+
{
544+
Assert.AreEqual (12, DsfDataChunk.HeaderSizeValue);
545+
}
546+
547+
[TestMethod]
548+
public void DsfDataChunk_RenderHeader_RoundTrips ()
549+
{
550+
var original = DsfDataChunk.Create (5000);
551+
var rendered = original.RenderHeader ();
552+
var reparsed = DsfDataChunk.Parse (rendered);
553+
554+
Assert.IsTrue (reparsed.IsSuccess);
555+
Assert.AreEqual (original.ChunkSize, reparsed.Chunk!.ChunkSize);
556+
}
557+
558+
[TestMethod]
559+
public void DsfDataChunk_Parse_TooShort_Fails ()
560+
{
561+
var data = new byte[8]; // Less than HeaderSize (12)
562+
data[0] = (byte)'d';
563+
data[1] = (byte)'a';
564+
data[2] = (byte)'t';
565+
data[3] = (byte)'a';
566+
567+
var result = DsfDataChunk.Parse (data);
568+
Assert.IsFalse (result.IsSuccess);
569+
Assert.IsTrue (result.Error!.Contains ("short") || result.Error.Contains ("size"));
570+
}
571+
572+
[TestMethod]
573+
public void DsfDataChunkParseResult_OperatorEquals_Works ()
574+
{
575+
var failure1 = DsfDataChunkParseResult.Failure ("Error A");
576+
var failure2 = DsfDataChunkParseResult.Failure ("Error A");
577+
578+
Assert.IsTrue (failure1 == failure2);
579+
}
580+
581+
[TestMethod]
582+
public void DsfDataChunkParseResult_OperatorNotEquals_Works ()
583+
{
584+
var failure1 = DsfDataChunkParseResult.Failure ("Error A");
585+
var failure2 = DsfDataChunkParseResult.Failure ("Error B");
586+
587+
Assert.IsTrue (failure1 != failure2);
588+
}
589+
519590
#endregion
520591

521592
#region Full DSF File Parsing Tests

0 commit comments

Comments
 (0)