From 951145d746f316cc40b78e46e359b2513831da32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20Czy=C5=BC?= Date: Fri, 29 Aug 2025 08:03:10 +0200 Subject: [PATCH] feat: add generating storege config validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bartosz Czyż # Conflicts: # here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/CopyCommand.java # here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/service/CopyService.java # here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/CopyCliTest.java --- .../cli/PrintExceptionMessageHandler.java | 8 +- .../com/here/naksha/cli/copy/CopyCommand.java | 18 +-- .../naksha/cli/copy/service/CopyService.java | 12 +- .../naksha/cli/parsers/JsonFileParser.java | 20 +-- .../naksha/cli/results/CommandFailure.java | 4 - .../naksha/cli/results/CommandResult.java | 8 -- .../naksha/cli/results/CommandSuccess.java | 4 - .../naksha/cli/results/FailureResult.java | 4 + .../com/here/naksha/cli/results/Result.java | 8 ++ .../naksha/cli/results/SuccessResult.java | 4 + .../cli/storages/GeneratingSession.java | 10 ++ .../cli/storages/GeneratingStorageConfig.java | 40 ++++++ .../GeneratingStorageConfigProperties.java | 74 ++++++++--- .../storages/GeneratingStorageService.java | 14 ++- .../naksha/cli/validations/Validator.java | 49 ++++++++ .../cli/validations/ValidatorUtils.java | 35 ++++++ .../naksha/cli/validations/Validators.java | 105 ++++++++++++++++ .../exceptions/FieldValidationException.java | 7 ++ .../exceptions/OrValidationException.java | 30 +++++ .../exceptions/ValidationException.java | 26 ++++ .../com/here/naksha/cli/copy/CopyCliTest.java | 8 +- .../cli/copy/service/CopyServiceTest.java | 68 +++++----- .../cli/copy/service/psql/PsqlCopyTest.java | 8 +- .../cli/parsers/JsonFileParserTest.java | 9 +- ...GeneratingStorageConfigPropertiesTest.java | 118 ++++++++++++++++++ .../storages/GeneratingStorageConfigTest.java | 35 ++++++ .../cli/storages/GeneratingStorageTest.java | 20 --- 27 files changed, 611 insertions(+), 135 deletions(-) delete mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandFailure.java delete mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandResult.java delete mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandSuccess.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/FailureResult.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/Result.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/SuccessResult.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validator.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/ValidatorUtils.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validators.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/FieldValidationException.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/OrValidationException.java create mode 100644 here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/ValidationException.java create mode 100644 here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigPropertiesTest.java create mode 100644 here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigTest.java diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/PrintExceptionMessageHandler.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/PrintExceptionMessageHandler.java index fe093b5eb..e663c5c98 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/PrintExceptionMessageHandler.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/PrintExceptionMessageHandler.java @@ -8,10 +8,10 @@ public int handleExecutionException( CommandLine cmd, CommandLine.ParseResult parseResult ) { - - cmd.getErr().println(cmd.getColorScheme().errorText(ex.getMessage())); - if (ex.getCause() != null) { - cmd.getErr().println(cmd.getColorScheme().errorText(ex.getCause().getMessage())); + Throwable cause = ex; + while (cause != null) { + cmd.getErr().println(cmd.getColorScheme().errorText(cause.getMessage())); + cause = cause.getCause(); } return cmd.getExitCodeExceptionMapper() != null diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/CopyCommand.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/CopyCommand.java index 621ebe58e..a1f3670c3 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/CopyCommand.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/CopyCommand.java @@ -4,9 +4,9 @@ import com.here.naksha.cli.loggers.LoggingMixin; import com.here.naksha.cli.parsers.JsonFileParser; import com.here.naksha.cli.parsers.JsonFileParserException; -import com.here.naksha.cli.results.CommandFailure; -import com.here.naksha.cli.results.CommandResult; -import com.here.naksha.cli.results.CommandSuccess; +import com.here.naksha.cli.results.FailureResult; +import com.here.naksha.cli.results.Result; +import com.here.naksha.cli.results.SuccessResult; import naksha.model.NakshaContext; import naksha.model.SessionOptions; import naksha.model.objects.NakshaStorage; @@ -102,11 +102,13 @@ public Integer call() throws JsonFileParserException, CopyServiceException { NakshaContext.currentContext().withAppId("nakshacli"); SessionOptions sessionOptions = SessionOptions.from(NakshaContext.currentContext()); - CommandResult copyResult = copy( + + Result copyResult = copy( srcCopyElement, targetCopyElement, sessionOptions ); + CopyServiceSuccessResultPayload resultPayload = requireSuccessResultAndGetPayload(copyResult); PrintWriter commandLineOut = getCommandLineOut(); @@ -134,11 +136,11 @@ private String buildCopySuccessMessage( } private CopyServiceSuccessResultPayload requireSuccessResultAndGetPayload( - CommandResult copyResult + Result copyResult ) throws CopyServiceException { return switch (copyResult) { - case CommandFailure(CopyServiceException exception) -> throw exception; - case CommandSuccess(CopyServiceSuccessResultPayload payload) -> payload; + case FailureResult(CopyServiceException exception) -> throw exception; + case SuccessResult(CopyServiceSuccessResultPayload payload) -> payload; }; } @@ -158,7 +160,7 @@ private CopyElement buildTargetCopyElement() throws JsonFileParserException { .build(); } - private CommandResult copy( + private Result copy( CopyElement srcCopyElement, CopyElement targetCopyElement, SessionOptions sessionOptions diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/service/CopyService.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/service/CopyService.java index fb57ddd15..93ac8f3d6 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/service/CopyService.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/copy/service/CopyService.java @@ -1,8 +1,8 @@ package com.here.naksha.cli.copy.service; -import com.here.naksha.cli.results.CommandFailure; -import com.here.naksha.cli.results.CommandResult; -import com.here.naksha.cli.results.CommandSuccess; +import com.here.naksha.cli.results.FailureResult; +import com.here.naksha.cli.results.Result; +import com.here.naksha.cli.results.SuccessResult; import naksha.base.StringList; import naksha.model.IStorage; import naksha.model.NakshaError; @@ -35,7 +35,7 @@ public CopyService( } @NotNull - public CommandResult copy( + public Result copy( @NotNull CopyElement src, @NotNull CopyElement target, boolean autoCreateTarget @@ -47,9 +47,9 @@ public CommandResult copy } List features = readFeaturesFromSrc(src); writeFeaturesToTarget(features, target, targetStorage); - return new CommandSuccess<>(buildSuccessResultPayload(features)); + return new SuccessResult<>(buildSuccessResultPayload(features)); } catch (CopyServiceException exception) { - return new CommandFailure<>(exception); + return new FailureResult<>(exception); } } diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/parsers/JsonFileParser.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/parsers/JsonFileParser.java index fa4a1daee..5b44a9f06 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/parsers/JsonFileParser.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/parsers/JsonFileParser.java @@ -4,6 +4,8 @@ import naksha.base.Platform; import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import java.nio.file.FileSystemException; import java.nio.file.Files; import java.nio.file.Path; @@ -12,28 +14,18 @@ public final class JsonFileParser { @NotNull public T parse(@NotNull Path path, @NotNull Class clazz) throws JsonFileParserException { - requireFileExists(path); - requireIsRegularFile(path); String json = readFile(path); Object raw = parseJsonToObject(json, path); return box(raw, clazz, path); } - private void requireFileExists(Path path) throws JsonFileParserException { - if (!Files.exists(path)) { - throw new JsonFileParserException("File does not exist!", path); - } - } - - private void requireIsRegularFile(Path path) throws JsonFileParserException { - if (!Files.isRegularFile(path)) { - throw new JsonFileParserException("It is not a file!", path); - } - } - private String readFile(Path path) throws JsonFileParserException { try { return Files.readString(path); + } catch (FileSystemException e) { + throw new JsonFileParserException("Problem with reading! " + e.getClass().getSimpleName(), path); + } catch (IOException e) { + throw new JsonFileParserException("Problem with reading! " + e.getMessage(), path); } catch (Exception e) { throw new JsonFileParserException("Problem with reading!", path, e); } diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandFailure.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandFailure.java deleted file mode 100644 index 926c7086c..000000000 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandFailure.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.here.naksha.cli.results; - -public record CommandFailure(S payload) implements CommandResult { -} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandResult.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandResult.java deleted file mode 100644 index 88381d1fd..000000000 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandResult.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.here.naksha.cli.results; - -/** - * @param type of {@link CommandSuccess}'s payload - * @param type of {@link CommandFailure}'s payload - */ -public sealed interface CommandResult permits CommandSuccess, CommandFailure { -} \ No newline at end of file diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandSuccess.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandSuccess.java deleted file mode 100644 index 1b6cf349d..000000000 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/CommandSuccess.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.here.naksha.cli.results; - -public record CommandSuccess(T payload) implements CommandResult { -} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/FailureResult.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/FailureResult.java new file mode 100644 index 000000000..265e05f78 --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/FailureResult.java @@ -0,0 +1,4 @@ +package com.here.naksha.cli.results; + +public record FailureResult(S payload) implements Result { +} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/Result.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/Result.java new file mode 100644 index 000000000..3fdeec6de --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/Result.java @@ -0,0 +1,8 @@ +package com.here.naksha.cli.results; + +/** + * @param type of {@link SuccessResult}'s payload + * @param type of {@link FailureResult}'s payload + */ +public sealed interface Result permits SuccessResult, FailureResult { +} \ No newline at end of file diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/SuccessResult.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/SuccessResult.java new file mode 100644 index 000000000..f7ed58774 --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/results/SuccessResult.java @@ -0,0 +1,4 @@ +package com.here.naksha.cli.results; + +public record SuccessResult(T payload) implements Result { +} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingSession.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingSession.java index 109756c7c..e811f8b00 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingSession.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingSession.java @@ -1,5 +1,6 @@ package com.here.naksha.cli.storages; +import com.here.naksha.cli.validations.exceptions.FieldValidationException; import naksha.model.*; import naksha.model.objects.NakshaCollection; import naksha.model.objects.NakshaFeature; @@ -30,6 +31,7 @@ final class GeneratingSession implements IReadSession { public Response execute(@NotNull Request request) { GeneratingStorageService service = storage.getService(); GeneratingStorageConfig config = storage.getConfig(); + requireValidConfig(config); List generatedFeatures = service.generateFeatures(config.getProperties()); return new SuccessResponse(generatedFeatures); } @@ -125,4 +127,12 @@ public void loadTuples(@NotNull List featureTuples) { public void loadTuples(@NotNull List featureTuples, int from, int to, int mode) { throw new NakshaException(NakshaError.UNSUPPORTED_OPERATION, ""); } + + private void requireValidConfig(GeneratingStorageConfig config) { + try { + config.validateFields(); + } catch (FieldValidationException e) { + throw new NakshaException(NakshaError.EXCEPTION, "Generating storage config is invalid!", e); + } + } } diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfig.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfig.java index e6d8d01f5..d358b48a9 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfig.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfig.java @@ -1,9 +1,17 @@ package com.here.naksha.cli.storages; +import com.here.naksha.cli.validations.Validator; +import com.here.naksha.cli.validations.exceptions.FieldValidationException; +import naksha.base.AnyMap; import naksha.base.JvmBoxingUtil; +import naksha.model.objects.NakshaProperties; import naksha.model.objects.NakshaStorage; import org.jetbrains.annotations.NotNull; +import static com.here.naksha.cli.validations.ValidatorUtils.requireValidArgument; +import static com.here.naksha.cli.validations.ValidatorUtils.requireValidField; +import static com.here.naksha.cli.validations.Validators.canBeBoxed; +import static com.here.naksha.cli.validations.Validators.isNotNull; import static java.util.Objects.requireNonNull; public final class GeneratingStorageConfig extends NakshaStorage { @@ -12,4 +20,36 @@ public final class GeneratingStorageConfig extends NakshaStorage { public GeneratingStorageConfigProperties getProperties() { return requireNonNull(JvmBoxingUtil.box(super.getProperties(), GeneratingStorageConfigProperties.class)); } + + @Override + public void setProperties(@NotNull NakshaProperties generatingStorageConfigProperties) { + requireValidArgument(propertiesFieldValidator.validate(generatingStorageConfigProperties)); + super.setProperties(generatingStorageConfigProperties); + } + + @Override + @NotNull + public GeneratingStorageConfig withProperties(@NotNull NakshaProperties generatingStorageConfigProperties) { + setProperties(generatingStorageConfigProperties); + return this; + } + + @Override + public void onCreation() { + super.onCreation(); + setRaw(PROPERTIES_KEY, new GeneratingStorageConfigProperties()); + } + + public void validateFields() throws FieldValidationException { + AnyMap map = requireNonNull(JvmBoxingUtil.box(platformObject(), AnyMap.class)); + validatePropertiesField(map); + } + + private final Validator propertiesFieldValidator = isNotNull() + .and(canBeBoxed(GeneratingStorageConfigProperties.class)); + + private void validatePropertiesField(AnyMap map) throws FieldValidationException { + requireValidField(PROPERTIES_KEY, map, propertiesFieldValidator); + getProperties().validateFields(); + } } \ No newline at end of file diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfigProperties.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfigProperties.java index 1343c4981..06b23c8e6 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfigProperties.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageConfigProperties.java @@ -1,30 +1,41 @@ package com.here.naksha.cli.storages; -import naksha.base.JvmBoxingUtil; -import naksha.base.JvmList; -import naksha.base.StringList; +import com.here.naksha.cli.validations.Validator; +import com.here.naksha.cli.validations.exceptions.FieldValidationException; +import naksha.base.*; import naksha.model.objects.NakshaProperties; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.here.naksha.cli.validations.ValidatorUtils.requireValidArgument; +import static com.here.naksha.cli.validations.ValidatorUtils.requireValidField; +import static com.here.naksha.cli.validations.Validators.*; +import static java.util.Objects.requireNonNull; + public final class GeneratingStorageConfigProperties extends NakshaProperties { - private static final String COUNT_KEY = "count"; - private static final String IDS_PREFIX_KEY = "idsPrefix"; - private static final String TILE_IDS_KEY = "tileIds"; - private static final String TILE_IDS_CSV_FILE_PATH_KEY = "tileIdsCsvFile"; - private static final String FEATURE_TEMPLATE_FILE_PATH_KEY = "featureTemplateFile"; + public static final String COUNT_KEY = "count"; + public static final String IDS_PREFIX_KEY = "idsPrefix"; + public static final String TILE_IDS_KEY = "tileIds"; + public static final String TILE_IDS_CSV_FILE_PATH_KEY = "tileIdsCsvFile"; + public static final String FEATURE_TEMPLATE_FILE_PATH_KEY = "featureTemplateFile"; + + @Override + public void onCreation() { + super.onCreation(); + setRaw(COUNT_KEY, 0); + } - @Nullable - public Integer getCount() { - return (Integer) getRaw(COUNT_KEY); + public int getCount() { + return (int) requireNonNull(getRaw(COUNT_KEY)); } - public void setCount(@Nullable Integer count) { + public void setCount(int count) { + requireValidArgument(countFieldValidator.validate(count)); setRaw(COUNT_KEY, count); } @NotNull - public GeneratingStorageConfigProperties withCount(@NotNull Integer count) { + public GeneratingStorageConfigProperties withCount(int count) { setCount(count); return this; } @@ -46,8 +57,8 @@ public GeneratingStorageConfigProperties withIdsPrefix(@Nullable String idsPrefi @Nullable public StringList getTileIds() { - JvmList jvmList = (JvmList) getRaw(TILE_IDS_KEY); - return JvmBoxingUtil.box(jvmList, StringList.class); + PlatformList platformList = (PlatformList) getRaw(TILE_IDS_KEY); + return JvmBoxingUtil.box(platformList, StringList.class); } public void setTileIds(@Nullable StringList tileIds) { @@ -89,4 +100,37 @@ public GeneratingStorageConfigProperties withFeatureTemplateFilePath(@Nullable S setFeatureTemplateFilePath(path); return this; } + + public void validateFields() throws FieldValidationException { + AnyMap map = requireNonNull(JvmBoxingUtil.box(platformObject(), AnyMap.class)); + validateCountField(map); + validateTileIdsField(map); + requireStringOrNull(IDS_PREFIX_KEY, map); + requireStringOrNull(TILE_IDS_CSV_FILE_PATH_KEY, map); + requireStringOrNull(FEATURE_TEMPLATE_FILE_PATH_KEY, map); + } + + private void requireStringOrNull(String key, AnyMap map) throws FieldValidationException { + Validator validator = isNotNull() + .and(isInstanceOf(String.class)) + .or(isNull()); + requireValidField(key, map, validator); + } + + private final Validator countFieldValidator = isNotNull() + .and(isInstanceOf(Integer.class)) + .and(fulfillPredicate(count -> count >= 0, "The count should be >= 0, but %s is provided."::formatted)); + + private void validateTileIdsField(AnyMap map) throws FieldValidationException { + Validator validator = isNotNull() + .and(canBeBoxed(AnyList.class)) + .and(allElements(isInstanceOf(String.class))) + .and(canBeBoxed(StringList.class)) + .or(isNull()); + requireValidField(TILE_IDS_KEY, map, validator); + } + + private void validateCountField(AnyMap map) throws FieldValidationException { + requireValidField(COUNT_KEY, map, countFieldValidator); + } } \ No newline at end of file diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageService.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageService.java index 374247e4c..840000dd0 100644 --- a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageService.java +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/storages/GeneratingStorageService.java @@ -2,6 +2,7 @@ import com.here.naksha.cli.parsers.JsonFileParser; import com.here.naksha.cli.parsers.JsonFileParserException; +import com.here.naksha.cli.validations.exceptions.FieldValidationException; import com.here.naksha.lib.core.models.geojson.HQuad; import naksha.base.StringList; import naksha.geo.LineStringCoord; @@ -29,7 +30,8 @@ final class GeneratingStorageService { @NotNull List generateFeatures(@NotNull GeneratingStorageConfigProperties configProperties) { - int count = requireCount(configProperties.getCount()); + requireValidConfigProperties(configProperties); + int count = configProperties.getCount(); String idsPrefix = getIdsPrefixOrDefault(configProperties, DEFAULT_IDS_PREFIX); List tileIds = requireTileIds(configProperties); NakshaFeature templateFeature = loadTemplateFeatureOrEmpty(configProperties.getFeatureTemplateFilePath()); @@ -47,12 +49,12 @@ List generateFeatures(@NotNull GeneratingStorageConfigProperties return features; } - private int requireCount(@Nullable Integer count) { - if (count == null) { - throw new NakshaException(NakshaError.ILLEGAL_ARGUMENT, "Provide count in the config properties."); + private void requireValidConfigProperties(GeneratingStorageConfigProperties configProperties) { + try { + configProperties.validateFields(); + } catch (FieldValidationException exception) { + throw new NakshaException(NakshaError.EXCEPTION, "Generating storage config properties are invalid!", exception); } - - return count; } private String getIdsPrefixOrDefault(GeneratingStorageConfigProperties configProperties, String defaultPrefix) { diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validator.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validator.java new file mode 100644 index 000000000..3aa395a11 --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validator.java @@ -0,0 +1,49 @@ +package com.here.naksha.cli.validations; + +import com.here.naksha.cli.results.FailureResult; +import com.here.naksha.cli.results.Result; +import com.here.naksha.cli.results.SuccessResult; +import com.here.naksha.cli.validations.exceptions.OrValidationException; +import com.here.naksha.cli.validations.exceptions.ValidationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@FunctionalInterface +public interface Validator { + @NotNull + Result validate(@Nullable T toValidate); + + @NotNull + default Validator and(@NotNull Validator other) { + return obj -> { + Result result = validate(obj); + return switch (result) { + case FailureResult(ValidationException exception) -> new FailureResult<>(exception); + case SuccessResult(S payload) -> other.validate(payload); + }; + }; + } + + @NotNull + default Validator or(@NotNull Validator other) { + return obj -> { + Result result = validate(obj); + return switch (result) { + case FailureResult(ValidationException exception) -> other.orValidate(obj, exception); + case SuccessResult successResult -> successResult; + }; + }; + } + + private Result orValidate(@Nullable T toValidate, ValidationException prevException) { + Result result = validate(toValidate); + return switch (result) { + case FailureResult(ValidationException exception) -> new FailureResult<>( + new OrValidationException(List.of(prevException, exception)) + ); + case SuccessResult successResult -> successResult; + }; + } +} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/ValidatorUtils.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/ValidatorUtils.java new file mode 100644 index 000000000..ca5d4e29a --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/ValidatorUtils.java @@ -0,0 +1,35 @@ +package com.here.naksha.cli.validations; + +import com.here.naksha.cli.results.FailureResult; +import com.here.naksha.cli.results.Result; +import com.here.naksha.cli.validations.exceptions.FieldValidationException; +import com.here.naksha.cli.validations.exceptions.ValidationException; +import naksha.base.AnyMap; +import org.jetbrains.annotations.NotNull; + +public final class ValidatorUtils { + private ValidatorUtils() { + } + + public static void requireValidField( + @NotNull String key, @NotNull AnyMap map, @NotNull Validator validator + ) throws FieldValidationException { + Object object = map.get(key); + Result result = validator.validate(object); + handleFieldValidationResult(result, key); + } + + public static void requireValidArgument(@NotNull Result result) { + if (result instanceof FailureResult(ValidationException exception)) { + throw new IllegalArgumentException(exception.getMessage()); + } + } + + private static void handleFieldValidationResult( + Result result, String fieldName + ) throws FieldValidationException { + if (result instanceof FailureResult(ValidationException exception)) { + throw new FieldValidationException(fieldName, exception); + } + } +} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validators.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validators.java new file mode 100644 index 000000000..471cee081 --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/Validators.java @@ -0,0 +1,105 @@ +package com.here.naksha.cli.validations; + +import com.here.naksha.cli.results.FailureResult; +import com.here.naksha.cli.results.SuccessResult; +import com.here.naksha.cli.validations.exceptions.ValidationException; +import naksha.base.JvmBoxingUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Function; +import java.util.function.Predicate; + +import static java.util.Objects.requireNonNull; + +public final class Validators { + private Validators() { + } + + @NotNull + public static Validator isNotNull() { + return obj -> { + if (obj == null) { + return new FailureResult<>(new ValidationException("Cannot be null.")); + } + return new SuccessResult<>(obj); + }; + } + + @NotNull + public static Validator isNull() { + return obj -> { + if (obj != null) { + return new FailureResult<>(new ValidationException("Should be null.")); + } + return new SuccessResult<>((S) null); + }; + } + + @NotNull + public static Validator isInstanceOf(@NotNull Class clazz) { + return obj -> { + requireNonNull(obj); + if (clazz.isInstance(obj)) { + return new SuccessResult<>(clazz.cast(obj)); + } + return new FailureResult<>( + new ValidationException( + "Should be %s. Received %s.".formatted( + clazz.getSimpleName(), + obj.getClass().getSimpleName() + ) + ) + ); + }; + } + + @NotNull + public static Validator fulfillPredicate(@NotNull Predicate predicate, @NotNull String exceptionMessage) { + return obj -> { + requireNonNull(obj); + if (predicate.test(obj)) { + return new SuccessResult<>(obj); + } + return new FailureResult<>(new ValidationException(exceptionMessage)); + }; + } + + @NotNull + public static Validator fulfillPredicate( + @NotNull Predicate predicate, @NotNull Function exceptionMessage + ) { + return obj -> fulfillPredicate(predicate, exceptionMessage.apply(obj)).validate(obj); + } + + @NotNull + public static , S, E> Validator allElements(@NotNull Validator elementValidator) { + return iter -> { + requireNonNull(iter); + for (E element : iter) { + if (elementValidator.validate(element) instanceof FailureResult(ValidationException e)) { + return new FailureResult<>(new ValidationException("All elements of the iterable should pass the validation.", e)); + } + } + return new SuccessResult<>(iter); + }; + } + + @NotNull + public static Validator canBeBoxed(@NotNull Class clazz) { + return obj -> { + requireNonNull(obj); + try { + S boxed = requireNonNull(JvmBoxingUtil.box(obj, clazz)); + return new SuccessResult<>(boxed); + } catch (Exception exception) { + return new FailureResult<>( + new ValidationException( + "The instance of the class %s should be able to be boxed into %s." + .formatted(obj.getClass().getSimpleName(), clazz.getSimpleName()), + exception + ) + ); + } + }; + } +} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/FieldValidationException.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/FieldValidationException.java new file mode 100644 index 000000000..011f545cf --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/FieldValidationException.java @@ -0,0 +1,7 @@ +package com.here.naksha.cli.validations.exceptions; + +public class FieldValidationException extends Exception { + public FieldValidationException(String fieldName, ValidationException validationException) { + super("Invalid `%s` field.%n".formatted(fieldName) + validationException.computeFullMessage().indent(1)); + } +} diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/OrValidationException.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/OrValidationException.java new file mode 100644 index 000000000..5f52eebc9 --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/OrValidationException.java @@ -0,0 +1,30 @@ +package com.here.naksha.cli.validations.exceptions; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class OrValidationException extends ValidationException { + List validationExceptions; + + public OrValidationException(List validationExceptions) { + super(buildMessage(validationExceptions, ValidationException::getMessage)); + this.validationExceptions = validationExceptions; + } + + private static String buildMessage( + List messages, Function exceptionMessageFunction + ) { + String header = "At least one of the following conditions must be satisfied:\n"; + String joinedMessages = messages.stream() + .map(e -> "-" + exceptionMessageFunction.apply(e).indent(1)) + .collect(Collectors.joining("\n")); + return header + joinedMessages; + } + + @Override + public String computeFullMessage() { + return buildMessage(validationExceptions, ValidationException::computeFullMessage); + } +} \ No newline at end of file diff --git a/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/ValidationException.java b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/ValidationException.java new file mode 100644 index 000000000..8b1d8060f --- /dev/null +++ b/here-naksha-cli/src/jvmMain/java/com/here/naksha/cli/validations/exceptions/ValidationException.java @@ -0,0 +1,26 @@ +package com.here.naksha.cli.validations.exceptions; + +public class ValidationException extends Exception { + public ValidationException(String message) { + super(message); + } + + public ValidationException(String message, Throwable cause) { + super(message, cause); + } + + public String computeFullMessage() { + StringBuilder fullMessage = new StringBuilder(); + Throwable cause = this.getCause(); + while (cause != null) { + fullMessage.append("\n"); + if (cause instanceof ValidationException validationException) { + fullMessage.append(validationException.computeFullMessage()); + } else { + fullMessage.append(cause.getMessage()); + } + cause = cause.getCause(); + } + return getMessage() + fullMessage.toString().indent(1); + } +} diff --git a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/CopyCliTest.java b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/CopyCliTest.java index e1b0fa3fb..9f563ef92 100644 --- a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/CopyCliTest.java +++ b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/CopyCliTest.java @@ -4,8 +4,8 @@ import com.here.naksha.cli.TestCommandLine; import com.here.naksha.cli.copy.service.*; import com.here.naksha.cli.parsers.JsonFileParser; -import com.here.naksha.cli.results.CommandFailure; -import com.here.naksha.cli.results.CommandSuccess; +import com.here.naksha.cli.results.FailureResult; +import com.here.naksha.cli.results.SuccessResult; import naksha.model.objects.NakshaStorage; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -251,7 +251,7 @@ Unexpected character ('c' (code 99)): was expecting double-quote to start field private CopyService copyServiceReturningErrorResult(String exceptionMessage) { CopyService copyService = mock(); when(copyService.copy(any(), any(), anyBoolean())).thenReturn( - new CommandFailure<>(new CopyServiceException(exceptionMessage)) + new FailureResult<>(new CopyServiceException(exceptionMessage)) ); return copyService; } @@ -292,7 +292,7 @@ private void assertCopyServiceParams( private CopyService copyServiceReturningSuccessResult(int numberOfCopiedElements) { CopyService copyService = mock(); when(copyService.copy(any(), any(), anyBoolean())).thenReturn( - new CommandSuccess<>( + new SuccessResult<>( new CopyServiceSuccessResultPayload(numberOfCopiedElements) ) ); diff --git a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/CopyServiceTest.java b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/CopyServiceTest.java index e30d14701..1f219d8de 100644 --- a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/CopyServiceTest.java +++ b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/CopyServiceTest.java @@ -1,8 +1,8 @@ package com.here.naksha.cli.copy.service; -import com.here.naksha.cli.results.CommandFailure; -import com.here.naksha.cli.results.CommandResult; -import com.here.naksha.cli.results.CommandSuccess; +import com.here.naksha.cli.results.FailureResult; +import com.here.naksha.cli.results.Result; +import com.here.naksha.cli.results.SuccessResult; import naksha.base.fn.Fn1; import naksha.model.*; import naksha.model.objects.NakshaFeature; @@ -66,19 +66,19 @@ void shouldSucceedWithExistingTargetMapAndCollection() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, false ); // Then: assert success result - CommandSuccess commandSuccess = assertInstanceOf( - CommandSuccess.class, copyResult + SuccessResult successResult = assertInstanceOf( + SuccessResult.class, copyResult ); // And: assert result payload - CopyServiceSuccessResultPayload payload = commandSuccess.payload(); + CopyServiceSuccessResultPayload payload = successResult.payload(); assertEquals(features.size(), payload.numberOfCopiedElements()); // And: assert read request @@ -123,15 +123,15 @@ void shouldSucceedWithAutoCreateTargetAndAbsentTargetMapAndCollection() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true ); // Then: assert success result - CommandSuccess commandSuccess = assertInstanceOf( - CommandSuccess.class, copyResult + SuccessResult commandSuccess = assertInstanceOf( + SuccessResult.class, copyResult ); @@ -185,15 +185,15 @@ void shouldSucceedWithAutoCreateTargetAndAbsentTargetCollection() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true ); // Then: assert success result - CommandSuccess commandSuccess = assertInstanceOf( - CommandSuccess.class, copyResult + SuccessResult commandSuccess = assertInstanceOf( + SuccessResult.class, copyResult ); @@ -247,15 +247,15 @@ void shouldSucceedWithAutoCreateTargetAndExistingTargetMapAndCollection() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true ); // Then: assert success result - CommandSuccess commandSuccess = assertInstanceOf( - CommandSuccess.class, copyResult + SuccessResult commandSuccess = assertInstanceOf( + SuccessResult.class, copyResult ); @@ -299,7 +299,7 @@ void shouldFailWhenReadingFromSourceFails(boolean autoCreateTarget) { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, autoCreateTarget @@ -328,7 +328,7 @@ void shouldFailWhenReadSessionFails(boolean autoCreateTarget) { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, autoCreateTarget @@ -355,7 +355,7 @@ void shouldFailWhenCanNotGetSourceStorage(boolean autoCreateTarget) { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, autoCreateTarget @@ -384,7 +384,7 @@ void shouldFailOnUnexpectedResponseFromSource(boolean autoCreateTarget) { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, autoCreateTarget @@ -413,7 +413,7 @@ void shouldFailWhenWriteSessionFails(boolean autoCreateTarget) { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, autoCreateTarget @@ -443,7 +443,7 @@ void shouldFailWhenWritingToTargetFails() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, false @@ -474,7 +474,7 @@ void shouldFailWhenUnableToUseTarget(boolean autoCreateTarget) { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, autoCreateTarget @@ -503,7 +503,7 @@ void shouldFailOnUnexpectedResponseFromTargetWhileWritingFeatures() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, false @@ -537,7 +537,7 @@ void shouldFailOnUnexpectedResponseFromTargetWhileCreatingMap() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true @@ -571,7 +571,7 @@ void shouldFailOnErrorResponseFromTargetWhileCreatingMap() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true @@ -607,7 +607,7 @@ void shouldFailOnUnexpectedResponseFromTargetWhileCreatingCollection() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true @@ -643,7 +643,7 @@ void shouldFailOnErrorResponseFromTargetWhileCreatingCollection() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true @@ -673,7 +673,7 @@ void shouldFailWhenAutoCreateTargetAndTargetsMapIdNull() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true @@ -700,7 +700,7 @@ void shouldFailWhenAutoCreateTargetAndTargetsCollectionIdNull() { ); // When - CommandResult copyResult = copyService.copy( + Result copyResult = copyService.copy( srcCopyElement, targetCopyElement, true @@ -723,15 +723,15 @@ private CopyElement targetCopyElementWithoutCollectionId() { } private void assertIsErrorResultWithGivenMessage( - CommandResult copyResult, + Result copyResult, String errorMessage ) { - CommandFailure commandFailure = assertInstanceOf( - CommandFailure.class, copyResult + FailureResult failureResult = assertInstanceOf( + FailureResult.class, copyResult ); // And: assert result payload - CopyServiceException exception = commandFailure.payload(); + CopyServiceException exception = failureResult.payload(); assertEquals(errorMessage, exception.getMessage()); } diff --git a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/psql/PsqlCopyTest.java b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/psql/PsqlCopyTest.java index db654f566..9bdcb2f7e 100644 --- a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/psql/PsqlCopyTest.java +++ b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/copy/service/psql/PsqlCopyTest.java @@ -1,8 +1,8 @@ package com.here.naksha.cli.copy.service.psql; import com.here.naksha.cli.copy.service.*; -import com.here.naksha.cli.results.CommandResult; -import com.here.naksha.cli.results.CommandSuccess; +import com.here.naksha.cli.results.Result; +import com.here.naksha.cli.results.SuccessResult; import com.here.naksha.cli.storages.GeneratingStorage; import com.here.naksha.cli.storages.GeneratingStorageConfig; import com.here.naksha.cli.testcontainers.TestContainersPsqlStoragePool; @@ -299,7 +299,7 @@ private void makeWriteRequest(IStorage storage, WriteRequest writeRequest, Sessi }); } - private void assertCommandSuccessResult(CommandResult commandResult) { - assertInstanceOf(CommandSuccess.class, commandResult); + private void assertCommandSuccessResult(Result commandResult) { + assertInstanceOf(SuccessResult.class, commandResult); } } diff --git a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/parsers/JsonFileParserTest.java b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/parsers/JsonFileParserTest.java index 1f0323e70..5d3a075cf 100644 --- a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/parsers/JsonFileParserTest.java +++ b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/parsers/JsonFileParserTest.java @@ -10,6 +10,7 @@ import java.nio.file.Path; import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; class JsonFileParserTest { @Test @@ -23,7 +24,7 @@ void shouldFailWithFileDoesNotExist(@TempDir Path dir) { JsonFileParserException.class, () -> jsonFileParser.parse(pathToFile, AnyObject.class) ); - assertEquals("File does not exist! file: %s".formatted(pathToFile), exception.getMessage()); + assertEquals("Problem with reading! NoSuchFileException file: %s".formatted(pathToFile), exception.getMessage()); } @Test @@ -32,7 +33,7 @@ void shouldFailWithNoReadable(@TempDir Path dir) throws IOException { Path pathToFile = dir.resolve("file"); Files.writeString(pathToFile, "{}"); File file = pathToFile.toFile(); - assertTrue(file.setReadable(false), "Can not set file as unreadable!"); + assumeTrue(file.setReadable(false), "Can not set file as unreadable!"); JsonFileParser jsonFileParser = new JsonFileParser(); // When & Then @@ -40,7 +41,7 @@ void shouldFailWithNoReadable(@TempDir Path dir) throws IOException { JsonFileParserException.class, () -> jsonFileParser.parse(pathToFile, AnyObject.class) ); - assertEquals("Problem with reading! file: %s".formatted(pathToFile), exception.getMessage()); + assertEquals("Problem with reading! AccessDeniedException file: %s".formatted(pathToFile), exception.getMessage()); } @Test @@ -53,7 +54,7 @@ void shouldFailWithItIsNoFile(@TempDir Path dir) { JsonFileParserException.class, () -> jsonFileParser.parse(dir, AnyObject.class) ); - assertEquals("It is not a file! file: %s".formatted(dir), exception.getMessage()); + assertEquals("Problem with reading! Is a directory file: %s".formatted(dir), exception.getMessage()); } @Test diff --git a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigPropertiesTest.java b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigPropertiesTest.java new file mode 100644 index 000000000..f76edba6f --- /dev/null +++ b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigPropertiesTest.java @@ -0,0 +1,118 @@ +package com.here.naksha.cli.storages; + +import com.here.naksha.cli.validations.exceptions.FieldValidationException; +import naksha.base.JvmList; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.stream.Stream; + +import static com.here.naksha.cli.storages.GeneratingStorageConfigProperties.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class GeneratingStorageConfigPropertiesTest { + GeneratingStorageConfigProperties configProperties = new GeneratingStorageConfigProperties(); + + @ParameterizedTest + @MethodSource + void shouldThrowWhenValidatingWithInvalidCountField(Object invalidCount) { + // Given + configProperties.setRaw(COUNT_KEY, invalidCount); + + // When & Then + assertThrowsFieldValidationExceptionOnValidate(); + } + + @ParameterizedTest + @MethodSource + void shouldThrowWhenValidatingWithInvalidTileIdsField(Object invalidTileIds) { + // Given + configProperties.setRaw(TILE_IDS_KEY, invalidTileIds); + + // When & Then + assertThrowsFieldValidationExceptionOnValidate(); + } + + @ParameterizedTest + @MethodSource("requireStringOrNullInvalidCases") + void shouldThrowWhenValidatingWithInvalidIdsPrefixField(Object invalidIdsPrefix) { + // Given + configProperties.setRaw(IDS_PREFIX_KEY, invalidIdsPrefix); + + // When & Then + assertThrowsFieldValidationExceptionOnValidate(); + } + + @ParameterizedTest + @MethodSource("requireStringOrNullInvalidCases") + void shouldThrowWhenValidatingWithInvalidTileIdsCsvFilePath(Object invalidTileIdsCsvFilePath) { + // Given + configProperties.setRaw(TILE_IDS_CSV_FILE_PATH_KEY, invalidTileIdsCsvFilePath); + + // When & Then + assertThrowsFieldValidationExceptionOnValidate(); + } + + @ParameterizedTest + @MethodSource("requireStringOrNullInvalidCases") + void shouldThrowWhenValidatingWithInvalidFeatureTemplateFilePath(Object invalidFeatureTemplateFilePath) { + // Given + configProperties.setRaw(FEATURE_TEMPLATE_FILE_PATH_KEY, invalidFeatureTemplateFilePath); + + // When & Then + assertThrowsFieldValidationExceptionOnValidate(); + } + + @ParameterizedTest + @ValueSource(ints = {-1, -10}) + void shouldThrowWhenSettingInvalidCount(int invalidCount) { + // When & Then + assertThrows( + IllegalArgumentException.class, + () -> configProperties.setCount(invalidCount) + ); + } + + @ParameterizedTest + @ValueSource(ints = {-1, -10}) + void shouldThrowWhenWithInvalidCount(int invalidCount) { + // When & Then + assertThrows( + IllegalArgumentException.class, + () -> configProperties.withCount(invalidCount) + ); + } + + private static Stream requireStringOrNullInvalidCases() { + return Stream.of( + Arguments.of(new Object()), + Arguments.of(321) + ); + } + + private static Stream shouldThrowWhenValidatingWithInvalidTileIdsField() { + return Stream.of( + Arguments.of(new Object()), + Arguments.of(new JvmList("02110", 1)), + Arguments.of(new JvmList(321, 11)), + Arguments.of(new JvmList(new Object(), new Object())) + ); + } + + private static Stream shouldThrowWhenValidatingWithInvalidCountField() { + return Stream.of( + Arguments.of(-1), + Arguments.of(-10), + Arguments.of(new Object()) + ); + } + + private void assertThrowsFieldValidationExceptionOnValidate() { + assertThrows( + FieldValidationException.class, + configProperties::validateFields + ); + } +} \ No newline at end of file diff --git a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigTest.java b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigTest.java new file mode 100644 index 000000000..2690ce57d --- /dev/null +++ b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageConfigTest.java @@ -0,0 +1,35 @@ +package com.here.naksha.cli.storages; + +import com.here.naksha.cli.validations.exceptions.FieldValidationException; +import naksha.base.JvmBoxingUtil; +import org.junit.jupiter.api.Test; + +import static naksha.model.objects.NakshaFeature.PROPERTIES_KEY; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class GeneratingStorageConfigTest { + GeneratingStorageConfig config = new GeneratingStorageConfig(); + + @Test + void shouldCreateAndInit() { + // When + Object raw = config.getRaw(PROPERTIES_KEY); + + // Then + GeneratingStorageConfigProperties properties = JvmBoxingUtil.box(raw, GeneratingStorageConfigProperties.class); + assertNotNull(properties); + } + + @Test + void shouldThrowWhenValidatingWithAbsentProperties() { + // Given + config.setRaw(PROPERTIES_KEY, null); + + // When & Then + assertThrows( + FieldValidationException.class, + config::validateFields + ); + } +} \ No newline at end of file diff --git a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageTest.java b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageTest.java index a429ed05d..699e49c29 100644 --- a/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageTest.java +++ b/here-naksha-cli/src/jvmTest/java/com/here/naksha/cli/storages/GeneratingStorageTest.java @@ -272,26 +272,6 @@ void shouldFailWhenProblemWithFeatureTemplateFile() { assertErrorMessageAndCode(exception, "Problem while loading the feature template!", NakshaError.EXCEPTION); } - @Test - void shouldFailWhenCountIsNotProvided() { - // Given: config - GeneratingStorageConfig config = getSampleConfig(); - config.getProperties() - .withCount(null); - - // And: storage - GeneratingStorage storage = generatingStorageWithConfig(config); - - // When: read features - NakshaException exception = assertThrows( - NakshaException.class, () -> storage.useReadSession(sessionOptions, reader -> - reader.execute(new ReadFeatures()) - )); - - // Then: - assertErrorMessageAndCode(exception, "Provide count in the config properties.", NakshaError.ILLEGAL_ARGUMENT); - } - @Test void shouldFailWhenWrite() { // Given