diff options
author | ByteHamster <info@bytehamster.com> | 2021-08-28 09:52:45 +0200 |
---|---|---|
committer | ByteHamster <info@bytehamster.com> | 2021-08-28 10:59:26 +0200 |
commit | ca64739f363e585758b6ada6cc4e6c9d43191724 (patch) | |
tree | 3b5b6634792a3997d9302053e628ec8cda205ff5 /parser/media/src/test | |
parent | ddae5e2278fe6b6e950576cdc460ec7ffe761d5d (diff) | |
download | AntennaPod-ca64739f363e585758b6ada6cc4e6c9d43191724.zip |
Moved media file parser to its own module
Diffstat (limited to 'parser/media/src/test')
3 files changed, 400 insertions, 0 deletions
diff --git a/parser/media/src/test/java/de/danoeh/antennapod/parser/media/id3/ChapterReaderTest.java b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/id3/ChapterReaderTest.java new file mode 100644 index 000000000..af535b12a --- /dev/null +++ b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/id3/ChapterReaderTest.java @@ -0,0 +1,205 @@ +package de.danoeh.antennapod.parser.media.id3; + +import de.danoeh.antennapod.model.feed.Chapter; +import de.danoeh.antennapod.model.feed.EmbeddedChapterImage; +import de.danoeh.antennapod.parser.media.id3.model.FrameHeader; +import org.apache.commons.io.input.CountingInputStream; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class ChapterReaderTest { + private static final byte CHAPTER_WITHOUT_SUBFRAME_START_TIME = 23; + private static final byte[] CHAPTER_WITHOUT_SUBFRAME = { + 'C', 'H', '1', 0, // String ID for mapping to CTOC + 0, 0, 0, CHAPTER_WITHOUT_SUBFRAME_START_TIME, // Start time + 0, 0, 0, 0, // End time + 0, 0, 0, 0, // Start offset + 0, 0, 0, 0 // End offset + }; + + @Test + public void testReadFullTagWithChapter() throws IOException, ID3ReaderException { + byte[] chapter = Id3ReaderTest.concat( + Id3ReaderTest.generateFrameHeader(ChapterReader.FRAME_ID_CHAPTER, CHAPTER_WITHOUT_SUBFRAME.length), + CHAPTER_WITHOUT_SUBFRAME); + byte[] data = Id3ReaderTest.concat( + Id3ReaderTest.generateId3Header(chapter.length), + chapter); + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + ChapterReader reader = new ChapterReader(inputStream); + reader.readInputStream(); + assertEquals(1, reader.getChapters().size()); + assertEquals(CHAPTER_WITHOUT_SUBFRAME_START_TIME, reader.getChapters().get(0).getStart()); + } + + @Test + public void testReadFullTagWithMultipleChapters() throws IOException, ID3ReaderException { + byte[] chapter = Id3ReaderTest.concat( + Id3ReaderTest.generateFrameHeader(ChapterReader.FRAME_ID_CHAPTER, CHAPTER_WITHOUT_SUBFRAME.length), + CHAPTER_WITHOUT_SUBFRAME); + byte[] data = Id3ReaderTest.concat( + Id3ReaderTest.generateId3Header(2 * chapter.length), + chapter, + chapter); + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + ChapterReader reader = new ChapterReader(inputStream); + reader.readInputStream(); + assertEquals(2, reader.getChapters().size()); + assertEquals(CHAPTER_WITHOUT_SUBFRAME_START_TIME, reader.getChapters().get(0).getStart()); + assertEquals(CHAPTER_WITHOUT_SUBFRAME_START_TIME, reader.getChapters().get(1).getStart()); + } + + @Test + public void testReadChapterWithoutSubframes() throws IOException, ID3ReaderException { + FrameHeader header = new FrameHeader(ChapterReader.FRAME_ID_CHAPTER, + CHAPTER_WITHOUT_SUBFRAME.length, (short) 0); + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(CHAPTER_WITHOUT_SUBFRAME)); + Chapter chapter = new ChapterReader(inputStream).readChapter(header); + assertEquals(CHAPTER_WITHOUT_SUBFRAME_START_TIME, chapter.getStart()); + } + + @Test + public void testReadChapterWithTitle() throws IOException, ID3ReaderException { + byte[] title = { + ID3Reader.ENCODING_ISO, + 'H', 'e', 'l', 'l', 'o', // Title + 0 // Null-terminated + }; + byte[] chapterData = Id3ReaderTest.concat( + CHAPTER_WITHOUT_SUBFRAME, + Id3ReaderTest.generateFrameHeader(ChapterReader.FRAME_ID_TITLE, title.length), + title); + FrameHeader header = new FrameHeader(ChapterReader.FRAME_ID_CHAPTER, chapterData.length, (short) 0); + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(chapterData)); + ChapterReader reader = new ChapterReader(inputStream); + Chapter chapter = reader.readChapter(header); + assertEquals(CHAPTER_WITHOUT_SUBFRAME_START_TIME, chapter.getStart()); + assertEquals("Hello", chapter.getTitle()); + } + + @Test + public void testReadTitleWithGarbage() throws IOException, ID3ReaderException { + byte[] titleSubframeContent = { + ID3Reader.ENCODING_ISO, + 'A', // Title + 0, // Null-terminated + 42, 42, 42, 42 // Garbage, should be ignored + }; + FrameHeader header = new FrameHeader(ChapterReader.FRAME_ID_TITLE, titleSubframeContent.length, (short) 0); + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(titleSubframeContent)); + ChapterReader reader = new ChapterReader(inputStream); + Chapter chapter = new ID3Chapter("", 0); + reader.readChapterSubFrame(header, chapter); + assertEquals("A", chapter.getTitle()); + + // Should skip the garbage and point to the next frame + assertEquals(titleSubframeContent.length, reader.getPosition()); + } + + @Test + public void testRealFileUltraschall() throws IOException, ID3ReaderException { + CountingInputStream inputStream = new CountingInputStream(getClass().getClassLoader() + .getResource("ultraschall5.mp3").openStream()); + ChapterReader reader = new ChapterReader(inputStream); + reader.readInputStream(); + List<Chapter> chapters = reader.getChapters(); + + assertEquals(3, chapters.size()); + + assertEquals(0, chapters.get(0).getStart()); + assertEquals(4004, chapters.get(1).getStart()); + assertEquals(7999, chapters.get(2).getStart()); + + assertEquals("Marke 1", chapters.get(0).getTitle()); + assertEquals("Marke 2", chapters.get(1).getTitle()); + assertEquals("Marke 3", chapters.get(2).getTitle()); + + assertEquals("https://example.com", chapters.get(0).getLink()); + assertEquals("https://example.com", chapters.get(1).getLink()); + assertEquals("https://example.com", chapters.get(2).getLink()); + + assertEquals(EmbeddedChapterImage.makeUrl(16073, 2750569), chapters.get(0).getImageUrl()); + assertEquals(EmbeddedChapterImage.makeUrl(2766765, 15740), chapters.get(1).getImageUrl()); + assertEquals(EmbeddedChapterImage.makeUrl(2782628, 2750569), chapters.get(2).getImageUrl()); + } + + @Test + public void testRealFileAuphonic() throws IOException, ID3ReaderException { + CountingInputStream inputStream = new CountingInputStream(getClass().getClassLoader() + .getResource("auphonic.mp3").openStream()); + ChapterReader reader = new ChapterReader(inputStream); + reader.readInputStream(); + List<Chapter> chapters = reader.getChapters(); + + assertEquals(4, chapters.size()); + + assertEquals(0, chapters.get(0).getStart()); + assertEquals(3000, chapters.get(1).getStart()); + assertEquals(6000, chapters.get(2).getStart()); + assertEquals(9000, chapters.get(3).getStart()); + + assertEquals("Chapter 1 - ❤️😊", chapters.get(0).getTitle()); + assertEquals("Chapter 2 - ßöÄ", chapters.get(1).getTitle()); + assertEquals("Chapter 3 - 爱", chapters.get(2).getTitle()); + assertEquals("Chapter 4", chapters.get(3).getTitle()); + + assertEquals("https://example.com", chapters.get(0).getLink()); + assertEquals("https://example.com", chapters.get(1).getLink()); + assertEquals("https://example.com", chapters.get(2).getLink()); + assertEquals("https://example.com", chapters.get(3).getLink()); + + assertEquals(EmbeddedChapterImage.makeUrl(765, 308), chapters.get(0).getImageUrl()); + assertEquals(EmbeddedChapterImage.makeUrl(1271, 308), chapters.get(1).getImageUrl()); + assertEquals(EmbeddedChapterImage.makeUrl(1771, 308), chapters.get(2).getImageUrl()); + assertEquals(EmbeddedChapterImage.makeUrl(2259, 308), chapters.get(3).getImageUrl()); + } + + @Test + public void testRealFileHindenburgJournalistPro() throws IOException, ID3ReaderException { + CountingInputStream inputStream = new CountingInputStream(getClass().getClassLoader() + .getResource("hindenburg-journalist-pro.mp3").openStream()); + ChapterReader reader = new ChapterReader(inputStream); + reader.readInputStream(); + List<Chapter> chapters = reader.getChapters(); + + assertEquals(2, chapters.size()); + + assertEquals(0, chapters.get(0).getStart()); + assertEquals(5006, chapters.get(1).getStart()); + + assertEquals("Chapter Marker 1", chapters.get(0).getTitle()); + assertEquals("Chapter Marker 2", chapters.get(1).getTitle()); + + assertEquals("https://example.com/chapter1url", chapters.get(0).getLink()); + assertEquals("https://example.com/chapter2url", chapters.get(1).getLink()); + + assertEquals(EmbeddedChapterImage.makeUrl(5330, 4015), chapters.get(0).getImageUrl()); + assertEquals(EmbeddedChapterImage.makeUrl(9498, 4364), chapters.get(1).getImageUrl()); + } + + @Test + public void testRealFileMp3chapsPy() throws IOException, ID3ReaderException { + CountingInputStream inputStream = new CountingInputStream(getClass().getClassLoader() + .getResource("mp3chaps-py.mp3").openStream()); + ChapterReader reader = new ChapterReader(inputStream); + reader.readInputStream(); + List<Chapter> chapters = reader.getChapters(); + + assertEquals(4, chapters.size()); + + assertEquals(0, chapters.get(0).getStart()); + assertEquals(7000, chapters.get(1).getStart()); + assertEquals(9000, chapters.get(2).getStart()); + assertEquals(11000, chapters.get(3).getStart()); + + assertEquals("Start", chapters.get(0).getTitle()); + assertEquals("Chapter 1", chapters.get(1).getTitle()); + assertEquals("Chapter 2", chapters.get(2).getTitle()); + assertEquals("Chapter 3", chapters.get(3).getTitle()); + } +} diff --git a/parser/media/src/test/java/de/danoeh/antennapod/parser/media/id3/Id3ReaderTest.java b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/id3/Id3ReaderTest.java new file mode 100644 index 000000000..4b0bb2113 --- /dev/null +++ b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/id3/Id3ReaderTest.java @@ -0,0 +1,151 @@ +package de.danoeh.antennapod.parser.media.id3; + +import de.danoeh.antennapod.parser.media.id3.model.FrameHeader; +import de.danoeh.antennapod.parser.media.id3.model.TagHeader; +import org.apache.commons.io.input.CountingInputStream; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class Id3ReaderTest { + @Test + public void testReadString() throws IOException { + byte[] data = { + ID3Reader.ENCODING_ISO, + 'T', 'e', 's', 't', + 0 // Null-terminated + }; + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + String string = new ID3Reader(inputStream).readEncodingAndString(1000); + assertEquals("Test", string); + } + + @Test + public void testReadMultipleStrings() throws IOException { + byte[] data = { + ID3Reader.ENCODING_ISO, + 'F', 'o', 'o', + 0, // Null-terminated + ID3Reader.ENCODING_ISO, + 'B', 'a', 'r', + 0 // Null-terminated + }; + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + ID3Reader reader = new ID3Reader(inputStream); + assertEquals("Foo", reader.readEncodingAndString(1000)); + assertEquals("Bar", reader.readEncodingAndString(1000)); + } + + @Test + public void testReadingLimit() throws IOException { + byte[] data = { + ID3Reader.ENCODING_ISO, + 'A', 'B', 'C', 'D' + }; + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + ID3Reader reader = new ID3Reader(inputStream); + assertEquals("ABC", reader.readEncodingAndString(4)); // Includes encoding + assertEquals('D', reader.readByte()); + } + + @Test + public void testReadUtf16RespectsBom() throws IOException { + byte[] data = { + ID3Reader.ENCODING_UTF16_WITH_BOM, + (byte) 0xff, (byte) 0xfe, // BOM: Little-endian + 'A', 0, 'B', 0, 'C', 0, + 0, 0, // Null-terminated + ID3Reader.ENCODING_UTF16_WITH_BOM, + (byte) 0xfe, (byte) 0xff, // BOM: Big-endian + 0, 'D', 0, 'E', 0, 'F', + 0, 0, // Null-terminated + }; + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + ID3Reader reader = new ID3Reader(inputStream); + assertEquals("ABC", reader.readEncodingAndString(1000)); + assertEquals("DEF", reader.readEncodingAndString(1000)); + } + + @Test + public void testReadUtf16NullPrefix() throws IOException { + byte[] data = { + ID3Reader.ENCODING_UTF16_WITH_BOM, + (byte) 0xff, (byte) 0xfe, // BOM + 0x00, 0x01, // Latin Capital Letter A with macron (Ā) + 0, 0, // Null-terminated + }; + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + String string = new ID3Reader(inputStream).readEncodingAndString(1000); + assertEquals("Ā", string); + } + + @Test + public void testReadingLimitUtf16() throws IOException { + byte[] data = { + ID3Reader.ENCODING_UTF16_WITHOUT_BOM, + 'A', 0, 'B', 0, 'C', 0, 'D', 0 + }; + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + ID3Reader reader = new ID3Reader(inputStream); + reader.readEncodingAndString(6); // Includes encoding, produces broken string + assertTrue("Should respect limit even if it breaks a symbol", reader.getPosition() <= 6); + } + + @Test + public void testReadTagHeader() throws IOException, ID3ReaderException { + byte[] data = generateId3Header(23); + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + TagHeader header = new ID3Reader(inputStream).readTagHeader(); + assertEquals("ID3", header.getId()); + assertEquals(42, header.getVersion()); + assertEquals(23, header.getSize()); + } + + @Test + public void testReadFrameHeader() throws IOException { + byte[] data = generateFrameHeader("CHAP", 42); + CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(data)); + FrameHeader header = new ID3Reader(inputStream).readFrameHeader(); + assertEquals("CHAP", header.getId()); + assertEquals(42, header.getSize()); + } + + public static byte[] generateFrameHeader(String id, int size) { + return concat( + id.getBytes(StandardCharsets.ISO_8859_1), // Frame ID + new byte[] { + (byte) (size >> 24), (byte) (size >> 16), + (byte) (size >> 8), (byte) (size), // Size + 0, 0 // Flags + }); + } + + static byte[] generateId3Header(int size) { + return new byte[] { + 'I', 'D', '3', // Identifier + 0, 42, // Version + 0, // Flags + (byte) (size >> 24), (byte) (size >> 16), + (byte) (size >> 8), (byte) (size), // Size + }; + } + + static byte[] concat(byte[]... arrays) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + for (byte[] array : arrays) { + outputStream.write(array); + } + } catch (IOException e) { + fail(e.getMessage()); + } + return outputStream.toByteArray(); + } +} diff --git a/parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentChapterReaderTest.java b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentChapterReaderTest.java new file mode 100644 index 000000000..b81ce4651 --- /dev/null +++ b/parser/media/src/test/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentChapterReaderTest.java @@ -0,0 +1,44 @@ +package de.danoeh.antennapod.parser.media.vorbis; + +import de.danoeh.antennapod.model.feed.Chapter; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class VorbisCommentChapterReaderTest { + + @Test + public void testRealFilesAuphonic() throws IOException, VorbisCommentReaderException { + testRealFileAuphonic("auphonic.ogg"); + testRealFileAuphonic("auphonic.opus"); + } + + public void testRealFileAuphonic(String filename) throws IOException, VorbisCommentReaderException { + InputStream inputStream = getClass().getClassLoader() + .getResource(filename).openStream(); + VorbisCommentChapterReader reader = new VorbisCommentChapterReader(); + reader.readInputStream(inputStream); + List<Chapter> chapters = reader.getChapters(); + + assertEquals(4, chapters.size()); + + assertEquals(0, chapters.get(0).getStart()); + assertEquals(3000, chapters.get(1).getStart()); + assertEquals(6000, chapters.get(2).getStart()); + assertEquals(9000, chapters.get(3).getStart()); + + assertEquals("Chapter 1 - ❤️😊", chapters.get(0).getTitle()); + assertEquals("Chapter 2 - ßöÄ", chapters.get(1).getTitle()); + assertEquals("Chapter 3 - 爱", chapters.get(2).getTitle()); + assertEquals("Chapter 4", chapters.get(3).getTitle()); + + assertEquals("https://example.com", chapters.get(0).getLink()); + assertEquals("https://example.com", chapters.get(1).getLink()); + assertEquals("https://example.com", chapters.get(2).getLink()); + assertEquals("https://example.com", chapters.get(3).getLink()); + } +} |