diff --git a/pom.xml b/pom.xml index f739365..4038330 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ MKVAudioSubtileChanger MKVAudioSubtitleChanger - 2.1 + 3.0 clean package @@ -117,7 +117,7 @@ org.projectlombok lombok - 1.18.8 + 1.18.24 provided @@ -155,7 +155,7 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml - 2.13.1 + 2.13.4 com.fasterxml.jackson.core @@ -182,20 +182,26 @@ org.junit.jupiter junit-jupiter-api - 5.4.2 + 5.9.0 test org.junit.jupiter junit-jupiter-engine - 5.4.2 + 5.9.0 test org.mockito mockito-all - 1.9.5 + 1.10.19 + test + + + org.junit.jupiter + junit-jupiter-params + 5.9.0 test diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java index 99a7681..c009087 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/AttributeUpdaterKernel.java @@ -24,7 +24,7 @@ import java.util.stream.Collectors; @Log4j2 public class AttributeUpdaterKernel { - private final ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreadCount()); + private final ExecutorService executor = Executors.newFixedThreadPool(Config.getInstance().getThreads()); private final FileCollector collector; private final FileProcessor processor; private final ResultStatistic statistic = new ResultStatistic(); @@ -43,7 +43,7 @@ public class AttributeUpdaterKernel { .map(collector::loadFiles) .flatMap(Collection::stream) .collect(Collectors.toList()); - List files = collector.loadFiles(Config.getInstance().getLibraryPath()).stream() + List files = collector.loadFiles(Config.getInstance().getLibraryPath().getAbsolutePath()).stream() .filter(file -> !excludedFiles.contains(file)) .collect(Collectors.toList()); progressBar.maxHint(files.size()); @@ -68,9 +68,9 @@ public class AttributeUpdaterKernel { processor.update(file, fileInfo); statistic.success(); log.info("Updated {}", file.getAbsolutePath()); - } catch (IOException e) { + } catch (IOException | RuntimeException e) { statistic.failedChanging(); - log.warn("File couldn't be updated: {}", file.getAbsoluteFile()); + log.warn("File couldn't be updated: '{}', Error: {}", file.getAbsoluteFile(), e.getMessage().replaceAll("\\r|\\n", " ")); } } } else if (fileInfo.isUnableToApplyConfig()) { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java index 6e26216..efd6077 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/Main.java @@ -1,6 +1,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger; import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ConfigLoader; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileProcessor; import lombok.extern.log4j.Log4j2; @@ -8,7 +9,7 @@ import lombok.extern.log4j.Log4j2; @Log4j2 public class Main { public static void main(String[] args) { - Config.getInstance().initConfig(args); + ConfigLoader.initConfig(args); AttributeUpdaterKernel kernel = new AttributeUpdaterKernel(new MkvFileCollector(), new MkvFileProcessor()); kernel.execute(); } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java index 5e66832..536830c 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/Config.java @@ -2,223 +2,83 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix; -import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.VersionUtil; -import at.pcgamingfreaks.yaml.YAML; -import at.pcgamingfreaks.yaml.YamlInvalidContentException; import lombok.AccessLevel; import lombok.Getter; -import lombok.SneakyThrows; +import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.extern.log4j.Log4j2; -import org.apache.commons.cli.*; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Function; +import java.util.*; import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; -import java.util.stream.Collectors; - -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; -import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid; @Log4j2 @Getter +@Setter +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class Config { + @Getter(AccessLevel.NONE) + @Setter(AccessLevel.NONE) + private static Config config = null; @Getter(AccessLevel.NONE) CommandLineParser parser = new DefaultParser(); @Getter(AccessLevel.NONE) HelpFormatter formatter = new HelpFormatter(); - - @Getter(AccessLevel.NONE) - private static Config config = null; - private File configPath; - private String libraryPath; - private boolean isSafeMode; - - private int threadCount; - private Pattern includePattern; + private File libraryPath; @Getter(AccessLevel.NONE) - private String mkvToolNixPath; + private File mkvToolNix; - private boolean isWindows; + private int threads; + private Pattern includePattern; + private boolean safeMode; - private final Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs")); - private final Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); - private final Set excludedDirectories = new HashSet<>(); + private Set forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs")); + private Set commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); + private Set excludedDirectories = new HashSet<>(); private List attributeConfig; public static Config getInstance() { - if (config == null) { + return getInstance(false); + } + + public static Config getInstance(boolean reset) { + if (config == null || reset) { config = new Config(); } return config; } - public void initConfig(String[] args) throws InvalidConfigException { - ConfigErrors errors = new ConfigErrors(); - CommandLine cmd = null; - Options options = initOptions(); - - try { - cmd = parser.parse(options, args); - if (cmd == null) throw new NullPointerException(); - } catch (ParseException | NullPointerException e) { - formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ", - "\nParameters:", options, - "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues"); - System.exit(1); - } - - exitIfHelp(cmd, options); - exitIfVersion(cmd); - - configPath = loadConfigPath(cmd, errors); - libraryPath = loadLibraryPath(cmd, errors); - isSafeMode = cmd.hasOption(SAFE_MODE.prop()); - - try (YAML config = new YAML(configPath)) { - threadCount = loadThreadCount(cmd, config); - includePattern = loadIncludePattern(cmd, config, errors); - mkvToolNixPath = loadMkvToolNixPath(cmd, config, errors); - - isWindows = loadOperatingSystem(); - - loadForcedKeywords(cmd, config); - loadExcludedDirectories(cmd, config); - - attributeConfig = loadAttributeConfig(config, errors); - } catch (IOException | YamlInvalidContentException ignored) {} - - if (errors.hasErrors()) { - throw new InvalidConfigException(errors); - } + /** + * Get path to specific mkvtoolnix application. + * + * @return absolute path to desired application. + */ + public String getPathFor(MkvToolNix application) { + return mkvToolNix.getAbsolutePath().endsWith("/") ? mkvToolNix.getAbsolutePath() + application : + mkvToolNix.getAbsolutePath() + "/" + application; } - private static Options initOptions() { - Options options = new Options(); - options.addOption(optionOf(HELP, "h", false)); - options.addOption(optionOf(VERSION, "v", false)); - options.addOption(optionOf(LIBRARY, "l", true)); - options.addOption(optionOf(MKV_TOOL_NIX, "m", true)); - options.addOption(optionOf(CONFIG_PATH, "c", true)); - options.addOption(optionOf(THREADS, "t", true)); - options.addOption(optionOf(SAFE_MODE, "s", false)); - options.addOption(optionOf(FORCED_KEYWORDS, "k", Option.UNLIMITED_VALUES, false)); - options.addOption(optionOf(EXCLUDE_DIRECTORY, "e", Option.UNLIMITED_VALUES, false)); - options.addOption(optionOf(INCLUDE_PATTERN, "i", true)); - return options; - } - - private void exitIfHelp(CommandLine cmd, Options options) { - if (cmd.hasOption("help")) { - formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ", - "\nParameters:", options, - "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues"); - System.exit(0); - } - } - - private void exitIfVersion(CommandLine cmd) { - if (cmd.hasOption(VERSION.prop())) { - System.out.printf("MKV Audio Subtitle Changer Version %s%n", VersionUtil.getVersion()); - System.exit(0); - } - } - - private File loadConfigPath(CommandLine cmd, ConfigErrors errors) { - File configPath = new File(cmd.getOptionValue(CONFIG_PATH.prop(), "config.yaml")); - if (configPath.isFile()) return configPath; - - errors.add("invalid config path"); - return null; - } - - private String loadLibraryPath(CommandLine cmd, ConfigErrors errors) { - if (cmd.hasOption(LIBRARY.prop())) { - File libraryPath = new File(cmd.getOptionValue(LIBRARY.prop())); - if (libraryPath.isFile() || libraryPath.isDirectory()) { - return libraryPath.getAbsolutePath(); - } else { - errors.add("invalid library path"); - } - } else { - errors.add("missing library path"); - } - return null; - } - - private int loadThreadCount(CommandLine cmd, YAML config) { - return cmd.hasOption(THREADS.prop()) - ? Integer.parseInt(cmd.getOptionValue(THREADS.prop())) - : config.getInt(THREADS.prop(), 2); - } - - private Pattern loadIncludePattern(CommandLine cmd, YAML config, ConfigErrors errors) { - try { - return Pattern.compile(cmd.hasOption(INCLUDE_PATTERN.prop()) - ? cmd.getOptionValue(INCLUDE_PATTERN.prop()) - : config.getString(INCLUDE_PATTERN.prop(), ".*")); - } catch (PatternSyntaxException e) { - errors.add("invalid regex pattern"); - } - return null; - } - - @SneakyThrows - private String loadMkvToolNixPath(CommandLine cmd, YAML config, ConfigErrors errors){ - if (cmd.hasOption(MKV_TOOL_NIX.prop())) return cmd.getOptionValue(MKV_TOOL_NIX.prop()); - if (config.isSet(MKV_TOOL_NIX.prop())) return config.getString(MKV_TOOL_NIX.prop()); - errors.add("path to mkv tool nix installation missing"); - return null; - } - - private boolean loadOperatingSystem() { - return System.getProperty("os.name").toLowerCase().contains("windows"); - } - - @SneakyThrows - private void loadForcedKeywords(CommandLine cmd, YAML config) { - if (cmd.hasOption(FORCED_KEYWORDS.prop())) forcedKeywords.addAll(List.of(cmd.getOptionValues(FORCED_KEYWORDS.prop()))); - if (config.isSet(FORCED_KEYWORDS.prop())) forcedKeywords.addAll(config.getStringList(FORCED_KEYWORDS.prop())); - } - - @SneakyThrows - private void loadExcludedDirectories(CommandLine cmd, YAML config) { - if (cmd.hasOption(EXCLUDE_DIRECTORY.prop())) excludedDirectories.addAll(List.of(cmd.getOptionValues(EXCLUDE_DIRECTORY.prop()))); - if (config.isSet(EXCLUDE_DIRECTORY.prop())) excludedDirectories.addAll(config.getStringList(EXCLUDE_DIRECTORY.prop())); - } - - private List loadAttributeConfig(YAML config, ConfigErrors errors) { - Function audio = key -> config.getString(key + ".audio", null); - Function subtitle = key -> config.getString(key + ".subtitle", null); - - List attributeConfigs = config.getKeysFiltered(".*audio.*").stream() - .sorted() - .map(key -> key.replace(".audio", "")) - .map(key -> new AttributeConfig(audio.apply(key), subtitle.apply(key))) - .collect(Collectors.toList()); - - if (attributeConfigs.isEmpty()) { - errors.add("no language configuration"); - } else { - for (AttributeConfig attributeConfig : attributeConfigs) { - isLanguageValid(attributeConfig.getAudioLanguage(), errors); - isLanguageValid(attributeConfig.getSubtitleLanguage(), errors); - } - } - - return attributeConfigs; - } - - public String getPathFor(MkvToolNix exe) { - return mkvToolNixPath.endsWith("/") ? mkvToolNixPath + exe : mkvToolNixPath + "/" + exe; + @Override + public String toString() { + return new StringJoiner(", ", Config.class.getSimpleName() + "[", "]") + .add("parser=" + parser).add("\n") + .add("formatter=" + formatter).add("\n") + .add("configPath=" + configPath).add("\n") + .add("libraryPath=" + libraryPath).add("\n") + .add("isSafeMode=" + safeMode).add("\n") + .add("forcedKeywords=" + forcedKeywords).add("\n") + .add("commentaryKeywords=" + commentaryKeywords).add("\n") + .add("excludedDirectories=" + excludedDirectories).add("\n") + .add("threadCount=" + threads).add("\n") + .add("includePattern=" + includePattern).add("\n") + .add("mkvToolNixPath='" + mkvToolNix + "'").add("\n") + .add("attributeConfig=" + attributeConfig) + .toString(); } } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigErrors.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigErrors.java deleted file mode 100644 index 50cecae..0000000 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigErrors.java +++ /dev/null @@ -1,22 +0,0 @@ -package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; - -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.List; - -public class ConfigErrors { - private final List errors = new ArrayList<>(); - - public void add(String errorMessage) { - errors.add(errorMessage); - } - - public boolean hasErrors() { - return !errors.isEmpty(); - } - - public String toString() { - return StringUtils.capitalize(String.join(", ", errors)); - } -} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java new file mode 100644 index 0000000..df22e31 --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ConfigLoader.java @@ -0,0 +1,106 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator.*; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.VersionUtil; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.*; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; + +public class ConfigLoader { + private static final List> VALIDATORS = List.of( + new ConfigPathValidator(CONFIG_PATH, true, Path.of("./config.yaml").toFile()), + new PathValidator(LIBRARY, true, null), + new ThreadValidator(THREADS, false, 2), + new MkvToolNixPathValidator(MKV_TOOL_NIX, true, Path.of("C:\\Program Files\\MKVToolNix").toFile()), + new BooleanValidator(SAFE_MODE, false), + new PatternValidator(INCLUDE_PATTERN, false, Pattern.compile(".*")), + new SetValidator(FORCED_KEYWORDS, false, true), + new SetValidator(COMMENTARY_KEYWORDS, false, true), + new SetValidator(EXCLUDE_DIRECTORY, false, true), + new AttributeConfigValidator() + ); + + public static void initConfig(String[] args) { + HelpFormatter formatter = new HelpFormatter(); + YAML yamlConfig = null; + + Options options = initOptions(); + CommandLine cmd = parseCommandLineArgs(formatter, options, args); + + exitIfHelp(cmd, options, formatter); + exitIfVersion(cmd); + + List results = new ArrayList<>(); + + for (ConfigValidator validator: VALIDATORS) { + results.add(validator.validate(yamlConfig, cmd)); + if (yamlConfig == null && Config.getInstance().getConfigPath() != null) { + try { + yamlConfig = Config.getInstance().getConfigPath() != null + ? new YAML(Config.getInstance().getConfigPath()) + : new YAML(""); + } catch (IOException | YamlInvalidContentException ignored) {} + } + } + + if (results.contains(ValidationResult.INVALID)) System.exit(1); + System.out.println(); + } + + private static Options initOptions() { + Options options = new Options(); + options.addOption(optionOf(HELP, HELP.abrv(), HELP.args())); + options.addOption(optionOf(VERSION, VERSION.abrv(), VERSION.args())); + options.addOption(optionOf(LIBRARY, LIBRARY.abrv(), LIBRARY.args() )); + options.addOption(optionOf(MKV_TOOL_NIX, MKV_TOOL_NIX.abrv(), MKV_TOOL_NIX.args() )); + options.addOption(optionOf(CONFIG_PATH, CONFIG_PATH.abrv(), CONFIG_PATH.args() )); + options.addOption(optionOf(THREADS, THREADS.abrv(), THREADS.args())); + options.addOption(optionOf(SAFE_MODE, SAFE_MODE.abrv(), SAFE_MODE.args() )); + options.addOption(optionOf(FORCED_KEYWORDS, FORCED_KEYWORDS.abrv(), FORCED_KEYWORDS.args())); + options.addOption(optionOf(EXCLUDE_DIRECTORY, FORCED_KEYWORDS.abrv(), FORCED_KEYWORDS.args())); + options.addOption(optionOf(INCLUDE_PATTERN, INCLUDE_PATTERN.abrv(), INCLUDE_PATTERN.args())); + return options; + } + + private static CommandLine parseCommandLineArgs(HelpFormatter formatter, Options options, String[] args) { + CommandLineParser parser = new DefaultParser(); + + try { + CommandLine cmd = parser.parse(options, args); + if (cmd == null) throw new NullPointerException(); + return cmd; + } catch (ParseException | NullPointerException e) { + formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ", + "\nParameters:", options, + "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues"); + System.exit(1); + } + return null; // can't be reached + } + + private static void exitIfHelp(CommandLine cmd, Options options, HelpFormatter formatter) { + if (cmd.hasOption("help")) { + formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l ", + "\nParameters:", options, + "\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues"); + System.exit(0); + } + } + + private static void exitIfVersion(CommandLine cmd) { + if (cmd.hasOption(VERSION.prop())) { + System.out.printf("MKV Audio Subtitle Changer Version %s%n", VersionUtil.getVersion()); + System.exit(0); + } + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/InvalidConfigException.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/InvalidConfigException.java deleted file mode 100644 index 9a42eb9..0000000 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/InvalidConfigException.java +++ /dev/null @@ -1,7 +0,0 @@ -package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; - -public class InvalidConfigException extends RuntimeException{ - public InvalidConfigException(ConfigErrors errors) { - super("Errors in config: " + errors); - } -} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java new file mode 100644 index 0000000..5ac257e --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/ValidationResult.java @@ -0,0 +1,9 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; + +public enum ValidationResult { + VALID, + DEFAULT, + NOT_PRESENT, + MISSING, + INVALID; +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java new file mode 100644 index 0000000..2166a18 --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidator.java @@ -0,0 +1,78 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import org.apache.commons.cli.CommandLine; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid; + +public class AttributeConfigValidator extends ConfigValidator> { + + public AttributeConfigValidator() { + super(ConfigProperty.ATTRIBUTE_CONFIG, true, null); + } + + /** + * {@inheritDoc} + */ + public ValidationResult validate(YAML yaml, CommandLine cmd) { + System.out.printf("%s: ", property.prop()); + List result; + + Function audio = key -> yaml.getString(key + ".audio", null); + Function subtitle = key -> yaml.getString(key + ".subtitle", null); + + if (yaml.getKeysFiltered(property.prop() + ".*").size() > 0) { + result = yaml.getKeysFiltered(".*audio.*").stream() + .sorted() + .map(key -> key.replace(".audio", "")) + .map(key -> new AttributeConfig(audio.apply(key), subtitle.apply(key))) + .collect(Collectors.toList()); + } else if (required) { + System.out.println("missing"); + return ValidationResult.MISSING; + } else { + System.out.println("ok"); + return ValidationResult.NOT_PRESENT; + } + + if (!isValid(result) || !setValue(result)) { + System.out.println("invalid"); + return ValidationResult.INVALID; + } + + System.out.println("ok"); + return ValidationResult.VALID; + } + + /** + * {@inheritDoc} + */ + @Override + List parse(String value) { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + boolean isValid(List result) { + if (result.isEmpty()) { + return false; + } + boolean isValid = true; + for (AttributeConfig attributeConfig : result) { + isValid = isLanguageValid(attributeConfig.getAudioLanguage()) + && isLanguageValid(attributeConfig.getSubtitleLanguage()); + if (!isValid) return false; + } + return true; + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java new file mode 100644 index 0000000..d192e25 --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidator.java @@ -0,0 +1,63 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlKeyNotFoundException; +import org.apache.commons.cli.CommandLine; + +import java.util.List; +import java.util.Optional; +import java.util.function.BiFunction; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.ARGUMENTS; + +public class BooleanValidator extends ConfigValidator { + + public BooleanValidator(ConfigProperty property, boolean required) { + super(property, required, null); + } + + /** + * {@inheritDoc} + */ + protected BiFunction> provideDataYaml() { + return (yaml, property) -> { + if (yaml.isSet(ARGUMENTS.prop()) + && yaml.getStringList(ARGUMENTS.prop(), List.of()).contains(property.prop())) { + return Optional.of(true); + } + return Optional.empty(); + }; + } + + /** + * {@inheritDoc} + */ + protected BiFunction> provideDataCmd() { + return (cmd, property) -> { + if (cmd.hasOption(property.prop())) { + return Optional.of(true); + } + return Optional.empty(); + }; + } + + /** + * {@inheritDoc} + * This should not be used. + */ + @Override + Boolean parse(String value) { + throw new RuntimeException("This should not be called"); + } + + /** + * {@inheritDoc} + * Validation is skipped. + */ + @Override + boolean isValid(Boolean result) { + return true; // skip + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java new file mode 100644 index 0000000..54422f3 --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidator.java @@ -0,0 +1,30 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; + +import java.io.File; +import java.util.Optional; +import java.util.function.BiFunction; + +public class ConfigPathValidator extends PathValidator { + public ConfigPathValidator(ConfigProperty property, boolean required, File defaultValue) { + super(property, required, defaultValue); + } + + /** + * {@inheritDoc} + */ + @Override + protected BiFunction> provideDataYaml() { + return (yaml, property) -> Optional.empty(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean isValid(File result) { + return super.isValid(result) && (result.getAbsolutePath().endsWith(".yml") || result.getAbsolutePath().endsWith(".yaml")); + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java new file mode 100644 index 0000000..0aa4fc3 --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigValidator.java @@ -0,0 +1,149 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlKeyNotFoundException; +import lombok.RequiredArgsConstructor; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public abstract class ConfigValidator { + protected final ConfigProperty property; + protected final boolean required; + protected final FieldType defaultValue; + + /** + * Validate the user input. Parameters of cmd are prioritised. + * + * @param yaml config file + * @param cmd command line parameters + * @return {@link ValidationResult} containing validity of input. + */ + public ValidationResult validate(YAML yaml, CommandLine cmd) { + System.out.printf("%s: ", property.prop()); + FieldType result; + + Optional cmdResult = provideDataCmd().apply(cmd, property); + Optional yamlResult = provideDataYaml().apply(yaml, property); + + if (cmdResult.isPresent()) { + result = cmdResult.get(); + } else if (yamlResult.isPresent()) { + result = yamlResult.get(); + } else { + if (defaultValue != null) { + if (setValue(defaultValue)) { + System.out.println("default"); + return ValidationResult.DEFAULT; + } else { + System.out.println("invalid"); + return ValidationResult.INVALID; + } + } + if (required) { + System.out.println("missing"); + return ValidationResult.MISSING; + } else { + System.out.println("ok"); + return ValidationResult.NOT_PRESENT; + } + } + + if (!isValid(result) || !setValue(result)) { + System.out.println("invalid"); + return ValidationResult.INVALID; + } + + System.out.println("ok"); + return ValidationResult.VALID; + } + + /** + * @return parsed input of yaml config for property + */ + protected BiFunction> provideDataYaml() { + return (yaml, property) -> { + if (yaml.isSet(property.prop())) { + try { + return Optional.of(parse(yaml.getString(property.prop()))); + } catch (YamlKeyNotFoundException e) { + throw new RuntimeException(e); + } + } + return Optional.empty(); + }; + } + + /** + * @return parsed input of command line parameters config for property + */ + protected BiFunction> provideDataCmd() { + return (cmd, property) -> { + if (cmd.hasOption(property.prop())) { + return Optional.of(parse(cmd.getOptionValue(property.prop()))); + } + return Optional.empty(); + }; + } + + /** + * Parse input parameter to desired format. + * + * @param value input parameter + * @return parsed property + */ + abstract FieldType parse(String value); + + /** + * Validate if the data has the desired and allowed format. + * + * @param result parsed property + * @return true if data is in desired format. + */ + abstract boolean isValid(FieldType result); + + /** + * Sets valid properties to {@link Config} via reflections. + * + * @param result parsed property + * @return false if method invocation failed + */ + protected boolean setValue(FieldType result) { + List methods = Arrays.stream(Config.getInstance().getClass().getDeclaredMethods()) + .filter(containsSetterOf(property)) + .collect(Collectors.toList()); + if (methods.size() != 1) { + return false; + } + try { + methods.get(0).invoke(Config.getInstance(), result); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return true; + } + + protected Predicate containsSetterOf(ConfigProperty property) { + return method -> StringUtils.containsIgnoreCase(method.getName(), "set") + && StringUtils.containsIgnoreCase(method.getName(), property.prop().replace("-", "")); + } + + protected Predicate containsGetterOf(ConfigProperty property) { + return method -> StringUtils.containsIgnoreCase(method.getName(), "get") + && StringUtils.containsIgnoreCase(method.getName(), property.prop().replace("-", "")); + } + + +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java new file mode 100644 index 0000000..4095921 --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidator.java @@ -0,0 +1,26 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; + +import java.io.File; +import java.nio.file.Path; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_MERGER; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_PROP_EDIT; + +public class MkvToolNixPathValidator extends PathValidator { + private static final String EXE = ".exe"; + + public MkvToolNixPathValidator(ConfigProperty property, boolean required, File defaultValue) { + super(property, required, defaultValue); + } + + @Override + protected boolean isValid(File result) { + return result.isDirectory() + && (Path.of(result.getAbsolutePath() + "/" + MKV_MERGER + EXE).toFile().isFile() + && Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT + EXE).toFile().isFile()) + || (Path.of(result.getAbsolutePath() + "/" + MKV_MERGER).toFile().isFile() + && Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT).toFile().isFile()); + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java new file mode 100644 index 0000000..3cc712d --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidator.java @@ -0,0 +1,30 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; + +import java.io.File; +import java.nio.file.Path; + +public class PathValidator extends ConfigValidator { + + public PathValidator(ConfigProperty property, boolean required, File defaultValue) { + super(property, required, defaultValue); + } + + /** + * {@inheritDoc} + */ + @Override + protected File parse(String value) { + return Path.of(value).toFile(); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean isValid(File result) { + return result.isDirectory() || result.isFile(); + } + +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java new file mode 100644 index 0000000..d2c0f1e --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidator.java @@ -0,0 +1,34 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class PatternValidator extends ConfigValidator { + private static final Pattern EMPTY_PATTERN = Pattern.compile(""); + + public PatternValidator(ConfigProperty property, boolean required, Pattern defaultValue) { + super(property, required, defaultValue); + } + + /** + * {@inheritDoc} + */ + @Override + Pattern parse(String value) { + try { + return Pattern.compile(value); + } catch (PatternSyntaxException e) { + return EMPTY_PATTERN; + } + } + + /** + * {@inheritDoc} + */ + @Override + boolean isValid(Pattern result) { + return !result.equals(EMPTY_PATTERN); + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java new file mode 100644 index 0000000..796513f --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidator.java @@ -0,0 +1,111 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlKeyNotFoundException; +import org.apache.commons.cli.CommandLine; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +public class SetValidator extends ConfigValidator> { + private final boolean append; + + public SetValidator(ConfigProperty property, boolean required, boolean append) { + super(property, required, null); + this.append = append; + } + + public ValidationResult validate(YAML yaml, CommandLine cmd) { + System.out.printf("%s: ", property.prop()); + List resultList = null; + + if (cmd.hasOption(property.prop())) { + resultList = List.of(cmd.getOptionValues(property.prop())); + } else if (yaml.isSet(property.prop())) { + try { + resultList = yaml.getStringList(property.prop()); + } catch (YamlKeyNotFoundException ignored) {} + } else if (required) { + System.out.println("missing"); + return ValidationResult.MISSING; + } else { + System.out.println("ok"); + return ValidationResult.NOT_PRESENT; + } + + Set result = parse(resultList); + + if (!isValid(result) || !setValue(result)) { + System.out.println("invalid"); + return ValidationResult.INVALID; + } + + System.out.println("ok"); + return ValidationResult.VALID; + } + + protected BiFunction>> provideDataYaml() { + return (yaml, property) -> { + if (yaml.isSet(property.prop())) { + try { + return Optional.of(parse(yaml.getStringList(property.prop()))); + } catch (YamlKeyNotFoundException ignored) { + } + } + return Optional.empty(); + }; + } + + protected BiFunction>> provideDataCmd() { + return (cmd, property) -> { + if (cmd.hasOption(property.prop())) { + return Optional.of(parse(List.of(cmd.getOptionValues(property.prop())))); + } + return Optional.empty(); + }; + } + + @Override + Set parse(String value) { + throw new RuntimeException("This should not be called"); + } + + protected Set parse(List value) { + return new HashSet<>(value); + } + + @Override + boolean isValid(Set result) { + return true; + } + + @SuppressWarnings("unchecked") + protected boolean setValue(Set result) { + List methods = append + ? Arrays.stream(Config.getInstance().getClass().getDeclaredMethods()) + .filter(containsGetterOf(property)) + .collect(Collectors.toList()) + : Arrays.stream(Config.getInstance().getClass().getDeclaredMethods()) + .filter(containsSetterOf(property)) + .collect(Collectors.toList()); + if (methods.size() != 1) { + return false; + } + try { + if (append) { + ((Set) methods.get(0).invoke(Config.getInstance())).addAll(result); + } else { + methods.get(0).invoke(Config.getInstance(), result); + } + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return true; + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java new file mode 100644 index 0000000..8d3e5cb --- /dev/null +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidator.java @@ -0,0 +1,26 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import org.apache.commons.lang3.math.NumberUtils; + +public class ThreadValidator extends ConfigValidator{ + public ThreadValidator(ConfigProperty property, boolean required, Integer defaultValue) { + super(property, required, defaultValue); + } + + /** + * {@inheritDoc} + */ + @Override + Integer parse(String value) { + return NumberUtils.isParsable(value) ? Integer.parseInt(value) : defaultValue; + } + + /** + * {@inheritDoc} + */ + @Override + boolean isValid(Integer result) { + return result > 0; + } +} diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java index 65bc848..0457d38 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/impl/MkvFileProcessor.java @@ -22,12 +22,12 @@ import static java.lang.String.format; @Log4j2 public class MkvFileProcessor implements FileProcessor { private final ObjectMapper mapper = new ObjectMapper(); - private final String[] forcedKeywords = new String[]{"forced", "signs"}; private static final String DISABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=0 "; private static final String ENABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=1 "; private static final String ENABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=1 "; + @SuppressWarnings("unchecked") @Override public List loadAttributes(File file) { Map jsonMap; @@ -90,7 +90,7 @@ public class MkvFileProcessor implements FileProcessor { return info; } - private void detectDefaultTracks(FileInfoDto info, List attributes, List nonForcedTracks) { + protected void detectDefaultTracks(FileInfoDto info, List attributes, List nonForcedTracks) { Set detectedForcedSubtitleLanes = new HashSet<>(); for (FileAttribute attribute : attributes) { if (attribute.isDefaultTrack() && AUDIO.equals(attribute.getType())) @@ -108,7 +108,7 @@ public class MkvFileProcessor implements FileProcessor { ); } - private void detectDesiredTracks(FileInfoDto info, List nonForcedTracks, List nonCommentaryTracks) { + protected void detectDesiredTracks(FileInfoDto info, List nonForcedTracks, List nonCommentaryTracks) { for (AttributeConfig config : Config.getInstance().getAttributeConfig()) { FileAttribute desiredAudio = null; FileAttribute desiredSubtitle = null; @@ -127,7 +127,7 @@ public class MkvFileProcessor implements FileProcessor { } @Override - public void update(File file, FileInfoDto fileInfo) throws IOException { + public void update(File file, FileInfoDto fileInfo) throws IOException, RuntimeException { StringBuilder sb = new StringBuilder(); sb.append(format("\"%s\" ", Config.getInstance().getPathFor(MkvToolNix.MKV_PROP_EDIT))); sb.append(format("\"%s\" ", file.getAbsolutePath())); @@ -154,6 +154,8 @@ public class MkvFileProcessor implements FileProcessor { } InputStream inputstream = Runtime.getRuntime().exec(sb.toString()).getInputStream(); - log.debug(IOUtils.toString(new InputStreamReader(inputstream))); + String output = IOUtils.toString(new InputStreamReader(inputstream)); + log.debug(output); + if (output.contains("Error")) throw new RuntimeException(output); } } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java index 3208cc6..53dd213 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/AttributeConfig.java @@ -4,6 +4,8 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.extern.log4j.Log4j2; +import java.util.Objects; + @Log4j2 @Getter @AllArgsConstructor @@ -11,6 +13,19 @@ public class AttributeConfig { private final String audioLanguage; private final String subtitleLanguage; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AttributeConfig that = (AttributeConfig) o; + return Objects.equals(audioLanguage, that.audioLanguage) && Objects.equals(subtitleLanguage, that.subtitleLanguage); + } + + @Override + public int hashCode() { + return Objects.hash(audioLanguage, subtitleLanguage); + } + @Override public String toString() { return "AttributeConfig{" diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java index 203b4b2..475f591 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ConfigProperty.java @@ -1,28 +1,64 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.model; import lombok.AllArgsConstructor; +import org.apache.commons.cli.Option; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; @AllArgsConstructor public enum ConfigProperty { - CONFIG_PATH("config", "Path to config file"), - LIBRARY("library", "Path to library"), - SAFE_MODE("safe-mode", "Test run (no files will be changes)"), - THREADS("threads", "thread count (default: 2)"), - INCLUDE_PATTERN("include-pattern", "Include files matching pattern"), - MKV_TOOL_NIX("mkvtoolnix", "Path to mkv tool nix installation"), - FORCED_KEYWORDS("forcedKeywords", "Additional keywords to identify forced tracks, combines with config file"), - EXCLUDE_DIRECTORY("exclude-directories", "Directories to be excluded, combines with config file"), - HELP("help", "\"for help this is\" - Yoda"), - VERSION("version", "Display version"); + CONFIG_PATH("config-path", "Path to config file", "p", 1), + LIBRARY("library", "Path to library", "l", 1), + SAFE_MODE("safe-mode", "Test run (no files will be changes)", "s", 0), + WINDOWS("windows", "Is operating system windows", null, 0), + THREADS("threads", "thread count (default: 2)", "t", 1), + INCLUDE_PATTERN("include-pattern", "Include files matching pattern", "i", 1), + MKV_TOOL_NIX("mkvtoolnix", "Path to mkv tool nix installation", "m", 1), + FORCED_KEYWORDS("forcedKeywords", "Additional keywords to identify forced tracks", "fk", Option.UNLIMITED_VALUES), + COMMENTARY_KEYWORDS("commentary-keywords", "Additional keywords to identify commentary tracks", "ck", Option.UNLIMITED_VALUES), + EXCLUDE_DIRECTORY("exclude-directories", "Directories to be excluded, combines with config file", "e", 1), + COHERENT("coherent", "Try to match whole series with same config", "c", 0), + HELP("help", "\"for help this is\" - Yoda", "h", 0), + VERSION("version", "Display version", "v", 0), + ARGUMENTS("arguments", "List of arguments", null, 0), + ATTRIBUTE_CONFIG("attribute-config", "Attribute config to decide which tracks to choose when", "a", 1); private final String property; private final String description; + private final String shortParameter; + private final int args; + + public String prop() { + return property; + } public String desc() { return description; } - public String prop() { - return property; + public String abrv() { + return shortParameter; + } + + public int args() { + return args; + } + + /* + * Verify at startup that there are no duplicated shortParameters. + */ + static { + Set shortParameters = new HashSet<>(); + for (String param: Arrays.stream(ConfigProperty.values()).map(ConfigProperty::abrv).collect(Collectors.toList())) { + if (shortParameters.contains(param)) { + throw new IllegalStateException("It is not allowed to have multiple properties with the same abbreviation!"); + } + if (param != null) { + shortParameters.add(param); + } + } } } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java index 5bf698b..0e6e853 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/MkvToolNix.java @@ -4,8 +4,8 @@ import lombok.AllArgsConstructor; @AllArgsConstructor public enum MkvToolNix { - MKV_MERGER("mkvmerge.exe"), - MKV_PROP_EDIT("mkvpropedit.exe"); + MKV_MERGER("mkvmerge"), + MKV_PROP_EDIT("mkvpropedit"); private final String file; diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java index 49a1974..99acefd 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/model/ResultStatistic.java @@ -12,7 +12,7 @@ public class ResultStatistic { "├─ No suitable config found: %s%n" + "├─ Already fit config: %s%n" + "└─ Failed: %s%n" + - "Runtime: %ss"; + "Runtime: %s"; private int filesTotal = 0; @@ -64,9 +64,26 @@ public class ResultStatistic { runtime = System.currentTimeMillis() - startTime; } + private String formatTimer() { + int seconds = (int) (runtime / 1000); + int minutes = seconds / 60; + int hours = minutes / 60; + int days = hours / 24; + + if (days >= 1) { + return String.format("%sd %sh %sm %ss", days, hours % 24, minutes % 60, seconds % 60); + } else if (hours >= 1) { + return String.format("%sh %sm %ss", hours, minutes % 60, seconds % 60); + } else if (minutes >= 1) { + return String.format("%sm %ss", minutes , seconds % 60); + } else { + return String.format("%ss", seconds % 60); + } + } + @Override public String toString() { return String.format(result, filesTotal, shouldChange, failedChanging, successfullyChanged, - noSuitableConfigFound, alreadyFits, failed, runtime / 1000); + noSuitableConfigFound, alreadyFits, failed, formatTimer()); } } diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java index 95607ac..3b887a8 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/CommandLineOptionsUtil.java @@ -4,8 +4,8 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import org.apache.commons.cli.Option; public class CommandLineOptionsUtil { - public static Option optionOf(ConfigProperty property, String opt, boolean hasArg) { - return optionOf(property, opt, hasArg ? 1 : 0, false); + public static Option optionOf(ConfigProperty property, String opt, int args) { + return optionOf(property, opt, args, false); } public static Option optionOf(ConfigProperty property, String opt, boolean hasArg, boolean required) { diff --git a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java index 1ba46b4..7613eea 100644 --- a/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java +++ b/src/main/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/LanguageValidatorUtil.java @@ -1,7 +1,5 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; -import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ConfigErrors; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -28,10 +26,4 @@ public class LanguageValidatorUtil { public static boolean isLanguageValid(String language) { return ISO3_LANGUAGES.contains(language); } - - public static void isLanguageValid(String language, ConfigErrors errors) { - if (!isLanguageValid(language)) { - errors.add(String.format("%s is not a valid language", language)); - } - } } diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java new file mode 100644 index 0000000..9427272 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/AttributeConfigValidatorTest.java @@ -0,0 +1,82 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static org.junit.jupiter.api.Assertions.*; + +class AttributeConfigValidatorTest { + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(ATTRIBUTE_CONFIG, ATTRIBUTE_CONFIG.abrv(), ATTRIBUTE_CONFIG.args())); + } + + @BeforeEach + void beforeEach() { + Config.getInstance(true); + } + + private static Stream provideTestCases() { + return Stream.of( + Arguments.of(attrConfYaml("jpn", "ger"), new String[]{}, VALID, attrConf("jpn", "ger")), + Arguments.of(attrConfYaml("jpn", "ger", "jpn", "eng"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "eng")), + Arguments.of(attrConfYaml("jpn", "ger", "jpn", "OFF"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "OFF")), + Arguments.of(attrConfYaml("jpn", "invalid"), new String[]{}, INVALID, null), + Arguments.of("", new String[]{}, MISSING, null) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(String yamlArgs, String[] cmdArgs, ValidationResult expectedResult, List expectedConfig) + throws ParseException, YamlInvalidContentException { + AttributeConfigValidator underTest = new AttributeConfigValidator(); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + assertIterableEquals(expectedConfig, Config.getInstance().getAttributeConfig()); + } + + private static String attrConfYaml(String... languages) { + StringBuilder yaml = new StringBuilder("attribute-config: "); + int counter = 0; + for (int i = 0; i < languages.length; i += 2) { + counter++; + yaml.append(String.format("\n %s:\n audio: %s\n subtitle: %s", counter, languages[0], languages[1])); + } + return yaml.toString(); + } + + private static List attrConf(String... languages) { + List conf = new ArrayList<>(); + for (int i = 0; i < languages.length; i += 2) { + conf.add(new AttributeConfig(languages[0], languages[1])); + } + return conf; + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java new file mode 100644 index 0000000..15411c6 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/BooleanValidatorTest.java @@ -0,0 +1,58 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.yamlList; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BooleanValidatorTest { + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(SAFE_MODE, SAFE_MODE.abrv(), SAFE_MODE.args())); + } + + private static Stream provideTestCases() { + return Stream.of( + Arguments.of(SAFE_MODE, false, "", new String[]{"-safe-mode"}, VALID), + Arguments.of(SAFE_MODE, true, "", new String[]{"-safe-mode"}, VALID), + Arguments.of(SAFE_MODE, false, "", new String[]{""}, NOT_PRESENT), + Arguments.of(SAFE_MODE, true, "", new String[]{""}, MISSING), + Arguments.of(SAFE_MODE, false, yamlList(ARGUMENTS, SAFE_MODE), new String[]{""}, VALID), + Arguments.of(SAFE_MODE, true, yamlList(ARGUMENTS, SAFE_MODE), new String[]{""}, VALID), + Arguments.of(SAFE_MODE, false, yamlList(ARGUMENTS, WINDOWS), new String[]{""}, NOT_PRESENT), + Arguments.of(SAFE_MODE, true, yamlList(ARGUMENTS, WINDOWS), new String[]{""}, MISSING) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(ConfigProperty property, boolean required, String yamlArgs, String[] cmdArgs, + ValidationResult expectedResult) throws ParseException, YamlInvalidContentException { + BooleanValidator underTest = new BooleanValidator(property, required); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidatorTest.java new file mode 100644 index 0000000..5cbaa41 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ConfigPathValidatorTest.java @@ -0,0 +1,61 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.File; +import java.nio.file.Path; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.CONFIG_PATH; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.*; + +class ConfigPathValidatorTest { + private static final String TEST_FILE = "src/test/resources/test-dir/test-file.mkv"; + private static final String TEST_CONFIG = "src/test/resources/test-dir/test-config.yml"; + + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(CONFIG_PATH, CONFIG_PATH.abrv(), CONFIG_PATH.args())); + } + + private static Stream provideTestCases() { + return Stream.of( + argumentsOf(CONFIG_PATH, true, null, "", new String[]{"-p", TEST_CONFIG}, VALID), + argumentsOf(CONFIG_PATH, true, null, "config-path: " + TEST_CONFIG, new String[]{}, MISSING), + argumentsOf(CONFIG_PATH, false, null, "config-path: " + TEST_CONFIG, new String[]{}, NOT_PRESENT), + argumentsOf(CONFIG_PATH, false, Path.of(TEST_CONFIG).toFile(), "", new String[]{}, DEFAULT), + argumentsOf(CONFIG_PATH, true, null, "", new String[]{"-p", TEST_FILE}, INVALID) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs, + ValidationResult expectedResult) throws ParseException, YamlInvalidContentException { + ConfigPathValidator underTest = new ConfigPathValidator(property, required, defaultValue); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java new file mode 100644 index 0000000..fb66685 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/MkvToolNixPathValidatorTest.java @@ -0,0 +1,65 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.File; +import java.nio.file.Path; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.MISSING; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static org.junit.jupiter.api.Assertions.*; + +class MkvToolNixPathValidatorTest { + private static final String TEST_INVALID_DIR = "src/test/resources/test-dir"; + private static final String TEST_MKVTOOLNIX_DIR = "src/test/resources/mkvtoolnix"; + private static final String TEST_MKVTOOLNIX_EXE_DIR = "src/test/resources/mkvtoolnix_exe"; + + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(MKV_TOOL_NIX, MKV_TOOL_NIX.abrv(), MKV_TOOL_NIX.args())); + } + + private static Stream provideTestCases() { + return Stream.of( + Arguments.of(MKV_TOOL_NIX, false, null, "", new String[]{"-m", TEST_MKVTOOLNIX_DIR}, VALID), + Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{"-m", TEST_MKVTOOLNIX_EXE_DIR}, VALID), + Arguments.of(MKV_TOOL_NIX, false, null, "mkvtoolnix: " + TEST_MKVTOOLNIX_EXE_DIR, new String[]{}, VALID), + Arguments.of(MKV_TOOL_NIX, true, null, "mkvtoolnix: " + TEST_MKVTOOLNIX_DIR, new String[]{}, VALID), + Arguments.of(MKV_TOOL_NIX, false, Path.of(TEST_MKVTOOLNIX_EXE_DIR).toFile(), "", new String[]{}, DEFAULT), + Arguments.of(MKV_TOOL_NIX, false, null, "", new String[]{}, NOT_PRESENT), + Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{}, MISSING), + Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{"-m", TEST_INVALID_DIR}, INVALID) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs, + ValidationResult expectedResult) throws ParseException, YamlInvalidContentException { + MkvToolNixPathValidator underTest = new MkvToolNixPathValidator(property, required, defaultValue); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + } + +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java new file mode 100644 index 0000000..4e91a56 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PathValidatorTest.java @@ -0,0 +1,66 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.File; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.LIBRARY; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.*; + +class PathValidatorTest { + private static final String TEST_DIR = "src/test/resources/test-dir"; + private static final String TEST_FILE = "src/test/resources/test-dir/test-file.mkv"; + + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(LIBRARY, LIBRARY.abrv(), LIBRARY.args())); + } + + private static Stream provideTestCases() { + return Stream.of( + argumentsOf(LIBRARY, false, null, "library: " + TEST_DIR, new String[]{}, VALID), + argumentsOf(LIBRARY, true, null, "", new String[]{"-l", TEST_FILE}, VALID), + + argumentsOf(LIBRARY, false, TEST_DIR, "", new String[]{}, DEFAULT), + argumentsOf(LIBRARY, true, TEST_FILE, "", new String[]{}, DEFAULT), + argumentsOf(LIBRARY, true, null, "", new String[]{}, MISSING), + argumentsOf(LIBRARY, false, null, "", new String[]{}, NOT_PRESENT), + + argumentsOf(LIBRARY, true, null, "", new String[]{"-l", TEST_DIR + "/invalid"}, INVALID), + argumentsOf(LIBRARY, false, null, "library: " + TEST_DIR + "/invalid", new String[]{}, INVALID), + argumentsOf(LIBRARY, true, TEST_DIR, "", new String[]{"-l", TEST_DIR + "/invalid"}, INVALID) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs, + ValidationResult expectedResult) throws ParseException, YamlInvalidContentException { + PathValidator underTest = new PathValidator(property, required, defaultValue); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java new file mode 100644 index 0000000..cae1059 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/PatternValidatorTest.java @@ -0,0 +1,64 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.INCLUDE_PATTERN; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.*; + +class PatternValidatorTest { + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(INCLUDE_PATTERN, INCLUDE_PATTERN.abrv(), INCLUDE_PATTERN.args())); + } + + private static Stream provideTestCases() { + return Stream.of( + argumentsOf(INCLUDE_PATTERN, false, null, "include-pattern: \"[abd]?.*\"", new String[]{}, VALID), + argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{"-i", "[abd]?.*"}, VALID), + + argumentsOf(INCLUDE_PATTERN, false, Pattern.compile(".*"), "", new String[]{}, DEFAULT), + argumentsOf(INCLUDE_PATTERN, true, Pattern.compile(".*"), "", new String[]{}, DEFAULT), + + argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{}, MISSING), + argumentsOf(INCLUDE_PATTERN, false, null, "", new String[]{}, NOT_PRESENT), + + argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{"-i", "?."}, INVALID), + argumentsOf(INCLUDE_PATTERN, false, null, "include-pattern: \"[arst*\"", new String[]{}, INVALID), + argumentsOf(INCLUDE_PATTERN, true, Pattern.compile(".?"), "", new String[]{"-i", "?."}, INVALID) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(ConfigProperty property, boolean required, Pattern defaultValue, String yamlArgs, String[] cmdArgs, + ValidationResult expectedResult) throws ParseException, YamlInvalidContentException { + PatternValidator underTest = new PatternValidator(property, required, defaultValue); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java new file mode 100644 index 0000000..0a82951 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/SetValidatorTest.java @@ -0,0 +1,67 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.COMMENTARY_KEYWORDS; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class SetValidatorTest { + + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(COMMENTARY_KEYWORDS, COMMENTARY_KEYWORDS.abrv(), COMMENTARY_KEYWORDS.args())); + } + + @BeforeEach + void beforeEach() { + Config.getInstance(true); + } + + private static Stream provideTestCases() { + return Stream.of( + argumentsOf(COMMENTARY_KEYWORDS, true, true, "", new String[]{"-ck", "test"}, VALID, 3), + argumentsOf(COMMENTARY_KEYWORDS, true, false, COMMENTARY_KEYWORDS.prop() + ": [test]", new String[]{}, VALID, 1), + argumentsOf(COMMENTARY_KEYWORDS, false, true, COMMENTARY_KEYWORDS.prop() + ": [test]", new String[]{}, VALID, 3), + argumentsOf(COMMENTARY_KEYWORDS, false, false, "", new String[]{"-ck", "test"}, VALID, 1), + argumentsOf(COMMENTARY_KEYWORDS, true, true, COMMENTARY_KEYWORDS.prop() + ": [commentary]", new String[]{}, VALID, 2), + + argumentsOf(COMMENTARY_KEYWORDS, true, true, "", new String[]{}, MISSING, 2), + argumentsOf(COMMENTARY_KEYWORDS, false, true, "", new String[]{}, NOT_PRESENT, 2) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(ConfigProperty property, boolean required, boolean append, String yamlArgs, String[] cmdArgs, + ValidationResult expectedResult, int expectedSize) throws ParseException, YamlInvalidContentException { + SetValidator underTest = new SetValidator(property, required, append); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + assertEquals(expectedSize, Config.getInstance().getCommentaryKeywords().size()); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java new file mode 100644 index 0000000..d3d5dd3 --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/config/validator/ThreadValidatorTest.java @@ -0,0 +1,61 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import at.pcgamingfreaks.yaml.YAML; +import at.pcgamingfreaks.yaml.YamlInvalidContentException; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.THREADS; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf; +import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ThreadValidatorTest { + + private static CommandLineParser parser; + private static Options options; + + @BeforeAll + static void before() { + parser = new DefaultParser(); + options = new Options(); + options.addOption(optionOf(THREADS, "t", THREADS.args())); + } + + private static Stream provideTestCases() { + return Stream.of( + argumentsOf(THREADS, false, null, "", new String[]{"-t", "10"}, VALID), + argumentsOf(THREADS, true, null, "", new String[]{"-t", "10"}, VALID), + argumentsOf(THREADS, false, null, "threads: 10", new String[]{}, VALID), + argumentsOf(THREADS, true, null, "threads: 10", new String[]{}, VALID), + argumentsOf(THREADS, false, 2, "", new String[]{}, DEFAULT), + argumentsOf(THREADS, true, null, "", new String[]{}, MISSING), + argumentsOf(THREADS, false, null, "", new String[]{}, NOT_PRESENT), + argumentsOf(THREADS, true, null, "", new String[]{"-t", "-1"}, INVALID), + argumentsOf(THREADS, true, null, "threads: 0", new String[]{}, INVALID), + argumentsOf(THREADS, true, 2, "", new String[]{"-t", "0"}, INVALID) + ); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + void validate(ConfigProperty property, boolean required, Integer defaultValue, String yamlArgs, String[] cmdArgs, + ValidationResult expectedResult) throws ParseException, YamlInvalidContentException { + ThreadValidator underTest = new ThreadValidator(property, required, defaultValue); + + ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs)); + + assertEquals(expectedResult, result); + } +} \ No newline at end of file diff --git a/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java new file mode 100644 index 0000000..ffd452a --- /dev/null +++ b/src/test/java/at/pcgamingfreaks/mkvaudiosubtitlechanger/util/TestUtil.java @@ -0,0 +1,28 @@ +package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; + +import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; +import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; +import org.junit.jupiter.params.provider.Arguments; + +import java.util.Arrays; + +import static java.util.stream.Collectors.joining; + +public class TestUtil { + public static String yamlList(ConfigProperty main, ConfigProperty... child) { + return main.prop() + ":\n" + Arrays.stream(child) + .map(ConfigProperty::prop) + .collect(joining("\n", " - ", "")); + } + + public static Arguments argumentsOf(ConfigProperty property, boolean required, T defaultValue, String yaml, String[] cmd, + ValidationResult result) { + return Arguments.of(property, required, defaultValue, yaml, cmd, result); + } + + public static Arguments argumentsOf(ConfigProperty property, boolean required, boolean append, String yaml, String[] cmd, + ValidationResult result, int expectedSize) { + return Arguments.of(property, required, append, yaml, cmd, result, expectedSize); + } + +} diff --git a/src/test/resources/mkvmerge.exe b/src/test/resources/mkvtoolnix/mkvmerge similarity index 100% rename from src/test/resources/mkvmerge.exe rename to src/test/resources/mkvtoolnix/mkvmerge diff --git a/src/test/resources/mkvpropedit.exe b/src/test/resources/mkvtoolnix/mkvpropedit similarity index 100% rename from src/test/resources/mkvpropedit.exe rename to src/test/resources/mkvtoolnix/mkvpropedit diff --git a/src/test/resources/mkvtoolnix_exe/mkvmerge.exe b/src/test/resources/mkvtoolnix_exe/mkvmerge.exe new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mkvtoolnix_exe/mkvpropedit.exe b/src/test/resources/mkvtoolnix_exe/mkvpropedit.exe new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/test-dir/test-config.yml b/src/test/resources/test-dir/test-config.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/test-dir/test-file.mkv b/src/test/resources/test-dir/test-file.mkv new file mode 100644 index 0000000..e69de29