using System; using UnitTestSharp; using static Susurrus.UnitTests.TestSounds; namespace Susurrus.UnitTests { public class OggPagesTests : TestFixture { public static byte[] Padded(byte[] page, int before) { byte[] returnMe = new byte[before + page.Length]; Array.Copy(page, 0, returnMe, before, page.Length); return returnMe; } public class ChecksumTests : TestFixture { public void OfARealEncodersFirstPage_MatchesTheOneItStored() { byte[] file = LoadFixture("Mono441Hz.ogg"); CheckEqual(BitConverter.ToUInt32(file, 22), OggPages.Checksum(file, 0, 58)); } public void IgnoresWhatTheChecksumFieldHolds() { byte[] page = MakePage(granule: 5, flags: 0, lacing: new byte[] { 4 }, bodySize: 4); uint expected = OggPages.Checksum(page, 0, page.Length); page[22] = 0xFF; page[25] = 0x12; CheckEqual(expected, OggPages.Checksum(page, 0, page.Length)); } public void ChangesWhenABodyByteChanges() { byte[] page = MakePage(granule: 5, flags: 0, lacing: new byte[] { 4 }, bodySize: 4); uint before = OggPages.Checksum(page, 0, page.Length); page[page.Length - 1] ^= 1; CheckTrue(before != OggPages.Checksum(page, 0, page.Length)); } public void OfAPageInTheMiddleOfAnArray_LooksOnlyAtThatPage() { byte[] page = MakePage(granule: 5, flags: 0, lacing: new byte[] { 4 }, bodySize: 4); CheckEqual(OggPages.Checksum(page, 0, page.Length), OggPages.Checksum(Padded(page, 9), 9, page.Length)); } } public class TryReadTests : TestFixture { public void ARealEncodersFirstPage_IsTheIdentificationHeader() { byte[] file = LoadFixture("Mono441Hz.ogg"); CheckTrue(OggPages.TryRead(file, 0, file.Length, out OggPage page)); CheckEqual(58, page.Size); CheckEqual(0L, page.Granule); CheckEqual((byte)2, page.Flags); CheckEqual(58, page.LastPacketEnd); } public void ReadsTheGranuleAndFlagsOfALaterPage() { byte[] page = MakePage(granule: 0x123456789AL, flags: OggPages.EndOfStreamFlag, lacing: new byte[] { 7 }, bodySize: 7); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckEqual(0x123456789AL, read.Granule); CheckTrue(read.IsEndOfStream); CheckEqual(page.Length, read.Size); } public void APageWithoutTheEndOfStreamFlag_IsNotTheEnd() { byte[] page = MakePage(granule: 1, flags: OggPages.ContinuedFlag, lacing: new byte[] { 1 }, bodySize: 1); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckFalse(read.IsEndOfStream); } public void ANegativeGranule_IsKept() { byte[] page = MakePage(granule: -1, flags: 0, lacing: new byte[] { 255 }, bodySize: 255); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckEqual(-1L, read.Granule); } public void APageStartingPartWayIntoTheData_IsReadFromThere() { byte[] page = MakePage(granule: 9, flags: 0, lacing: new byte[] { 3 }, bodySize: 3); byte[] data = Padded(page, 11); CheckTrue(OggPages.TryRead(data, 11, data.Length, out OggPage read)); CheckEqual(9L, read.Granule); } public void LastPacketEnd_IsWhereTheLastPacketThatFinishesEnds() { byte[] page = MakePage(granule: 4, flags: 0, lacing: new byte[] { 10, 20, 255 }, bodySize: 285); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckEqual(OggPages.HeaderSize + 3 + 10 + 20, read.LastPacketEnd); } public void LastPacketEnd_CountsAPacketMadeOfFullSegmentsAndAShortOne() { byte[] page = MakePage(granule: 4, flags: 0, lacing: new byte[] { 255, 5 }, bodySize: 260); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckEqual(page.Length, read.LastPacketEnd); } public void LastPacketEnd_CountsAnEmptyPacket() { byte[] page = MakePage(granule: 4, flags: 0, lacing: new byte[] { 0 }, bodySize: 0); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckEqual(OggPages.HeaderSize + 1, read.LastPacketEnd); } public void LastPacketEnd_IsZeroWhenNoPacketFinishes() { byte[] page = MakePage(granule: -1, flags: 0, lacing: new byte[] { 255, 255 }, bodySize: 510); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckEqual(0, read.LastPacketEnd); } public void APageWithNoSegments_IsJustItsHeader() { byte[] page = MakePage(granule: 0, flags: OggPages.EndOfStreamFlag, lacing: new byte[0], bodySize: 0); CheckTrue(OggPages.TryRead(page, 0, page.Length, out OggPage read)); CheckEqual(OggPages.HeaderSize, read.Size); CheckEqual(0, read.LastPacketEnd); } public void AWrongCapturePattern_IsNotAPage() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 1 }, bodySize: 1); page[3] = (byte)'T'; CheckFalse(OggPages.TryRead(page, 0, page.Length, out OggPage read)); } public void AStreamStructureVersionOtherThanZero_IsNotAPage() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 1 }, bodySize: 1); page[4] = 1; FixPageChecksum(page, 0); CheckFalse(OggPages.TryRead(page, 0, page.Length, out OggPage read)); } public void FewerBytesThanAHeader_IsNotAPage() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 1 }, bodySize: 1); CheckFalse(OggPages.TryRead(page, 0, OggPages.HeaderSize - 1, out OggPage read)); } public void ASegmentTableCutShort_IsNotAPage() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 1, 1, 1 }, bodySize: 3); CheckFalse(OggPages.TryRead(page, 0, OggPages.HeaderSize + 2, out OggPage read)); } public void ABodyCutShort_IsNotAPage() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 9 }, bodySize: 9); CheckFalse(OggPages.TryRead(page, 0, page.Length - 1, out OggPage read)); } public void AChangedBodyByte_IsNotAPage() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 9 }, bodySize: 9); page[page.Length - 1] ^= 0x40; CheckFalse(OggPages.TryRead(page, 0, page.Length, out OggPage read)); } public void AStartBeforeTheData_IsNotAPage() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 1 }, bodySize: 1); CheckFalse(OggPages.TryRead(page, -1, page.Length, out OggPage read)); } public void ASuccessfulRead_LeavesTheOffsetForTheCallerToSet() { byte[] page = MakePage(granule: 1, flags: 0, lacing: new byte[] { 1 }, bodySize: 1); OggPages.TryRead(page, 0, page.Length, out OggPage read); CheckEqual(0L, read.Offset); } } } }