From 7522bdab116769953942b0b1f409f562aecbe660 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:13:22 +0200 Subject: [PATCH 1/2] sort tests --- core/pom.xml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 9182367d..31f519e5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -101,25 +101,32 @@ ${project.build.directory}/jsonschematests + + **/tests/draft2020-12/additionalProperties.json **/tests/draft2020-12/boolean_schema.json - **/tests/draft2020-12/type.json - **/tests/draft2020-12/minLength.json - **/tests/draft2020-12/maxLength.json - **/tests/draft2020-12/pattern.json - **/tests/draft2020-12/minimum.json - **/tests/draft2020-12/exclusiveMinimum.json - **/tests/draft2020-12/maximum.json + **/tests/draft2020-12/exclusiveMaximum.json - **/tests/draft2020-12/multipleOf.json - **/tests/draft2020-12/prefixItems.json + **/tests/draft2020-12/exclusiveMinimum.json - **/tests/draft2020-12/minItems.json **/tests/draft2020-12/maxItems.json + **/tests/draft2020-12/maxLength.json + **/tests/draft2020-12/maximum.json + **/tests/draft2020-12/minItems.json + **/tests/draft2020-12/minLength.json + **/tests/draft2020-12/minimum.json + **/tests/draft2020-12/multipleOf.json + **/tests/draft2020-12/pattern.json **/tests/draft2020-12/patternProperties.json + **/tests/draft2020-12/prefixItems.json **/tests/draft2020-12/properties.json - **/tests/draft2020-12/additionalProperties.json + + **/tests/draft2020-12/type.json From b19e1ca043c97255375a66d5d6a5158a005202a4 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Tue, 26 Sep 2023 21:26:20 +0200 Subject: [PATCH 2/2] add support for required keyword --- core/pom.xml | 1 + .../vocab/validation/RequiredKeywordType.java | 75 ++++++++++++++++ .../validation/ValidationVocabulary.java | 1 + .../validation/RequiredKeywordTypeTest.java | 88 +++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordType.java create mode 100644 core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTypeTest.java diff --git a/core/pom.xml b/core/pom.xml index 31f519e5..093f1b7b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -126,6 +126,7 @@ **/tests/draft2020-12/prefixItems.json **/tests/draft2020-12/properties.json + **/tests/draft2020-12/required.json **/tests/draft2020-12/type.json diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordType.java new file mode 100644 index 00000000..1b4cafad --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordType.java @@ -0,0 +1,75 @@ +/* + * The MIT License + * + * Copyright 2023 sebastian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.sebastiantoepfer.jsonschema.core.vocab.validation; + +import io.github.sebastiantoepfer.jsonschema.InstanceType; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; +import io.github.sebastiantoepfer.jsonschema.keyword.Assertion; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import java.util.Objects; + +class RequiredKeywordType implements KeywordType { + + @Override + public String name() { + return "required"; + } + + @Override + public Keyword createKeyword(final JsonSchema schema, final JsonValue value) { + return new RequiredKeyword(value.asJsonArray()); + } + + private class RequiredKeyword implements Assertion { + + private final JsonArray required; + + public RequiredKeyword(final JsonArray required) { + this.required = Objects.requireNonNull(required); + } + + @Override + public boolean isValidFor(final JsonValue instance) { + return !InstanceType.OBJECT.isInstance(instance) || hasAllRequiredProperties(instance.asJsonObject()); + } + + private boolean hasAllRequiredProperties(final JsonObject instance) { + return required + .stream() + .map(JsonString.class::cast) + .map(JsonString::getString) + .allMatch(instance.keySet()::contains); + } + + @Override + public boolean hasName(final String name) { + return Objects.equals(name(), name); + } + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java index 0963b0f6..21bdb7a2 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java @@ -37,6 +37,7 @@ public ValidationVocabulary() { this.vocab = new DefaultVocabulary( URI.create("https://json-schema.org/draft/2020-12/vocab/validation"), + new RequiredKeywordType(), new TypeKeywordType(), new MinLengthKeywordType(), new MaxLengthKeywordType(), diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTypeTest.java new file mode 100644 index 00000000..eb475225 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTypeTest.java @@ -0,0 +1,88 @@ +/* + * The MIT License + * + * Copyright 2023 sebastian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.sebastiantoepfer.jsonschema.core.vocab.validation; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import jakarta.json.Json; +import jakarta.json.JsonValue; +import java.math.BigDecimal; +import org.junit.jupiter.api.Test; + +class RequiredKeywordTypeTest { + + @Test + void should_know_his_name() { + final Keyword required = new RequiredKeywordType() + .createKeyword(new DefaultJsonSchemaFactory().create(JsonValue.TRUE), JsonValue.EMPTY_JSON_ARRAY); + + assertThat(required.hasName("required"), is(true)); + assertThat(required.hasName("test"), is(false)); + } + + @Test + void should_invalid_if_not_all_properties_in_the_instance() { + assertThat( + new RequiredKeywordType() + .createKeyword( + new DefaultJsonSchemaFactory().create(JsonValue.TRUE), + Json.createArrayBuilder().add("foo").add("bar").build() + ) + .asAssertion() + .isValidFor(Json.createObjectBuilder().add("foo", BigDecimal.ONE).build()), + is(false) + ); + } + + @Test + void should_valid_for_non_objects() { + assertThat( + new RequiredKeywordType() + .createKeyword( + new DefaultJsonSchemaFactory().create(JsonValue.TRUE), + Json.createArrayBuilder().add("foo").add("bar").build() + ) + .asAssertion() + .isValidFor(JsonValue.EMPTY_JSON_ARRAY), + is(true) + ); + } + + @Test + void should_valid_if_all_properties_are_in_the_instance() { + assertThat( + new RequiredKeywordType() + .createKeyword( + new DefaultJsonSchemaFactory().create(JsonValue.TRUE), + Json.createArrayBuilder().add("foo").add("bar").build() + ) + .asAssertion() + .isValidFor(Json.createObjectBuilder().add("foo", BigDecimal.ONE).add("bar", "test").build()), + is(true) + ); + } +}