From dcadbcaf36b2e4a001b45477b9150d8a1a57d119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20T=C3=A2che?= Date: Thu, 29 Aug 2024 21:50:39 +0200 Subject: [PATCH] Adds tests for core --- .../process/impl/ProcessRunnerImpl.java | 2 - .../converter/impl/ASSSubtitleConverter.java | 5 +- .../impl/SubtitleImporterExporterImpl.java | 33 ++- .../impl/TestArchiverProviderImpl.java | 48 +++++ .../archive/impl/TestZipDecompresser.java | 6 + .../modules/impl/TestCoreModule.java | 26 +++ .../modules/setup/impl/TestSetupModule.java | 12 ++ .../impl/TestASSSubtitleConverter.java | 137 ++++++++++++ .../impl/TestSRTSubtitleConverter.java | 5 +- .../TestSubtitleConverterProviderImpl.java | 44 ++++ .../TestSubtitleImporterExporterImpl.java | 197 ++++++++++++++++++ 11 files changed, 492 insertions(+), 23 deletions(-) create mode 100644 core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestArchiverProviderImpl.java create mode 100644 core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestASSSubtitleConverter.java create mode 100644 core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSubtitleConverterProviderImpl.java create mode 100644 core/src/test/java/com/github/gtache/autosubtitle/subtitle/impl/TestSubtitleImporterExporterImpl.java diff --git a/core/src/main/java/com/github/gtache/autosubtitle/process/impl/ProcessRunnerImpl.java b/core/src/main/java/com/github/gtache/autosubtitle/process/impl/ProcessRunnerImpl.java index a78e446..d51b474 100644 --- a/core/src/main/java/com/github/gtache/autosubtitle/process/impl/ProcessRunnerImpl.java +++ b/core/src/main/java/com/github/gtache/autosubtitle/process/impl/ProcessRunnerImpl.java @@ -42,6 +42,4 @@ public class ProcessRunnerImpl implements ProcessRunner { final var process = start(args); return new ProcessListenerImpl(process); } - - } diff --git a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/impl/ASSSubtitleConverter.java b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/impl/ASSSubtitleConverter.java index d91d13a..d1894ee 100644 --- a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/impl/ASSSubtitleConverter.java +++ b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/converter/impl/ASSSubtitleConverter.java @@ -46,6 +46,9 @@ public class ASSSubtitleConverter implements SubtitleConverter { this.translator = requireNonNull(translator); this.preferences = requireNonNull(preferences); this.defaultFontName = Objects.requireNonNull(defaultFontName); + if (defaultFontSize <= 0) { + throw new IllegalArgumentException("Font size must be positive : " + defaultFontSize); + } this.defaultFontSize = defaultFontSize; } @@ -55,7 +58,7 @@ public class ASSSubtitleConverter implements SubtitleConverter { final var scriptInfo = getScriptInfo(videoInfo); final var styles = getStyles(subtitles); final var events = getEvents(subtitles); - return scriptInfo + "\n\n" + styles + "\n\n" + events; + return scriptInfo + "\n\n" + styles + "\n\n" + events + "\n"; } private String getEvents(final Collection subtitles) { diff --git a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleImporterExporterImpl.java b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleImporterExporterImpl.java index d95cbde..b79cba1 100644 --- a/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleImporterExporterImpl.java +++ b/core/src/main/java/com/github/gtache/autosubtitle/subtitle/impl/SubtitleImporterExporterImpl.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.Map; +import java.util.stream.Collectors; import static java.util.Objects.requireNonNull; @@ -51,18 +52,6 @@ public class SubtitleImporterExporterImpl implements SubtitleImporterExporter loadSingleFile(final Path file) throws ParseException { - final var fileName = file.getFileName().toString(); - final var extension = fileName.substring(fileName.lastIndexOf('.') + 1); - final var parser = converterProvider.getConverter(extension); - if (parser == null) { - throw new ParseException("No converter found for " + file); - } else { - final var parsed = parser.parse(file); - return new SubtitleCollectionImpl<>(parsed.text(), parsed.subtitles().stream().map(SubtitleImpl::new).toList(), parsed.language()); - } - } - private Map> loadArchive(final Path file) throws IOException, ParseException { final var fileName = file.getFileName().toString(); final var extension = fileName.substring(fileName.lastIndexOf('.') + 1); @@ -84,6 +73,18 @@ public class SubtitleImporterExporterImpl implements SubtitleImporterExporter loadSingleFile(final Path file) throws ParseException { + final var fileName = file.getFileName().toString(); + final var extension = fileName.substring(fileName.lastIndexOf('.') + 1); + final var parser = converterProvider.getConverter(extension); + if (parser == null) { + throw new ParseException("No converter found for " + file); + } else { + final var parsed = parser.parse(file); + return new SubtitleCollectionImpl<>(parsed.text(), parsed.subtitles().stream().map(SubtitleImpl::new).toList(), parsed.language()); + } + } + @Override public void exportSubtitles(final Collection> collections, final VideoInfo videoInfo, final Path file) throws IOException { final var fileName = file.getFileName().toString(); @@ -101,10 +102,9 @@ public class SubtitleImporterExporterImpl implements SubtitleImporterExporter(); @@ -132,14 +132,13 @@ public class SubtitleImporterExporterImpl implements SubtitleImporterExporter supportedArchiveExtensions() { - return archiverProvider.allArchivers().stream().map(Archiver::archiveExtension).toList(); + return archiverProvider.allArchivers().stream().map(Archiver::archiveExtension).collect(Collectors.toSet()); } @Override public Collection supportedSingleFileExtensions() { - return converterProvider.allConverters().stream().map(SubtitleConverter::formatName).toList(); + return converterProvider.allConverters().stream().map(SubtitleConverter::formatName).collect(Collectors.toSet()); } } diff --git a/core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestArchiverProviderImpl.java b/core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestArchiverProviderImpl.java new file mode 100644 index 0000000..8bb5e79 --- /dev/null +++ b/core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestArchiverProviderImpl.java @@ -0,0 +1,48 @@ +package com.github.gtache.autosubtitle.archive.impl; + +import com.github.gtache.autosubtitle.archive.Archiver; +import com.github.gtache.autosubtitle.archive.ArchiverProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class TestArchiverProviderImpl { + + private final Archiver zipArchiver; + private final Archiver rarArchiver; + private final ArchiverProvider archiverProvider; + + TestArchiverProviderImpl(@Mock final Archiver zipArchiver, @Mock final Archiver rarArchiver) { + when(zipArchiver.archiveExtension()).thenReturn("zip"); + when(rarArchiver.archiveExtension()).thenReturn("rar"); + this.zipArchiver = Objects.requireNonNull(zipArchiver); + this.rarArchiver = Objects.requireNonNull(rarArchiver); + this.archiverProvider = new ArchiverProviderImpl(Map.of("zip", zipArchiver, "rar", rarArchiver)); + } + + @Test + void testAllArchivers() { + final Collection allArchivers = archiverProvider.allArchivers(); + assertEquals(2, allArchivers.size()); + assertTrue(allArchivers.contains(zipArchiver)); + assertTrue(allArchivers.contains(rarArchiver)); + } + + @Test + void testGetArchiver() { + assertEquals(zipArchiver, archiverProvider.getArchiver("zip")); + assertEquals(zipArchiver, archiverProvider.getArchiver("ZIP")); + assertEquals(rarArchiver, archiverProvider.getArchiver("rar")); + assertEquals(rarArchiver, archiverProvider.getArchiver("RAR")); + assertNull(archiverProvider.getArchiver("unknown")); + } +} diff --git a/core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestZipDecompresser.java b/core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestZipDecompresser.java index c89c8cf..1c7bc0c 100644 --- a/core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestZipDecompresser.java +++ b/core/src/test/java/com/github/gtache/autosubtitle/archive/impl/TestZipDecompresser.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -26,6 +27,11 @@ class TestZipDecompresser { assertFalse(zipDecompresser.isPathSupported(Path.of("test.zip2"))); } + @Test + void testCompress() { + assertThrows(UnsupportedOperationException.class, () -> zipDecompresser.compress(List.of(Paths.get("file.txt")), Paths.get("target"))); + } + @Test void testDecompress(@TempDir final Path tempDir) throws IOException { final var file = tempDir.resolve("test.zip"); diff --git a/core/src/test/java/com/github/gtache/autosubtitle/modules/impl/TestCoreModule.java b/core/src/test/java/com/github/gtache/autosubtitle/modules/impl/TestCoreModule.java index 44e10a6..9e251ae 100644 --- a/core/src/test/java/com/github/gtache/autosubtitle/modules/impl/TestCoreModule.java +++ b/core/src/test/java/com/github/gtache/autosubtitle/modules/impl/TestCoreModule.java @@ -57,4 +57,30 @@ class TestCoreModule { assertEquals("", CoreModule.providesExecutableExtension(OS.MAC)); assertEquals("", CoreModule.providesExecutableExtension(OS.LINUX)); } + + @Test + void testProvidesPreferences() { + final var preferences = CoreModule.providesPreferences(); + assertEquals("/com/github/gtache/autosubtitle", preferences.absolutePath()); + } + + @Test + void testProvidesMaxLineLength() { + assertEquals(40, CoreModule.providesMaxLineLength()); + } + + @Test + void testProvidesMaxLines() { + assertEquals(1, CoreModule.providesMaxLines()); + } + + @Test + void testProvidesFontName() { + assertEquals("Arial", CoreModule.providesFontName()); + } + + @Test + void testProvidesFontSize() { + assertEquals(12, CoreModule.providesFontSize()); + } } diff --git a/core/src/test/java/com/github/gtache/autosubtitle/modules/setup/impl/TestSetupModule.java b/core/src/test/java/com/github/gtache/autosubtitle/modules/setup/impl/TestSetupModule.java index 005e0b1..632de07 100644 --- a/core/src/test/java/com/github/gtache/autosubtitle/modules/setup/impl/TestSetupModule.java +++ b/core/src/test/java/com/github/gtache/autosubtitle/modules/setup/impl/TestSetupModule.java @@ -3,11 +3,23 @@ package com.github.gtache.autosubtitle.modules.setup.impl; import org.junit.jupiter.api.Test; import java.net.http.HttpClient; +import java.nio.file.Paths; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; class TestSetupModule { + @Test + void testCacheRoot() { + assertEquals(Paths.get("cache"), SetupModule.providesCacheRoot()); + } + + @Test + void testToolsRoot() { + assertEquals(Paths.get("tools"), SetupModule.providesToolsRoot()); + } + @Test void testHttpClient() { assertInstanceOf(HttpClient.class, SetupModule.providesHttpClient()); diff --git a/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestASSSubtitleConverter.java b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestASSSubtitleConverter.java new file mode 100644 index 0000000..5740486 --- /dev/null +++ b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestASSSubtitleConverter.java @@ -0,0 +1,137 @@ +package com.github.gtache.autosubtitle.subtitle.converter.impl; + +import com.github.gtache.autosubtitle.Language; +import com.github.gtache.autosubtitle.VideoInfo; +import com.github.gtache.autosubtitle.subtitle.converter.ParseException; +import com.github.gtache.autosubtitle.subtitle.impl.FontImpl; +import com.github.gtache.autosubtitle.subtitle.impl.SubtitleCollectionImpl; +import com.github.gtache.autosubtitle.subtitle.impl.SubtitleImpl; +import com.github.gtache.autosubtitle.translation.Translator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Arrays; +import java.util.Objects; +import java.util.prefs.Preferences; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class TestASSSubtitleConverter { + + private final Translator translator; + private final Preferences preferences; + private final Language language; + private final VideoInfo videoInfo; + private final String defaultFontName; + private final int defaultFontSize; + private final ASSSubtitleConverter converter; + + TestASSSubtitleConverter(@Mock final Translator translator, + @Mock final Preferences preferences, + @Mock final Language language, + @Mock final VideoInfo videoInfo) { + this.translator = Objects.requireNonNull(translator); + this.preferences = Objects.requireNonNull(preferences); + this.language = Objects.requireNonNull(language); + this.videoInfo = Objects.requireNonNull(videoInfo); + when(videoInfo.width()).thenReturn(1920); + when(videoInfo.height()).thenReturn(1080); + this.defaultFontName = "Arial"; + this.defaultFontSize = 12; + this.converter = new ASSSubtitleConverter(translator, preferences, defaultFontName, defaultFontSize); + when(translator.getLanguage(anyString())).thenReturn(language); + } + + @Test + void testParseFormat() throws ParseException { + final var in = """ + [Script Info] + PlayResX: 1920 + PlayResY: 1080 + WrapStyle: 1 + + [V4+ Styles] + Format: Name, Fontname, Fontsize + Style: Times New Roman13, Times New Roman, 13 + Style: Arial12, Arial, 12 + + [Events] + Format: Start, End, Style, Text + Dialogue: 0:00:00.00,0:00:00.41,Arial12,Test ? + Dialogue: 123:45:54.32,124:00:00.00,Times New Roman13,Test2. + """; + + final var start1 = 0L; + final var end1 = 410L; + final var start2 = 123 * 3600 * 1000 + 45 * 60 * 1000 + 54 * 1000 + 320; + final var end2 = 124 * 3600 * 1000; + final var arial = new FontImpl("Arial", 12); + final var times = new FontImpl("Times New Roman", 13); + final var subtitle1 = new SubtitleImpl("Test ?", start1, end1, arial, null); + final var subtitle2 = new SubtitleImpl("Test2.", start2, end2, times, null); + final var subtitles = new SubtitleCollectionImpl<>(subtitle1.content() + subtitle2.content(), Arrays.asList(subtitle1, subtitle2), language); + assertEquals(subtitles, converter.parse(in)); + assertEquals(in, converter.format(subtitles, videoInfo)); + } + + @Test + void testParseDifferentFormat() throws ParseException { + final var in = """ + [Script Info] + PlayResX: 1920 + PlayResY: 1080 + WrapStyle: 1 + + [V4+ Styles] + Format: Name, Fontsize, Fontname, Other + Style: Arial12, 12, Arial, ttt + Style: Times New Roman13, 13, Times New Roman, lara + + [Events] + Format: Style, End, Start, Text + Dialogue: Arial12,0:00:00.41,0:00:00.00,Test ? + Dialogue: Times New Roman13,124:00:00.00,123:45:54.32,Test2. + """; + + final var start1 = 0L; + final var end1 = 410L; + final var start2 = 123 * 3600 * 1000 + 45 * 60 * 1000 + 54 * 1000 + 320; + final var end2 = 124 * 3600 * 1000; + final var arial = new FontImpl("Arial", 12); + final var times = new FontImpl("Times New Roman", 13); + final var subtitle1 = new SubtitleImpl("Test ?", start1, end1, arial, null); + final var subtitle2 = new SubtitleImpl("Test2.", start2, end2, times, null); + final var subtitles = new SubtitleCollectionImpl<>(subtitle1.content() + subtitle2.content(), Arrays.asList(subtitle1, subtitle2), language); + assertEquals(subtitles, converter.parse(in)); + } + + @Test + void testParseException() { + final var in = """ + 1 + 121:23:344,456 --> 12:23:34,457 + test1 test2 + test3 test4 + """; + assertThrows(ParseException.class, () -> converter.parse(in)); + } + + @Test + void testFormatName() { + assertEquals("ass", converter.formatName()); + } + + @Test + void testIllegal() { + assertThrows(NullPointerException.class, () -> new ASSSubtitleConverter(null, preferences, defaultFontName, defaultFontSize)); + assertThrows(NullPointerException.class, () -> new ASSSubtitleConverter(translator, null, defaultFontName, defaultFontSize)); + assertThrows(NullPointerException.class, () -> new ASSSubtitleConverter(translator, preferences, null, defaultFontSize)); + assertThrows(IllegalArgumentException.class, () -> new ASSSubtitleConverter(translator, preferences, defaultFontName, 0)); + } +} diff --git a/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSRTSubtitleConverter.java b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSRTSubtitleConverter.java index d93671e..cd68c8d 100644 --- a/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSRTSubtitleConverter.java +++ b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSRTSubtitleConverter.java @@ -25,11 +25,13 @@ class TestSRTSubtitleConverter { private final Translator translator; private final Language language; private final VideoInfo videoInfo; + private final SRTSubtitleConverter converter; TestSRTSubtitleConverter(@Mock final Translator translator, @Mock final Language language, @Mock final VideoInfo videoInfo) { this.translator = Objects.requireNonNull(translator); this.language = Objects.requireNonNull(language); this.videoInfo = Objects.requireNonNull(videoInfo); + this.converter = new SRTSubtitleConverter(translator); when(translator.getLanguage(anyString())).thenReturn(language); } @@ -54,7 +56,6 @@ class TestSRTSubtitleConverter { final var subtitle1 = new SubtitleImpl("test5 test6\ntest7 test8", start1, end1, null, null); final var subtitle2 = new SubtitleImpl("test1 test2\ntest3 test4", start2, end2, null, null); final var subtitles = new SubtitleCollectionImpl<>(subtitle1.content() + " " + subtitle2.content(), Arrays.asList(subtitle1, subtitle2), language); - final var converter = new SRTSubtitleConverter(translator); assertEquals(subtitles, converter.parse(in)); assertEquals(in, converter.format(subtitles, videoInfo)); } @@ -67,13 +68,11 @@ class TestSRTSubtitleConverter { test1 test2 test3 test4 """; - final var converter = new SRTSubtitleConverter(translator); assertThrows(ParseException.class, () -> converter.parse(in)); } @Test void testFormatName() { - final var converter = new SRTSubtitleConverter(translator); assertEquals("srt", converter.formatName()); } diff --git a/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSubtitleConverterProviderImpl.java b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSubtitleConverterProviderImpl.java new file mode 100644 index 0000000..e8cef94 --- /dev/null +++ b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/converter/impl/TestSubtitleConverterProviderImpl.java @@ -0,0 +1,44 @@ +package com.github.gtache.autosubtitle.subtitle.converter.impl; + +import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter; +import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Map; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(MockitoExtension.class) +class TestSubtitleConverterProviderImpl { + + private final SubtitleConverter first; + private final SubtitleConverter second; + private final SubtitleConverterProvider provider; + + TestSubtitleConverterProviderImpl(@Mock final SubtitleConverter first, @Mock final SubtitleConverter second) { + this.first = Objects.requireNonNull(first); + this.second = Objects.requireNonNull(second); + this.provider = new SubtitleConverterProviderImpl(Map.of("first", first, "second", second)); + } + + @Test + void testAllConverters() { + final var converters = provider.allConverters(); + assertEquals(2, converters.size()); + assertTrue(converters.contains(first)); + assertTrue(converters.contains(second)); + } + + @Test + void testGetConverter() { + assertEquals(first, provider.getConverter("first")); + assertEquals(first, provider.getConverter("FIRST")); + assertEquals(second, provider.getConverter("second")); + assertEquals(second, provider.getConverter("SECOND")); + assertNull(provider.getConverter("third")); + } +} diff --git a/core/src/test/java/com/github/gtache/autosubtitle/subtitle/impl/TestSubtitleImporterExporterImpl.java b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/impl/TestSubtitleImporterExporterImpl.java new file mode 100644 index 0000000..0741cbd --- /dev/null +++ b/core/src/test/java/com/github/gtache/autosubtitle/subtitle/impl/TestSubtitleImporterExporterImpl.java @@ -0,0 +1,197 @@ +package com.github.gtache.autosubtitle.subtitle.impl; + +import com.github.gtache.autosubtitle.Language; +import com.github.gtache.autosubtitle.VideoInfo; +import com.github.gtache.autosubtitle.archive.Archiver; +import com.github.gtache.autosubtitle.archive.ArchiverProvider; +import com.github.gtache.autosubtitle.subtitle.SubtitleCollection; +import com.github.gtache.autosubtitle.subtitle.SubtitleImporterExporter; +import com.github.gtache.autosubtitle.subtitle.converter.ParseException; +import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverter; +import com.github.gtache.autosubtitle.subtitle.converter.SubtitleConverterProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Set; + +import static java.util.Objects.requireNonNull; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class TestSubtitleImporterExporterImpl { + + private final ArchiverProvider archiverProvider; + private final SubtitleConverterProvider converterProvider; + private final SubtitleImporterExporter subtitleImporterExporter; + private final VideoInfo videoInfo; + private final Path path; + private final SubtitleCollection firstCollection; + private final SubtitleCollection secondCollection; + + TestSubtitleImporterExporterImpl(@Mock final ArchiverProvider archiverProvider, + @Mock final SubtitleConverterProvider converterProvider, + @Mock final VideoInfo videoInfo, + @Mock final SubtitleCollection firstCollection, + @Mock final SubtitleCollection secondCollection) { + this.archiverProvider = requireNonNull(archiverProvider); + this.converterProvider = requireNonNull(converterProvider); + this.videoInfo = requireNonNull(videoInfo); + this.subtitleImporterExporter = new SubtitleImporterExporterImpl(archiverProvider, converterProvider); + this.path = Paths.get("out.out"); + this.firstCollection = requireNonNull(firstCollection); + this.secondCollection = requireNonNull(secondCollection); + } + + @Test + void testImportSubtitlesArchive() throws IOException, ParseException { + final var archiver = mock(Archiver.class); + when(archiverProvider.getArchiver("out")).thenReturn(archiver); + doAnswer(i -> { + final var outDir = i.getArgument(1, Path.class); + final var f1 = outDir.resolve("out.srt"); + final var f2 = outDir.resolve("out.ass"); + Files.createFile(f1); + Files.createFile(f2); + return null; + }).when(archiver).decompress(eq(path), any()); + + final var converter1 = mock(SubtitleConverter.class); + when(converterProvider.getConverter("srt")).thenReturn(converter1); + final var converter2 = mock(SubtitleConverter.class); + when(converterProvider.getConverter("ass")).thenReturn(converter2); + + final var s1 = new SubtitleImpl("test", 0, 100, null, null); + final var s2 = new SubtitleImpl("test2", 100, 200, null, null); + final var subtitles = List.of(s1, s2); + when(firstCollection.subtitles()).thenReturn(subtitles); + when(firstCollection.text()).thenReturn("text"); + when(firstCollection.language()).thenReturn(Language.EN); + when(converter1.parse(any(Path.class))).thenReturn(firstCollection); + + final var s3 = new SubtitleImpl("test3", 0, 100, null, null); + final var s4 = new SubtitleImpl("test4", 100, 200, null, null); + final var subtitles2 = List.of(s3, s4); + when(secondCollection.subtitles()).thenReturn(subtitles2); + when(secondCollection.text()).thenReturn("text2"); + when(secondCollection.language()).thenReturn(Language.FR); + when(converter2.parse(any(Path.class))).thenReturn(secondCollection); + + final var result = subtitleImporterExporter.importSubtitles(path); + + assertEquals(2, result.size()); + final var collection1 = result.get(Language.EN); + assertEquals("text", collection1.text()); + assertEquals(subtitles, collection1.subtitles()); + assertEquals(Language.EN, collection1.language()); + final var collection2 = result.get(Language.FR); + assertEquals("text2", collection2.text()); + assertEquals(subtitles2, collection2.subtitles()); + assertEquals(Language.FR, collection2.language()); + } + + @Test + void testImportSubtitlesSingle() throws IOException, ParseException { + final var converter = mock(SubtitleConverter.class); + when(converterProvider.getConverter("out")).thenReturn(converter); + when(converter.parse(path)).thenReturn(firstCollection); + final var s1 = new SubtitleImpl("test", 0, 100, null, null); + final var s2 = new SubtitleImpl("test2", 100, 200, null, null); + final var subtitles = List.of(s1, s2); + when(firstCollection.subtitles()).thenReturn(subtitles); + when(firstCollection.text()).thenReturn("text"); + when(firstCollection.language()).thenReturn(Language.EN); + + final var result = subtitleImporterExporter.importSubtitles(path); + + assertEquals(1, result.size()); + final var collection = result.get(Language.EN); + assertEquals("text", collection.text()); + assertEquals(subtitles, collection.subtitles()); + assertEquals(Language.EN, collection.language()); + } + + @Test + void testImportSubtitlesSingleParseException() throws IOException, ParseException { + assertThrows(ParseException.class, () -> subtitleImporterExporter.importSubtitles(path)); + } + + @Test + void testExportSubtitlesArchive(@TempDir final Path outputDir) throws IOException, ParseException { + final var outputPath = outputDir.resolve("out.out"); + final var collection = List.of(firstCollection, secondCollection); + final var archiver = mock(Archiver.class); + when(archiverProvider.getArchiver("out")).thenReturn(archiver); + final var converter = mock(SubtitleConverter.class); + when(converterProvider.getConverter("json")).thenReturn(converter); + when(firstCollection.language()).thenReturn(Language.EN); + when(secondCollection.language()).thenReturn(Language.FR); + when(converter.format(firstCollection, videoInfo)).thenReturn("en"); + when(converter.format(secondCollection, videoInfo)).thenReturn("fr"); + + subtitleImporterExporter.exportSubtitles(collection, videoInfo, outputPath); + + verify(converter).format(collection.get(0), videoInfo); + verify(converter).format(collection.get(1), videoInfo); + final var captor = ArgumentCaptor.forClass(List.class); + verify(archiver).compress(captor.capture(), eq(outputPath)); + final var files = (List) captor.getValue(); + assertEquals(2, files.size()); + assertTrue(files.stream().anyMatch(p -> p.getFileName().toString().equals("en.json"))); + assertTrue(files.stream().anyMatch(p -> p.getFileName().toString().equals("fr.json"))); + } + + @Test + void testExportSubtitlesSingle(@TempDir final Path outputDir) throws IOException { + final var outputPath = outputDir.resolve("out.out"); + final var collection = List.of(firstCollection); + final var converter = mock(SubtitleConverter.class); + when(converterProvider.getConverter("out")).thenReturn(converter); + final var expected = "expected"; + when(converter.format(collection.getFirst(), videoInfo)).thenReturn(expected); + subtitleImporterExporter.exportSubtitles(collection, videoInfo, outputPath); + assertEquals(expected, Files.readString(outputPath)); + } + + @Test + void testExportSubtitlesSingleException() { + final var collection = List.of(firstCollection); + assertThrows(IOException.class, () -> subtitleImporterExporter.exportSubtitles(collection, videoInfo, path)); + } + + @Test + void testExportSubtitlesMultipleException() { + assertThrows(IllegalArgumentException.class, () -> subtitleImporterExporter.exportSubtitles(List.of(firstCollection, secondCollection), videoInfo, path)); + } + + @Test + void testSupportedArchiveExtensions() { + final var zip = mock(Archiver.class); + final var rar = mock(Archiver.class); + when(zip.archiveExtension()).thenReturn("zip"); + when(rar.archiveExtension()).thenReturn("rar"); + when(archiverProvider.allArchivers()).thenReturn(Set.of(zip, rar)); + final var extensions = subtitleImporterExporter.supportedArchiveExtensions(); + assertEquals(Set.of("zip", "rar"), extensions); + } + + @Test + void testSupportedSingleFileExtensions() { + final var zip = mock(SubtitleConverter.class); + final var rar = mock(SubtitleConverter.class); + when(zip.formatName()).thenReturn("zip"); + when(rar.formatName()).thenReturn("rar"); + when(converterProvider.allConverters()).thenReturn(Set.of(zip, rar)); + final var extensions = subtitleImporterExporter.supportedSingleFileExtensions(); + assertEquals(Set.of("zip", "rar"), extensions); + } +}