diff --git a/pom.xml b/pom.xml index 733544f..b556686 100644 --- a/pom.xml +++ b/pom.xml @@ -9,8 +9,7 @@ - 21 - 21 + 21 UTF-8 @@ -19,7 +18,7 @@ 2.20.0 5.9.2 - 4.11.0 + 5.23.0 3.11.0 @@ -65,8 +64,7 @@ maven-compiler-plugin ${maven-compiler-plugin.version} - 21 - 21 + 21 diff --git a/src/main/java/de/gecheckt/asv/cli/AsvValidatorApplication.java b/src/main/java/de/gecheckt/asv/cli/AsvValidatorApplication.java new file mode 100644 index 0000000..6e1cd7f --- /dev/null +++ b/src/main/java/de/gecheckt/asv/cli/AsvValidatorApplication.java @@ -0,0 +1,163 @@ +package de.gecheckt.asv.cli; + +import de.gecheckt.asv.domain.model.InputFile; +import de.gecheckt.asv.parser.DefaultInputFileParser; +import de.gecheckt.asv.parser.DefaultSegmentLineTokenizer; +import de.gecheckt.asv.parser.InputFileParseException; +import de.gecheckt.asv.parser.InputFileParser; +import de.gecheckt.asv.parser.SegmentLineTokenizer; +import de.gecheckt.asv.validation.DefaultInputFileValidator; +import de.gecheckt.asv.validation.InputFileValidator; +import de.gecheckt.asv.validation.field.DefaultFieldValidator; +import de.gecheckt.asv.validation.field.FieldValidator; +import de.gecheckt.asv.validation.model.ValidationResult; +import de.gecheckt.asv.validation.structure.DefaultStructureValidator; +import de.gecheckt.asv.validation.structure.StructureValidator; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Haupteinstiegspunkt für die ASV Format Validator CLI-Anwendung. + * + * Diese Anwendung validiert Dateien gegen ein segmentorientiertes Dateiformat. + * Sie nimmt einen Dateipfad als Kommandozeilenargument entgegen, parst die Datei, + * validiert sie und gibt die Ergebnisse auf der Konsole aus. + */ +public class AsvValidatorApplication { + + private static final int EXIT_CODE_SUCCESS = 0; + private static final int EXIT_CODE_INVALID_ARGUMENTS = 1; + private static final int EXIT_CODE_FILE_ERROR = 2; + private static final int EXIT_CODE_VALIDATION_ERRORS = 3; + + private static final Logger logger = LogManager.getLogger(AsvValidatorApplication.class); + + private final InputFileParser parser; + private final InputFileValidator validator; + private final ValidationResultPrinter printer; + + /** + * Konstruktor für einen AsvValidatorApplication mit Standardkomponenten. + */ + public AsvValidatorApplication() { + // Initialize all required components + SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer(); + this.parser = new DefaultInputFileParser(tokenizer); + + StructureValidator structureValidator = new DefaultStructureValidator(); + FieldValidator fieldValidator = new DefaultFieldValidator(); + this.validator = new DefaultInputFileValidator(structureValidator, fieldValidator); + + this.printer = new ValidationResultPrinter(); + } + + /** + * Konstruktor für einen AsvValidatorApplication mit den bereitgestellten Komponenten. + * Dieser Konstruktor unterstützt Dependency Injection für bessere Testbarkeit. + * + * @param parser der Parser zum Parsen von Eingabedateien + * @param validator der Validator zum Validieren geparster Dateien + * @param printer der Printer zum Anzeigen von Validierungsergebnissen + */ + public AsvValidatorApplication(InputFileParser parser, InputFileValidator validator, ValidationResultPrinter printer) { + this.parser = parser; + this.validator = validator; + this.printer = printer; + } + + /** + * Haupteinstiegspunkt für die Anwendung. + * + * @param args Kommandozeilenargumente - erwartet genau ein Argument: den Dateipfad + */ + public static void main(String[] args) { + AsvValidatorApplication app = new AsvValidatorApplication(); + int exitCode = app.run(args); + System.exit(exitCode); + } + + /** + * Führt die Anwendung mit den bereitgestellten Argumenten aus. + * + * @param args Kommandozeilenargumente + * @return Exit-Code (0 für Erfolg, ungleich 0 für Fehler) + */ + public int run(String[] args) { + // Validate command line arguments + if (args.length != 1) { + printUsage(); + return EXIT_CODE_INVALID_ARGUMENTS; + } + + String filePath = args[0]; + + try { + // Parse the file + InputFile inputFile = parseFile(filePath); + + // Validate the parsed file + ValidationResult result = validator.validate(inputFile); + + // Output results + printer.printToConsole(result); + + // Return appropriate exit code based on validation results + return result.hasErrors() ? EXIT_CODE_VALIDATION_ERRORS : EXIT_CODE_SUCCESS; + + } catch (IOException e) { + logger.error("Fehler beim Lesen der Datei: {}", e.getMessage(), e); + System.err.println("Fehler beim Lesen der Datei: " + e.getMessage()); + return EXIT_CODE_FILE_ERROR; + } catch (InputFileParseException e) { + logger.error("Fehler beim Parsen der Datei: {}", e.getMessage(), e); + System.err.println("Fehler beim Parsen der Datei: " + e.getMessage()); + return EXIT_CODE_FILE_ERROR; + } catch (Exception e) { + logger.error("Unerwarteter Fehler während der Validierung: {}", e.getMessage(), e); + System.err.println("Unerwarteter Fehler während der Validierung: " + e.getMessage()); + return EXIT_CODE_FILE_ERROR; + } + } + + /** + * Parst eine Datei unter dem gegebenen Pfad. + * + * @param filePath Pfad zur zu parsenden Datei + * @return geparstes InputFile-Objekt + * @throws IOException wenn die Datei nicht gelesen werden kann + * @throws InputFileParseException wenn die Datei nicht geparst werden kann + */ + private InputFile parseFile(String filePath) throws IOException, InputFileParseException { + Path path = Paths.get(filePath); + if (!Files.exists(path)) { + throw new IOException("File does not exist: " + filePath); + } + + if (!Files.isRegularFile(path)) { + throw new IOException("Path is not a regular file: " + filePath); + } + + if (!Files.isReadable(path)) { + throw new IOException("File is not readable: " + filePath); + } + + String fileContent = Files.readString(path, StandardCharsets.UTF_8); + return parser.parse(path.getFileName().toString(), fileContent); + } + + /** + * Gibt Nutzungsinformationen auf der Konsole aus. + */ + private void printUsage() { + System.out.println("ASV Format Validator"); + System.out.println("Verwendung: java -jar asv-format-validator.jar "); + System.out.println(" Pfad zur zu validierenden Datei"); + } +} \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/cli/ValidationResultPrinter.java b/src/main/java/de/gecheckt/asv/cli/ValidationResultPrinter.java new file mode 100644 index 0000000..f49d476 --- /dev/null +++ b/src/main/java/de/gecheckt/asv/cli/ValidationResultPrinter.java @@ -0,0 +1,67 @@ +package de.gecheckt.asv.cli; + +import de.gecheckt.asv.validation.model.ValidationError; +import de.gecheckt.asv.validation.model.ValidationResult; + +/** + * Printer-Klasse zum Ausgeben von ValidationResult-Objekten auf der Konsole. + * Diese Klasse trennt die Darstellungslogik vom Datenmodell. + */ +public class ValidationResultPrinter { + + /** + * Gibt ein ValidationResult formatiert auf der Konsole aus. + * + * @param result das auszugebende ValidationResult (darf nicht null sein) + */ + public void printToConsole(ValidationResult result) { + if (result == null) { + throw new IllegalArgumentException("ValidationResult must not be null"); + } + + System.out.println("=== Validierungsergebnis ==="); + + if (result.hasErrors()) { + System.out.println("Fehler (" + result.getErrors().size() + "):"); + result.getErrors().forEach(error -> System.out.println(" [ERROR] " + formatError(error))); + } + + if (result.hasWarnings()) { + System.out.println("Warnungen (" + result.getWarnings().size() + "):"); + result.getWarnings().forEach(error -> System.out.println(" [WARNING] " + formatError(error))); + } + + if (result.hasInfos()) { + System.out.println("Informationen (" + result.getInfos().size() + "):"); + result.getInfos().forEach(error -> System.out.println(" [INFO] " + formatError(error))); + } + + if (!result.hasErrors() && !result.hasWarnings() && !result.hasInfos()) { + System.out.println("Keine Probleme gefunden."); + } + + System.out.println("============================"); + } + + /** + * Formatiert einen ValidationError für die Konsolenausgabe. + * + * @param error der zu formatierende Fehler + * @return formatierte Zeichenkettendarstellung des Fehlers + */ + private String formatError(ValidationError error) { + var sb = new StringBuilder(); + sb.append(error.description()); + sb.append(" (Code: ").append(error.errorCode()).append(")"); + sb.append(" im Segment '").append(error.segmentName()).append("' Position ").append(error.segmentPosition()); + sb.append(", Feld '").append(error.fieldName()).append("' Position ").append(error.fieldPosition()); + + error.getActualValue().ifPresent(value -> + sb.append(", Ist-Wert: '").append(value).append("'")); + + error.getExpectedRule().ifPresent(rule -> + sb.append(", Erwartet: '").append(rule).append("'")); + + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/domain/model/Message.java b/src/main/java/de/gecheckt/asv/domain/model/Message.java index 7c39f42..db44963 100644 --- a/src/main/java/de/gecheckt/asv/domain/model/Message.java +++ b/src/main/java/de/gecheckt/asv/domain/model/Message.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; /** * Represents a message in an input file. @@ -92,7 +91,7 @@ public record Message(int messagePosition, List segments) { return segments.stream() .filter(segment -> segmentName.equals(segment.segmentName())) - .collect(Collectors.toList()); + .toList(); } /** diff --git a/src/main/java/de/gecheckt/asv/parser/DefaultInputFileParser.java b/src/main/java/de/gecheckt/asv/parser/DefaultInputFileParser.java index 8253d08..ce75db8 100644 --- a/src/main/java/de/gecheckt/asv/parser/DefaultInputFileParser.java +++ b/src/main/java/de/gecheckt/asv/parser/DefaultInputFileParser.java @@ -5,29 +5,28 @@ import de.gecheckt.asv.domain.model.InputFile; import de.gecheckt.asv.domain.model.Message; import de.gecheckt.asv.domain.model.Segment; import java.io.BufferedReader; -import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; /** - * Default implementation of InputFileParser. + * Standardimplementierung von InputFileParser. */ public class DefaultInputFileParser implements InputFileParser { private final SegmentLineTokenizer tokenizer; /** - * Constructs a DefaultInputFileParser with the specified tokenizer. + * Konstruktor für einen DefaultInputFileParser mit dem angegebenen Tokenizer. * - * @param tokenizer the tokenizer to use for parsing segment lines + * @param tokenizer der für das Parsen von Segmentzeilen zu verwendende Tokenizer */ public DefaultInputFileParser(SegmentLineTokenizer tokenizer) { this.tokenizer = tokenizer; } @Override - public InputFile parse(String fileName, String fileContent) throws IOException { + public InputFile parse(String fileName, String fileContent) throws InputFileParseException { if (fileName == null || fileName.isEmpty()) { throw new IllegalArgumentException("File name must not be null or empty"); } @@ -58,7 +57,8 @@ public class DefaultInputFileParser implements InputFileParser { return new InputFile(fileName, messages); } catch (Exception e) { - throw new IOException("Error parsing file: " + fileName, e); + // Wrap all exceptions as parsing exceptions + throw new InputFileParseException("Error parsing file: " + fileName, e); } } } \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/parser/DefaultSegmentLineTokenizer.java b/src/main/java/de/gecheckt/asv/parser/DefaultSegmentLineTokenizer.java index 009bc84..04f3780 100644 --- a/src/main/java/de/gecheckt/asv/parser/DefaultSegmentLineTokenizer.java +++ b/src/main/java/de/gecheckt/asv/parser/DefaultSegmentLineTokenizer.java @@ -5,8 +5,8 @@ import java.util.ArrayList; import java.util.List; /** - * Default implementation of SegmentLineTokenizer that uses '+' as field separator - * and assumes the first token is the segment name. + * Standardimplementierung von SegmentLineTokenizer, die '+' als Feldtrennzeichen verwendet + * und annimmt, dass das erste Token der Segmentname ist. */ public class DefaultSegmentLineTokenizer implements SegmentLineTokenizer { diff --git a/src/main/java/de/gecheckt/asv/parser/InputFileParseException.java b/src/main/java/de/gecheckt/asv/parser/InputFileParseException.java new file mode 100644 index 0000000..5a2315c --- /dev/null +++ b/src/main/java/de/gecheckt/asv/parser/InputFileParseException.java @@ -0,0 +1,30 @@ +package de.gecheckt.asv.parser; + +/** + * Exception thrown when an input file cannot be parsed due to format or content issues. + * This exception is used specifically for parsing-related problems, as opposed to + * I/O issues which would be represented by IOException. + */ +public class InputFileParseException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs a new InputFileParseException with the specified detail message. + * + * @param message the detail message + */ + public InputFileParseException(String message) { + super(message); + } + + /** + * Constructs a new InputFileParseException with the specified detail message and cause. + * + * @param message the detail message + * @param cause the cause of this exception + */ + public InputFileParseException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/parser/InputFileParser.java b/src/main/java/de/gecheckt/asv/parser/InputFileParser.java index 4309fd2..869a7b1 100644 --- a/src/main/java/de/gecheckt/asv/parser/InputFileParser.java +++ b/src/main/java/de/gecheckt/asv/parser/InputFileParser.java @@ -1,20 +1,19 @@ package de.gecheckt.asv.parser; import de.gecheckt.asv.domain.model.InputFile; -import java.io.IOException; /** - * Interface for parsing input files into the domain model. + * Interface für das Parsen von Eingabedateien in das Domänenmodell. */ public interface InputFileParser { /** - * Parses the content of a file into an InputFile domain object. + * Parst den Inhalt einer Datei in ein InputFile-Domänenobjekt. * - * @param fileName the name of the file to parse - * @param fileContent the content of the file to parse - * @return the parsed InputFile domain object - * @throws IOException if there is an error reading or parsing the file + * @param fileName der Name der zu parsenden Datei + * @param fileContent der Inhalt der zu parsenden Datei + * @return das geparste InputFile-Domänenobjekt + * @throws InputFileParseException wenn beim Parsen des Dateiinhalts ein Fehler auftritt */ - InputFile parse(String fileName, String fileContent) throws IOException; + InputFile parse(String fileName, String fileContent) throws InputFileParseException; } \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/parser/SegmentLineTokenizer.java b/src/main/java/de/gecheckt/asv/parser/SegmentLineTokenizer.java index 345af2a..3e5e2c4 100644 --- a/src/main/java/de/gecheckt/asv/parser/SegmentLineTokenizer.java +++ b/src/main/java/de/gecheckt/asv/parser/SegmentLineTokenizer.java @@ -4,23 +4,23 @@ import de.gecheckt.asv.domain.model.Field; import java.util.List; /** - * Interface for splitting a segment line into its components. + * Interface für das Aufteilen einer Segmentzeile in ihre Bestandteile. */ public interface SegmentLineTokenizer { /** - * Extracts the segment name from a segment line. + * Extrahiert den Segmentnamen aus einer Segmentzeile. * - * @param segmentLine the line to extract the segment name from - * @return the segment name + * @param segmentLine die Zeile, aus der der Segmentname extrahiert werden soll + * @return der Segmentname */ String extractSegmentName(String segmentLine); /** - * Splits a segment line into fields. + * Teilt eine Segmentzeile in Felder auf. * - * @param segmentLine the line to split into fields - * @return the list of fields + * @param segmentLine die in Felder aufzuteilende Zeile + * @return die Liste der Felder */ List tokenizeFields(String segmentLine); } \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/validation/DefaultInputFileValidator.java b/src/main/java/de/gecheckt/asv/validation/DefaultInputFileValidator.java index 5089a6b..54b8f2f 100644 --- a/src/main/java/de/gecheckt/asv/validation/DefaultInputFileValidator.java +++ b/src/main/java/de/gecheckt/asv/validation/DefaultInputFileValidator.java @@ -10,13 +10,14 @@ import de.gecheckt.asv.validation.model.ValidationResult; import de.gecheckt.asv.validation.structure.StructureValidator; /** - * Default implementation of InputFileValidator that orchestrates multiple specialized validators. + * Standardimplementierung von InputFileValidator, die mehrere spezialisierte Validatoren orchestriert. * - * This orchestrator executes validators in a predefined order: - * 1. StructureValidator - validates structural integrity - * 2. FieldValidator - validates field-specific rules + * Dieser Orchestrator führt Validatoren in einer vordefinierten Reihenfolge aus: + * 1. StructureValidator - validiert die strukturelle Integrität + * 2. FieldValidator - validiert feldspezifische Regeln * - * Additional validators can be added in the future by extending this class or modifying the validation sequence. + * Zusätzliche Validatoren können in Zukunft hinzugefügt werden, indem diese Klasse erweitert + * oder die Validierungssequenz modifiziert wird. */ public class DefaultInputFileValidator implements InputFileValidator { @@ -24,10 +25,10 @@ public class DefaultInputFileValidator implements InputFileValidator { private final FieldValidator fieldValidator; /** - * Constructs a DefaultInputFileValidator with the required validators. + * Konstruktor für einen DefaultInputFileValidator mit den erforderlichen Validatoren. * - * @param structureValidator the structure validator to use (must not be null) - * @param fieldValidator the field validator to use (must not be null) + * @param structureValidator der zu verwendende Strukturvalidator (darf nicht null sein) + * @param fieldValidator der zu verwendende Feldvalidator (darf nicht null sein) */ public DefaultInputFileValidator(StructureValidator structureValidator, FieldValidator fieldValidator) { this.structureValidator = Objects.requireNonNull(structureValidator, "structureValidator must not be null"); diff --git a/src/main/java/de/gecheckt/asv/validation/InputFileValidator.java b/src/main/java/de/gecheckt/asv/validation/InputFileValidator.java index 954f128..7fc5dbc 100644 --- a/src/main/java/de/gecheckt/asv/validation/InputFileValidator.java +++ b/src/main/java/de/gecheckt/asv/validation/InputFileValidator.java @@ -4,17 +4,17 @@ import de.gecheckt.asv.domain.model.InputFile; import de.gecheckt.asv.validation.model.ValidationResult; /** - * Interface for orchestrating the validation of an ASV input file. - * This validator coordinates multiple specialized validators to perform a complete validation. + * Interface für die Orchestrierung der Validierung einer ASV-Eingabedatei. + * Dieser Validator koordiniert mehrere spezialisierte Validatoren, um eine vollständige Validierung durchzuführen. */ public interface InputFileValidator { /** - * Validates the given input file using all configured validators. + * Validiert die gegebene Eingabedatei unter Verwendung aller konfigurierten Validatoren. * - * @param inputFile the input file to validate (must not be null) - * @return a validation result containing all errors found by all validators - * @throws IllegalArgumentException if inputFile is null + * @param inputFile die zu validierende Eingabedatei (darf nicht null sein) + * @return ein Validierungsergebnis, das alle von allen Validatoren gefundenen Fehler enthält + * @throws IllegalArgumentException wenn inputFile null ist */ ValidationResult validate(InputFile inputFile); } \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/validation/example/ValidationExample.java b/src/main/java/de/gecheckt/asv/validation/example/ValidationExample.java deleted file mode 100644 index e35e0f5..0000000 --- a/src/main/java/de/gecheckt/asv/validation/example/ValidationExample.java +++ /dev/null @@ -1,60 +0,0 @@ -package de.gecheckt.asv.validation.example; - -import de.gecheckt.asv.validation.model.ValidationError; -import de.gecheckt.asv.validation.model.ValidationResult; -import de.gecheckt.asv.validation.model.ValidationSeverity; - -import java.util.Arrays; -import java.util.List; - -/** - * Beispielanwendung zur Demonstration der Verwendung der Validierungsmodelle. - */ -public class ValidationExample { - - public static void main(String[] args) { - // Erstelle einige Beispielvalidierungsfehler - ValidationError error1 = new ValidationError( - "FORMAT001", - "Ungültiges Datumsformat", - ValidationSeverity.ERROR, - "KOPF", - 1, - "ERSTELLUNGSDATUM", - 3, - "2023-99-99", - "YYYY-MM-DD" - ); - - ValidationError warning1 = new ValidationError( - "LENGTH001", - "Feldlänge überschritten", - ValidationSeverity.WARNING, - "POSITION", - 5, - "ARTIKELBEZEICHNUNG", - 2, - "Extrem langer Artikelname, der die maximale Feldlänge überschreitet", - "Max. 30 Zeichen" - ); - - ValidationError info1 = new ValidationError( - "OPTIONAL001", - "Optionales Feld ist leer", - ValidationSeverity.INFO, - "FUSS", - 100, - "BEMERKUNG", - 1, - null, - "Freitextfeld für zusätzliche Informationen" - ); - - // Erstelle ein ValidationResult-Objekt - List validationErrors = Arrays.asList(error1, warning1, info1); - ValidationResult result = new ValidationResult(validationErrors); - - // Gib das Ergebnis auf der Konsole aus - result.printToConsole(); - } -} \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/validation/field/DefaultFieldValidator.java b/src/main/java/de/gecheckt/asv/validation/field/DefaultFieldValidator.java index 5569db5..33475d6 100644 --- a/src/main/java/de/gecheckt/asv/validation/field/DefaultFieldValidator.java +++ b/src/main/java/de/gecheckt/asv/validation/field/DefaultFieldValidator.java @@ -13,12 +13,10 @@ import de.gecheckt.asv.validation.model.ValidationSeverity; * Default implementation of FieldValidator that checks general field rules. * * Rules checked: - * 1. Field.rawValue must not be null - * 2. Field.rawValue must not be empty - * 3. Field.rawValue must not consist only of whitespaces - * 4. fieldPosition must be positive - * 5. Field positions within a segment should be consecutive without gaps, starting at 1 - * 6. If fieldName is set, it must not be empty or only whitespace + * 1. Field.rawValue must not be empty + * 2. Field.rawValue must not consist only of whitespaces + * 3. Field positions within a segment should be consecutive without gaps, starting at 1 + * 4. If fieldName is set, it must not be empty or only whitespace */ public class DefaultFieldValidator implements FieldValidator { @@ -73,65 +71,33 @@ public class DefaultFieldValidator implements FieldValidator { var fieldPosition = field.fieldPosition(); var fieldName = field.getFieldName().orElse(""); - // Rule 1: Field.rawValue must not be null - // (This is already enforced by the domain model, but we check for completeness) - if (rawValue == null) { + // Rule 2: Field.rawValue must not be empty + if (rawValue.isEmpty()) { errors.add(createError( - "FIELD_001", - "Field raw value must not be null", + "FIELD_002", + "Field raw value must not be empty", ValidationSeverity.ERROR, segmentName, segmentPosition, fieldName, fieldPosition, - "null", - "Non-null raw value required" + rawValue, + "Non-empty raw value required" )); - } else { - // Rule 2: Field.rawValue must not be empty - if (rawValue.isEmpty()) { - errors.add(createError( - "FIELD_002", - "Field raw value must not be empty", - ValidationSeverity.ERROR, - segmentName, - segmentPosition, - fieldName, - fieldPosition, - rawValue, - "Non-empty raw value required" - )); - } - - // Rule 3: Field.rawValue must not consist only of whitespaces - if (rawValue.trim().isEmpty() && !rawValue.isEmpty()) { - errors.add(createError( - "FIELD_003", - "Field raw value must not consist only of whitespaces", - ValidationSeverity.ERROR, - segmentName, - segmentPosition, - fieldName, - fieldPosition, - rawValue, - "Non-whitespace-only raw value required" - )); - } } - // Rule 4: fieldPosition must be positive - // (This is already enforced by the domain model, but we check for completeness) - if (fieldPosition <= 0) { + // Rule 3: Field.rawValue must not consist only of whitespaces + if (rawValue.trim().isEmpty() && !rawValue.isEmpty()) { errors.add(createError( - "FIELD_004", - "Field position must be positive", + "FIELD_003", + "Field raw value must not consist only of whitespaces", ValidationSeverity.ERROR, segmentName, segmentPosition, fieldName, fieldPosition, - String.valueOf(fieldPosition), - "Positive field position required" + rawValue, + "Non-whitespace-only raw value required" )); } diff --git a/src/main/java/de/gecheckt/asv/validation/field/FieldValidator.java b/src/main/java/de/gecheckt/asv/validation/field/FieldValidator.java index 4b10906..cca2a16 100644 --- a/src/main/java/de/gecheckt/asv/validation/field/FieldValidator.java +++ b/src/main/java/de/gecheckt/asv/validation/field/FieldValidator.java @@ -4,17 +4,17 @@ import de.gecheckt.asv.domain.model.InputFile; import de.gecheckt.asv.validation.model.ValidationResult; /** - * Interface for validating fields in an ASV input file. - * This validator checks general field rules without requiring specification details. + * Interface für die Validierung von Feldern in einer ASV-Eingabedatei. + * Dieser Validator prüft allgemeine Feldregeln ohne Angabe von Spezifikationsdetails. */ public interface FieldValidator { /** - * Validates the fields in the given input file. + * Validiert die Felder in der gegebenen Eingabedatei. * - * @param inputFile the input file to validate (must not be null) - * @return a validation result containing any field errors found - * @throws IllegalArgumentException if inputFile is null + * @param inputFile die zu validierende Eingabedatei (darf nicht null sein) + * @return ein Validierungsergebnis, das alle gefundenen Feldfehler enthält + * @throws IllegalArgumentException wenn inputFile null ist */ ValidationResult validate(InputFile inputFile); } \ No newline at end of file diff --git a/src/main/java/de/gecheckt/asv/validation/model/ValidationResult.java b/src/main/java/de/gecheckt/asv/validation/model/ValidationResult.java index f7fbe9e..fee83a0 100644 --- a/src/main/java/de/gecheckt/asv/validation/model/ValidationResult.java +++ b/src/main/java/de/gecheckt/asv/validation/model/ValidationResult.java @@ -109,56 +109,6 @@ public final class ValidationResult { return errors; } - /** - * Gibt eine textbasierte Darstellung des Validierungsergebnisses auf der Konsole aus. - */ - public void printToConsole() { - System.out.println("=== Validierungsergebnis ==="); - - if (hasErrors()) { - System.out.println("Fehler (" + getErrors().size() + "):"); - getErrors().forEach(error -> System.out.println(" [ERROR] " + formatError(error))); - } - - if (hasWarnings()) { - System.out.println("Warnungen (" + getWarnings().size() + "):"); - getWarnings().forEach(error -> System.out.println(" [WARNING] " + formatError(error))); - } - - if (hasInfos()) { - System.out.println("Informationen (" + getInfos().size() + "):"); - getInfos().forEach(error -> System.out.println(" [INFO] " + formatError(error))); - } - - if (!hasErrors() && !hasWarnings() && !hasInfos()) { - System.out.println("Keine Probleme gefunden."); - } - - System.out.println("============================"); - } - - /** - * Formatiert einen ValidationError für die Konsolenausgabe. - * - * @param error der zu formatierende Fehler - * @return formatierte Zeichenkette - */ - private String formatError(ValidationError error) { - var sb = new StringBuilder(); - sb.append(error.description()); - sb.append(" (Code: ").append(error.errorCode()).append(")"); - sb.append(" im Segment '").append(error.segmentName()).append("' Position ").append(error.segmentPosition()); - sb.append(", Feld '").append(error.fieldName()).append("' Position ").append(error.fieldPosition()); - - error.getActualValue().ifPresent(value -> - sb.append(", Ist-Wert: '").append(value).append("'")); - - error.getExpectedRule().ifPresent(rule -> - sb.append(", Erwartet: '").append(rule).append("'")); - - return sb.toString(); - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/de/gecheckt/asv/validation/structure/StructureValidator.java b/src/main/java/de/gecheckt/asv/validation/structure/StructureValidator.java index 13ba385..d205bbd 100644 --- a/src/main/java/de/gecheckt/asv/validation/structure/StructureValidator.java +++ b/src/main/java/de/gecheckt/asv/validation/structure/StructureValidator.java @@ -4,17 +4,17 @@ import de.gecheckt.asv.domain.model.InputFile; import de.gecheckt.asv.validation.model.ValidationResult; /** - * Interface for validating the structural integrity of an ASV input file. - * This validator checks general structural rules without requiring specification details. + * Interface für die Validierung der strukturellen Integrität einer ASV-Eingabedatei. + * Dieser Validator prüft allgemeine Strukturregeln ohne Angabe von Spezifikationsdetails. */ public interface StructureValidator { /** - * Validates the structural integrity of the given input file. + * Validiert die strukturelle Integrität der gegebenen Eingabedatei. * - * @param inputFile the input file to validate (must not be null) - * @return a validation result containing any structural errors found - * @throws IllegalArgumentException if inputFile is null + * @param inputFile die zu validierende Eingabedatei (darf nicht null sein) + * @return ein Validierungsergebnis, das alle gefundenen Strukturfehler enthält + * @throws IllegalArgumentException wenn inputFile null ist */ ValidationResult validate(InputFile inputFile); } \ No newline at end of file diff --git a/src/test/java/de/gecheckt/asv/cli/AsvValidatorApplicationAdditionalTest.java b/src/test/java/de/gecheckt/asv/cli/AsvValidatorApplicationAdditionalTest.java new file mode 100644 index 0000000..ff9662f --- /dev/null +++ b/src/test/java/de/gecheckt/asv/cli/AsvValidatorApplicationAdditionalTest.java @@ -0,0 +1,218 @@ +package de.gecheckt.asv.cli; + +import de.gecheckt.asv.domain.model.Field; +import de.gecheckt.asv.domain.model.InputFile; +import de.gecheckt.asv.domain.model.Message; +import de.gecheckt.asv.domain.model.Segment; +import de.gecheckt.asv.parser.InputFileParseException; +import de.gecheckt.asv.parser.InputFileParser; +import de.gecheckt.asv.validation.InputFileValidator; +import de.gecheckt.asv.validation.model.ValidationError; +import de.gecheckt.asv.validation.model.ValidationResult; +import de.gecheckt.asv.validation.model.ValidationSeverity; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +/** + * Zusätzliche Unittests für AsvValidatorApplication. + */ +class AsvValidatorApplicationAdditionalTest { + + @TempDir + Path tempDir; + + @Test + void testRunWithValidFileShouldReturnSuccessExitCode() throws InputFileParseException, IOException { + // Given + InputFileParser parser = mock(InputFileParser.class); + InputFileValidator validator = mock(InputFileValidator.class); + ValidationResultPrinter printer = mock(ValidationResultPrinter.class); + + AsvValidatorApplication app = new AsvValidatorApplication(parser, validator, printer); + + // Create a test file + Path testFile = tempDir.resolve("valid-file.txt"); + String validContent = "HDR|TestHeader\n" + + "DTL|TestData|MoreData\n" + + "TRL|3"; + Files.writeString(testFile, validContent); + + String[] args = {testFile.toString()}; + + // Create real objects instead of mocks for final classes + Field hdrField1 = new Field(1, "HDR"); + Field hdrField2 = new Field(2, "TestHeader"); + Segment hdrSegment = new Segment("HDR", 1, List.of(hdrField1, hdrField2)); + + Field dtlField1 = new Field(1, "DTL"); + Field dtlField2 = new Field(2, "TestData"); + Field dtlField3 = new Field(3, "MoreData"); + Segment dtlSegment = new Segment("DTL", 2, List.of(dtlField1, dtlField2, dtlField3)); + + Field trlField1 = new Field(1, "TRL"); + Field trlField2 = new Field(2, "3"); + Segment trlSegment = new Segment("TRL", 3, List.of(trlField1, trlField2)); + + Message message = new Message(1, List.of(hdrSegment, dtlSegment, trlSegment)); + InputFile inputFile = new InputFile("valid-file.txt", List.of(message)); + + // Mock the parser and validator behavior + when(parser.parse(anyString(), anyString())).thenReturn(inputFile); + + // Create a real ValidationResult with no errors + ValidationResult validationResult = new ValidationResult(List.of()); + + when(validator.validate(inputFile)).thenReturn(validationResult); + + // Capture System.out + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + try { + // When + int exitCode = app.run(args); + + // Then + assertEquals(0, exitCode); + // Verify that the printer was called + verify(printer).printToConsole(validationResult); + } finally { + // Restore System.out + System.setOut(originalOut); + } + } + + @Test + void testRunWithInvalidFileShouldReturnValidationErrorsExitCode() throws InputFileParseException, IOException { + // Given + InputFileParser parser = mock(InputFileParser.class); + InputFileValidator validator = mock(InputFileValidator.class); + ValidationResultPrinter printer = mock(ValidationResultPrinter.class); + + AsvValidatorApplication app = new AsvValidatorApplication(parser, validator, printer); + + // Create an invalid test file (missing required segments) + Path testFile = tempDir.resolve("invalid-file.txt"); + String invalidContent = "DTL|TestData|MoreData\n" + // Missing HDR + "DTL|MoreData|EvenMoreData\n"; // Missing TRL + Files.writeString(testFile, invalidContent); + + String[] args = {testFile.toString()}; + + // Create real objects instead of mocks for final classes + Field dtlField1 = new Field(1, "DTL"); + Field dtlField2 = new Field(2, "TestData"); + Field dtlField3 = new Field(3, "MoreData"); + Segment dtlSegment1 = new Segment("DTL", 1, List.of(dtlField1, dtlField2, dtlField3)); + + Field dtlField4 = new Field(1, "DTL"); + Field dtlField5 = new Field(2, "MoreData"); + Field dtlField6 = new Field(3, "EvenMoreData"); + Segment dtlSegment2 = new Segment("DTL", 2, List.of(dtlField4, dtlField5, dtlField6)); + + Message message = new Message(1, List.of(dtlSegment1, dtlSegment2)); + InputFile inputFile = new InputFile("invalid-file.txt", List.of(message)); + + // Mock the parser and validator behavior + when(parser.parse(anyString(), anyString())).thenReturn(inputFile); + + // Create a real ValidationResult with errors + ValidationError error = new ValidationError( + "MISSING_SEGMENT", + "Required segment HDR is missing", + ValidationSeverity.ERROR, + "HDR", + 1, + "HDR", + 1, + null, + "HDR segment is required" + ); + ValidationResult validationResult = new ValidationResult(List.of(error)); + + when(validator.validate(inputFile)).thenReturn(validationResult); + + // Capture System.out + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + try { + // When + int exitCode = app.run(args); + + // Then + assertEquals(3, exitCode); // Validation errors exit code + // Verify that the printer was called + verify(printer).printToConsole(validationResult); + } finally { + // Restore System.out + System.setOut(originalOut); + } + } + + /** + * Spezialisierter Test für den Fall, dass ein technisch lesbares/parstabares Dokument + * Validierungsfehler enthält und der CLI Exit-Code 3 zurückgibt. + * + * Dieser Test konzentriert sich explizit auf: + * 1. Parser liefert ein InputFile + * 2. Validator liefert ein ValidationResult mit mindestens einem ERROR + * 3. CLI gibt daraufhin Exit-Code 3 zurück + */ + @Test + void testParserReturnsInputFileAndValidatorReturnsErrorsShouldReturnExitCodeThree() throws InputFileParseException, IOException { + // Given + InputFileParser parser = mock(InputFileParser.class); + InputFileValidator validator = mock(InputFileValidator.class); + ValidationResultPrinter printer = mock(ValidationResultPrinter.class); + + AsvValidatorApplication app = new AsvValidatorApplication(parser, validator, printer); + + // Create a dummy test file (content doesn't matter since we're mocking the parser) + Path testFile = tempDir.resolve("dummy-file.txt"); + Files.writeString(testFile, "dummy content"); + + String[] args = {testFile.toString()}; + + // Mock: Parser liefert ein gültiges InputFile + InputFile inputFile = mock(InputFile.class); + when(parser.parse(anyString(), anyString())).thenReturn(inputFile); + + // Mock: Validator liefert ein ValidationResult mit mindestens einem ERROR + ValidationError validationError = new ValidationError( + "TEST_ERROR_CODE", + "Test error message", + ValidationSeverity.ERROR, // Wichtig: ValidationSeverity.ERROR + "TEST_SEGMENT", + 1, + "TEST_FIELD", + 1, + null, + "Test error description" + ); + ValidationResult validationResultWithErrors = new ValidationResult(List.of(validationError)); + when(validator.validate(inputFile)).thenReturn(validationResultWithErrors); + + // When + int exitCode = app.run(args); + + // Then + // Prüfe explizit, dass der Exit-Code 3 ist + assertEquals(3, exitCode, "CLI should return exit code 3 when validation errors occur"); + + // Verify that the printer was called with the validation result + verify(printer).printToConsole(validationResultWithErrors); + } +} \ No newline at end of file diff --git a/src/test/java/de/gecheckt/asv/cli/AsvValidatorApplicationTest.java b/src/test/java/de/gecheckt/asv/cli/AsvValidatorApplicationTest.java new file mode 100644 index 0000000..fefc1b1 --- /dev/null +++ b/src/test/java/de/gecheckt/asv/cli/AsvValidatorApplicationTest.java @@ -0,0 +1,103 @@ +package de.gecheckt.asv.cli; + +import de.gecheckt.asv.parser.InputFileParser; +import de.gecheckt.asv.validation.InputFileValidator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +/** + * Unittests für AsvValidatorApplication. + */ +class AsvValidatorApplicationTest { + + @TempDir + Path tempDir; + + @Test + void testRunWithNoArgumentsShouldPrintUsageAndReturnInvalidArgumentsExitCode() { + // Given + InputFileParser parser = mock(InputFileParser.class); + InputFileValidator validator = mock(InputFileValidator.class); + ValidationResultPrinter printer = mock(ValidationResultPrinter.class); + AsvValidatorApplication app = new AsvValidatorApplication(parser, validator, printer); + String[] args = {}; + + // Capture System.out + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + try { + // When + int exitCode = app.run(args); + + // Then + assertEquals(1, exitCode); + assertEquals(true, outContent.toString().contains("Verwendung:"), "Output should contain usage information"); + } finally { + // Restore System.out + System.setOut(originalOut); + } + } + + @Test + void testRunWithTooManyArgumentsShouldPrintUsageAndReturnInvalidArgumentsExitCode() { + // Given + InputFileParser parser = mock(InputFileParser.class); + InputFileValidator validator = mock(InputFileValidator.class); + ValidationResultPrinter printer = mock(ValidationResultPrinter.class); + AsvValidatorApplication app = new AsvValidatorApplication(parser, validator, printer); + String[] args = {"file1.txt", "file2.txt"}; + + // Capture System.out + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + try { + // When + int exitCode = app.run(args); + + // Then + assertEquals(1, exitCode); + assertEquals(true, outContent.toString().contains("Verwendung:"), "Output should contain usage information"); + } finally { + // Restore System.out + System.setOut(originalOut); + } + } + + @Test + void testRunWithNonExistentFileShouldReturnFileErrorExitCode() { + // Given + InputFileParser parser = mock(InputFileParser.class); + InputFileValidator validator = mock(InputFileValidator.class); + ValidationResultPrinter printer = mock(ValidationResultPrinter.class); + AsvValidatorApplication app = new AsvValidatorApplication(parser, validator, printer); + String[] args = {"/non/existent/file.txt"}; + + // Capture System.err + ByteArrayOutputStream errContent = new ByteArrayOutputStream(); + PrintStream originalErr = System.err; + System.setErr(new PrintStream(errContent)); + + try { + // When + int exitCode = app.run(args); + + // Then + assertEquals(2, exitCode); + assertEquals(true, errContent.toString().contains("File does not exist"), "Error output should contain file not found message"); + } finally { + // Restore System.err + System.setErr(originalErr); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/gecheckt/asv/cli/ValidationResultPrinterTest.java b/src/test/java/de/gecheckt/asv/cli/ValidationResultPrinterTest.java new file mode 100644 index 0000000..ed1834d --- /dev/null +++ b/src/test/java/de/gecheckt/asv/cli/ValidationResultPrinterTest.java @@ -0,0 +1,69 @@ +package de.gecheckt.asv.cli; + +import de.gecheckt.asv.validation.model.ValidationError; +import de.gecheckt.asv.validation.model.ValidationResult; +import de.gecheckt.asv.validation.model.ValidationSeverity; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ValidationResultPrinterTest { + + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + + @BeforeEach + void setUp() { + System.setOut(new PrintStream(outContent)); + } + + @AfterEach + void tearDown() { + System.setOut(originalOut); + } + + @Test + void testPrintToConsoleWithNullResult() { + ValidationResultPrinter printer = new ValidationResultPrinter(); + assertThrows(IllegalArgumentException.class, () -> printer.printToConsole(null)); + } + + @Test + void testPrintToConsoleWithEmptyResult() { + ValidationResultPrinter printer = new ValidationResultPrinter(); + ValidationResult result = new ValidationResult(List.of()); + printer.printToConsole(result); + + String output = outContent.toString(); + assertTrue(output.contains("=== Validierungsergebnis ===")); + assertTrue(output.contains("Keine Probleme gefunden.")); + assertTrue(output.contains("============================")); + } + + @Test + void testPrintToConsoleWithError() { + ValidationError error = new ValidationError( + "TEST001", "Test error", ValidationSeverity.ERROR, + "SEGMENT", 1, "FIELD", 1, "actual", "expected" + ); + ValidationResult result = new ValidationResult(List.of(error)); + + ValidationResultPrinter printer = new ValidationResultPrinter(); + printer.printToConsole(result); + + String output = outContent.toString(); + assertTrue(output.contains("=== Validierungsergebnis ===")); + assertTrue(output.contains("Fehler (1):")); + assertTrue(output.contains("[ERROR] Test error (Code: TEST001)")); + assertTrue(output.contains("im Segment 'SEGMENT' Position 1, Feld 'FIELD' Position 1")); + assertTrue(output.contains("Ist-Wert: 'actual'")); + assertTrue(output.contains("Erwartet: 'expected'")); + assertTrue(output.contains("============================")); + } +} \ No newline at end of file diff --git a/src/test/java/de/gecheckt/asv/domain/model/InputFileTest.java b/src/test/java/de/gecheckt/asv/domain/model/InputFileTest.java index 7e096d2..8a1ba22 100644 --- a/src/test/java/de/gecheckt/asv/domain/model/InputFileTest.java +++ b/src/test/java/de/gecheckt/asv/domain/model/InputFileTest.java @@ -2,6 +2,7 @@ package de.gecheckt.asv.domain.model; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import java.util.List; /** * Unit tests for the InputFile class. @@ -20,7 +21,7 @@ class InputFileTest { @Test void constructorWithFileNameAndMessagesShouldCreateInputFile() { Message message = new Message(1); - InputFile inputFile = new InputFile("test.txt", java.util.Arrays.asList(message)); + InputFile inputFile = new InputFile("test.txt", List.of(message)); assertEquals("test.txt", inputFile.sourceFileName()); assertEquals(1, inputFile.messages().size()); @@ -45,7 +46,7 @@ class InputFileTest { @Test void getMessagesShouldReturnUnmodifiableList() { Message message = new Message(1); - InputFile inputFile = new InputFile("test.txt", java.util.Arrays.asList(message)); + InputFile inputFile = new InputFile("test.txt", List.of(message)); assertThrows(UnsupportedOperationException.class, () -> { inputFile.getMessages().add(message); @@ -62,7 +63,7 @@ class InputFileTest { void getMessageCountShouldReturnCorrectCount() { Message message1 = new Message(1); Message message2 = new Message(2); - InputFile inputFile = new InputFile("test.txt", java.util.Arrays.asList(message1, message2)); + InputFile inputFile = new InputFile("test.txt", List.of(message1, message2)); assertEquals(2, inputFile.getMessageCount()); } @@ -70,9 +71,9 @@ class InputFileTest { @Test void equalsAndHashCodeShouldWorkCorrectly() { Message message = new Message(1); - InputFile inputFile1 = new InputFile("test.txt", java.util.Arrays.asList(message)); - InputFile inputFile2 = new InputFile("test.txt", java.util.Arrays.asList(message)); - InputFile inputFile3 = new InputFile("other.txt", java.util.Arrays.asList(message)); + InputFile inputFile1 = new InputFile("test.txt", List.of(message)); + InputFile inputFile2 = new InputFile("test.txt", List.of(message)); + InputFile inputFile3 = new InputFile("other.txt", List.of(message)); assertEquals(inputFile1, inputFile2); assertNotEquals(inputFile1, inputFile3); @@ -82,7 +83,7 @@ class InputFileTest { @Test void toStringShouldReturnValidString() { Message message = new Message(1); - InputFile inputFile = new InputFile("test.txt", java.util.Arrays.asList(message)); + InputFile inputFile = new InputFile("test.txt", List.of(message)); String result = inputFile.toString(); assertTrue(result.contains("sourceFileName=test.txt")); diff --git a/src/test/java/de/gecheckt/asv/domain/model/MessageTest.java b/src/test/java/de/gecheckt/asv/domain/model/MessageTest.java index 6779644..5f3a336 100644 --- a/src/test/java/de/gecheckt/asv/domain/model/MessageTest.java +++ b/src/test/java/de/gecheckt/asv/domain/model/MessageTest.java @@ -2,6 +2,7 @@ package de.gecheckt.asv.domain.model; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import java.util.List; /** * Unit tests for the Message class. @@ -20,7 +21,7 @@ class MessageTest { @Test void constructorWithPositionAndSegmentsShouldCreateMessage() { Segment segment = new Segment("TEST", 1); - Message message = new Message(1, java.util.Arrays.asList(segment)); + Message message = new Message(1, List.of(segment)); assertEquals(1, message.messagePosition()); assertEquals(1, message.segments().size()); @@ -41,7 +42,7 @@ class MessageTest { @Test void getSegmentsShouldReturnUnmodifiableList() { Segment segment = new Segment("TEST", 1); - Message message = new Message(1, java.util.Arrays.asList(segment)); + Message message = new Message(1, List.of(segment)); assertThrows(UnsupportedOperationException.class, () -> { message.getSegments().add(segment); @@ -58,7 +59,7 @@ class MessageTest { void hasSegmentShouldWorkCorrectly() { Segment segment1 = new Segment("TEST1", 1); Segment segment2 = new Segment("TEST2", 2); - Message message = new Message(1, java.util.Arrays.asList(segment1, segment2)); + Message message = new Message(1, List.of(segment1, segment2)); assertTrue(message.hasSegment("TEST1")); assertTrue(message.hasSegment("TEST2")); @@ -71,7 +72,7 @@ class MessageTest { void getSegmentCountShouldReturnCorrectCount() { Segment segment1 = new Segment("TEST1", 1); Segment segment2 = new Segment("TEST2", 2); - Message message = new Message(1, java.util.Arrays.asList(segment1, segment2)); + Message message = new Message(1, List.of(segment1, segment2)); assertEquals(2, message.getSegmentCount()); } @@ -81,7 +82,7 @@ class MessageTest { Segment segment1 = new Segment("TEST", 1); Segment segment2 = new Segment("TEST", 2); Segment segment3 = new Segment("OTHER", 3); - Message message = new Message(1, java.util.Arrays.asList(segment1, segment2, segment3)); + Message message = new Message(1, List.of(segment1, segment2, segment3)); var segments = message.getSegments("TEST"); assertEquals(2, segments.size()); @@ -95,7 +96,7 @@ class MessageTest { void getFirstSegmentShouldReturnCorrectSegment() { Segment segment1 = new Segment("TEST1", 1); Segment segment2 = new Segment("TEST2", 2); - Message message = new Message(1, java.util.Arrays.asList(segment1, segment2)); + Message message = new Message(1, List.of(segment1, segment2)); assertTrue(message.getFirstSegment("TEST1").isPresent()); assertEquals(segment1, message.getFirstSegment("TEST1").get()); @@ -109,9 +110,9 @@ class MessageTest { @Test void equalsAndHashCodeShouldWorkCorrectly() { Segment segment = new Segment("TEST", 1); - Message message1 = new Message(1, java.util.Arrays.asList(segment)); - Message message2 = new Message(1, java.util.Arrays.asList(segment)); - Message message3 = new Message(2, java.util.Arrays.asList(segment)); + Message message1 = new Message(1, List.of(segment)); + Message message2 = new Message(1, List.of(segment)); + Message message3 = new Message(2, List.of(segment)); assertEquals(message1, message2); assertNotEquals(message1, message3); @@ -121,7 +122,7 @@ class MessageTest { @Test void toStringShouldReturnValidString() { Segment segment = new Segment("TEST", 1); - Message message = new Message(1, java.util.Arrays.asList(segment)); + Message message = new Message(1, List.of(segment)); String result = message.toString(); assertTrue(result.contains("messagePosition=1")); diff --git a/src/test/java/de/gecheckt/asv/domain/model/SegmentTest.java b/src/test/java/de/gecheckt/asv/domain/model/SegmentTest.java index 3a9aa63..98ed6cd 100644 --- a/src/test/java/de/gecheckt/asv/domain/model/SegmentTest.java +++ b/src/test/java/de/gecheckt/asv/domain/model/SegmentTest.java @@ -2,6 +2,7 @@ package de.gecheckt.asv.domain.model; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import java.util.List; /** * Unit tests for the Segment class. @@ -21,7 +22,7 @@ class SegmentTest { @Test void constructorWithNamePositionAndFieldsShouldCreateSegment() { Field field = new Field(1, "value"); - Segment segment = new Segment("TEST", 1, java.util.Arrays.asList(field)); + Segment segment = new Segment("TEST", 1, List.of(field)); assertEquals("TEST", segment.segmentName()); assertEquals(1, segment.segmentPosition()); @@ -53,7 +54,7 @@ class SegmentTest { @Test void getFieldsShouldReturnUnmodifiableList() { Field field = new Field(1, "value"); - Segment segment = new Segment("TEST", 1, java.util.Arrays.asList(field)); + Segment segment = new Segment("TEST", 1, List.of(field)); assertThrows(UnsupportedOperationException.class, () -> { segment.getFields().add(field); @@ -70,7 +71,7 @@ class SegmentTest { void hasFieldAtShouldWorkCorrectly() { Field field1 = new Field(1, "value1"); Field field2 = new Field(3, "value3"); - Segment segment = new Segment("TEST", 1, java.util.Arrays.asList(field1, field2)); + Segment segment = new Segment("TEST", 1, List.of(field1, field2)); assertTrue(segment.hasFieldAt(1)); assertFalse(segment.hasFieldAt(2)); @@ -82,7 +83,7 @@ class SegmentTest { void getFieldCountShouldReturnCorrectCount() { Field field1 = new Field(1, "value1"); Field field2 = new Field(2, "value2"); - Segment segment = new Segment("TEST", 1, java.util.Arrays.asList(field1, field2)); + Segment segment = new Segment("TEST", 1, List.of(field1, field2)); assertEquals(2, segment.getFieldCount()); } @@ -91,7 +92,7 @@ class SegmentTest { void getFieldShouldReturnCorrectField() { Field field1 = new Field(1, "value1"); Field field2 = new Field(2, "value2"); - Segment segment = new Segment("TEST", 1, java.util.Arrays.asList(field1, field2)); + Segment segment = new Segment("TEST", 1, List.of(field1, field2)); assertTrue(segment.getField(1).isPresent()); assertEquals(field1, segment.getField(1).get()); @@ -103,9 +104,9 @@ class SegmentTest { @Test void equalsAndHashCodeShouldWorkCorrectly() { Field field = new Field(1, "value"); - Segment segment1 = new Segment("TEST", 1, java.util.Arrays.asList(field)); - Segment segment2 = new Segment("TEST", 1, java.util.Arrays.asList(field)); - Segment segment3 = new Segment("OTHER", 1, java.util.Arrays.asList(field)); + Segment segment1 = new Segment("TEST", 1, List.of(field)); + Segment segment2 = new Segment("TEST", 1, List.of(field)); + Segment segment3 = new Segment("OTHER", 1, List.of(field)); assertEquals(segment1, segment2); assertNotEquals(segment1, segment3); @@ -115,7 +116,7 @@ class SegmentTest { @Test void toStringShouldReturnValidString() { Field field = new Field(1, "value"); - Segment segment = new Segment("TEST", 1, java.util.Arrays.asList(field)); + Segment segment = new Segment("TEST", 1, List.of(field)); String result = segment.toString(); assertTrue(result.contains("segmentName=TEST")); diff --git a/src/test/java/de/gecheckt/asv/parser/DefaultInputFileParserTest.java b/src/test/java/de/gecheckt/asv/parser/DefaultInputFileParserTest.java index f502d28..d86498d 100644 --- a/src/test/java/de/gecheckt/asv/parser/DefaultInputFileParserTest.java +++ b/src/test/java/de/gecheckt/asv/parser/DefaultInputFileParserTest.java @@ -6,13 +6,12 @@ import de.gecheckt.asv.domain.model.InputFile; import de.gecheckt.asv.domain.model.Message; import de.gecheckt.asv.domain.model.Segment; import de.gecheckt.asv.domain.model.Field; -import java.io.IOException; import java.util.List; class DefaultInputFileParserTest { @Test - void testParseSimpleFile() throws IOException { + void testParseSimpleFile() throws InputFileParseException { // Given SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer(); InputFileParser parser = new DefaultInputFileParser(tokenizer); @@ -80,7 +79,7 @@ class DefaultInputFileParserTest { } @Test - void testParseWithEmptyLines() throws IOException { + void testParseWithEmptyLines() throws InputFileParseException { // Given SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer(); InputFileParser parser = new DefaultInputFileParser(tokenizer); @@ -115,7 +114,7 @@ class DefaultInputFileParserTest { } @Test - void testParseWithNoFields() throws IOException { + void testParseWithNoFields() throws InputFileParseException { // Given SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer(); InputFileParser parser = new DefaultInputFileParser(tokenizer); @@ -184,4 +183,89 @@ class DefaultInputFileParserTest { parser.parse(fileName, null); }); } + + @Test + void testParseInvalidContent() { + // Given + SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer(); + InputFileParser parser = new DefaultInputFileParser(tokenizer); + String fileName = "test.asv"; + String fileContent = "HDR+20260325+12345\n" + + "DAT+field1+field2+field3\n" + + "TRL"; // Missing field that might cause issues in downstream processing + + // When / Then + // This should not throw an exception as our simple parser handles this case + assertDoesNotThrow(() -> { + parser.parse(fileName, fileContent); + }); + } + + @Test + void testParseWithWindowsLineEndings() throws InputFileParseException { + // Given + SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer(); + InputFileParser parser = new DefaultInputFileParser(tokenizer); + String fileName = "test-windows.asv"; + String fileContent = "HDR+20260325+12345\r\n" + + "DAT+field1+field2+field3\r\n" + + "TRL+5"; + + // When + InputFile inputFile = parser.parse(fileName, fileContent); + + // Then + assertNotNull(inputFile); + assertEquals(fileName, inputFile.sourceFileName()); + assertEquals(1, inputFile.messages().size()); + + List messages = inputFile.messages(); + assertEquals(1, messages.size()); + + Message message = messages.get(0); + assertEquals(1, message.messagePosition()); + assertEquals(3, message.segments().size()); + + // Check HDR segment + Segment hdrSegment = message.segments().get(0); + assertEquals("HDR", hdrSegment.segmentName()); + assertEquals(1, hdrSegment.segmentPosition()); + assertEquals(2, hdrSegment.fields().size()); + + Field hdrField1 = hdrSegment.fields().get(0); + assertEquals(1, hdrField1.fieldPosition()); + assertEquals("20260325", hdrField1.rawValue()); + + Field hdrField2 = hdrSegment.fields().get(1); + assertEquals(2, hdrField2.fieldPosition()); + assertEquals("12345", hdrField2.rawValue()); + + // Check DAT segment + Segment datSegment = message.segments().get(1); + assertEquals("DAT", datSegment.segmentName()); + assertEquals(2, datSegment.segmentPosition()); + assertEquals(3, datSegment.fields().size()); + + Field datField1 = datSegment.fields().get(0); + assertEquals(1, datField1.fieldPosition()); + assertEquals("field1", datField1.rawValue()); + + Field datField2 = datSegment.fields().get(1); + assertEquals(2, datField2.fieldPosition()); + assertEquals("field2", datField2.rawValue()); + + Field datField3 = datSegment.fields().get(2); + assertEquals(3, datField3.fieldPosition()); + assertEquals("field3", datField3.rawValue()); + + // Check TRL segment + Segment trlSegment = message.segments().get(2); + assertEquals("TRL", trlSegment.segmentName()); + assertEquals(3, trlSegment.segmentPosition()); + assertEquals(1, trlSegment.fields().size()); + + Field trlField1 = trlSegment.fields().get(0); + assertEquals(1, trlField1.fieldPosition()); + assertEquals("5", trlField1.rawValue()); + } } \ No newline at end of file diff --git a/src/test/java/de/gecheckt/asv/parser/ParserExample.java b/src/test/java/de/gecheckt/asv/parser/ParserExample.java deleted file mode 100644 index 9573981..0000000 --- a/src/test/java/de/gecheckt/asv/parser/ParserExample.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.gecheckt.asv.parser; - -import de.gecheckt.asv.domain.model.InputFile; -import de.gecheckt.asv.domain.model.Message; -import de.gecheckt.asv.domain.model.Segment; -import de.gecheckt.asv.domain.model.Field; -import java.io.IOException; - -/** - * Example usage of the parser. - */ -public class ParserExample { - - public static void main(String[] args) { - try { - // Create the parser - SegmentLineTokenizer tokenizer = new DefaultSegmentLineTokenizer(); - InputFileParser parser = new DefaultInputFileParser(tokenizer); - - // Sample file content - String fileName = "sample.asv"; - String fileContent = "HDR+20260325+12345\n" + - "DAT+John+Doe+30\n" + - "DAT+Jane+Smith+25\n" + - "TRL+2"; - - // Parse the file - InputFile inputFile = parser.parse(fileName, fileContent); - - // Print the results - System.out.println("Parsed file: " + inputFile.sourceFileName()); - System.out.println("Number of messages: " + inputFile.messages().size()); - - for (Message message : inputFile.messages()) { - System.out.println(" Message " + message.messagePosition() + - " has " + message.segments().size() + " segments:"); - - for (Segment segment : message.segments()) { - System.out.println(" Segment " + segment.segmentPosition() + - " (" + segment.segmentName() + ") has " + - segment.fields().size() + " fields:"); - - for (Field field : segment.fields()) { - System.out.println(" Field " + field.fieldPosition() + - ": '" + field.rawValue() + "'"); - } - } - } - } catch (IOException e) { - System.err.println("Error parsing file: " + e.getMessage()); - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/src/test/java/de/gecheckt/asv/validation/field/DefaultFieldValidatorTest.java b/src/test/java/de/gecheckt/asv/validation/field/DefaultFieldValidatorTest.java index 5a737b8..bec395b 100644 --- a/src/test/java/de/gecheckt/asv/validation/field/DefaultFieldValidatorTest.java +++ b/src/test/java/de/gecheckt/asv/validation/field/DefaultFieldValidatorTest.java @@ -2,8 +2,8 @@ package de.gecheckt.asv.validation.field; import static org.junit.jupiter.api.Assertions.*; -import java.util.Arrays; import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.Test; @@ -29,9 +29,9 @@ class DefaultFieldValidatorTest { // Arrange Field field1 = new Field(1, "value1", "Field1"); Field field2 = new Field(2, "value2", "Field2"); - Segment segment = new Segment("SEG1", 1, Arrays.asList(field1, field2)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field1, field2)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); @@ -47,9 +47,9 @@ class DefaultFieldValidatorTest { void testValidate_withEmptyRawValue_returnsError() { // Arrange Field field = new Field(1, "", "Field1"); - Segment segment = new Segment("SEG1", 1, Arrays.asList(field)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); @@ -74,9 +74,9 @@ class DefaultFieldValidatorTest { void testValidate_withWhitespaceOnlyRawValue_returnsError() { // Arrange Field field = new Field(1, " ", "Field1"); - Segment segment = new Segment("SEG1", 1, Arrays.asList(field)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); @@ -97,30 +97,14 @@ class DefaultFieldValidatorTest { assertEquals("Non-whitespace-only raw value required", error.getExpectedRule().orElse(null)); } - @Test - void testValidate_withZeroFieldPosition_returnsError() { - // Note: This test creates a field with an invalid position that would normally be rejected by the domain model. - // We're testing the validator's ability to handle such cases if they were to occur. - // In practice, the domain model prevents this, but we include the check for completeness. - - // For this test, we'll simulate the scenario by directly creating the objects - // Since the domain model prevents zero/negative positions, we'll skip this test for now - // as it would require changing the domain model which is outside our scope. - } - - @Test - void testValidate_withNegativeFieldPosition_returnsError() { - // Note: Similar to the zero position test, this would require bypassing the domain model restrictions. - // We'll skip this test for the same reasons. - } @Test void testValidate_withEmptyFieldName_returnsError() { // Arrange Field field = new Field(1, "value1", ""); - Segment segment = new Segment("SEG1", 1, Arrays.asList(field)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); @@ -145,9 +129,9 @@ class DefaultFieldValidatorTest { void testValidate_withWhitespaceOnlyFieldName_returnsError() { // Arrange Field field = new Field(1, "value1", " "); - Segment segment = new Segment("SEG1", 1, Arrays.asList(field)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); @@ -173,9 +157,9 @@ class DefaultFieldValidatorTest { // Arrange Field field1 = new Field(1, "value1", "Field1"); Field field3 = new Field(3, "value3", "Field3"); // Missing field at position 2 - Segment segment = new Segment("SEG1", 1, Arrays.asList(field1, field3)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field1, field3)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); @@ -202,9 +186,9 @@ class DefaultFieldValidatorTest { // Arrange Field field1 = new Field(1, "", "Field1"); // Empty value Field field2 = new Field(2, " ", " "); // Whitespace only value and name - Segment segment = new Segment("SEG1", 1, Arrays.asList(field1, field2)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field1, field2)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); @@ -235,8 +219,8 @@ class DefaultFieldValidatorTest { void testValidate_withNoFields_returnsNoErrors() { // Arrange Segment segment = new Segment("SEG1", 1, Collections.emptyList()); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.asv", Arrays.asList(message)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.asv", List.of(message)); // Act ValidationResult result = validator.validate(inputFile); diff --git a/src/test/java/de/gecheckt/asv/validation/model/ValidationResultTest.java b/src/test/java/de/gecheckt/asv/validation/model/ValidationResultTest.java index 697ac4d..b651e05 100644 --- a/src/test/java/de/gecheckt/asv/validation/model/ValidationResultTest.java +++ b/src/test/java/de/gecheckt/asv/validation/model/ValidationResultTest.java @@ -2,6 +2,7 @@ package de.gecheckt.asv.validation.model; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import java.util.List; class ValidationResultTest { @@ -12,7 +13,7 @@ class ValidationResultTest { "TEST001", "Test error", ValidationSeverity.ERROR, "SEGMENT", 1, "FIELD", 1, "actual", "expected" ); - ValidationResult result = new ValidationResult(java.util.Arrays.asList(error)); + ValidationResult result = new ValidationResult(List.of(error)); // When & Then assertTrue(result.hasErrors()); @@ -27,33 +28,11 @@ class ValidationResultTest { "TEST001", "Test error", ValidationSeverity.ERROR, "SEGMENT", 1, "FIELD", 1, "actual", "expected" ); - ValidationResult result = new ValidationResult(java.util.Arrays.asList(error)); + ValidationResult result = new ValidationResult(List.of(error)); // When & Then assertThrows(UnsupportedOperationException.class, () -> { result.getErrors().add(error); }); } - - @Test - void testValidationErrorCreationAndAccess() { - // Given - ValidationError error = new ValidationError( - "TEST001", "Test error", ValidationSeverity.ERROR, - "SEGMENT", 1, "FIELD", 2, "actualValue", "expectedRule" - ); - - // When & Then - assertEquals("TEST001", error.errorCode()); - assertEquals("Test error", error.description()); - assertEquals(ValidationSeverity.ERROR, error.severity()); - assertEquals("SEGMENT", error.segmentName()); - assertEquals(1, error.segmentPosition()); - assertEquals("FIELD", error.fieldName()); - assertEquals(2, error.fieldPosition()); - assertTrue(error.getActualValue().isPresent()); - assertEquals("actualValue", error.getActualValue().get()); - assertTrue(error.getExpectedRule().isPresent()); - assertEquals("expectedRule", error.getExpectedRule().get()); - } } \ No newline at end of file diff --git a/src/test/java/de/gecheckt/asv/validation/structure/DefaultStructureValidatorTest.java b/src/test/java/de/gecheckt/asv/validation/structure/DefaultStructureValidatorTest.java index ef8a73c..734567b 100644 --- a/src/test/java/de/gecheckt/asv/validation/structure/DefaultStructureValidatorTest.java +++ b/src/test/java/de/gecheckt/asv/validation/structure/DefaultStructureValidatorTest.java @@ -2,8 +2,8 @@ package de.gecheckt.asv.validation.structure; import static org.junit.jupiter.api.Assertions.*; -import java.util.Arrays; import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -50,7 +50,7 @@ class DefaultStructureValidatorTest { @Test void validate_shouldReportErrorWhenMessageHasNoSegments() { Message message = new Message(1, Collections.emptyList()); - InputFile inputFile = new InputFile("test.txt", Arrays.asList(message)); + InputFile inputFile = new InputFile("test.txt", List.of(message)); ValidationResult result = validator.validate(inputFile); @@ -68,8 +68,8 @@ class DefaultStructureValidatorTest { void validate_shouldReportErrorWhenSegmentHasDuplicatePositions() { Segment segment1 = new Segment("SEG1", 1); Segment segment2 = new Segment("SEG2", 1); // Duplicate position - Message message = new Message(1, Arrays.asList(segment1, segment2)); - InputFile inputFile = new InputFile("test.txt", Arrays.asList(message)); + Message message = new Message(1, List.of(segment1, segment2)); + InputFile inputFile = new InputFile("test.txt", List.of(message)); ValidationResult result = validator.validate(inputFile); @@ -87,9 +87,9 @@ class DefaultStructureValidatorTest { void validate_shouldReportErrorWhenFieldHasDuplicatePositions() { Field field1 = new Field(1, "value1"); Field field2 = new Field(1, "value2"); // Duplicate position - Segment segment = new Segment("SEG1", 1, Arrays.asList(field1, field2)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.txt", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field1, field2)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.txt", List.of(message)); ValidationResult result = validator.validate(inputFile); @@ -108,9 +108,9 @@ class DefaultStructureValidatorTest { void validate_shouldReturnNoErrorsForValidStructure() { Field field1 = new Field(1, "value1"); Field field2 = new Field(2, "value2"); - Segment segment = new Segment("SEG1", 1, Arrays.asList(field1, field2)); - Message message = new Message(1, Arrays.asList(segment)); - InputFile inputFile = new InputFile("test.txt", Arrays.asList(message)); + Segment segment = new Segment("SEG1", 1, List.of(field1, field2)); + Message message = new Message(1, List.of(segment)); + InputFile inputFile = new InputFile("test.txt", List.of(message)); ValidationResult result = validator.validate(inputFile);