From 3c90ecb6c66011f383f364c8f0520c2359d4ea79 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:46:26 +0200 Subject: [PATCH 1/8] use keyword relationship for additionalproperties keyword --- .../AdditionalPropertiesKeyword.java | 25 ++++++++++--------- .../applicator/ApplicatorVocabulary.java | 17 ++++++++++++- .../AdditionalPropertiesKeywordTest.java | 23 ++++++++++++----- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java index 85714078..52571818 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java @@ -23,9 +23,11 @@ */ package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator; +import static java.util.function.Predicate.not; + import io.github.sebastiantoepfer.ddd.common.Media; import io.github.sebastiantoepfer.jsonschema.InstanceType; -import io.github.sebastiantoepfer.jsonschema.JsonSubSchema; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; import io.github.sebastiantoepfer.jsonschema.keyword.Annotation; import io.github.sebastiantoepfer.jsonschema.keyword.Applicator; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; @@ -38,8 +40,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; -import java.util.function.Predicate; import java.util.stream.Stream; /** @@ -61,10 +61,15 @@ final class AdditionalPropertiesKeyword implements Applicator, Annotation { static final String NAME = "additionalProperties"; - private final JsonSubSchema additionalPropertiesSchema; + private final Collection affectedBy; + private final JsonSchema additionalPropertiesSchema; - public AdditionalPropertiesKeyword(final JsonSubSchema additionalPropertiesSchema) { + public AdditionalPropertiesKeyword( + final Collection affectedBy, + final JsonSchema additionalPropertiesSchema + ) { this.additionalPropertiesSchema = additionalPropertiesSchema; + this.affectedBy = List.copyOf(affectedBy); } @Override @@ -93,16 +98,12 @@ public JsonValue valueFor(final JsonValue instance) { private Stream> findPropertiesForValidation(final JsonObject instance) { final Collection ignoredProperties = findPropertyNamesAlreadyConveredByOthersIn(instance); - return instance.entrySet().stream().filter(Predicate.not(e -> ignoredProperties.contains(e.getKey()))); + return instance.entrySet().stream().filter(not(e -> ignoredProperties.contains(e.getKey()))); } private Collection findPropertyNamesAlreadyConveredByOthersIn(final JsonValue instance) { - return Stream.of( - additionalPropertiesSchema.owner().keywordByName("properties"), - additionalPropertiesSchema.owner().keywordByName("patternProperties") - ) - .flatMap(Optional::stream) - .map(Keyword::asAnnotation) + return affectedBy + .stream() .map(anno -> anno.valueFor(instance)) .map(JsonValue::asJsonArray) .flatMap(Collection::stream) diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java index 0f19c90c..ad18b208 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java @@ -27,11 +27,14 @@ import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectByType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedBy; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedByKeywordType; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SchemaArrayKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import jakarta.json.JsonValue; import java.net.URI; import java.util.List; import java.util.Optional; @@ -55,7 +58,19 @@ public ApplicatorVocabulary() { new SchemaArrayKeywordType(OneOfKeyword.NAME, OneOfKeyword::new), new SubSchemaKeywordType(NotKeyword.NAME, NotKeyword::new), new NamedJsonSchemaKeywordType(PropertiesKeyword.NAME, PropertiesKeyword::new), - new SubSchemaKeywordType(AdditionalPropertiesKeyword.NAME, AdditionalPropertiesKeyword::new), + //nomally affectedBy ... but we had the needed function only in affects :( + new AffectsKeywordType( + AdditionalPropertiesKeyword.NAME, + List.of( + new Affects("properties", JsonValue.EMPTY_JSON_ARRAY), + new Affects("patternProperties", JsonValue.EMPTY_JSON_ARRAY) + ), + (affects, schema) -> + new SubSchemaKeywordType( + AdditionalPropertiesKeyword.NAME, + s -> new AdditionalPropertiesKeyword(affects, s) + ).createKeyword(schema) + ), new NamedJsonSchemaKeywordType(PatternPropertiesKeyword.NAME, PatternPropertiesKeyword::new), new NamedJsonSchemaKeywordType(DependentSchemasKeyword.NAME, DependentSchemasKeyword::new), new SubSchemaKeywordType(ItemsKeyword.NAME, ItemsKeyword::new), diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java index 053791be..eeed5958 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java @@ -30,12 +30,16 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; import jakarta.json.JsonObject; import jakarta.json.JsonValue; +import java.util.List; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +47,7 @@ class AdditionalPropertiesKeywordTest { @Test void should_know_his_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("additionalProperties", JsonValue.EMPTY_JSON_OBJECT).build() - ); + final Keyword keyword = new AdditionalPropertiesKeyword(List.of(), JsonSchemas.load(JsonValue.TRUE)); assertThat(keyword.hasName("additionalProperties"), is(true)); assertThat(keyword.hasName("test"), is(false)); } @@ -147,8 +149,17 @@ void should_be_printable() { } private static Keyword createKeywordFrom(final JsonObject json) { - return new SubSchemaKeywordType("additionalProperties", AdditionalPropertiesKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); + return new AffectsKeywordType( + "additionalProperties", + List.of( + new Affects("properties", JsonValue.EMPTY_JSON_ARRAY), + new Affects("patternProperties", JsonValue.EMPTY_JSON_ARRAY) + ), + (affects, schema) -> + new SubSchemaKeywordType( + "additionalProperties", + s -> new AdditionalPropertiesKeyword(affects, s) + ).createKeyword(schema) + ).createKeyword(new DefaultJsonSchemaFactory().create(json)); } } From cfa5be433524edaa74988c8238404c7e330eeaa8 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:46:26 +0200 Subject: [PATCH 2/8] use keyword relationship for items keyword --- .../keyword/type/SubSchemaKeywordType.java | 2 +- .../applicator/ApplicatorVocabulary.java | 21 +++++++++++- .../core/vocab/applicator/ItemsKeyword.java | 34 ++++++++++--------- .../vocab/applicator/ItemsKeywordTest.java | 29 +++++++++++----- 4 files changed, 60 insertions(+), 26 deletions(-) diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/SubSchemaKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/SubSchemaKeywordType.java index 12f94047..4b8cadc3 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/SubSchemaKeywordType.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/SubSchemaKeywordType.java @@ -47,6 +47,6 @@ public String name() { @Override public Keyword createKeyword(final JsonSchema schema) { - return schema.asSubSchema(name).map(keywordCreator).orElseThrow(IllegalArgumentException::new); + return schema.asSubSchema(name()).map(keywordCreator).orElseThrow(IllegalArgumentException::new); } } diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java index ad18b208..5c65bb01 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java @@ -34,6 +34,7 @@ import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import jakarta.json.Json; import jakarta.json.JsonValue; import java.net.URI; import java.util.List; @@ -73,7 +74,25 @@ public ApplicatorVocabulary() { ), new NamedJsonSchemaKeywordType(PatternPropertiesKeyword.NAME, PatternPropertiesKeyword::new), new NamedJsonSchemaKeywordType(DependentSchemasKeyword.NAME, DependentSchemasKeyword::new), - new SubSchemaKeywordType(ItemsKeyword.NAME, ItemsKeyword::new), + //this example shows my missunderstanding from affects, affectedBy and keywordtypes :( + new AffectedByKeywordType( + ItemsKeyword.NAME, + List.of( + new AffectedBy(AffectByType.EXTENDS, "minItems"), + new AffectedBy(AffectByType.EXTENDS, "maxItems") + ), + //nomally affectedBy too ... but we had the needed function only in affects :( + schema -> + new AffectsKeywordType( + ItemsKeyword.NAME, + List.of(new Affects("prefixItems", Json.createValue(-1))), + (affects, subSchema) -> + new SubSchemaKeywordType( + ItemsKeyword.NAME, + s -> new ItemsKeyword(affects, s) + ).createKeyword(subSchema) + ).createKeyword(schema) + ), new SchemaArrayKeywordType(PrefixItemsKeyword.NAME, PrefixItemsKeyword::new), new AffectedByKeywordType( ContainsKeyword.NAME, diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java index 2a8acd31..e20494b6 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java @@ -25,17 +25,16 @@ import io.github.sebastiantoepfer.ddd.common.Media; import io.github.sebastiantoepfer.jsonschema.InstanceType; -import io.github.sebastiantoepfer.jsonschema.JsonSubSchema; -import io.github.sebastiantoepfer.jsonschema.Validator; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; import io.github.sebastiantoepfer.jsonschema.keyword.Annotation; import io.github.sebastiantoepfer.jsonschema.keyword.Applicator; -import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.JsonArray; import jakarta.json.JsonNumber; import jakarta.json.JsonValue; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.stream.Stream; /** * items : Schema
@@ -56,9 +55,11 @@ final class ItemsKeyword implements Applicator, Annotation { static final String NAME = "items"; - private final JsonSubSchema schema; + private final Collection affectedBys; + private final JsonSchema schema; - public ItemsKeyword(final JsonSubSchema schema) { + public ItemsKeyword(final Collection affectedBys, final JsonSchema schema) { + this.affectedBys = List.copyOf(affectedBys); this.schema = Objects.requireNonNull(schema); } @@ -89,28 +90,29 @@ public JsonValue valueFor(final JsonValue value) { } private boolean appliesToAnyFor(final JsonArray value) { - return startIndexFor(value) == -1; + return itemsForValidation(value).anyMatch(schema.validator()::isValid); } @Override public boolean applyTo(final JsonValue instance) { - return !InstanceType.ARRAY.isInstance(instance) || matchesSchema(instance.asJsonArray()); + return !InstanceType.ARRAY.isInstance(instance) || applyTo(instance.asJsonArray()); } - private boolean matchesSchema(final JsonArray items) { - final Validator itemValidator = schema.validator(); - return items.stream().skip(startIndexFor(items) + 1L).allMatch(itemValidator::isValid); + private boolean applyTo(final JsonArray items) { + return itemsForValidation(items).allMatch(schema.validator()::isValid); + } + + private Stream itemsForValidation(final JsonArray items) { + return items.stream().skip(startIndexFor(items) + 1L); } private int startIndexFor(final JsonArray value) { - return schema - .owner() - .keywordByName("prefixItems") - .map(Keyword::asAnnotation) + return affectedBys + .stream() .map(anno -> anno.valueFor(value)) .map(v -> new MaxIndexCalculator(value, v)) - .map(MaxIndexCalculator::maxIndex) - .orElse(-1); + .mapToInt(MaxIndexCalculator::maxIndex) + .sum(); } private static class MaxIndexCalculator { diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java index a346d3c0..f7007d0a 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java @@ -27,22 +27,26 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.is; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectByType; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedBy; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedByKeywordType; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; import jakarta.json.JsonObject; import jakarta.json.JsonValue; +import java.util.List; import org.junit.jupiter.api.Test; class ItemsKeywordTest { @Test void should_know_his_name() { - final Keyword items = createKeywordFrom( - Json.createObjectBuilder().add("items", JsonValue.EMPTY_JSON_OBJECT).build() - ); - + final Keyword items = new ItemsKeyword(List.of(), JsonSchemas.load(JsonValue.TRUE)); assertThat(items.hasName("items"), is(true)); assertThat(items.hasName("test"), is(false)); } @@ -84,7 +88,7 @@ void should_be_applicator_and_annotation() { @Test void should_produces_true_if_is_applied_to_any_instance() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("items", JsonValue.EMPTY_JSON_OBJECT).build()) + createKeywordFrom(Json.createObjectBuilder().add("items", JsonValue.TRUE).build()) .asAnnotation() .valueFor(Json.createArrayBuilder().add(1).build()), is(JsonValue.TRUE) @@ -137,8 +141,17 @@ void should_be_invalid_if_invaliditem_is_not_already_checked_by_prefixItems() { } private static Keyword createKeywordFrom(final JsonObject json) { - return new SubSchemaKeywordType("items", ItemsKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); + return new AffectedByKeywordType( + "items", + List.of(new AffectedBy(AffectByType.EXTENDS, "minItems"), new AffectedBy(AffectByType.EXTENDS, "maxItems")), + //nomally affectedBy too ... but we had the needed function only in affects :( + schema -> + new AffectsKeywordType( + "items", + List.of(new Affects("prefixItems", Json.createValue(-1))), + (affects, inner_schema) -> + new SubSchemaKeywordType("items", s -> new ItemsKeyword(affects, s)).createKeyword(inner_schema) + ).createKeyword(schema) + ).createKeyword(new DefaultJsonSchemaFactory().create(json)); } } From b2f1f2032ddca9ec542fe743013a93f62bbaa655 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:04:16 +0200 Subject: [PATCH 3/8] refactor all test of keywords defined by applicator vocab --- .../core/vocab/applicator/ItemsKeyword.java | 18 ++- .../AdditionalPropertiesKeywordTest.java | 72 +++------ .../vocab/applicator/AllOfKeywordTest.java | 100 ++++-------- .../vocab/applicator/AnyOfKeywordTest.java | 58 ++++--- .../vocab/applicator/ContainsKeywordTest.java | 59 ++----- .../DependentSchemasKeywordTest.java | 48 ++---- .../vocab/applicator/ItemsKeywordTest.java | 62 ++------ .../core/vocab/applicator/NotKeywordTest.java | 38 ++--- .../vocab/applicator/OneOfKeywordTest.java | 147 ++++++++---------- .../PatternPropertiesKeywordTest.java | 76 +++------ .../applicator/PrefixItemsKeywordTest.java | 55 +++---- .../applicator/PropertiesKeywordTest.java | 55 ++----- 12 files changed, 258 insertions(+), 530 deletions(-) diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java index e20494b6..0591c7ed 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java @@ -107,12 +107,18 @@ private Stream itemsForValidation(final JsonArray items) { } private int startIndexFor(final JsonArray value) { - return affectedBys - .stream() - .map(anno -> anno.valueFor(value)) - .map(v -> new MaxIndexCalculator(value, v)) - .mapToInt(MaxIndexCalculator::maxIndex) - .sum(); + final int result; + if (affectedBys.isEmpty()) { + result = -1; + } else { + result = affectedBys + .stream() + .map(anno -> anno.valueFor(value)) + .map(v -> new MaxIndexCalculator(value, v)) + .mapToInt(MaxIndexCalculator::maxIndex) + .sum(); + } + return result; } private static class MaxIndexCalculator { diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java index eeed5958..711ca283 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java @@ -31,13 +31,9 @@ import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; import io.github.sebastiantoepfer.jsonschema.JsonSchemas; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import java.util.List; import org.hamcrest.Matcher; @@ -55,11 +51,9 @@ void should_know_his_name() { @Test void should_be_valid_for_non_objects() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .add("additionalProperties", JsonValue.FALSE) - .build() + new AdditionalPropertiesKeyword( + List.of(new StaticAnnotation("properties", JsonValue.EMPTY_JSON_ARRAY)), + JsonSchemas.load(JsonValue.FALSE) ) .asApplicator() .applyTo(JsonValue.EMPTY_JSON_ARRAY), @@ -70,11 +64,9 @@ void should_be_valid_for_non_objects() { @Test void should_not_valid_if_no_additionals_are_allow() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .add("additionalProperties", JsonValue.FALSE) - .build() + new AdditionalPropertiesKeyword( + List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())), + JsonSchemas.load(JsonValue.FALSE) ) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).add("foo", 1).build()), @@ -85,11 +77,9 @@ void should_not_valid_if_no_additionals_are_allow() { @Test void should_valid_if_additionals_are_allow() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .add("additionalProperties", JsonValue.TRUE) - .build() + new AdditionalPropertiesKeyword( + List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())), + JsonSchemas.load(JsonValue.TRUE) ) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).add("foo", 1).build()), @@ -100,11 +90,9 @@ void should_valid_if_additionals_are_allow() { @Test void should_valid_if_no_additionals_are_allow_and_no_additionals_their() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .add("additionalProperties", JsonValue.FALSE) - .build() + new AdditionalPropertiesKeyword( + List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())), + JsonSchemas.load(JsonValue.FALSE) ) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).build()), @@ -115,8 +103,9 @@ void should_valid_if_no_additionals_are_allow_and_no_additionals_their() { @Test void should_be_an_applicator_and_an_annotation() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("additionalProperties", JsonValue.TRUE).build() + new AdditionalPropertiesKeyword( + List.of(new StaticAnnotation("properties", JsonValue.EMPTY_JSON_ARRAY)), + JsonSchemas.load(JsonValue.FALSE) ).categories(), containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION) ); @@ -125,11 +114,9 @@ void should_be_an_applicator_and_an_annotation() { @Test void should_return_propertynames_which_will_be_validated() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .add("additionalProperties", JsonValue.TRUE) - .build() + new AdditionalPropertiesKeyword( + List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())), + JsonSchemas.load(JsonValue.TRUE) ) .asAnnotation() .valueFor(Json.createObjectBuilder().add("test", 1).add("foo", 1).build()) @@ -141,25 +128,10 @@ void should_return_propertynames_which_will_be_validated() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("additionalProperties", JsonValue.EMPTY_JSON_OBJECT).build() - ).printOn(new HashMapMedia()), + new AdditionalPropertiesKeyword(List.of(), JsonSchemas.load(JsonValue.EMPTY_JSON_OBJECT)).printOn( + new HashMapMedia() + ), (Matcher) hasEntry(is("additionalProperties"), anEmptyMap()) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new AffectsKeywordType( - "additionalProperties", - List.of( - new Affects("properties", JsonValue.EMPTY_JSON_ARRAY), - new Affects("patternProperties", JsonValue.EMPTY_JSON_ARRAY) - ), - (affects, schema) -> - new SubSchemaKeywordType( - "additionalProperties", - s -> new AdditionalPropertiesKeyword(affects, s) - ).createKeyword(schema) - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeywordTest.java index 940908cf..86bc7560 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeywordTest.java @@ -25,16 +25,14 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SchemaArrayKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,10 +41,9 @@ class AllOfKeywordTest { @Test void should_know_his_name() { - final Keyword items = createKeywordFrom( - Json.createObjectBuilder().add("allOf", Json.createArrayBuilder().add(JsonValue.TRUE)).build() + final Keyword items = new AllOfKeyword( + Json.createArrayBuilder().add(JsonValue.TRUE).build().stream().map(JsonSchemas::load).toList() ); - assertThat(items.hasName("allOf"), is(true)); assertThat(items.hasName("test"), is(false)); } @@ -54,56 +51,30 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder() - .add( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder().add(Json.createObjectBuilder().add("type", "number")) - ) - ) - .add( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder().add(Json.createObjectBuilder().add("minimum", 18)) - ) - ) - ) + new AllOfKeyword( + Json.createArrayBuilder() + .add(Json.createObjectBuilder().add("type", "number")) + .add(Json.createObjectBuilder().add("minimum", 18)) .build() + .stream() + .map(JsonSchemas::load) + .toList() ).printOn(new HashMapMedia()), - (Matcher) hasEntry(is("allOf"), hasItem((hasKey("allOf")))) + (Matcher) hasEntry(is("allOf"), hasItems(hasKey("type"), hasKey("minimum"))) ); } @Test void should_be_valid_if_all_schemas_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder() - .add( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder().add(Json.createObjectBuilder().add("type", "number")) - ) - ) - .add( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder().add(Json.createObjectBuilder().add("minimum", 18)) - ) - ) - ) + new AllOfKeyword( + Json.createArrayBuilder() + .add(Json.createObjectBuilder().add("type", "number")) + .add(Json.createObjectBuilder().add("minimum", 18)) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createValue(25)), @@ -114,37 +85,18 @@ void should_be_valid_if_all_schemas_applies() { @Test void should_be_invalid_if_any_schemas_not_apply() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder() - .add( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder().add(Json.createObjectBuilder().add("type", "number")) - ) - ) - .add( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder().add(Json.createObjectBuilder().add("minimum", 18)) - ) - ) - ) + new AllOfKeyword( + Json.createArrayBuilder() + .add(Json.createObjectBuilder().add("type", "number")) + .add(Json.createObjectBuilder().add("minimum", 18)) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createValue(10)), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new SchemaArrayKeywordType("allOf", AllOfKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeywordTest.java index 7befdafb..f7fa853e 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeywordTest.java @@ -30,12 +30,11 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SchemaArrayKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; +import java.util.List; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +42,7 @@ class AnyOfKeywordTest { @Test void should_know_his_name() { - final Keyword items = createKeywordFrom( - Json.createObjectBuilder().add("anyOf", Json.createArrayBuilder().add(JsonValue.TRUE)).build() - ); + final Keyword items = new AnyOfKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))); assertThat(items.hasName("anyOf"), is(true)); assertThat(items.hasName("test"), is(false)); @@ -54,20 +51,17 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "anyOf", - Json.createArrayBuilder() + new AnyOfKeyword( + List.of( + JsonSchemas.load( + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "allOf", - Json.createArrayBuilder().add(Json.createObjectBuilder().add("type", "number")) - ) + "allOf", + Json.createArrayBuilder().add(Json.createObjectBuilder().add("type", "number")) ) + .build() ) - .build() + ) ).printOn(new HashMapMedia()), (Matcher) hasEntry(is("anyOf"), hasItem((hasKey("allOf")))) ); @@ -76,13 +70,15 @@ void should_be_printable() { @Test void should_be_valid_if_any_schemas_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "anyOf", - Json.createArrayBuilder().add(JsonValue.FALSE).add(JsonValue.TRUE).add(JsonValue.FALSE) - ) + new AnyOfKeyword( + Json.createArrayBuilder() + .add(JsonValue.FALSE) + .add(JsonValue.TRUE) + .add(JsonValue.FALSE) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createValue(25)), @@ -93,20 +89,18 @@ void should_be_valid_if_any_schemas_applies() { @Test void should_be_invalid_if_no_schemas_apply() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("anyOf", Json.createArrayBuilder().add(JsonValue.FALSE).add(JsonValue.FALSE)) + new AnyOfKeyword( + Json.createArrayBuilder() + .add(JsonValue.FALSE) + .add(JsonValue.FALSE) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createValue(10)), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new SchemaArrayKeywordType("anyOf", AnyOfKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java index 02c8c5f8..f94a4c35 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java @@ -31,11 +31,8 @@ import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; import io.github.sebastiantoepfer.jsonschema.JsonSchemas; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import org.hamcrest.Matcher; import org.hamcrest.Matchers; @@ -46,9 +43,9 @@ class ContainsKeywordTest { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ).printOn(new HashMapMedia()), + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())).printOn( + new HashMapMedia() + ), (Matcher) hasEntry(is("contains"), hasEntry(is("type"), is("number"))) ); } @@ -64,8 +61,8 @@ void should_know_his_name() { @Test void should_be_an_applicator_and_annotation() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() + new ContainsKeyword( + JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()) ).categories(), Matchers.containsInAnyOrder(Keyword.KeywordCategory.ANNOTATION, Keyword.KeywordCategory.APPLICATOR) ); @@ -74,9 +71,7 @@ void should_be_an_applicator_and_annotation() { @Test void should_apply_for_non_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asApplicator() .applyTo(JsonValue.EMPTY_JSON_OBJECT), is(true) @@ -86,9 +81,7 @@ void should_apply_for_non_array() { @Test void should_not_apply_to_empty_array_if_non_min_andor_max_is_provided() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asApplicator() .applyTo(JsonValue.EMPTY_JSON_ARRAY), is(false) @@ -98,9 +91,7 @@ void should_not_apply_to_empty_array_if_non_min_andor_max_is_provided() { @Test void should_apply_if_one_item_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asApplicator() .applyTo( Json.createArrayBuilder() @@ -118,9 +109,7 @@ void should_apply_if_one_item_applies() { @Test void should_apply_if_all_item_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "string")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "string").build())) .asApplicator() .applyTo(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()), is(true) @@ -130,9 +119,7 @@ void should_apply_if_all_item_applies() { @Test void should_not_apply_if_non_item_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asApplicator() .applyTo( Json.createArrayBuilder().add("foo").add(false).add(Json.createArrayBuilder().add("bar")).build() @@ -144,9 +131,7 @@ void should_not_apply_if_non_item_applies() { @Test void should_return_false_for_non_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asAnnotation() .valueFor(JsonValue.EMPTY_JSON_OBJECT), is(JsonValue.FALSE) @@ -156,9 +141,7 @@ void should_return_false_for_non_array() { @Test void should_return_empty_array_if_no_item_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asAnnotation() .valueFor(Json.createArrayBuilder().add("foo").build()) .asJsonArray(), @@ -169,9 +152,7 @@ void should_return_empty_array_if_no_item_applies() { @Test void should_return_empty_array_for_empty_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asAnnotation() .valueFor(JsonValue.EMPTY_JSON_ARRAY) .asJsonArray(), @@ -182,9 +163,7 @@ void should_return_empty_array_for_empty_array() { @Test void should_return_matching_items() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asAnnotation() .valueFor( Json.createArrayBuilder() @@ -203,18 +182,10 @@ void should_return_matching_items() { @Test void should_return_true_if_all_item_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "string")).build() - ) + new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "string").build())) .asAnnotation() .valueFor(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()), is(JsonValue.TRUE) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new SubSchemaKeywordType("contains", ContainsKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeywordTest.java index 0d064ad7..e0b1b7b4 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeywordTest.java @@ -29,12 +29,12 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; +import java.util.Map; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -42,9 +42,7 @@ class DependentSchemasKeywordTest { @Test void should_know_his_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("dependentSchemas", JsonValue.EMPTY_JSON_OBJECT).build() - ); + final Keyword keyword = new DependentSchemasKeyword(new NamedJsonSchemas(Map.of())); assertThat(keyword.hasName("dependentSchemas"), is(true)); assertThat(keyword.hasName("test"), is(false)); @@ -53,11 +51,9 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("dependentSchemas", Json.createObjectBuilder().add("foo", JsonValue.TRUE)) - .build() - ).printOn(new HashMapMedia()), + new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("foo", JsonSchemas.load(JsonValue.TRUE)))).printOn( + new HashMapMedia() + ), (Matcher) hasEntry(is("dependentSchemas"), hasEntry(is("foo"), anEmptyMap())) ); } @@ -65,9 +61,7 @@ void should_be_printable() { @Test void should_be_valid_for_non_object() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("dependentSchemas", JsonValue.EMPTY_JSON_OBJECT).build()) - .asApplicator() - .applyTo(JsonValue.FALSE), + new DependentSchemasKeyword(new NamedJsonSchemas(Map.of())).asApplicator().applyTo(JsonValue.FALSE), is(true) ); } @@ -75,7 +69,7 @@ void should_be_valid_for_non_object() { @Test void should_be_valid_for_empty_object() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("dependentSchemas", JsonValue.EMPTY_JSON_OBJECT).build()) + new DependentSchemasKeyword(new NamedJsonSchemas(Map.of())) .asApplicator() .applyTo(JsonValue.EMPTY_JSON_OBJECT), is(true) @@ -85,11 +79,7 @@ void should_be_valid_for_empty_object() { @Test void should_be_valid_if_property_not_present() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("dependentSchemas", Json.createObjectBuilder().add("test", JsonValue.FALSE)) - .build() - ) + new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("foo", 1).build()), is(true) @@ -99,11 +89,7 @@ void should_be_valid_if_property_not_present() { @Test void should_be_valid_if_property_is_present_and_schema_apply() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("dependentSchemas", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .build() - ) + new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.TRUE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("true", 1).build()), is(true) @@ -113,20 +99,10 @@ void should_be_valid_if_property_is_present_and_schema_apply() { @Test void should_be_invalid_if_property_is_present_and_schema_not_apply() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("dependentSchemas", Json.createObjectBuilder().add("test", JsonValue.FALSE)) - .build() - ) + new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("true", 1).build()), is(true) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NamedJsonSchemaKeywordType("dependentSchemas", DependentSchemasKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java index f7007d0a..ef61862d 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java @@ -28,16 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.jsonschema.JsonSchemas; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectByType; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedBy; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedByKeywordType; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import java.util.List; import org.junit.jupiter.api.Test; @@ -54,9 +47,7 @@ void should_know_his_name() { @Test void should_be_invalid_if_items_does_not_match_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("items", Json.createObjectBuilder().add("type", "number")).build() - ) + new ItemsKeyword(List.of(), JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asApplicator() .applyTo(Json.createArrayBuilder().add(1).add("invalid").add(2).build()), is(false) @@ -66,9 +57,7 @@ void should_be_invalid_if_items_does_not_match_schema() { @Test void should_be_valid_if_all_items_match_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("items", Json.createObjectBuilder().add("type", "number")).build() - ) + new ItemsKeyword(List.of(), JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())) .asApplicator() .applyTo(Json.createArrayBuilder().add(1).add(2).build()), is(true) @@ -78,9 +67,7 @@ void should_be_valid_if_all_items_match_schema() { @Test void should_be_applicator_and_annotation() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("items", JsonValue.EMPTY_JSON_OBJECT).build() - ).categories(), + new ItemsKeyword(List.of(), JsonSchemas.load(JsonValue.EMPTY_JSON_OBJECT)).categories(), contains(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION) ); } @@ -88,7 +75,7 @@ void should_be_applicator_and_annotation() { @Test void should_produces_true_if_is_applied_to_any_instance() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("items", JsonValue.TRUE).build()) + new ItemsKeyword(List.of(), JsonSchemas.load(JsonValue.TRUE)) .asAnnotation() .valueFor(Json.createArrayBuilder().add(1).build()), is(JsonValue.TRUE) @@ -98,11 +85,9 @@ void should_produces_true_if_is_applied_to_any_instance() { @Test void should_return_false_if_not_applies_to_any_item() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("prefixItems", Json.createArrayBuilder().add(true)) - .add("items", JsonValue.FALSE) - .build() + new ItemsKeyword( + List.of(new StaticAnnotation("prefixItems", JsonValue.TRUE)), + JsonSchemas.load(JsonValue.FALSE) ) .asAnnotation() .valueFor(Json.createArrayBuilder().add(1).build()), @@ -113,11 +98,9 @@ void should_return_false_if_not_applies_to_any_item() { @Test void should_be_valid_if_invaliditem_is_already_checked_by_prefixItems() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("prefixItems", Json.createArrayBuilder().add(true).add(true)) - .add("items", Json.createObjectBuilder().add("type", "integer")) - .build() + new ItemsKeyword( + List.of(new StaticAnnotation("prefixItems", JsonValue.TRUE)), + JsonSchemas.load(Json.createObjectBuilder().add("type", "integer").build()) ) .asApplicator() .applyTo(Json.createArrayBuilder().add("1").add("2").add(1).build()), @@ -128,30 +111,13 @@ void should_be_valid_if_invaliditem_is_already_checked_by_prefixItems() { @Test void should_be_invalid_if_invaliditem_is_not_already_checked_by_prefixItems() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("prefixItems", Json.createArrayBuilder().add(true)) - .add("items", Json.createObjectBuilder().add("type", "integer")) - .build() + new ItemsKeyword( + List.of(new StaticAnnotation("prefixItems", Json.createValue(0))), + JsonSchemas.load(Json.createObjectBuilder().add("type", "integer").build()) ) .asApplicator() .applyTo(Json.createArrayBuilder().add("1").add("2").add(1).build()), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new AffectedByKeywordType( - "items", - List.of(new AffectedBy(AffectByType.EXTENDS, "minItems"), new AffectedBy(AffectByType.EXTENDS, "maxItems")), - //nomally affectedBy too ... but we had the needed function only in affects :( - schema -> - new AffectsKeywordType( - "items", - List.of(new Affects("prefixItems", Json.createValue(-1))), - (affects, inner_schema) -> - new SubSchemaKeywordType("items", s -> new ItemsKeyword(affects, s)).createKeyword(inner_schema) - ).createKeyword(schema) - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeywordTest.java index f03d810d..28cc6849 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeywordTest.java @@ -29,11 +29,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -42,7 +40,7 @@ class NotKeywordTest { @Test void should_know_his_name() { - final Keyword items = createKeywordFrom(Json.createObjectBuilder().add("not", JsonValue.FALSE).build()); + final Keyword items = new NotKeyword(JsonSchemas.load(JsonValue.FALSE)); assertThat(items.hasName("not"), is(true)); assertThat(items.hasName("test"), is(false)); @@ -51,18 +49,16 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "not", - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string")) - ) - .add("required", Json.createArrayBuilder().add("foo")) - ) - .build() + new NotKeyword( + JsonSchemas.load( + Json.createObjectBuilder() + .add( + "properties", + Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string")) + ) + .add("required", Json.createArrayBuilder().add("foo")) + .build() + ) ).printOn(new HashMapMedia()), (Matcher) hasEntry(is("not"), hasKey("properties")) ); @@ -71,7 +67,7 @@ void should_be_printable() { @Test void should_be_valid_if_schema_not_apply() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("not", JsonValue.FALSE).build()) + new NotKeyword(JsonSchemas.load(JsonValue.FALSE)) .asApplicator() .applyTo(Json.createObjectBuilder().add("foo", "foo").build()), is(true) @@ -81,16 +77,10 @@ void should_be_valid_if_schema_not_apply() { @Test void should_be_invalid_if_schema_apply() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("not", JsonValue.TRUE).build()) + new NotKeyword(JsonSchemas.load(JsonValue.TRUE)) .asApplicator() .applyTo(Json.createObjectBuilder().add("foo", 3).add("bar", "bar").build()), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new SubSchemaKeywordType("not", NotKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeywordTest.java index 94315583..62b9f8da 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeywordTest.java @@ -30,12 +30,11 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SchemaArrayKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; +import java.util.List; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +42,7 @@ class OneOfKeywordTest { @Test void should_know_his_name() { - final Keyword items = createKeywordFrom( - Json.createObjectBuilder().add("oneOf", Json.createArrayBuilder().add(JsonValue.TRUE)).build() - ); + final Keyword items = new OneOfKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))); assertThat(items.hasName("oneOf"), is(true)); assertThat(items.hasName("test"), is(false)); @@ -54,31 +51,28 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() + new OneOfKeyword( + Json.createArrayBuilder() .add( - "oneOf", - Json.createArrayBuilder() + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("foo", Json.createObjectBuilder().add("type", "string")) - ) - .add("required", Json.createArrayBuilder().add("foo")) + "properties", + Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string")) ) + .add("required", Json.createArrayBuilder().add("foo")) + ) + .add( + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("bar", Json.createObjectBuilder().add("type", "number")) - ) - .add("required", Json.createArrayBuilder().add("bar")) + "properties", + Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number")) ) + .add("required", Json.createArrayBuilder().add("bar")) ) .build() + .stream() + .map(JsonSchemas::load) + .toList() ).printOn(new HashMapMedia()), (Matcher) hasEntry(is("oneOf"), hasItem((hasKey("properties")))) ); @@ -87,31 +81,28 @@ void should_be_printable() { @Test void should_be_valid_if_exactly_one_schema_applies() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() + new OneOfKeyword( + Json.createArrayBuilder() .add( - "oneOf", - Json.createArrayBuilder() + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("foo", Json.createObjectBuilder().add("type", "string")) - ) - .add("required", Json.createArrayBuilder().add("foo")) + "properties", + Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string")) ) + .add("required", Json.createArrayBuilder().add("foo")) + ) + .add( + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("bar", Json.createObjectBuilder().add("type", "number")) - ) - .add("required", Json.createArrayBuilder().add("bar")) + "properties", + Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number")) ) + .add("required", Json.createArrayBuilder().add("bar")) ) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createObjectBuilder().add("foo", "foo").build()), @@ -122,31 +113,28 @@ void should_be_valid_if_exactly_one_schema_applies() { @Test void should_be_invalid_if_none_schema_not_apply() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() + new OneOfKeyword( + Json.createArrayBuilder() .add( - "oneOf", - Json.createArrayBuilder() + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("foo", Json.createObjectBuilder().add("type", "string")) - ) - .add("required", Json.createArrayBuilder().add("foo")) + "properties", + Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string")) ) + .add("required", Json.createArrayBuilder().add("foo")) + ) + .add( + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("bar", Json.createObjectBuilder().add("type", "number")) - ) - .add("required", Json.createArrayBuilder().add("bar")) + "properties", + Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number")) ) + .add("required", Json.createArrayBuilder().add("bar")) ) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createObjectBuilder().add("foo", 3).add("bar", "bar").build()), @@ -157,41 +145,32 @@ void should_be_invalid_if_none_schema_not_apply() { @Test void should_be_invalid_if_more_than_one_schema_apply() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() + new OneOfKeyword( + Json.createArrayBuilder() .add( - "oneOf", - Json.createArrayBuilder() + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("foo", Json.createObjectBuilder().add("type", "string")) - ) - .add("required", Json.createArrayBuilder().add("foo")) + "properties", + Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string")) ) + .add("required", Json.createArrayBuilder().add("foo")) + ) + .add( + Json.createObjectBuilder() .add( - Json.createObjectBuilder() - .add( - "properties", - Json.createObjectBuilder() - .add("bar", Json.createObjectBuilder().add("type", "number")) - ) - .add("required", Json.createArrayBuilder().add("bar")) + "properties", + Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number")) ) + .add("required", Json.createArrayBuilder().add("bar")) ) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createObjectBuilder().add("foo", "foo").add("bar", 33).build()), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new SchemaArrayKeywordType("oneOf", OneOfKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java index 88245040..f015d7c9 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java @@ -30,14 +30,14 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonString; import jakarta.json.JsonValue; import java.math.BigDecimal; +import java.util.Map; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -45,9 +45,7 @@ class PatternPropertiesKeywordTest { @Test void should_know_his_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build() - ); + final Keyword keyword = new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of())); assertThat(keyword.hasName("patternProperties"), is(true)); assertThat(keyword.hasName("test"), is(false)); @@ -56,9 +54,7 @@ void should_know_his_name() { @Test void should_be_an_applicator_and_an_annotation() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build() - ).categories(), + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of())).categories(), containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION) ); } @@ -66,9 +62,7 @@ void should_be_an_applicator_and_an_annotation() { @Test void should_be_valid_for_non_object() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build()) - .asApplicator() - .applyTo(JsonValue.FALSE), + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of())).asApplicator().applyTo(JsonValue.FALSE), is(true) ); } @@ -76,7 +70,7 @@ void should_be_valid_for_non_object() { @Test void should_be_valid_for_empty_object() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build()) + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of())) .asApplicator() .applyTo(JsonValue.EMPTY_JSON_OBJECT), is(true) @@ -86,11 +80,7 @@ void should_be_valid_for_empty_object() { @Test void should_be_valid_if_properties_applies_to_his_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("patternProperties", Json.createObjectBuilder().add("t.st", JsonValue.TRUE)) - .build() - ) + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("t.st", JsonSchemas.load(JsonValue.TRUE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).build()), is(true) @@ -100,32 +90,20 @@ void should_be_valid_if_properties_applies_to_his_schema() { @Test void should_be_invalid_if_properties_not_applies_to_his_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("patternProperties", Json.createObjectBuilder().add("t.st", JsonValue.FALSE)) - .build() - ) + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("t.st", JsonSchemas.load(JsonValue.FALSE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).build()), is(false) ); } - /* - Attention can be falky. - JsonObject is a map, so the properties occurred in random order. - This means for this test it could be green without using all assertions. - */ @Test - void should_be_invalid_if_one_schema_doesn_apply() { + void should_be_invalid_if_one_schema_does_not_apply() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "patternProperties", - Json.createObjectBuilder().add("t.st", JsonValue.TRUE).add("t.*", JsonValue.FALSE) - ) - .build() + new PatternPropertiesKeyword( + new NamedJsonSchemas( + Map.of("t.st", JsonSchemas.load(JsonValue.TRUE), "t.*", JsonSchemas.load(JsonValue.FALSE)) + ) ) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).build()), @@ -136,11 +114,7 @@ void should_be_invalid_if_one_schema_doesn_apply() { @Test void should_be_valid_if_properties_not_covered() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("patternProperties", Json.createObjectBuilder().add("t.st", JsonValue.FALSE)) - .build() - ) + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("t.st", JsonSchemas.load(JsonValue.FALSE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("foo", 1).build()), is(true) @@ -150,11 +124,7 @@ void should_be_valid_if_properties_not_covered() { @Test void should_return_the_matching_property_names() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("patternProperties", Json.createObjectBuilder().add("f.o", JsonValue.TRUE)) - .build() - ) + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("f.o", JsonSchemas.load(JsonValue.TRUE)))) .asAnnotation() .valueFor( Json.createObjectBuilder() @@ -175,18 +145,10 @@ void should_return_the_matching_property_names() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("patternProperties", Json.createObjectBuilder().add("f.o", JsonValue.TRUE)) - .build() - ).printOn(new HashMapMedia()), + new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("f.o", JsonSchemas.load(JsonValue.TRUE)))).printOn( + new HashMapMedia() + ), (Matcher) hasEntry(is("patternProperties"), hasEntry(is("f.o"), anEmptyMap())) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NamedJsonSchemaKeywordType("patternProperties", PatternPropertiesKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java index a433f374..9ba9728b 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java @@ -31,12 +31,11 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SchemaArrayKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; +import java.util.List; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -44,9 +43,7 @@ class PrefixItemsKeywordTest { @Test void should_know_his_name() { - final Keyword items = createKeywordFrom( - Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build() - ); + final Keyword items = new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))); assertThat(items.hasName("prefixItems"), is(true)); assertThat(items.hasName("test"), is(false)); @@ -55,9 +52,7 @@ void should_know_his_name() { @Test void should_return_zero_as_value() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build() - ) + new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))) .asAnnotation() .valueFor(Json.createArrayBuilder().add(1).add(2).build()), is(Json.createValue(0)) @@ -67,10 +62,14 @@ void should_return_zero_as_value() { @Test void should_retrun_true_if_is_applies_to_all_values() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE).add(JsonValue.TRUE)) + new PrefixItemsKeyword( + Json.createArrayBuilder() + .add(JsonValue.TRUE) + .add(JsonValue.TRUE) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asAnnotation() .valueFor(Json.createArrayBuilder().add(1).add(2).build()), @@ -81,9 +80,7 @@ void should_retrun_true_if_is_applies_to_all_values() { @Test void should_be_valid_for_non_arrays() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.FALSE)).build() - ) + new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.FALSE))) .asApplicator() .applyTo(Json.createValue(1)), is(true) @@ -93,9 +90,7 @@ void should_be_valid_for_non_arrays() { @Test void should_be_valid_if_first_item_match_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build() - ) + new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))) .asApplicator() .applyTo(Json.createArrayBuilder().add(1).build()), is(true) @@ -105,10 +100,14 @@ void should_be_valid_if_first_item_match_schema() { @Test void should_be_invalid_if_second_item_does_not_match_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE).add(JsonValue.FALSE)) + new PrefixItemsKeyword( + Json.createArrayBuilder() + .add(JsonValue.TRUE) + .add(JsonValue.FALSE) .build() + .stream() + .map(JsonSchemas::load) + .toList() ) .asApplicator() .applyTo(Json.createArrayBuilder().add(1).add(3).build()), @@ -119,9 +118,7 @@ void should_be_invalid_if_second_item_does_not_match_schema() { @Test void should_be_applicator_and_annotation() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("prefixItems", JsonValue.EMPTY_JSON_ARRAY).build() - ).categories(), + new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))).categories(), containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION) ); } @@ -129,16 +126,8 @@ void should_be_applicator_and_annotation() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build() - ).printOn(new HashMapMedia()), + new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))).printOn(new HashMapMedia()), (Matcher) hasEntry(is("prefixItems"), contains(anEmptyMap())) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new SchemaArrayKeywordType("prefixItems", PrefixItemsKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java index f3e88790..1d18e283 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java @@ -30,11 +30,10 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import java.util.Map; import org.hamcrest.Matcher; @@ -44,9 +43,7 @@ class PropertiesKeywordTest { @Test void should_be_know_his_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("properties", JsonValue.EMPTY_JSON_OBJECT).build() - ); + final Keyword keyword = new PropertiesKeyword(new NamedJsonSchemas(Map.of())); assertThat(keyword.hasName("properties"), is(true)); assertThat(keyword.hasName("test"), is(false)); @@ -55,9 +52,7 @@ void should_be_know_his_name() { @Test void should_be_an_applicator_and_annotation() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("properties", JsonValue.EMPTY_JSON_OBJECT).build() - ).categories(), + new PropertiesKeyword(new NamedJsonSchemas(Map.of())).categories(), containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION) ); } @@ -65,9 +60,7 @@ void should_be_an_applicator_and_annotation() { @Test void should_be_valid_for_non_objects() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("properties", JsonValue.EMPTY_JSON_OBJECT).build()) - .asApplicator() - .applyTo(JsonValue.EMPTY_JSON_ARRAY), + new PropertiesKeyword(new NamedJsonSchemas(Map.of())).asApplicator().applyTo(JsonValue.EMPTY_JSON_ARRAY), is(true) ); } @@ -75,11 +68,7 @@ void should_be_valid_for_non_objects() { @Test void should_be_valid_if_properties_applies_to_his_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .build() - ) + new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.TRUE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).build()), is(true) @@ -89,11 +78,7 @@ void should_be_valid_if_properties_applies_to_his_schema() { @Test void should_be_invalid_if_properties_not_applies_to_his_schema() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.FALSE)) - .build() - ) + new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE)))) .asApplicator() .applyTo(Json.createObjectBuilder().add("test", 1).build()), is(false) @@ -103,11 +88,7 @@ void should_be_invalid_if_properties_not_applies_to_his_schema() { @Test void should_be_valid_for_empty_objects() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.FALSE)) - .build() - ) + new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE)))) .asApplicator() .applyTo(JsonValue.EMPTY_JSON_OBJECT), is(true) @@ -117,10 +98,10 @@ void should_be_valid_for_empty_objects() { @Test void should_return_all_matched_propertynames() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", true).add("foo", true)) - .build() + new PropertiesKeyword( + new NamedJsonSchemas( + Map.of("test", JsonSchemas.load(JsonValue.TRUE), "foo", JsonSchemas.load(JsonValue.TRUE)) + ) ) .asAnnotation() .valueFor(Json.createObjectBuilder().add("foo", 1).build()) @@ -134,20 +115,10 @@ void should_return_all_matched_propertynames() { @Test void should_be_printable() { assertThat( - ((Map) createKeywordFrom( - Json.createObjectBuilder() - .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE)) - .build() - ) + ((Map) new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.TRUE)))) .printOn(new HashMapMedia()) .get("properties")).get("test"), (Matcher) anEmptyMap() ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NamedJsonSchemaKeywordType("properties", PropertiesKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } From bc9b0f180578b3c41eec23ac55173dd44396f436 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:17:08 +0200 Subject: [PATCH 4/8] refactor test for all keyword defined in corevocab --- .../core/vocab/core/VocabularyKeyword.java | 86 +++++++++++++++++++ .../vocab/core/VocabularyKeywordType.java | 63 +------------- .../core/vocab/core/CommentKeywordTest.java | 22 +---- .../core/vocab/core/DefsKeywordTest.java | 21 +---- .../vocab/core/DynamicRefKeywordTest.java | 35 +++----- .../core/vocab/core/IdKeywordTest.java | 27 +----- .../core/vocab/core/RefKeywordTest.java | 81 ++++++++--------- .../core/vocab/core/RefKeywordTypeTest.java | 28 ++++++ .../core/vocab/core/SchemaKeywordTest.java | 31 +------ .../vocab/core/VocabularyKeywordTypeTest.java | 50 +++-------- .../vocabulary/spi/VocabularyDefinitions.java | 3 +- 11 files changed, 188 insertions(+), 259 deletions(-) create mode 100644 core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java new file mode 100644 index 00000000..7dbb20ce --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java @@ -0,0 +1,86 @@ +/* + * The MIT License + * + * Copyright 2024 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.core; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.media.json.JsonObjectPrintable; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import java.net.URI; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * $vocabulary : Object<URI, Boolean>
+ * This keyword is used in meta-schemas to identify the required and optional vocabularies available for use in
+ * schemas described by that meta-schema.
+ *
+ *
    + *
  • identifier
  • + *
+ * + * source: https://www.learnjsonschema.com/2020-12/core/vocabulary/ + * spec: https://json-schema.org/draft/2020-12/json-schema-core.html#section-8.1.2 + */ +final class VocabularyKeyword implements VocabularyDefinitions { + + static final String NAME = "$vocabulary"; + private final JsonObject vocabularies; + + VocabularyKeyword(final JsonValue vocabularies) { + this(vocabularies.asJsonObject()); + } + + VocabularyKeyword(final JsonObject vocabularies) { + this.vocabularies = Objects.requireNonNull(vocabularies); + } + + @Override + public > T printOn(final T media) { + return media.withValue(NAME, new JsonObjectPrintable(vocabularies)); + } + + @Override + public boolean hasName(final String name) { + return Objects.equals(NAME, name); + } + + @Override + public Collection categories() { + //is a identifier after spec ... but how to implement it as it? + return List.of(); + } + + @Override + public Stream definitions() { + return vocabularies + .entrySet() + .stream() + .map(entry -> new VocabularyDefinition(URI.create(entry.getKey()), entry.getValue() == JsonValue.TRUE)); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java index 1bbac9ae..e099babb 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java @@ -23,21 +23,11 @@ */ package io.github.sebastiantoepfer.jsonschema.core.vocab.core; -import io.github.sebastiantoepfer.ddd.common.Media; -import io.github.sebastiantoepfer.ddd.media.json.JsonObjectPrintable; import io.github.sebastiantoepfer.jsonschema.InstanceType; import io.github.sebastiantoepfer.jsonschema.JsonSchema; -import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import java.net.URI; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; /** * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-vocabulary-keyword @@ -46,11 +36,11 @@ public final class VocabularyKeywordType implements KeywordType { @Override public String name() { - return "$vocabulary"; + return VocabularyKeyword.NAME; } @Override - public VocabularyKeyword createKeyword(final JsonSchema schema) { + public VocabularyDefinitions createKeyword(final JsonSchema schema) { final JsonValue value = schema.asJsonObject().get((name())); final VocabularyKeyword result; if (InstanceType.OBJECT.isInstance(value)) { @@ -64,53 +54,4 @@ public VocabularyKeyword createKeyword(final JsonSchema schema) { } return result; } - - /** - * $vocabulary : Object<URI, Boolean>
- * This keyword is used in meta-schemas to identify the required and optional vocabularies available for use in
- * schemas described by that meta-schema.
- *
- *
    - *
  • identifier
  • - *
- * - * source: https://www.learnjsonschema.com/2020-12/core/vocabulary/ - * spec: https://json-schema.org/draft/2020-12/json-schema-core.html#section-8.1.2 - */ - public final class VocabularyKeyword implements Keyword, VocabularyDefinitions { - - private final JsonObject vocabularies; - - VocabularyKeyword(final JsonValue vocabularies) { - this(vocabularies.asJsonObject()); - } - - VocabularyKeyword(final JsonObject vocabularies) { - this.vocabularies = Objects.requireNonNull(vocabularies); - } - - @Override - public > T printOn(final T media) { - return media.withValue(name(), new JsonObjectPrintable(vocabularies)); - } - - @Override - public boolean hasName(final String name) { - return Objects.equals(name(), name); - } - - @Override - public Collection categories() { - //is a identifier after spec ... but how to implement it as it? - return List.of(); - } - - @Override - public Stream definitions() { - return vocabularies - .entrySet() - .stream() - .map(entry -> new VocabularyDefinition(URI.create(entry.getKey()), entry.getValue() == JsonValue.TRUE)); - } - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java index a853cda2..625e81cf 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java @@ -28,21 +28,14 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.spi.JsonProvider; import org.junit.jupiter.api.Test; class CommentKeywordTest { @Test void should_know_her_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("$comment", Json.createValue("comment")).build() - ); + final Keyword keyword = new CommentKeyword("comment"); assertThat(keyword.hasName("$comment"), is(true)); assertThat(keyword.hasName("test"), is(false)); @@ -50,17 +43,6 @@ void should_know_her_name() { @Test void should_be_printable() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("$comment", Json.createValue("comment")).build()).printOn( - new HashMapMedia() - ), - hasEntry("$comment", "comment") - ); - } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new StringKeywordType(JsonProvider.provider(), "$comment", CommentKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); + assertThat(new CommentKeyword("comment").printOn(new HashMapMedia()), hasEntry("$comment", "comment")); } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java index 4dd22189..878f9d38 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java @@ -29,12 +29,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType; +import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; +import java.util.Map; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -42,9 +39,7 @@ class DefsKeywordTest { @Test void should_know_his_name() { - final Keyword defs = createKeywordFrom( - Json.createObjectBuilder().add("$defs", JsonValue.EMPTY_JSON_OBJECT).build() - ); + final Keyword defs = new DefsKeyword(new NamedJsonSchemas(Map.of())); assertThat(defs.hasName("$defs"), is(true)); assertThat(defs.hasName("test"), is(false)); @@ -53,16 +48,8 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("$defs", JsonValue.EMPTY_JSON_OBJECT).build()).printOn( - new HashMapMedia() - ), + new DefsKeyword(new NamedJsonSchemas(Map.of())).printOn(new HashMapMedia()), (Matcher) hasEntry(is("$defs"), anEmptyMap()) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NamedJsonSchemaKeywordType(DefsKeyword.NAME, DefsKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java index d909a1a9..5c708491 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java @@ -28,13 +28,8 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; -import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.net.URI; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,37 +38,27 @@ class DynamicRefKeywordTest { @Test void should_create_keyword_with_name() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("$dynamicRef", "test").build()).hasName("$dynamicRef"), - is(true) - ); - } - - @Test - void notFinischedYet() { - final Keyword keyword = createKeywordFrom(Json.createObjectBuilder().add("$dynamicRef", "test").build()); + final Keyword keyword = new DynamicRefKeyword(URI.create("test")); assertThat(keyword.hasName("$dynamicRef"), is(true)); assertThat(keyword.hasName("$id"), is(false)); - - assertThat(keyword.asApplicator().applyTo(JsonValue.TRUE), is(true)); } @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("$dynamicRef", "test").build()).printOn( - new HashMapMedia() - ), + new DynamicRefKeyword(URI.create("test")).printOn(new HashMapMedia()), (Matcher) hasEntry(is("$dynamicRef"), is("test")) ); } - private static Keyword createKeywordFrom(final JsonObject json) { - return new StringKeywordType( - JsonProvider.provider(), - DynamicRefKeyword.NAME, - s -> new DynamicRefKeyword(URI.create(s)) - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); + @Test + void notFinischedYet() { + final Keyword keyword = new DynamicRefKeyword(URI.create("test")); + + assertThat(keyword.hasName("$dynamicRef"), is(true)); + assertThat(keyword.hasName("$id"), is(false)); + + assertThat(keyword.asApplicator().applyTo(JsonValue.TRUE), is(true)); } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java index 0e23f507..3d9cb8fc 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java @@ -28,12 +28,7 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.spi.JsonProvider; import java.net.URI; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -42,7 +37,7 @@ class IdKeywordTest { @Test void should_know_his_name() { - final Keyword id = createKeywordFrom(Json.createObjectBuilder().add("$id", Json.createValue("/test")).build()); + final Keyword id = new IdKeyword(URI.create("/test")); assertThat(id.hasName("$id"), is(true)); assertThat(id.hasName("test"), is(false)); @@ -51,13 +46,7 @@ void should_know_his_name() { @Test void should_retun_his_uri() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("$id", Json.createValue("https://json-schema.org/draft/2020-12/schema")) - .build() - ) - .asIdentifier() - .asUri(), + new IdKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).asIdentifier().asUri(), is(URI.create("https://json-schema.org/draft/2020-12/schema")) ); } @@ -65,18 +54,8 @@ void should_retun_his_uri() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("$id", Json.createValue("https://json-schema.org/draft/2020-12/schema")) - .build() - ).printOn(new HashMapMedia()), + new IdKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).printOn(new HashMapMedia()), (Matcher) hasEntry(is("$id"), is("https://json-schema.org/draft/2020-12/schema")) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new StringKeywordType(JsonProvider.provider(), "$id", s -> new IdKeyword(URI.create(s))).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java index 489e2f0c..a1b5be96 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java @@ -26,52 +26,41 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.JsonSchema; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; +import java.net.URI; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; class RefKeywordTest { - @Test - void should_be_not_createable_from_non_string() { - final RefKeywordType keywordType = new RefKeywordType(JsonProvider.provider()); - final JsonSchema schema = new DefaultJsonSchemaFactory() - .create(Json.createObjectBuilder().add("$ref", JsonValue.TRUE).build()); - assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema)); - } - @Test void should_know_his_name() { - final Keyword ref = new RefKeywordType(JsonProvider.provider()).createKeyword( - new DefaultJsonSchemaFactory().create(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()) + final Keyword ref = new RefKeyword( + JsonSchemas.load(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()), + URI.create("#") ); - assertThat(ref.hasName("$ref"), is(true)); assertThat(ref.hasName("test"), is(false)); } @Test void should_use_local_referenced_schema_for_validation() { - final Keyword keyword = new RefKeywordType(JsonProvider.provider()).createKeyword( - new DefaultJsonSchemaFactory() - .create( - Json.createObjectBuilder() - .add( - "$defs", - Json.createObjectBuilder() - .add("positiveInteger", Json.createObjectBuilder().add("type", "integer")) - ) - .add("$ref", Json.createValue("#/$defs/positiveInteger")) - .build() - ) + final Keyword keyword = new RefKeyword( + JsonSchemas.load( + Json.createObjectBuilder() + .add( + "$defs", + Json.createObjectBuilder() + .add("positiveInteger", Json.createObjectBuilder().add("type", "integer")) + ) + .add("$ref", Json.createValue("#/$defs/positiveInteger")) + .build() + ), + URI.create("#/$defs/positiveInteger") ); assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true)); @@ -80,32 +69,30 @@ void should_use_local_referenced_schema_for_validation() { @Test void should_use_remote_referenced_schema_for_validation() { - final Keyword keyword = new RefKeywordType(JsonProvider.provider()).createKeyword( - new DefaultJsonSchemaFactory() - .create( - Json.createObjectBuilder() - .add( - "$defs", - Json.createObjectBuilder() - .add("positiveInteger", Json.createObjectBuilder().add("type", "integer")) - ) - .add("$ref", Json.createValue("#/$defs/positiveInteger")) - .build() - ) + final Keyword keyword = new RefKeyword( + JsonSchemas.load( + Json.createObjectBuilder() + .add( + "$defs", + Json.createObjectBuilder() + .add("positiveInteger", Json.createObjectBuilder().add("type", "integer")) + ) + .add("$ref", Json.createValue("#/$defs/positiveInteger")) + .build() + ), + URI.create("#/$defs/positiveInteger") ); - assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true)); + assertThat(keyword.asApplicator().applyTo(Json.createValue("invalid")), is(false)); } @Test void should_be_printable() { assertThat( - new RefKeywordType(JsonProvider.provider()) - .createKeyword( - new DefaultJsonSchemaFactory() - .create(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()) - ) - .printOn(new HashMapMedia()), + new RefKeyword( + JsonSchemas.load(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()), + URI.create("#") + ).printOn(new HashMapMedia()), (Matcher) hasEntry(is("$ref"), is("#")) ); } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java index ab7ed341..5750e79d 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java @@ -25,8 +25,16 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; +import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.Json; +import jakarta.json.JsonValue; import jakarta.json.spi.JsonProvider; import org.junit.jupiter.api.Test; @@ -40,4 +48,24 @@ void should_know_the_keywords_name() { assertThat(refKeywordType.hasName("ref"), is(false)); assertThat(refKeywordType.hasName("test"), is(false)); } + + @Test + void should_be_not_createable_from_non_string() { + final RefKeywordType keywordType = new RefKeywordType(JsonProvider.provider()); + final JsonSchema schema = new DefaultJsonSchemaFactory() + .create(Json.createObjectBuilder().add("$ref", JsonValue.TRUE).build()); + assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema)); + } + + @Test + void should_create_refkeyword() { + assertThat( + new RefKeywordType(JsonProvider.provider()).createKeyword( + JsonSchemas.load( + Json.createObjectBuilder().add("$ref", Json.createValue("#/$defs/positiveInteger")).build() + ) + ), + is(not(nullValue())) + ); + } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java index e2ff6c7f..cc3eb4b5 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java @@ -28,12 +28,7 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.spi.JsonProvider; import java.net.URI; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -42,9 +37,7 @@ class SchemaKeywordTest { @Test void should_know_his_name() { - final Keyword schema = createKeywordFrom( - Json.createObjectBuilder().add("$schema", Json.createValue("/test")).build() - ); + final Keyword schema = new SchemaKeyword(URI.create("/test")); assertThat(schema.hasName("$schema"), is(true)); assertThat(schema.hasName("test"), is(false)); @@ -53,13 +46,7 @@ void should_know_his_name() { @Test void should_retun_his_uri() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("$schema", Json.createValue("https://json-schema.org/draft/2020-12/schema")) - .build() - ) - .asIdentifier() - .asUri(), + new SchemaKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).asIdentifier().asUri(), is(URI.create("https://json-schema.org/draft/2020-12/schema")) ); } @@ -67,20 +54,8 @@ void should_retun_his_uri() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("$schema", Json.createValue("https://json-schema.org/draft/2020-12/schema")) - .build() - ).printOn(new HashMapMedia()), + new SchemaKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).printOn(new HashMapMedia()), (Matcher) hasEntry(is("$schema"), is("https://json-schema.org/draft/2020-12/schema")) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new StringKeywordType( - JsonProvider.provider(), - "$schema", - s -> new SchemaKeyword(URI.create(s)) - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java index 3ee97e25..5e7dbac9 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java @@ -30,10 +30,8 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions; import jakarta.json.Json; import jakarta.json.JsonValue; import java.net.URI; @@ -44,11 +42,7 @@ class VocabularyKeywordTypeTest { @Test void should_created_keyword_should_know_his_name() { - final Keyword vocabulary = new VocabularyKeywordType() - .createKeyword( - new DefaultJsonSchemaFactory() - .create(Json.createObjectBuilder().add("$vocabulary", JsonValue.EMPTY_JSON_OBJECT).build()) - ); + final Keyword vocabulary = new VocabularyKeyword(JsonValue.EMPTY_JSON_OBJECT); assertThat(vocabulary.hasName("$vocabulary"), is(true)); assertThat(vocabulary.hasName("$id"), is(false)); @@ -57,20 +51,13 @@ void should_created_keyword_should_know_his_name() { @Test void should_create_definitions() { assertThat( - ((VocabularyDefinitions) new VocabularyKeywordType() - .createKeyword( - new DefaultJsonSchemaFactory() - .create( - Json.createObjectBuilder() - .add( - "$vocabulary", - Json.createObjectBuilder() - .add("https://json-schema.org/draft/2020-12/vocab/core", true) - .add("http://openapi.org/test", false) - ) - .build() - ) - )).definitions() + new VocabularyKeyword( + Json.createObjectBuilder() + .add("https://json-schema.org/draft/2020-12/vocab/core", true) + .add("http://openapi.org/test", false) + .build() + ) + .definitions() .toList(), containsInAnyOrder( new VocabularyDefinition(URI.create("https://json-schema.org/draft/2020-12/vocab/core"), true), @@ -82,21 +69,12 @@ void should_create_definitions() { @Test void should_be_printable() { assertThat( - new VocabularyKeywordType() - .createKeyword( - new DefaultJsonSchemaFactory() - .create( - Json.createObjectBuilder() - .add( - "$vocabulary", - Json.createObjectBuilder() - .add("https://json-schema.org/draft/2020-12/vocab/core", true) - .add("http://openapi.org/test", false) - ) - .build() - ) - ) - .printOn(new HashMapMedia()), + new VocabularyKeyword( + Json.createObjectBuilder() + .add("https://json-schema.org/draft/2020-12/vocab/core", true) + .add("http://openapi.org/test", false) + .build() + ).printOn(new HashMapMedia()), (Matcher) hasEntry( is("$vocabulary"), allOf( diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java index fe9dd85f..d9822afd 100644 --- a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java @@ -23,8 +23,9 @@ */ package io.github.sebastiantoepfer.jsonschema.vocabulary.spi; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import java.util.stream.Stream; -public interface VocabularyDefinitions { +public interface VocabularyDefinitions extends Keyword { Stream definitions(); } From 1563195548efd13ee269095d9a3fd528dc6bd047 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:47:32 +0200 Subject: [PATCH 5/8] remove usage of record for VocabularyDefinition VocabularyDefinition is a interface now, the default implemention move into LazyVocabularyDefinition which no longer use the serviceloader directly. the vocabulary avaivable for a definitions will provided via a supplier. ServiceLoaderLazyVocabulariesSupplier can be use to use a ServiceLoader to find a requested vocabulary. VocabularyDefinition doesn't provide a method to retrieve the id instead it defines a method to ask if it has a given id (hasId("") instead of id().equals("")). --- .../jsonschema/core/Keywords.java | 4 +- .../applicator/ApplicatorVocabulary.java | 4 +- .../core/vocab/content/ContentVocabulary.java | 4 +- .../core/vocab/core/CoreVocabulary.java | 4 +- .../core/vocab/core/VocabularyKeyword.java | 11 +- .../format/FormatAnnotationVocabulary.java | 4 +- .../core/vocab/meta/MetaDataVocabulary.java | 4 +- .../unevaluated/UnevaluatedVocabulary.java | 4 +- .../validation/ValidationVocabulary.java | 4 +- .../jsonschema/core/KeywordsTest.java | 39 ++++++- ...peTest.java => VocabularyKeywordTest.java} | 40 ++++++- vocabulary-spi/pom.xml | 5 + .../spi/LazyVocabularyDefinition.java | 102 ++++++++++++++++++ ...ultVocabulary.java => ListVocabulary.java} | 6 +- ...ServiceLoaderLazyVocabulariesSupplier.java | 36 +++++++ .../vocabulary/spi/VocabularyDefinition.java | 20 ++-- ...java => LazyVocabularyDefinitionTest.java} | 39 ++++++- ...ularyTest.java => ListVocabularyTest.java} | 13 ++- 18 files changed, 292 insertions(+), 51 deletions(-) rename core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/{VocabularyKeywordTypeTest.java => VocabularyKeywordTest.java} (68%) create mode 100644 vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinition.java rename vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/{DefaultVocabulary.java => ListVocabulary.java} (89%) create mode 100644 vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ServiceLoaderLazyVocabulariesSupplier.java rename vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/{VocabularyDefinitionTest.java => LazyVocabularyDefinitionTest.java} (60%) rename vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/{DefaultVocabularyTest.java => ListVocabularyTest.java} (86%) diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java index a324741d..df243365 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java @@ -74,8 +74,8 @@ public Keywords(final Collection vocabDefs) { if ( vocabDefs .stream() - .filter(vocabDef -> MANDANTORY_VOCABS.containsKey(vocabDef.id())) - .anyMatch(not(VocabularyDefinition::required)) + .filter(vocabDef -> MANDANTORY_VOCABS.keySet().stream().anyMatch(vocabDef::hasid)) + .anyMatch(not(VocabularyDefinition::isRequired)) ) { throw new IllegalArgumentException("can not be created without core vocabulary is requiered!"); } diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java index 5c65bb01..75384f96 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java @@ -33,7 +33,7 @@ import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SchemaArrayKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import jakarta.json.Json; import jakarta.json.JsonValue; import java.net.URI; @@ -52,7 +52,7 @@ public final class ApplicatorVocabulary implements Vocabulary { private final Vocabulary vocab; public ApplicatorVocabulary() { - this.vocab = new DefaultVocabulary( + this.vocab = new ListVocabulary( URI.create("https://json-schema.org/draft/2020-12/vocab/applicator"), new SchemaArrayKeywordType(AllOfKeyword.NAME, AllOfKeyword::new), new SchemaArrayKeywordType(AnyOfKeyword.NAME, AnyOfKeyword::new), diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java index 2948db29..ef6e04e5 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java @@ -25,7 +25,7 @@ import io.github.sebastiantoepfer.jsonschema.Vocabulary; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import java.net.URI; import java.util.Optional; @@ -41,7 +41,7 @@ public final class ContentVocabulary implements Vocabulary { private final Vocabulary vocab; public ContentVocabulary() { - this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/content")); + this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/content")); } @Override diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java index 26673186..0232c6fb 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java @@ -27,7 +27,7 @@ import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import jakarta.json.spi.JsonProvider; import java.net.URI; import java.util.Optional; @@ -37,7 +37,7 @@ public final class CoreVocabulary implements Vocabulary { private final Vocabulary vocab; public CoreVocabulary(final JsonProvider jsonContext) { - this.vocab = new DefaultVocabulary( + this.vocab = new ListVocabulary( URI.create("https://json-schema.org/draft/2020-12/vocab/core"), new StringKeywordType(jsonContext, SchemaKeyword.NAME, value -> new SchemaKeyword(URI.create(value))), new StringKeywordType(jsonContext, IdKeyword.NAME, value -> new IdKeyword(URI.create(value))), diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java index 7dbb20ce..a2e62341 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java @@ -25,6 +25,8 @@ import io.github.sebastiantoepfer.ddd.common.Media; import io.github.sebastiantoepfer.ddd.media.json.JsonObjectPrintable; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularyDefinition; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ServiceLoaderLazyVocabulariesSupplier; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions; import jakarta.json.JsonObject; @@ -81,6 +83,13 @@ public Stream definitions() { return vocabularies .entrySet() .stream() - .map(entry -> new VocabularyDefinition(URI.create(entry.getKey()), entry.getValue() == JsonValue.TRUE)); + .map( + entry -> + new LazyVocabularyDefinition( + URI.create(entry.getKey()), + entry.getValue() == JsonValue.TRUE, + new ServiceLoaderLazyVocabulariesSupplier() + ) + ); } } diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatAnnotationVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatAnnotationVocabulary.java index 4b55ac37..1f918bdd 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatAnnotationVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatAnnotationVocabulary.java @@ -25,7 +25,7 @@ import io.github.sebastiantoepfer.jsonschema.Vocabulary; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import java.net.URI; import java.util.Optional; @@ -41,7 +41,7 @@ public final class FormatAnnotationVocabulary implements Vocabulary { private final Vocabulary vocab; public FormatAnnotationVocabulary() { - this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/format-annotation")); + this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/format-annotation")); } @Override diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java index aed1b3e1..b642fbee 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java @@ -25,7 +25,7 @@ import io.github.sebastiantoepfer.jsonschema.Vocabulary; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import java.net.URI; import java.util.Optional; @@ -41,7 +41,7 @@ public final class MetaDataVocabulary implements Vocabulary { private final Vocabulary vocab; public MetaDataVocabulary() { - this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/meta-data")); + this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/meta-data")); } @Override diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java index e868460d..6ae14692 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java @@ -25,7 +25,7 @@ import io.github.sebastiantoepfer.jsonschema.Vocabulary; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import java.net.URI; import java.util.Optional; @@ -41,7 +41,7 @@ public final class UnevaluatedVocabulary implements Vocabulary { private final Vocabulary vocab; public UnevaluatedVocabulary() { - this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/unevaluated")); + this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/unevaluated")); } @Override 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 86e69b80..9e4bd0f9 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 @@ -35,7 +35,7 @@ import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringArrayKeywordType; import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import jakarta.json.spi.JsonProvider; import java.net.URI; import java.util.List; @@ -46,7 +46,7 @@ public final class ValidationVocabulary implements Vocabulary { private final Vocabulary vocab; public ValidationVocabulary(final JsonProvider jsonContext) { - this.vocab = new DefaultVocabulary( + this.vocab = new ListVocabulary( URI.create("https://json-schema.org/draft/2020-12/vocab/validation"), new TypeKeywordType(), new AnyKeywordType(jsonContext, ConstKeyword.NAME, ConstKeyword::new), diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java index 0f42ad66..19c40788 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java @@ -29,12 +29,15 @@ import static org.hamcrest.Matchers.nullValue; import static org.junit.jupiter.api.Assertions.assertThrows; +import io.github.sebastiantoepfer.jsonschema.Vocabulary; import io.github.sebastiantoepfer.jsonschema.core.vocab.core.CoreVocabulary; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; import jakarta.json.spi.JsonProvider; import java.net.URI; import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.Optional; import org.junit.jupiter.api.Test; class KeywordsTest { @@ -42,7 +45,7 @@ class KeywordsTest { @Test void should_not_be_createbale_without_mandantory_core_vocabulary() { final Collection vocabDefs = List.of( - new VocabularyDefinition(new CoreVocabulary(JsonProvider.provider()).id(), false) + new TestVocabularyDefinition(new CoreVocabulary(JsonProvider.provider()).id(), false) ); assertThrows(IllegalArgumentException.class, () -> new Keywords(vocabDefs)); } @@ -50,7 +53,7 @@ void should_not_be_createbale_without_mandantory_core_vocabulary() { @Test void should_not_be_createbale_without_mandantory_base_vocabulary() { final Collection vocabDefs = List.of( - new VocabularyDefinition(new BasicVocabulary().id(), false) + new TestVocabularyDefinition(new BasicVocabulary().id(), false) ); assertThrows(IllegalArgumentException.class, () -> new Keywords(vocabDefs)); } @@ -58,8 +61,38 @@ void should_not_be_createbale_without_mandantory_base_vocabulary() { @Test void should_be_createbale_with_optional_vocabularies() { assertThat( - new Keywords(List.of(new VocabularyDefinition(URI.create("http://optinal"), false))), + new Keywords(List.of(new TestVocabularyDefinition(URI.create("http://optinal"), false))), is(not(nullValue())) ); } + + private static final class TestVocabularyDefinition implements VocabularyDefinition { + + private final URI id; + private final boolean required; + + public TestVocabularyDefinition(final URI id) { + this(id, false); + } + + public TestVocabularyDefinition(final URI id, final boolean required) { + this.id = id; + this.required = required; + } + + @Override + public Optional findVocabulary() { + return Optional.empty(); + } + + @Override + public boolean hasid(URI id) { + return Objects.equals(this.id, id); + } + + @Override + public boolean isRequired() { + return required; + } + } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java similarity index 68% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java rename to core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java index 5e7dbac9..c12e2907 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java @@ -26,6 +26,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.either; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; @@ -35,10 +36,13 @@ import jakarta.json.Json; import jakarta.json.JsonValue; import java.net.URI; +import java.util.Objects; +import org.hamcrest.Description; import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; import org.junit.jupiter.api.Test; -class VocabularyKeywordTypeTest { +class VocabularyKeywordTest { @Test void should_created_keyword_should_know_his_name() { @@ -60,8 +64,8 @@ void should_create_definitions() { .definitions() .toList(), containsInAnyOrder( - new VocabularyDefinition(URI.create("https://json-schema.org/draft/2020-12/vocab/core"), true), - new VocabularyDefinition(URI.create("http://openapi.org/test"), false) + new VocabularyDefinitionMatcher(URI.create("https://json-schema.org/draft/2020-12/vocab/core"), true), + new VocabularyDefinitionMatcher(URI.create("http://openapi.org/test"), false) ) ); } @@ -84,4 +88,34 @@ void should_be_printable() { ) ); } + + private static class VocabularyDefinitionMatcher extends TypeSafeMatcher { + + private final URI id; + private final Matcher required; + + public VocabularyDefinitionMatcher(final URI id) { + this(id, null); + } + + public VocabularyDefinitionMatcher(final URI id, final Boolean required) { + super(VocabularyDefinition.class); + this.id = Objects.requireNonNull(id); + this.required = required == null ? either(is(true)).or(is(false)) : is(required); + } + + @Override + protected boolean matchesSafely(final VocabularyDefinition item) { + return item.hasid(id) && required.matches(item.isRequired()); + } + + @Override + public void describeTo(final Description description) { + description + .appendText("Vocabulary definition with id: ") + .appendValue(id) + .appendText(" and required: ") + .appendDescriptionOf(required); + } + } } diff --git a/vocabulary-spi/pom.xml b/vocabulary-spi/pom.xml index 47ff506f..e36b01b3 100644 --- a/vocabulary-spi/pom.xml +++ b/vocabulary-spi/pom.xml @@ -42,6 +42,11 @@ hamcrest-optional test + + nl.jqno.equalsverifier + equalsverifier + test + jakarta.json diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinition.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinition.java new file mode 100644 index 00000000..de1a4e2a --- /dev/null +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinition.java @@ -0,0 +1,102 @@ +/* + * The MIT License + * + * Copyright 2024 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.vocabulary.spi; + +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import java.net.URI; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public final class LazyVocabularyDefinition implements VocabularyDefinition { + + private final URI id; + private final boolean required; + private final Supplier> lazyVocabularies; + + public LazyVocabularyDefinition( + final URI id, + final boolean required, + final Supplier> lazyVocabularies + ) { + this.id = Objects.requireNonNull(id); + this.required = required; + this.lazyVocabularies = Objects.requireNonNull(lazyVocabularies); + } + + @Override + public Optional findVocabulary() { + final Optional result = lazyVocabularies + .get() + .map(loader -> loader.loadVocabularyWithId(id)) + .flatMap(Optional::stream) + .findFirst(); + if (result.isEmpty() && isRequired()) { + throw new IllegalStateException("can not find required vocabulary: " + id); + } + return result; + } + + @Override + public boolean hasid(final URI id) { + return Objects.equals(this.id, id); + } + + @Override + public boolean isRequired() { + return required; + } + + @Override + public String toString() { + return "LazyVocabularyDefinition{" + "id=" + id + ", required=" + required + '}'; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 59 * hash + Objects.hashCode(this.id); + hash = 59 * hash + (this.required ? 1 : 0); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final LazyVocabularyDefinition other = (LazyVocabularyDefinition) obj; + if (this.required != other.required) { + return false; + } + return Objects.equals(this.id, other.id); + } +} diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabulary.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabulary.java similarity index 89% rename from vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabulary.java rename to vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabulary.java index 2d551ff6..4228a577 100644 --- a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabulary.java +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabulary.java @@ -32,16 +32,16 @@ import java.util.Objects; import java.util.Optional; -public final class DefaultVocabulary implements Vocabulary { +public final class ListVocabulary implements Vocabulary { private final URI id; private final List keywords; - public DefaultVocabulary(final URI id, final KeywordType... keywortds) { + public ListVocabulary(final URI id, final KeywordType... keywortds) { this(id, Arrays.asList(keywortds)); } - public DefaultVocabulary(final URI id, final Collection keywords) { + public ListVocabulary(final URI id, final Collection keywords) { this.id = Objects.requireNonNull(id); this.keywords = List.copyOf(keywords); } diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ServiceLoaderLazyVocabulariesSupplier.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ServiceLoaderLazyVocabulariesSupplier.java new file mode 100644 index 00000000..93774c89 --- /dev/null +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ServiceLoaderLazyVocabulariesSupplier.java @@ -0,0 +1,36 @@ +/* + * The MIT License + * + * Copyright 2024 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.vocabulary.spi; + +import java.util.ServiceLoader; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public final class ServiceLoaderLazyVocabulariesSupplier implements Supplier> { + + @Override + public Stream get() { + return ServiceLoader.load(LazyVocabularies.class).stream().map(ServiceLoader.Provider::get); + } +} diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java index a14c7d61..d53c3574 100644 --- a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java @@ -26,19 +26,11 @@ import io.github.sebastiantoepfer.jsonschema.Vocabulary; import java.net.URI; import java.util.Optional; -import java.util.ServiceLoader; -public record VocabularyDefinition(URI id, boolean required) { - public Optional findVocabulary() { - final Optional result = ServiceLoader.load(LazyVocabularies.class) - .stream() - .map(ServiceLoader.Provider::get) - .map(loader -> loader.loadVocabularyWithId(id)) - .flatMap(Optional::stream) - .findFirst(); - if (result.isEmpty() && required) { - throw new IllegalStateException("can not find required vocabulary: " + id); - } - return result; - } +public interface VocabularyDefinition { + Optional findVocabulary(); + + boolean hasid(URI id); + + boolean isRequired(); } diff --git a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitionTest.java b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinitionTest.java similarity index 60% rename from vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitionTest.java rename to vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinitionTest.java index dd582c88..72d6ab4d 100644 --- a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitionTest.java +++ b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinitionTest.java @@ -26,24 +26,41 @@ import static com.github.npathai.hamcrestopt.OptionalMatchers.isEmpty; import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAndIs; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertThrows; import io.github.sebastiantoepfer.jsonschema.Vocabulary; import java.net.URI; +import java.util.stream.Stream; +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; import org.junit.jupiter.api.Test; -class VocabularyDefinitionTest { +class LazyVocabularyDefinitionTest { + + @Test + void verifyEqualsContract() { + EqualsVerifier.forClass(LazyVocabularyDefinition.class).suppress(Warning.ALL_FIELDS_SHOULD_BE_USED).verify(); + } @Test void should_throw_illegal_state_if_a_required_vocabulary_can_not_be_loaded() { - final VocabularyDefinition vocabDef = new VocabularyDefinition(URI.create("https://invalid"), true); + final VocabularyDefinition vocabDef = new LazyVocabularyDefinition( + URI.create("https://invalid"), + true, + () -> Stream.empty() + ); assertThrows(IllegalStateException.class, () -> vocabDef.findVocabulary()); } @Test void should_find_mandatory_core_vocabulary() { assertThat( - new VocabularyDefinition(URI.create("https://json-schema.org/draft/2020-12/vocab/core"), true) + new LazyVocabularyDefinition( + URI.create("https://json-schema.org/draft/2020-12/vocab/core"), + true, + new ServiceLoaderLazyVocabulariesSupplier() + ) .findVocabulary() .map(Vocabulary::id), isPresentAndIs(URI.create("https://json-schema.org/draft/2020-12/vocab/core")) @@ -53,8 +70,22 @@ void should_find_mandatory_core_vocabulary() { @Test void should_retrun_empty_for_optional_vocabulary_which_can_not_be_loaded() { assertThat( - new VocabularyDefinition(URI.create("https://invalid"), false).findVocabulary().map(Vocabulary::id), + new LazyVocabularyDefinition(URI.create("https://invalid"), false, () -> Stream.empty()) + .findVocabulary() + .map(Vocabulary::id), isEmpty() ); } + + @Test + void should_know_this_id() { + final LazyVocabularyDefinition vocbDef = new LazyVocabularyDefinition( + URI.create("https://json-schema.org/draft/2020-12/vocab/core"), + false, + () -> Stream.empty() + ); + + assertThat(vocbDef.hasid(URI.create("https://json-schema.org/draft/2020-12/vocab/core")), is(true)); + assertThat(vocbDef.hasid(URI.create("https://invalid")), is(false)); + } } diff --git a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabularyTest.java b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabularyTest.java similarity index 86% rename from vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabularyTest.java rename to vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabularyTest.java index bcc681e4..96f08877 100644 --- a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabularyTest.java +++ b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabularyTest.java @@ -34,12 +34,12 @@ import java.net.URI; import org.junit.jupiter.api.Test; -class DefaultVocabularyTest { +class ListVocabularyTest { @Test void should_return_the_id() { assertThat( - new DefaultVocabulary(URI.create("http::/localhots/vocab")).id(), + new ListVocabulary(URI.create("http::/localhots/vocab")).id(), is(URI.create("http::/localhots/vocab")) ); } @@ -47,10 +47,9 @@ void should_return_the_id() { @Test void should_return_empty_if_requested_keyword_is_unknown() { assertThat( - new DefaultVocabulary( - URI.create("http://localhost"), - new SimpleTestKeywordType("name") - ).findKeywordTypeByName("test"), + new ListVocabulary(URI.create("http://localhost"), new SimpleTestKeywordType("name")).findKeywordTypeByName( + "test" + ), isEmpty() ); } @@ -59,7 +58,7 @@ void should_return_empty_if_requested_keyword_is_unknown() { void should_return_requested_keyword_if_is_it_known() { final KeywordType testKeywordType = new SimpleTestKeywordType("test"); assertThat( - new DefaultVocabulary(URI.create("http://localhost"), testKeywordType).findKeywordTypeByName("test"), + new ListVocabulary(URI.create("http://localhost"), testKeywordType).findKeywordTypeByName("test"), isPresentAndIs(testKeywordType) ); } From 2d5313609368b26ea1b15e2065a64f7bf9b3dc35 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:36:13 +0200 Subject: [PATCH 6/8] do not longer lazyload officalvocabs --- .../core/vocab/core/VocabularyKeyword.java | 62 +++++++++++---- .../vocab/core/VocabularyKeywordType.java | 9 ++- .../vocab/core/VocabularyKeywordTest.java | 75 ++++++++++++++++++- 3 files changed, 127 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java index a2e62341..1bff8b10 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java @@ -25,8 +25,10 @@ import io.github.sebastiantoepfer.ddd.common.Media; import io.github.sebastiantoepfer.ddd.media.json.JsonObjectPrintable; +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import io.github.sebastiantoepfer.jsonschema.core.vocab.OfficialVocabularies; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularyDefinition; -import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ServiceLoaderLazyVocabulariesSupplier; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions; import jakarta.json.JsonObject; @@ -34,7 +36,10 @@ import java.net.URI; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; import java.util.stream.Stream; /** @@ -53,13 +58,18 @@ final class VocabularyKeyword implements VocabularyDefinitions { static final String NAME = "$vocabulary"; private final JsonObject vocabularies; + private final Supplier> lazyVocabulariesSupplier; - VocabularyKeyword(final JsonValue vocabularies) { - this(vocabularies.asJsonObject()); + VocabularyKeyword(final JsonValue vocabularies, final Supplier> lazyVocabulariesSupplier) { + this(vocabularies.asJsonObject(), lazyVocabulariesSupplier); } - VocabularyKeyword(final JsonObject vocabularies) { + VocabularyKeyword( + final JsonObject vocabularies, + final Supplier> lazyVocabulariesSupplier + ) { this.vocabularies = Objects.requireNonNull(vocabularies); + this.lazyVocabulariesSupplier = Objects.requireNonNull(lazyVocabulariesSupplier); } @Override @@ -80,16 +90,38 @@ public Collection categories() { @Override public Stream definitions() { - return vocabularies - .entrySet() - .stream() - .map( - entry -> - new LazyVocabularyDefinition( - URI.create(entry.getKey()), - entry.getValue() == JsonValue.TRUE, - new ServiceLoaderLazyVocabulariesSupplier() - ) - ); + return vocabularies.entrySet().stream().map(LazyNonOfficalVocabularyDefinition::new); + } + + private final class LazyNonOfficalVocabularyDefinition implements VocabularyDefinition { + + private final URI id; + private final JsonValue required; + + public LazyNonOfficalVocabularyDefinition(final Map.Entry property) { + this(URI.create(property.getKey()), property.getValue()); + } + + public LazyNonOfficalVocabularyDefinition(final URI id, final JsonValue required) { + this.id = Objects.requireNonNull(id); + this.required = required; + } + + @Override + public Optional findVocabulary() { + return new OfficialVocabularies() + .loadVocabularyWithId(id) + .or(() -> new LazyVocabularyDefinition(id, isRequired(), lazyVocabulariesSupplier).findVocabulary()); + } + + @Override + public boolean hasid(final URI id) { + return Objects.equals(this.id, id); + } + + @Override + public boolean isRequired() { + return JsonValue.TRUE.equals(required); + } } } diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java index e099babb..78cff548 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java @@ -26,6 +26,7 @@ import io.github.sebastiantoepfer.jsonschema.InstanceType; import io.github.sebastiantoepfer.jsonschema.JsonSchema; import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ServiceLoaderLazyVocabulariesSupplier; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions; import jakarta.json.JsonValue; @@ -34,6 +35,12 @@ */ public final class VocabularyKeywordType implements KeywordType { + private final ServiceLoaderLazyVocabulariesSupplier lazyVocabulariesSupplier; + + public VocabularyKeywordType() { + this.lazyVocabulariesSupplier = new ServiceLoaderLazyVocabulariesSupplier(); + } + @Override public String name() { return VocabularyKeyword.NAME; @@ -44,7 +51,7 @@ public VocabularyDefinitions createKeyword(final JsonSchema schema) { final JsonValue value = schema.asJsonObject().get((name())); final VocabularyKeyword result; if (InstanceType.OBJECT.isInstance(value)) { - result = new VocabularyKeyword(value); + result = new VocabularyKeyword(value, lazyVocabulariesSupplier); } else { throw new IllegalArgumentException( "must be an object! " + diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java index c12e2907..e0356c83 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java @@ -31,12 +31,18 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; +import io.github.sebastiantoepfer.jsonschema.Vocabulary; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary; import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; import jakarta.json.Json; import jakarta.json.JsonValue; import java.net.URI; +import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; @@ -46,7 +52,7 @@ class VocabularyKeywordTest { @Test void should_created_keyword_should_know_his_name() { - final Keyword vocabulary = new VocabularyKeyword(JsonValue.EMPTY_JSON_OBJECT); + final Keyword vocabulary = new VocabularyKeyword(JsonValue.EMPTY_JSON_OBJECT, Stream::empty); assertThat(vocabulary.hasName("$vocabulary"), is(true)); assertThat(vocabulary.hasName("$id"), is(false)); @@ -59,7 +65,8 @@ void should_create_definitions() { Json.createObjectBuilder() .add("https://json-schema.org/draft/2020-12/vocab/core", true) .add("http://openapi.org/test", false) - .build() + .build(), + Stream::empty ) .definitions() .toList(), @@ -77,7 +84,8 @@ void should_be_printable() { Json.createObjectBuilder() .add("https://json-schema.org/draft/2020-12/vocab/core", true) .add("http://openapi.org/test", false) - .build() + .build(), + Stream::empty ).printOn(new HashMapMedia()), (Matcher) hasEntry( is("$vocabulary"), @@ -89,6 +97,67 @@ void should_be_printable() { ); } + @Test + void should_not_lazy_load_offical_vocabs() { + //security and peformance. it should not be possible to override keywords define by this module! + assertThat( + new VocabularyKeyword( + Json.createObjectBuilder().add("https://json-schema.org/draft/2020-12/vocab/core", true).build(), + Stream::empty + ) + .definitions() + .map(VocabularyDefinition::findVocabulary) + .flatMap(Optional::stream) + .map(Vocabulary::id) + .toList(), + containsInAnyOrder(URI.create("https://json-schema.org/draft/2020-12/vocab/core")) + ); + } + + @Test + void should_provide_vocab_which_know_they_id() { + final VocabularyDefinition vocabDef = new VocabularyKeyword( + Json.createObjectBuilder().add("https://json-schema.org/draft/2020-12/vocab/core", true).build(), + Stream::empty + ) + .definitions() + .findFirst() + .orElseThrow(); + + assertThat(vocabDef.hasid(URI.create("https://json-schema.org/draft/2020-12/vocab/core")), is(true)); + assertThat(vocabDef.hasid(URI.create("http://openapi.org/test")), is(false)); + } + + @Test + void should_lazy_load_non_offical_vocabs() { + assertThat( + new VocabularyKeyword( + Json.createObjectBuilder() + .add("https://json-schema.org/draft/2020-12/vocab/core", true) + .add("http://openapi.org/test", false) + .build(), + () -> + Stream.of( + new LazyVocabularies() { + @Override + public Optional loadVocabularyWithId(final URI id) { + return Optional.of(new ListVocabulary(id, List.of())); + } + } + ) + ) + .definitions() + .map(VocabularyDefinition::findVocabulary) + .flatMap(Optional::stream) + .map(Vocabulary::id) + .toList(), + containsInAnyOrder( + URI.create("https://json-schema.org/draft/2020-12/vocab/core"), + URI.create("http://openapi.org/test") + ) + ); + } + private static class VocabularyDefinitionMatcher extends TypeSafeMatcher { private final URI id; From 113096b7f3cd87e44c20acb5d4fcbb53edac6aaf Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Sun, 9 Jun 2024 15:35:15 +0200 Subject: [PATCH 7/8] improve refkeyword to improve test with remote schema --- .../core/vocab/core/RefKeyword.java | 21 ++++--- .../core/vocab/core/RefKeywordType.java | 4 +- .../core/vocab/core/SchemaRegistry.java | 60 +++++++++++++++++++ .../core/vocab/core/RefKeywordTest.java | 43 +++++++++---- .../core/vocab/core/SchemaRegistryTest.java | 42 +++++++++++++ 5 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistry.java create mode 100644 core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistryTest.java diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java index c337f5f4..de709526 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java @@ -29,7 +29,6 @@ import io.github.sebastiantoepfer.jsonschema.keyword.Applicator; import jakarta.json.Json; import jakarta.json.JsonPointer; -import jakarta.json.JsonReader; import jakarta.json.JsonStructure; import jakarta.json.JsonValue; import java.io.IOException; @@ -52,10 +51,12 @@ final class RefKeyword implements Applicator { static final String NAME = "$ref"; private final JsonSchema schema; private final URI uri; + private final SchemaRegistry schemaRegistry; - public RefKeyword(final JsonSchema schema, final URI uri) { + public RefKeyword(final JsonSchema schema, final URI uri, final SchemaRegistry schemaRegistry) { this.schema = Objects.requireNonNull(schema); this.uri = Objects.requireNonNull(uri); + this.schemaRegistry = Objects.requireNonNull(schemaRegistry); } @Override @@ -74,12 +75,12 @@ public boolean hasName(final String name) { } private JsonSchema retrieveJsonSchema() { - final JsonValue json; + final JsonSchema json; try { if (isRemote()) { - json = retrieveValueFromRemoteLocation(); + json = retrieveSchemaFromRegistry(); } else { - json = retrieveValueFromLocalSchema(); + json = retrieveSchemaFromLocalSchema(); } return JsonSchemas.load(json); } catch (IOException ex) { @@ -87,10 +88,10 @@ private JsonSchema retrieveJsonSchema() { } } - private JsonValue retrieveValueFromLocalSchema() throws IOException { + private JsonSchema retrieveSchemaFromLocalSchema() throws IOException { final JsonPointer pointer = createPointer(); if (pointer.containsValue(searchAnchor())) { - return pointer.getValue(searchAnchor()); + return JsonSchemas.load(pointer.getValue(searchAnchor())); } else { throw new IOException("can not find referenced value."); } @@ -111,10 +112,8 @@ private JsonPointer createPointer() { return pointer; } - private JsonValue retrieveValueFromRemoteLocation() throws IOException { - try (final JsonReader reader = Json.createReader(uri.toURL().openStream())) { - return reader.readValue(); - } + private JsonSchema retrieveSchemaFromRegistry() throws IOException { + return schemaRegistry.schemaForUrl(uri); } private boolean isRemote() { diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java index dcff9353..93dd6b77 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java @@ -34,9 +34,11 @@ final class RefKeywordType implements KeywordType { private final JsonProvider jsonContext; + private final SchemaRegistry schemaRegistry; public RefKeywordType(final JsonProvider jsonContext) { this.jsonContext = Objects.requireNonNull(jsonContext); + this.schemaRegistry = new SchemaRegistry.RemoteSchemaRegistry(); } @Override @@ -49,7 +51,7 @@ public Keyword createKeyword(final JsonSchema schema) { return new StringKeywordType( jsonContext, RefKeyword.NAME, - s -> new RefKeyword(schema, URI.create(s)) + s -> new RefKeyword(schema, URI.create(s), schemaRegistry) ).createKeyword(schema); } } diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistry.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistry.java new file mode 100644 index 00000000..1fb4ffe9 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistry.java @@ -0,0 +1,60 @@ +/* + * The MIT License + * + * Copyright 2024 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.core; + +import io.github.sebastiantoepfer.jsonschema.JsonSchema; +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; +import jakarta.json.Json; +import jakarta.json.JsonReader; +import jakarta.json.JsonValue; +import java.io.IOException; +import java.net.URI; + +interface SchemaRegistry { + JsonSchema schemaForUrl(URI uri) throws IOException; + + class DefaultSchemaRegistry implements SchemaRegistry { + + private JsonSchema schema; + + public DefaultSchemaRegistry() { + schema = JsonSchemas.load(JsonValue.FALSE); + } + + @Override + public JsonSchema schemaForUrl(final URI uri) throws IOException { + return schema; + } + } + + class RemoteSchemaRegistry implements SchemaRegistry { + + @Override + public JsonSchema schemaForUrl(final URI uri) throws IOException { + try (JsonReader reader = Json.createReader(uri.toURL().openStream())) { + return JsonSchemas.load(reader.readValue()); + } + } + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java index a1b5be96..0a1e9baf 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java @@ -28,9 +28,11 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; import io.github.sebastiantoepfer.jsonschema.JsonSchemas; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; +import java.io.IOException; import java.net.URI; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -41,7 +43,8 @@ class RefKeywordTest { void should_know_his_name() { final Keyword ref = new RefKeyword( JsonSchemas.load(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()), - URI.create("#") + URI.create("#"), + new SchemaRegistry.DefaultSchemaRegistry() ); assertThat(ref.hasName("$ref"), is(true)); assertThat(ref.hasName("test"), is(false)); @@ -60,7 +63,8 @@ void should_use_local_referenced_schema_for_validation() { .add("$ref", Json.createValue("#/$defs/positiveInteger")) .build() ), - URI.create("#/$defs/positiveInteger") + URI.create("#/$defs/positiveInteger"), + new SchemaRegistry.DefaultSchemaRegistry() ); assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true)); @@ -71,19 +75,31 @@ void should_use_local_referenced_schema_for_validation() { void should_use_remote_referenced_schema_for_validation() { final Keyword keyword = new RefKeyword( JsonSchemas.load( - Json.createObjectBuilder() - .add( - "$defs", - Json.createObjectBuilder() - .add("positiveInteger", Json.createObjectBuilder().add("type", "integer")) - ) - .add("$ref", Json.createValue("#/$defs/positiveInteger")) - .build() + Json.createObjectBuilder().add("$ref", Json.createValue("https://schema.org/byMonth")).build() ), - URI.create("#/$defs/positiveInteger") + URI.create("https://schema.org/byMonth"), + new SchemaRegistry() { + @Override + public JsonSchema schemaForUrl(final URI uri) throws IOException { + if (uri.equals(URI.create("https://schema.org/byMonth"))) { + //hen egg issue -> we need more than core :( + return JsonSchemas.load( + Json.createObjectBuilder() + .add("type", "integer") + .add("minimum", 1) + .add("maximum", 12) + .build() + ); + } else { + throw new IOException("can not retrieve remote schema!"); + } + } + } ); assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true)); - assertThat(keyword.asApplicator().applyTo(Json.createValue("invalid")), is(false)); + assertThat(keyword.asApplicator().applyTo(Json.createValue(12L)), is(true)); + assertThat(keyword.asApplicator().applyTo(Json.createValue(0L)), is(false)); + assertThat(keyword.asApplicator().applyTo(Json.createValue(13L)), is(false)); } @Test @@ -91,7 +107,8 @@ void should_be_printable() { assertThat( new RefKeyword( JsonSchemas.load(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()), - URI.create("#") + URI.create("#"), + new SchemaRegistry.DefaultSchemaRegistry() ).printOn(new HashMapMedia()), (Matcher) hasEntry(is("$ref"), is("#")) ); diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistryTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistryTest.java new file mode 100644 index 00000000..9723eec0 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistryTest.java @@ -0,0 +1,42 @@ +/* + * The MIT License + * + * Copyright 2024 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.core; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import jakarta.json.JsonValue; +import java.net.URI; +import org.junit.jupiter.api.Test; + +class SchemaRegistryTest { + + @Test + void should_return_false_schema() throws Exception { + assertThat( + new SchemaRegistry.DefaultSchemaRegistry().schemaForUrl(URI.create("test")).getValueType(), + is(JsonValue.ValueType.FALSE) + ); + } +} From f696547f9e79d0e1104ea9545568d5d56faeb85d Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:17:08 +0200 Subject: [PATCH 8/8] refactor test for all keyword defined in validationvocab --- .../vocab/validation/ConstKeywordTest.java | 42 ++++----- .../DependentRequiredKeywordTest.java | 48 ++--------- .../vocab/validation/EnumKeywordTest.java | 29 ++----- .../ExclusiveMaximumKeywordTest.java | 36 ++------ .../ExclusiveMinimumKeywordTest.java | 36 ++------ .../validation/MaxContainsKeywordTest.java | 86 ++++--------------- .../vocab/validation/MaxItemsKeywordTest.java | 28 ++---- .../validation/MaxLengthKeywordTest.java | 32 ++----- .../validation/MaxPropertiesKeywordTest.java | 26 ++---- .../vocab/validation/MaximumKeywordTest.java | 40 ++------- .../validation/MinContainsKeywordTest.java | 86 ++++--------------- .../vocab/validation/MinItemsKeywordTest.java | 30 ++----- .../validation/MinLengthKeywordTest.java | 34 ++------ .../validation/MinPropertiesKeywordTest.java | 26 ++---- .../vocab/validation/MinimumKeywordTest.java | 43 ++-------- .../validation/MultipleOfKeywordTest.java | 36 ++------ .../vocab/validation/PatternKeywordTest.java | 39 ++------- .../vocab/validation/RequiredKeywordTest.java | 33 ++----- .../validation/UniqueItemsKeywordTest.java | 39 ++------- 19 files changed, 149 insertions(+), 620 deletions(-) diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java index 15edcad9..63d7f2e9 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java @@ -29,11 +29,8 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AnyKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import jakarta.json.spi.JsonProvider; import org.hamcrest.Matcher; @@ -43,9 +40,7 @@ class ConstKeywordTest { @Test void should_know_his_name() { - final Keyword enumKeyword = createKeywordFrom( - Json.createObjectBuilder().add("const", JsonValue.EMPTY_JSON_ARRAY).build() - ); + final Keyword enumKeyword = new ConstKeyword(JsonProvider.provider(), JsonValue.EMPTY_JSON_ARRAY); assertThat(enumKeyword.hasName("const"), is(true)); assertThat(enumKeyword.hasName("test"), is(false)); @@ -54,7 +49,7 @@ void should_know_his_name() { @Test void should_be_valid_for_same_string_value() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue("hello")).build()) + new ConstKeyword(JsonProvider.provider(), Json.createValue("hello")) .asAssertion() .isValidFor(Json.createValue("hello")), is(true) @@ -64,7 +59,7 @@ void should_be_valid_for_same_string_value() { @Test void should_be_invalid_for_different_string_value() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue("hello")).build()) + new ConstKeyword(JsonProvider.provider(), Json.createValue("hello")) .asAssertion() .isValidFor(Json.createValue("world")), is(false) @@ -74,7 +69,7 @@ void should_be_invalid_for_different_string_value() { @Test void should_be_valid_for_same_number_value() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue(3.14159)).build()) + new ConstKeyword(JsonProvider.provider(), Json.createValue(3.14159)) .asAssertion() .isValidFor(Json.createValue(3.14159)), is(true) @@ -84,7 +79,7 @@ void should_be_valid_for_same_number_value() { @Test void should_be_invalid_for_value_with_different_type() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue(3.14159)).build()) + new ConstKeyword(JsonProvider.provider(), Json.createValue(3.14159)) .asAssertion() .isValidFor(Json.createValue("pi")), is(false) @@ -94,10 +89,9 @@ void should_be_invalid_for_value_with_different_type() { @Test void should_be_valid_for_exact_object_structure() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("const", Json.createObjectBuilder().add("name", "John Doe").add("age", 31)) - .build() + new ConstKeyword( + JsonProvider.provider(), + Json.createObjectBuilder().add("name", "John Doe").add("age", 31).build() ) .asAssertion() .isValidFor(Json.createObjectBuilder().add("name", "John Doe").add("age", 31).build()), @@ -108,10 +102,9 @@ void should_be_valid_for_exact_object_structure() { @Test void should_be_invalid_for_not_exact_object_structure() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("const", Json.createObjectBuilder().add("name", "John Doe").add("age", 31)) - .build() + new ConstKeyword( + JsonProvider.provider(), + Json.createObjectBuilder().add("name", "John Doe").add("age", 31).build() ) .asAssertion() .isValidFor(Json.createObjectBuilder().add("name", "Robert").add("age", 31).build()), @@ -122,7 +115,7 @@ void should_be_invalid_for_not_exact_object_structure() { @Test void should_be_valid_for_decimal_without_scale_if_number_is_valid() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("const", 1).build()) + new ConstKeyword(JsonProvider.provider(), Json.createValue(1)) .asAssertion() .isValidFor(Json.createValue(1.0)), is(true) @@ -132,16 +125,11 @@ void should_be_valid_for_decimal_without_scale_if_number_is_valid() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("const", Json.createArrayBuilder().add("TEST").add("VALID")).build() + new ConstKeyword( + JsonProvider.provider(), + Json.createArrayBuilder().add("TEST").add("VALID").build() ).printOn(new HashMapMedia()), (Matcher) hasEntry(is("const"), containsInAnyOrder("TEST", "VALID")) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new AnyKeywordType(JsonProvider.provider(), "const", ConstKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java index 00a0e529..0a361c80 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java @@ -30,8 +30,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.ObjectKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; import jakarta.json.JsonObject; @@ -62,9 +60,7 @@ void should_not_be_createable_with_object_contains_only_non_string_array_propert @Test void should_know_his_name() { - final Keyword enumKeyword = createKeywordFrom( - Json.createObjectBuilder().add("dependentRequired", JsonValue.EMPTY_JSON_OBJECT).build() - ); + final Keyword enumKeyword = new DependentRequiredKeyword(JsonValue.EMPTY_JSON_OBJECT); assertThat(enumKeyword.hasName("dependentRequired"), is(true)); assertThat(enumKeyword.hasName("test"), is(false)); @@ -73,13 +69,8 @@ void should_know_his_name() { @Test void should_be_valid_if_both_properties_available() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "dependentRequired", - Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")) - ) - .build() + new DependentRequiredKeyword( + Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build() ) .asAssertion() .isValidFor( @@ -92,13 +83,8 @@ void should_be_valid_if_both_properties_available() { @Test void should_be_valid_if_required_properties_is_missing() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "dependentRequired", - Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")) - ) - .build() + new DependentRequiredKeyword( + Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build() ) .asAssertion() .isValidFor(Json.createObjectBuilder().add("name", "John").add("license", "XYZ123").build()), @@ -109,13 +95,8 @@ void should_be_valid_if_required_properties_is_missing() { @Test void should_be_valid_if_both_properties_are_missing() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "dependentRequired", - Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")) - ) - .build() + new DependentRequiredKeyword( + Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build() ) .asAssertion() .isValidFor(Json.createObjectBuilder().add("name", "John").build()), @@ -126,21 +107,10 @@ void should_be_valid_if_both_properties_are_missing() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add( - "dependentRequired", - Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")) - ) - .build() + new DependentRequiredKeyword( + Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build() ).printOn(new HashMapMedia()), (Matcher) hasEntry(is("dependentRequired"), hasEntry(is("license"), contains("age"))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new ObjectKeywordType("dependentRequired", DependentRequiredKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java index cb7c6890..440da115 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java @@ -29,11 +29,8 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.ArrayKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -42,9 +39,7 @@ class EnumKeywordTest { @Test void should_know_his_name() { - final Keyword enumKeyword = createKeywordFrom( - Json.createObjectBuilder().add("enum", JsonValue.EMPTY_JSON_ARRAY).build() - ); + final Keyword enumKeyword = new EnumKeyword(JsonValue.EMPTY_JSON_ARRAY); assertThat(enumKeyword.hasName("enum"), is(true)); assertThat(enumKeyword.hasName("test"), is(false)); @@ -53,9 +48,7 @@ void should_know_his_name() { @Test void should_valid_for_string_value_which_is_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add("TEST").add("VALID")).build() - ) + new EnumKeyword(Json.createArrayBuilder().add("TEST").add("VALID").build()) .asAssertion() .isValidFor(Json.createValue("TEST")), is(true) @@ -65,9 +58,7 @@ void should_valid_for_string_value_which_is_in_array() { @Test void should_be_invalid_for_number_which_is_not_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add("TEST").add("VALID")).build() - ) + new EnumKeyword(Json.createArrayBuilder().add("TEST").add("VALID").build()) .asAssertion() .isValidFor(Json.createValue(2)), is(false) @@ -77,9 +68,7 @@ void should_be_invalid_for_number_which_is_not_in_array() { @Test void should_be_valid_for_decimal_without_scale_if_number_is_valid() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add(1)).build()) - .asAssertion() - .isValidFor(Json.createValue(1.0)), + new EnumKeyword(Json.createArrayBuilder().add(1).build()).asAssertion().isValidFor(Json.createValue(1.0)), is(true) ); } @@ -87,16 +76,8 @@ void should_be_valid_for_decimal_without_scale_if_number_is_valid() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add("TEST").add("VALID")).build() - ).printOn(new HashMapMedia()), + new EnumKeyword(Json.createArrayBuilder().add("TEST").add("VALID").build()).printOn(new HashMapMedia()), (Matcher) hasEntry(is("enum"), containsInAnyOrder("TEST", "VALID")) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new ArrayKeywordType("enum", EnumKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java index 9242c0a2..b1b51d47 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigDecimal; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class ExclusiveMaximumKeywordTest { @Test void should_know_his_name() { - final Keyword maximum = createKeywordFrom( - Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(1)).build() - ); + final Keyword maximum = new ExclusiveMaximumKeyword(BigDecimal.valueOf(1)); assertThat(maximum.hasName("exclusiveMaximum"), is(true)); assertThat(maximum.hasName("test"), is(false)); @@ -54,9 +48,7 @@ void should_know_his_name() { @Test void should_be_valid_for_non_number_values() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(1)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), + new ExclusiveMaximumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) ); } @@ -64,9 +56,7 @@ void should_be_valid_for_non_number_values() { @Test void should_be_invalid_for_greater_numbers() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build()) - .asAssertion() - .isValidFor(Json.createValue(11)), + new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(11)), is(false) ); } @@ -74,9 +64,7 @@ void should_be_invalid_for_greater_numbers() { @Test void should_be_invalid_for_equals_numbers() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build()) - .asAssertion() - .isValidFor(Json.createValue(10)), + new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(10)), is(false) ); } @@ -84,9 +72,7 @@ void should_be_invalid_for_equals_numbers() { @Test void shhould_be_valid_for_smaller_numbers() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build()) - .asAssertion() - .isValidFor(Json.createValue(9)), + new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(9)), is(true) ); } @@ -94,18 +80,8 @@ void shhould_be_valid_for_smaller_numbers() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build()).printOn( - new HashMapMedia() - ), + new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("exclusiveMaximum"), is(BigDecimal.valueOf(10))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NumberKeywordType( - JsonProvider.provider(), - "exclusiveMaximum", - ExclusiveMaximumKeyword::new - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java index c6ca0db8..d19d4185 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigDecimal; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class ExclusiveMinimumKeywordTest { @Test void should_know_his_name() { - final Keyword minimum = createKeywordFrom( - Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(1)).build() - ); + final Keyword minimum = new ExclusiveMinimumKeyword(BigDecimal.valueOf(1)); assertThat(minimum.hasName("exclusiveMinimum"), is(true)); assertThat(minimum.hasName("test"), is(false)); @@ -54,9 +48,7 @@ void should_know_his_name() { @Test void should_be_valid_for_non_number_values() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(1)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), + new ExclusiveMinimumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) ); } @@ -64,9 +56,7 @@ void should_be_valid_for_non_number_values() { @Test void should_be_invalid_for_smaller_numbers() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build()) - .asAssertion() - .isValidFor(Json.createValue(-1)), + new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(-1)), is(false) ); } @@ -74,9 +64,7 @@ void should_be_invalid_for_smaller_numbers() { @Test void should_be_invalid_for_equals_numbers() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build()) - .asAssertion() - .isValidFor(Json.createValue(0)), + new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(0)), is(false) ); } @@ -84,9 +72,7 @@ void should_be_invalid_for_equals_numbers() { @Test void shhould_be_valid_for_greater_numbers() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build()) - .asAssertion() - .isValidFor(Json.createValue(1)), + new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(1)), is(true) ); } @@ -94,18 +80,8 @@ void shhould_be_valid_for_greater_numbers() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build()).printOn( - new HashMapMedia() - ), + new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("exclusiveMinimum"), is(BigDecimal.valueOf(0))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NumberKeywordType( - JsonProvider.provider(), - "exclusiveMinimum", - ExclusiveMinimumKeyword::new - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java index bff8d9b2..4b1c889b 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java @@ -28,16 +28,10 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import java.util.List; import org.hamcrest.Matcher; @@ -47,10 +41,7 @@ class MaxContainsKeywordTest { @Test void should_know_his_name() { - final Keyword enumKeyword = new MaxContainsKeyword( - List.of(new StaticAnnotation("", JsonValue.NULL)), - BigInteger.ONE - ); + final Keyword enumKeyword = new MaxContainsKeyword(List.of(), BigInteger.ONE); assertThat(enumKeyword.hasName("maxContains"), is(true)); assertThat(enumKeyword.hasName("test"), is(false)); } @@ -58,7 +49,7 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxContains", 2).build()).printOn(new HashMapMedia()), + new MaxContainsKeyword(List.of(), BigInteger.valueOf(2)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("maxContains"), is(BigInteger.valueOf(2))) ); } @@ -66,12 +57,7 @@ void should_be_printable() { @Test void should_be_valid_for_non_arrays() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() - ) + new MaxContainsKeyword(List.of(), BigInteger.valueOf(2)) .asAssertion() .isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) @@ -81,11 +67,9 @@ void should_be_valid_for_non_arrays() { @Test void should_be_valid_if_contains_applies_to_exact_count() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() + new MaxContainsKeyword( + List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(1).build())), + BigInteger.valueOf(2) ) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add("bar").add(1).build()), @@ -96,11 +80,9 @@ void should_be_valid_if_contains_applies_to_exact_count() { @Test void should_be_valid_if_contains_applies_to_less_items() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() + new MaxContainsKeyword( + List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).build())), + BigInteger.valueOf(2) ) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add(2).add(3).build()), @@ -111,11 +93,9 @@ void should_be_valid_if_contains_applies_to_less_items() { @Test void should_be_valid_for_empty_arrays() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() + new MaxContainsKeyword( + List.of(new StaticAnnotation("contains", JsonValue.EMPTY_JSON_ARRAY)), + BigInteger.valueOf(2) ) .asAssertion() .isValidFor(JsonValue.EMPTY_JSON_ARRAY), @@ -126,11 +106,9 @@ void should_be_valid_for_empty_arrays() { @Test void should_be_invalid_if_contains_applies_to_more_items() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() + new MaxContainsKeyword( + List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(1).add(3).build())), + BigInteger.valueOf(2) ) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add("bar").add(1).add("baz").build()), @@ -141,12 +119,7 @@ void should_be_invalid_if_contains_applies_to_more_items() { @Test void should_be_valid_if_contains_applies_to_all_and_less_items_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() - ) + new MaxContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").build()), is(true) @@ -156,12 +129,7 @@ void should_be_valid_if_contains_applies_to_all_and_less_items_in_array() { @Test void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() - ) + new MaxContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add("bar").build()), is(true) @@ -171,28 +139,10 @@ void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array() @Test void should_be_invalid_if_contains_applies_to_all_and_more_items_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("maxContains", 2) - .build() - ) + new MaxContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new AffectsKeywordType( - "maxContains", - List.of(new Affects("contains", new Affects.ReplaceKeyword())), - (a, s) -> - new IntegerKeywordType( - JsonProvider.provider(), - "maxContains", - value -> new MaxContainsKeyword(a, value) - ).createKeyword(s) - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java index 182a3360..de931481 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class MaxItemsKeywordTest { @Test void should_know_his_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("maxItems", Json.createValue(1)).build() - ); + final Keyword keyword = new MaxItemsKeyword(BigInteger.valueOf(1)); assertThat(keyword.hasName("maxItems"), is(true)); assertThat(keyword.hasName("test"), is(false)); @@ -54,9 +48,7 @@ void should_know_his_name() { @Test void should_be_valid_for_non_arrays() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), + new MaxItemsKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) ); } @@ -64,7 +56,7 @@ void should_be_valid_for_non_arrays() { @Test void should_be_valid_for_array_with_same_size() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build()) + new MaxItemsKeyword(BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add(1).add(2).build()), is(true) @@ -74,7 +66,7 @@ void should_be_valid_for_array_with_same_size() { @Test void should_be_valid_for_array_with_smaller_size() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build()) + new MaxItemsKeyword(BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add(1).build()), is(true) @@ -84,7 +76,7 @@ void should_be_valid_for_array_with_smaller_size() { @Test void should_be_invalid_for_array_with_greather_size() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build()) + new MaxItemsKeyword(BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add(1).add(2).add(3).build()), is(false) @@ -94,16 +86,8 @@ void should_be_invalid_for_array_with_greather_size() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build()).printOn( - new HashMapMedia() - ), + new MaxItemsKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("maxItems"), is(BigInteger.valueOf(2))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new IntegerKeywordType(JsonProvider.provider(), "maxItems", MaxItemsKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java index 886a2ef8..b995e9bb 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,7 +39,7 @@ class MaxLengthKeywordTest { @Test void should_know_his_name() { - final Keyword keyword = createKeywordFrom(Json.createObjectBuilder().add("maxLength", 1).build()); + final Keyword keyword = new MaxLengthKeyword(BigInteger.valueOf(1)); assertThat(keyword.hasName("test"), is(false)); assertThat(keyword.hasName("maxLength"), is(true)); @@ -52,9 +48,7 @@ void should_know_his_name() { @Test void should_be_valid_for_non_string_values() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_ARRAY), + new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY), is(true) ); } @@ -62,9 +56,7 @@ void should_be_valid_for_non_string_values() { @Test void should_be_invalid_for_longer_string() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(Json.createValue("1234")), + new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("1234")), is(false) ); } @@ -72,9 +64,7 @@ void should_be_invalid_for_longer_string() { @Test void should_be_valid_for_string_with_length_is_equal() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(Json.createValue("12")), + new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("12")), is(true) ); } @@ -82,9 +72,7 @@ void should_be_valid_for_string_with_length_is_equal() { @Test void should_ne_valid_for_string_with_is_shorter() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(Json.createValue("1")), + new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("1")), is(true) ); } @@ -92,16 +80,8 @@ void should_ne_valid_for_string_with_is_shorter() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build()).printOn( - new HashMapMedia() - ), + new MaxLengthKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("maxLength"), is(BigInteger.valueOf(2L))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new IntegerKeywordType(JsonProvider.provider(), "maxLength", MaxLengthKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java index b82c2400..aad33a35 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,7 +39,7 @@ class MaxPropertiesKeywordTest { @Test void should_know_his_name() { - final Keyword enumKeyword = createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build()); + final Keyword enumKeyword = new MaxPropertiesKeyword(BigInteger.valueOf(2)); assertThat(enumKeyword.hasName("maxProperties"), is(true)); assertThat(enumKeyword.hasName("test"), is(false)); @@ -52,7 +48,7 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build()).printOn(new HashMapMedia()), + new MaxPropertiesKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("maxProperties"), is(BigInteger.valueOf(2))) ); } @@ -60,9 +56,7 @@ void should_be_printable() { @Test void should_be_valid_for_non_objects() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_ARRAY), + new MaxPropertiesKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY), is(true) ); } @@ -70,7 +64,7 @@ void should_be_valid_for_non_objects() { @Test void should_be_valid_for_less_properties() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build()) + new MaxPropertiesKeyword(BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", 3).build()), is(true) @@ -80,7 +74,7 @@ void should_be_valid_for_less_properties() { @Test void should_be_valid_exact_properties_count() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build()) + new MaxPropertiesKeyword(BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", 3).add("bar", "hi").build()), is(true) @@ -90,18 +84,10 @@ void should_be_valid_exact_properties_count() { @Test void should_be_invalid_for_more_properties() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build()) + new MaxPropertiesKeyword(BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", 3).add("bar", "hi").add("baz", true).build()), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new IntegerKeywordType( - JsonProvider.provider(), - "maxProperties", - MaxPropertiesKeyword::new - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java index 10bbd699..9e57fc3f 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigDecimal; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class MaximumKeywordTest { @Test void should_know_his_name() { - final Keyword maximum = createKeywordFrom( - Json.createObjectBuilder().add("maximum", Json.createValue(1)).build() - ); + final Keyword maximum = new MaximumKeyword(BigDecimal.valueOf(1)); assertThat(maximum.hasName("maximum"), is(true)); assertThat(maximum.hasName("test"), is(false)); @@ -54,9 +48,7 @@ void should_know_his_name() { @Test void should_be_valid_for_non_number_values() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(1)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), + new MaximumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) ); } @@ -64,46 +56,26 @@ void should_be_valid_for_non_number_values() { @Test void should_be_invalid_for_greater_numbers() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build()) - .asAssertion() - .isValidFor(Json.createValue(11)), + new MaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(11)), is(false) ); } @Test void should_be_valid_for_equals_numbers() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build()) - .asAssertion() - .isValidFor(Json.createValue(10)), - is(true) - ); + assertThat(new MaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(10)), is(true)); } @Test void shhould_be_valid_for_smaller_numbers() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build()) - .asAssertion() - .isValidFor(Json.createValue(9)), - is(true) - ); + assertThat(new MaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(9)), is(true)); } @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build()).printOn( - new HashMapMedia() - ), + new MaximumKeyword(BigDecimal.valueOf(10)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("maximum"), is(BigDecimal.valueOf(10))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NumberKeywordType(JsonProvider.provider(), "maximum", MaximumKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java index 645feeb1..aaf6f2e0 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java @@ -28,16 +28,10 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import java.util.List; import org.hamcrest.Matcher; @@ -47,10 +41,7 @@ class MinContainsKeywordTest { @Test void should_know_his_name() { - final Keyword enumKeyword = new MinContainsKeyword( - List.of(new StaticAnnotation("", JsonValue.NULL)), - BigInteger.ONE - ); + final Keyword enumKeyword = new MinContainsKeyword(List.of(), BigInteger.ONE); assertThat(enumKeyword.hasName("minContains"), is(true)); assertThat(enumKeyword.hasName("test"), is(false)); @@ -59,7 +50,7 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minContains", 2).build()).printOn(new HashMapMedia()), + new MinContainsKeyword(List.of(), BigInteger.valueOf(2)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("minContains"), is(BigInteger.valueOf(2))) ); } @@ -67,12 +58,7 @@ void should_be_printable() { @Test void should_be_valid_for_non_arrays() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("minContains", 2) - .build() - ) + new MinContainsKeyword(List.of(), BigInteger.valueOf(2)) .asAssertion() .isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) @@ -82,11 +68,9 @@ void should_be_valid_for_non_arrays() { @Test void should_be_valid_if_contains_applies_to_exact_count() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("minContains", 2) - .build() + new MinContainsKeyword( + List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(1).build())), + BigInteger.valueOf(2) ) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add("bar").add(1).build()), @@ -97,11 +81,9 @@ void should_be_valid_if_contains_applies_to_exact_count() { @Test void should_be_valid_if_contains_applies_to_more_items() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("minContains", 2) - .build() + new MinContainsKeyword( + List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(3).add(4).build())), + BigInteger.valueOf(2) ) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add(2).add(3).add("bar").add("baz").build()), @@ -112,11 +94,9 @@ void should_be_valid_if_contains_applies_to_more_items() { @Test void should_be_valid_for_empty_arrays() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("const", 1)) - .add("minContains", 0) - .build() + new MinContainsKeyword( + List.of(new StaticAnnotation("contains", Json.createArrayBuilder().build())), + BigInteger.valueOf(0) ) .asAssertion() .isValidFor(JsonValue.EMPTY_JSON_ARRAY), @@ -127,11 +107,9 @@ void should_be_valid_for_empty_arrays() { @Test void should_be_invalid_if_contains_applies_to_less_items() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("minContains", 2) - .build() + new MinContainsKeyword( + List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).build())), + BigInteger.valueOf(2) ) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add(1).build()), @@ -142,12 +120,7 @@ void should_be_invalid_if_contains_applies_to_less_items() { @Test void should_be_valid_if_contains_applies_to_all_and_more_items_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("minContains", 2) - .build() - ) + new MinContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()), is(true) @@ -157,12 +130,7 @@ void should_be_valid_if_contains_applies_to_all_and_more_items_in_array() { @Test void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("minContains", 2) - .build() - ) + new MinContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").add("bar").build()), is(true) @@ -172,28 +140,10 @@ void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array() @Test void should_be_invalid_if_contains_applies_to_all_and_less_items_in_array() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("contains", Json.createObjectBuilder().add("type", "string")) - .add("minContains", 2) - .build() - ) + new MinContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createArrayBuilder().add("foo").build()), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new AffectsKeywordType( - "minContains", - List.of(new Affects("contains", new Affects.ReplaceKeyword())), - (a, s) -> - new IntegerKeywordType( - JsonProvider.provider(), - "minContains", - value -> new MinContainsKeyword(a, value) - ).createKeyword(s) - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java index 1af26aa0..e25711f8 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class MinItemsKeywordTest { @Test void should_be_know_his_name() { - final Keyword minItems = createKeywordFrom( - Json.createObjectBuilder().add("minItems", Json.createValue(1)).build() - ); + final Keyword minItems = new MinItemsKeyword(BigInteger.valueOf(1)); assertThat(minItems.hasName("minItems"), is(true)); assertThat(minItems.hasName("test"), is(false)); @@ -54,9 +48,7 @@ void should_be_know_his_name() { @Test void should_be_valid_for_non_arrays() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), + new MinItemsKeyword(BigInteger.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) ); } @@ -64,7 +56,7 @@ void should_be_valid_for_non_arrays() { @Test void should_be_valid_for_arrays_with_equals_size() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build()) + new MinItemsKeyword(BigInteger.valueOf(1)) .asAssertion() .isValidFor(Json.createArrayBuilder().add(1).build()), is(true) @@ -74,7 +66,7 @@ void should_be_valid_for_arrays_with_equals_size() { @Test void should_be_valid_for_arrays_with_greater_size() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build()) + new MinItemsKeyword(BigInteger.valueOf(1)) .asAssertion() .isValidFor(Json.createArrayBuilder().add(1).add(2).build()), is(true) @@ -84,9 +76,7 @@ void should_be_valid_for_arrays_with_greater_size() { @Test void should_be_invalid_for_arrays_with_smaller_size() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build()) - .asAssertion() - .isValidFor(Json.createArrayBuilder().build()), + new MinItemsKeyword(BigInteger.valueOf(1)).asAssertion().isValidFor(Json.createArrayBuilder().build()), is(false) ); } @@ -94,16 +84,8 @@ void should_be_invalid_for_arrays_with_smaller_size() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build()).printOn( - new HashMapMedia() - ), + new MinItemsKeyword(BigInteger.valueOf(1)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("minItems"), is(BigInteger.valueOf(1))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new IntegerKeywordType(JsonProvider.provider(), "minItems", MinItemsKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java index 798ca931..d5b21c30 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class MinLengthKeywordTest { @Test void should_know_his_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("minLength", Json.createValue(1)).build() - ); + final Keyword keyword = new MinLengthKeyword(BigInteger.valueOf(1)); assertThat(keyword.hasName("test"), is(false)); assertThat(keyword.hasName("minLength"), is(true)); @@ -54,9 +48,7 @@ void should_know_his_name() { @Test void should_be_invalid_with_shorter_string() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(Json.createValue("A")), + new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("A")), is(false) ); } @@ -64,9 +56,7 @@ void should_be_invalid_with_shorter_string() { @Test void should_be_valid_with_string_with_equal_length() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(Json.createValue("AB")), + new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("AB")), is(true) ); } @@ -74,9 +64,7 @@ void should_be_valid_with_string_with_equal_length() { @Test void should_be_valid_with_string_that_is_longer() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(Json.createValue("ABC")), + new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("ABC")), is(true) ); } @@ -84,9 +72,7 @@ void should_be_valid_with_string_that_is_longer() { @Test void should_be_valid_for_non_string_values() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_ARRAY), + new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY), is(true) ); } @@ -94,16 +80,8 @@ void should_be_valid_for_non_string_values() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build()).printOn( - new HashMapMedia() - ), + new MinLengthKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("minLength"), is(BigInteger.valueOf(2L))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new IntegerKeywordType(JsonProvider.provider(), "minLength", MinLengthKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java index 9f7597af..1af6fa00 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigInteger; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,7 +39,7 @@ class MinPropertiesKeywordTest { @Test void should_know_his_name() { - final Keyword enumKeyword = createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build()); + final Keyword enumKeyword = new MinPropertiesKeyword(BigInteger.valueOf(1)); assertThat(enumKeyword.hasName("minProperties"), is(true)); assertThat(enumKeyword.hasName("test"), is(false)); @@ -52,7 +48,7 @@ void should_know_his_name() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build()).printOn(new HashMapMedia()), + new MinPropertiesKeyword(BigInteger.valueOf(1)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("minProperties"), is(BigInteger.valueOf(1))) ); } @@ -60,9 +56,7 @@ void should_be_printable() { @Test void should_be_valid_for_non_objects() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_ARRAY), + new MinPropertiesKeyword(BigInteger.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY), is(true) ); } @@ -70,7 +64,7 @@ void should_be_valid_for_non_objects() { @Test void should_be_valid_for_excat_properties_count() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build()) + new MinPropertiesKeyword(BigInteger.valueOf(1)) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", 1).build()), is(true) @@ -80,7 +74,7 @@ void should_be_valid_for_excat_properties_count() { @Test void should_be_valid_for_more_properties() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build()) + new MinPropertiesKeyword(BigInteger.valueOf(1)) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", 1).add("bar", "hi").build()), is(true) @@ -90,18 +84,10 @@ void should_be_valid_for_more_properties() { @Test void should_be_invalid_for_less_properties() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minProperties", 2).build()) + new MinPropertiesKeyword(BigInteger.valueOf(2)) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", 1).build()), is(false) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new IntegerKeywordType( - JsonProvider.provider(), - "minProperties", - MinPropertiesKeyword::new - ).createKeyword(new DefaultJsonSchemaFactory().create(json)); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java index 456a9784..b40b6f82 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigDecimal; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class MinimumKeywordTest { @Test void should_know_his_name() { - final Keyword minimum = createKeywordFrom( - Json.createObjectBuilder().add("minimum", Json.createValue(1)).build() - ); + final Keyword minimum = new MinimumKeyword(BigDecimal.valueOf(1)); assertThat(minimum.hasName("minimum"), is(true)); assertThat(minimum.hasName("test"), is(false)); @@ -54,56 +48,31 @@ void should_know_his_name() { @Test void should_be_valid_for_non_number_values() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(1)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), + new MinimumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) ); } @Test void should_be_invalid_for_smaller_numbers() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build()) - .asAssertion() - .isValidFor(Json.createValue(-1)), - is(false) - ); + assertThat(new MinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(-1)), is(false)); } @Test void should_be_valid_for_equals_numbers() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build()) - .asAssertion() - .isValidFor(Json.createValue(0)), - is(true) - ); + assertThat(new MinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(0)), is(true)); } @Test void shhould_be_valid_for_greater_numbers() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build()) - .asAssertion() - .isValidFor(Json.createValue(1)), - is(true) - ); + assertThat(new MinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(1)), is(true)); } @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build()).printOn( - new HashMapMedia() - ), + new MinimumKeyword(BigDecimal.valueOf(0)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("minimum"), is(BigDecimal.valueOf(0))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NumberKeywordType(JsonProvider.provider(), "minimum", MinimumKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java index ee677364..9f3a405c 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigDecimal; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -43,9 +39,7 @@ class MultipleOfKeywordTest { @Test void should_know_his_name() { - final Keyword multipleOf = createKeywordFrom( - Json.createObjectBuilder().add("multipleOf", Json.createValue(10)).build() - ); + final Keyword multipleOf = new MultipleOfKeyword(BigDecimal.valueOf(10)); assertThat(multipleOf.hasName("multipleOf"), is(true)); assertThat(multipleOf.hasName("test"), is(false)); @@ -54,9 +48,7 @@ void should_know_his_name() { @Test void should_be_valid_for_non_number_values() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(10)).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), + new MultipleOfKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true) ); } @@ -64,9 +56,7 @@ void should_be_valid_for_non_number_values() { @Test void should_be_valid_for_a_multipleOf() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(1.5)).build()) - .asAssertion() - .isValidFor(Json.createValue(4.5)), + new MultipleOfKeyword(BigDecimal.valueOf(1.5)).asAssertion().isValidFor(Json.createValue(4.5)), is(true) ); } @@ -74,9 +64,7 @@ void should_be_valid_for_a_multipleOf() { @Test void should_be_invalid_for_non_multipleOf() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(2)).build()) - .asAssertion() - .isValidFor(Json.createValue(7)), + new MultipleOfKeyword(BigDecimal.valueOf(2)).asAssertion().isValidFor(Json.createValue(7)), is(false) ); } @@ -84,11 +72,7 @@ void should_be_invalid_for_non_multipleOf() { @Test void should_be_valid_for_any_int_if_multipleOf_is_1en8() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("multipleOf", Json.createValue(new BigDecimal("1e-8"))).build() - ) - .asAssertion() - .isValidFor(Json.createValue(12391239123L)), + new MultipleOfKeyword(new BigDecimal("1e-8")).asAssertion().isValidFor(Json.createValue(12391239123L)), is(true) ); } @@ -96,16 +80,8 @@ void should_be_valid_for_any_int_if_multipleOf_is_1en8() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(2)).build()).printOn( - new HashMapMedia() - ), + new MultipleOfKeyword(BigDecimal.valueOf(2)).printOn(new HashMapMedia()), (Matcher) hasEntry(is("multipleOf"), is(new BigDecimal(2))) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new NumberKeywordType(JsonProvider.provider(), "multipleOf", MultipleOfKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java index 817ff41a..96250f0e 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -42,9 +38,7 @@ class PatternKeywordTest { @Test void should_be_know_his_name() { - final Keyword pattern = createKeywordFrom( - Json.createObjectBuilder().add("pattern", Json.createValue("a")).build() - ); + final Keyword pattern = new PatternKeyword("a"); assertThat(pattern.hasName("pattern"), is(true)); assertThat(pattern.hasName("test"), is(false)); @@ -52,22 +46,13 @@ void should_be_know_his_name() { @Test void should_be_valid_for_non_string_value() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("pattern", Json.createValue("a")).build()) - .asAssertion() - .isValidFor(JsonValue.TRUE), - is(true) - ); + assertThat(new PatternKeyword("a").asAssertion().isValidFor(JsonValue.TRUE), is(true)); } @Test void should_be_invalid_for_non_matching_value() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("pattern", Json.createValue("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$")) - .build() - ) + new PatternKeyword("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$") .asAssertion() .isValidFor(Json.createValue("(888)555-1212 ext. 532")), is(false) @@ -77,11 +62,7 @@ void should_be_invalid_for_non_matching_value() { @Test void should_be_valid_matching_value() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("pattern", Json.createValue("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$")) - .build() - ) + new PatternKeyword("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$") .asAssertion() .isValidFor(Json.createValue("(888)555-1212")), is(true) @@ -91,18 +72,8 @@ void should_be_valid_matching_value() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder() - .add("pattern", Json.createValue("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$")) - .build() - ).printOn(new HashMapMedia()), + new PatternKeyword("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$").printOn(new HashMapMedia()), (Matcher) hasEntry(is("pattern"), is("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$")) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new StringKeywordType(JsonProvider.provider(), "pattern", PatternKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java index f832e374..35374374 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java @@ -29,14 +29,11 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringArrayKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.math.BigDecimal; +import java.util.List; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -44,9 +41,7 @@ class RequiredKeywordTest { @Test void should_know_his_name() { - final Keyword required = createKeywordFrom( - Json.createObjectBuilder().add("required", JsonValue.EMPTY_JSON_ARRAY).build() - ); + final Keyword required = new RequiredKeyword(List.of()); assertThat(required.hasName("required"), is(true)); assertThat(required.hasName("test"), is(false)); @@ -55,9 +50,7 @@ void should_know_his_name() { @Test void should_invalid_if_not_all_properties_in_the_instance() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build() - ) + new RequiredKeyword(List.of("foo", "bar")) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", BigDecimal.ONE).build()), is(false) @@ -67,11 +60,7 @@ void should_invalid_if_not_all_properties_in_the_instance() { @Test void should_valid_for_non_objects() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build() - ) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_ARRAY), + new RequiredKeyword(List.of("foo", "bar")).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY), is(true) ); } @@ -79,9 +68,7 @@ void should_valid_for_non_objects() { @Test void should_valid_if_all_properties_are_in_the_instance() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build() - ) + new RequiredKeyword(List.of("foo", "bar")) .asAssertion() .isValidFor(Json.createObjectBuilder().add("foo", BigDecimal.ONE).add("bar", "test").build()), is(true) @@ -91,16 +78,8 @@ void should_valid_if_all_properties_are_in_the_instance() { @Test void should_be_printable() { assertThat( - createKeywordFrom( - Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build() - ).printOn(new HashMapMedia()), + new RequiredKeyword(List.of("foo", "bar")).printOn(new HashMapMedia()), (Matcher) hasEntry(is("required"), containsInAnyOrder("foo", "bar")) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new StringArrayKeywordType(JsonProvider.provider(), "required", RequiredKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java index 86db461c..9904d662 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java @@ -28,13 +28,9 @@ import static org.hamcrest.Matchers.is; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; -import io.github.sebastiantoepfer.jsonschema.core.keyword.type.BooleanKeywordType; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; import jakarta.json.Json; -import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import jakarta.json.spi.JsonProvider; import java.io.StringReader; import java.math.BigDecimal; import org.hamcrest.Matcher; @@ -44,9 +40,7 @@ class UniqueItemsKeywordTest { @Test void should_know_his_name() { - final Keyword keyword = createKeywordFrom( - Json.createObjectBuilder().add("uniqueItems", JsonValue.FALSE).build() - ); + final Keyword keyword = new UniqueItemsKeyword(false); assertThat(keyword.hasName("uniqueItems"), is(true)); assertThat(keyword.hasName("test"), is(false)); @@ -55,9 +49,7 @@ void should_know_his_name() { @Test void should_be_valid_for_uniqueItems() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build()) - .asAssertion() - .isValidFor(Json.createArrayBuilder().add("1").add("2").build()), + new UniqueItemsKeyword(true).asAssertion().isValidFor(Json.createArrayBuilder().add("1").add("2").build()), is(true) ); } @@ -65,9 +57,7 @@ void should_be_valid_for_uniqueItems() { @Test void should_be_valid_for_non_uniqueItems_if_false() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.FALSE).build()) - .asAssertion() - .isValidFor(Json.createArrayBuilder().add("1").add("1").build()), + new UniqueItemsKeyword(false).asAssertion().isValidFor(Json.createArrayBuilder().add("1").add("1").build()), is(true) ); } @@ -75,27 +65,20 @@ void should_be_valid_for_non_uniqueItems_if_false() { @Test void should_be_invalid_for_non_uniqueItems() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build()) - .asAssertion() - .isValidFor(Json.createArrayBuilder().add("1").add("1").build()), + new UniqueItemsKeyword(true).asAssertion().isValidFor(Json.createArrayBuilder().add("1").add("1").build()), is(false) ); } @Test void should_be_valid_for_non_arrays() { - assertThat( - createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.FALSE).build()) - .asAssertion() - .isValidFor(JsonValue.EMPTY_JSON_OBJECT), - is(true) - ); + assertThat(new UniqueItemsKeyword(false).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true)); } @Test void should_be_invalid_if_numbers_mathematically_unequal() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build()) + new UniqueItemsKeyword(true) .asAssertion() .isValidFor(Json.createReader(new StringReader("[1.0,1.00,1]")).readArray()), is(false) @@ -126,16 +109,8 @@ void pitests_say_i_must_write_this_tests() { @Test void should_be_printable() { assertThat( - createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build()).printOn( - new HashMapMedia() - ), + new UniqueItemsKeyword(true).printOn(new HashMapMedia()), (Matcher) hasEntry(is("uniqueItems"), is(true)) ); } - - private static Keyword createKeywordFrom(final JsonObject json) { - return new BooleanKeywordType(JsonProvider.provider(), "uniqueItems", UniqueItemsKeyword::new).createKeyword( - new DefaultJsonSchemaFactory().create(json) - ); - } }