diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordType.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordType.java index 435dd4e9..8ff11ffd 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordType.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordType.java @@ -23,6 +23,7 @@ */ package io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion; +import io.github.sebastiantoepfer.ddd.common.Media; import io.github.sebastiantoepfer.jsonschema.InstanceType; import io.github.sebastiantoepfer.jsonschema.JsonSchema; import io.github.sebastiantoepfer.jsonschema.keyword.Annotation; @@ -50,9 +51,13 @@ public String name() { } @Override - public Keyword createKeyword(final JsonSchema schema, final JsonValue value) { - if (InstanceType.STRING.isInstance(value)) { - return createKeyword(((JsonString) value).getString()); + public Keyword createKeyword(final JsonSchema js) { + if ( + js.getValueType() == JsonValue.ValueType.OBJECT && + js.asJsonObject().containsKey(name()) && + js.asJsonObject().get(name()).getValueType() == JsonValue.ValueType.STRING + ) { + return createKeyword(js.asJsonObject().getString(name())); } else { throw new IllegalArgumentException("Value must be a string!"); } @@ -94,5 +99,10 @@ public JsonValue valueFor(final JsonValue value) { public boolean isValidFor(final JsonValue instance) { return !InstanceType.STRING.isInstance(instance) || format.isValidFor(((JsonString) instance).getString()); } + + @Override + public > T printOn(final T media) { + return media.withValue(name(), format.name()); + } } } diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/Rule.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/Rule.java index 4bb978ec..cb28b179 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/Rule.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/Rule.java @@ -27,7 +27,10 @@ import io.github.sebastiantoepfer.ddd.common.Printable; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.Element; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.RuleName; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.ValidateableCodePoint; import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.IntStream; public final class Rule implements Printable { @@ -47,6 +50,15 @@ public boolean hasRuleName(final RuleName name) { return Objects.equals(this.name, name); } + Predicate asPredicate() { + return s -> + IntStream + .range(0, s.length()) + .boxed() + .map(i -> ValidateableCodePoint.of(i, s.codePointAt(i))) + .allMatch(elements::isValidFor); + } + @Override public > T printOn(final T media) { return media.withValue("name", name).withValue("type", "rule").withValue("elements", elements); diff --git a/vocabulary-format-assertion/src/main/java21/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ListValidation.java b/vocabulary-format-assertion/src/main/java21/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ListValidation.java deleted file mode 100644 index f1c2aa30..00000000 --- a/vocabulary-format-assertion/src/main/java21/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ListValidation.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * The MIT License - * - * Copyright 2023 sebastian. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element; - -import java.util.List; -import java.util.Objects; -import java.util.function.Function; - -class ListValidation { - - private final List elements; - private final Function, Element> newElement; - - public ListValidation(final List elements, final Function, Element> newElement) { - this.elements = List.copyOf(elements); - this.newElement = Objects.requireNonNull(newElement); - } - - public boolean isValidFor(final ValidateableCodePoint codePoint) { - final boolean result; - final Element first = elements.getFirst(); - if (first.dimension().isInRange(codePoint)) { - result = first.isValidFor(codePoint); - } else { - result = - newElement - .apply(elements.subList(1, elements.size())) - .isValidFor(codePoint.repositionBackBy(first.dimension())); - } - return result; - } -} diff --git a/vocabulary-format-assertion/src/main/java21/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ConcationTypeSwitch.java b/vocabulary-format-assertion/src/main/java21/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ConcationTypeSwitch.java deleted file mode 100644 index 5fc7a5db..00000000 --- a/vocabulary-format-assertion/src/main/java21/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ConcationTypeSwitch.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * The MIT License - * - * Copyright 2023 sebastian. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.reader; - -import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.Element; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -class ConcationTypeSwitch { - - private final ExtractorOwner owner; - private final ElementEndDetector endOfElementDetector; - private final List elements; - - public ConcationTypeSwitch( - final ExtractorOwner owner, - final ElementEndDetector endOfElementDetector, - final List elements - ) { - this.owner = Objects.requireNonNull(owner); - this.endOfElementDetector = Objects.requireNonNull(endOfElementDetector); - this.elements = List.copyOf(elements); - } - - public Extractor switchTo(final ExtractorOwnerFactory ownerFactory, final ExtractorFactory targetFactory) { - final List newElements = new ArrayList<>(elements); - final Element element = newElements.removeLast(); - return targetFactory.create( - ownerFactory.create(owner, endOfElementDetector, newElements), - endOfElementDetector, - element - ); - } -} diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordTypeTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordTypeTest.java index 31e5de1b..f316b82c 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordTypeTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/FormatAssertionKeywordTypeTest.java @@ -42,7 +42,7 @@ class FormatAssertionKeywordTypeTest { @Test void should_know_his_name() { final Keyword keyword = new FormatAssertionKeywordType(List.of(new TestFormat())) - .createKeyword(JsonSchemas.load(JsonValue.TRUE), Json.createValue("date")); + .createKeyword(JsonSchemas.load(Json.createObjectBuilder().add("format", "date").build())); assertThat(keyword.hasName("format"), is(true)); assertThat(keyword.hasName("test"), is(false)); @@ -52,25 +52,21 @@ void should_know_his_name() { void should_not_be_createable_with_non_string() { final JsonSchema schema = JsonSchemas.load(JsonValue.TRUE); final KeywordType keywordType = new FormatAssertionKeywordType(List.of(new TestFormat())); - assertThrows( - IllegalArgumentException.class, - () -> keywordType.createKeyword(schema, JsonValue.EMPTY_JSON_OBJECT) - ); + assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema)); } @Test void should_not_be_createable_with_unknown_formatname() { - final JsonSchema schema = JsonSchemas.load(JsonValue.TRUE); + final JsonSchema schema = JsonSchemas.load(Json.createObjectBuilder().add("format", "test").build()); final KeywordType keywordType = new FormatAssertionKeywordType(List.of(new TestFormat())); - final JsonValue unknownFormatName = Json.createValue("test"); - assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema, unknownFormatName)); + assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema)); } @Test void should_be_assertion_and_annotation() { assertThat( new FormatAssertionKeywordType(List.of(new TestFormat())) - .createKeyword(JsonSchemas.load(JsonValue.TRUE), Json.createValue("date")) + .createKeyword(JsonSchemas.load(Json.createObjectBuilder().add("format", "date").build())) .categories(), containsInAnyOrder(Keyword.KeywordCategory.ASSERTION, Keyword.KeywordCategory.ANNOTATION) ); @@ -80,7 +76,7 @@ void should_be_assertion_and_annotation() { void should_return_formatname_as_annotation() { assertThat( new FormatAssertionKeywordType(List.of(new TestFormat())) - .createKeyword(JsonSchemas.load(JsonValue.TRUE), Json.createValue("date")) + .createKeyword(JsonSchemas.load(Json.createObjectBuilder().add("format", "date").build())) .asAnnotation() .valueFor(JsonValue.EMPTY_JSON_OBJECT), is(Json.createValue("date")) diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/RuleTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/RuleTest.java index 124baa5c..9494d5c9 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/RuleTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/RuleTest.java @@ -31,11 +31,16 @@ import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.Alternative; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.Concatenation; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.RuleName; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.RuleReference; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.SequenceGroup; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.StringElement; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.VariableRepetition; import nl.jqno.equalsverifier.EqualsVerifier; import org.hamcrest.Matcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; class RuleTest { @@ -78,4 +83,49 @@ void should_be_printable() { ) ); } + + @Nested + class Validation { + + private Rule ruleName; + + @BeforeEach + void initRule() { + ruleName = + Rule.of( + RuleName.of("rulename"), + Concatenation.of( + CoreRules.ALPHA, + VariableRepetition.of( + SequenceGroup.of(Alternative.of(CoreRules.ALPHA, CoreRules.DIGIT, StringElement.of("-"))) + ) + ) + ); + } + + @Test + void should_be_valid_for_alphas_only() { + assertThat(ruleName.asPredicate().test("rulename"), is(true)); + } + + @Test + void should_be_valid_for_valid_alpha_and_digits() { + assertThat(ruleName.asPredicate().test("rul3nam3"), is(true)); + } + + @Test + void should_be_valid_for_valid_alpha_and_minus() { + assertThat(ruleName.asPredicate().test("rule-name"), is(true)); + } + + @Test + void should_be_invalid_for_value_with_digist_at_start() { + assertThat(ruleName.asPredicate().test("1rule"), is(false)); + } + + @Test + void should_be_invalid_for_value_with_solidus() { + assertThat(ruleName.asPredicate().test("rule/name"), is(false)); + } + } }