From 0c0faf228620e7da9b9b85581b716995baf9404f Mon Sep 17 00:00:00 2001 From: Marcus van Elst Date: Thu, 2 Apr 2026 17:31:14 +0200 Subject: [PATCH] =?UTF-8?q?Grenzfalltests=20f=C3=BCr=20StartConfigurationV?= =?UTF-8?q?alidator=20erg=C3=A4nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- .../StartConfigurationValidatorTest.java | 349 ++++++++++++++++++ review-input/.gitignore | 6 + 3 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 review-input/.gitignore diff --git a/.gitignore b/.gitignore index e21bf11..dd207db 100644 --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,5 @@ Desktop.ini # JVM Crash Logs # ========================================================= hs_err_pid* -replay_pid* \ No newline at end of file +replay_pid* +/review-input.zip diff --git a/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/config/StartConfigurationValidatorTest.java b/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/config/StartConfigurationValidatorTest.java index f8fbb81..0d70e83 100644 --- a/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/config/StartConfigurationValidatorTest.java +++ b/pdf-umbenenner-application/src/test/java/de/gecheckt/pdf/umbenenner/application/config/StartConfigurationValidatorTest.java @@ -343,6 +343,64 @@ class StartConfigurationValidatorTest { assertTrue(exception.getMessage().contains("max.text.characters: must be > 0")); } + @Test + void validate_maxRetriesTransientZeroIsValid() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("https://api.example.com"), + "gpt-4", + 30, + 0, // maxRetriesTransient = 0 ist gültig + 100, + 50000, + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + assertDoesNotThrow(() -> validator.validate(config)); + } + + @Test + void validate_failsWhenMaxTextCharactersIsZero() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("https://api.example.com"), + "gpt-4", + 30, + 3, + 100, + 0, // maxTextCharacters = 0 ist ungültig + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("max.text.characters: must be > 0")); + } + @Test void validate_failsWhenSourceFolderDoesNotExist() throws Exception { Path targetFolder = Files.createDirectory(tempDir.resolve("target")); @@ -832,4 +890,295 @@ class StartConfigurationValidatorTest { assertDoesNotThrow(() -> validatorWithMock.validate(config), "Validation should succeed when source folder checker returns null"); } + + // Neue Tests zur Verbesserung der Abdeckung + + @Test + void validate_failsWhenSqliteFileHasNoParent() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + // Ein Pfad ohne Parent (z.B. einfacher Dateiname) + Path sqliteFileWithoutParent = Path.of("db.sqlite"); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFileWithoutParent, + URI.create("https://api.example.com"), + "gpt-4", + 30, + 3, + 100, + 50000, + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("sqlite.file: has no parent directory")); + } + + @Test + void validate_failsWhenSqliteFileParentIsNotDirectory() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + // Erstelle eine Datei und versuche dann, eine Unterdatei davon zu erstellen + Path parentFile = Files.createFile(tempDir.resolve("parentFile.txt")); + Path sqliteFileWithFileAsParent = parentFile.resolve("db.sqlite"); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFileWithFileAsParent, + URI.create("https://api.example.com"), + "gpt-4", + 30, + 3, + 100, + 50000, + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("sqlite.file: parent is not a directory")); + } + + @Test + void validate_apiModelBlankString() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("https://api.example.com"), + " ", // Blank string + 30, + 3, + 100, + 50000, + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("api.model: must not be null or blank")); + } + + @Test + void validate_apiModelEmptyString() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("https://api.example.com"), + "", // Empty string + 30, + 3, + 100, + 50000, + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("api.model: must not be null or blank")); + } + + @Test + void validate_runtimeLockFileParentDoesNotExist() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("https://api.example.com"), + "gpt-4", + 30, + 3, + 100, + 50000, + promptTemplateFile, + tempDir.resolve("nonexistent/lock.lock"), // Lock file mit nicht existierendem Parent + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("runtime.lock.file: parent directory does not exist")); + } + + @Test + void validate_runtimeLockFileParentIsNotDirectory() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + // Erstelle eine Datei und versuche dann, eine Unterdatei davon zu erstellen + Path parentFile = Files.createFile(tempDir.resolve("parentFile.txt")); + Path lockFileWithFileAsParent = parentFile.resolve("lock.lock"); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("https://api.example.com"), + "gpt-4", + 30, + 3, + 100, + 50000, + promptTemplateFile, + lockFileWithFileAsParent, // Lock file mit Datei als Parent + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("runtime.lock.file: parent is not a directory")); + } + + @Test + void validate_logDirectoryExistsButIsNotDirectory() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + // Erstelle eine Datei, die als Log-Verzeichnis verwendet wird + Path logFileInsteadOfDirectory = Files.createFile(tempDir.resolve("logfile.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("https://api.example.com"), + "gpt-4", + 30, + 3, + 100, + 50000, + promptTemplateFile, + null, + logFileInsteadOfDirectory, // Datei statt Verzeichnis + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + assertTrue(exception.getMessage().contains("log.directory: exists but is not a directory")); + } + + @Test + void validate_apiBaseUrlHttpScheme() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("http://api.example.com"), // HTTP statt HTTPS + "gpt-4", + 30, + 3, + 100, + 50000, + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + assertDoesNotThrow(() -> validator.validate(config), + "HTTP scheme should be valid"); + } + + @Test + void validate_apiBaseUrlNullScheme() throws Exception { + Path sourceFolder = Files.createDirectory(tempDir.resolve("source")); + Path targetFolder = Files.createDirectory(tempDir.resolve("target")); + Path sqliteFile = Files.createFile(tempDir.resolve("db.sqlite")); + Path promptTemplateFile = Files.createFile(tempDir.resolve("prompt.txt")); + + StartConfiguration config = new StartConfiguration( + sourceFolder, + targetFolder, + sqliteFile, + URI.create("//api.example.com"), // Kein Schema + "gpt-4", + 30, + 3, + 100, + 50000, + promptTemplateFile, + null, + null, + "INFO", + "test-api-key" + ); + + InvalidStartConfigurationException exception = assertThrows( + InvalidStartConfigurationException.class, + () -> validator.validate(config) + ); + // Bei einer URI ohne Schema ist sie nicht absolut, daher kommt zuerst diese Fehlermeldung + assertTrue(exception.getMessage().contains("api.baseUrl: must be an absolute URI")); + } } \ No newline at end of file diff --git a/review-input/.gitignore b/review-input/.gitignore new file mode 100644 index 0000000..6d04a38 --- /dev/null +++ b/review-input/.gitignore @@ -0,0 +1,6 @@ +/jacoco-aggregate.xml +/pdf-umbenenner-adapter-in-cli-mutations.xml +/pdf-umbenenner-adapter-out-mutations.xml +/pdf-umbenenner-application-mutations.xml +/pdf-umbenenner-bootstrap-mutations.xml +/pdf-umbenenner-domain-mutations.xml