From 5a0fd4f7ca7c26f6bc67b8268705019ba920d9a1 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Sun, 19 Nov 2023 16:09:03 +0100 Subject: [PATCH] improve isValidFor --- .../format/assertion/abnf/CoreRules.java | 27 ++-- .../assertion/abnf/element/Alternative.java | 7 +- .../assertion/abnf/element/Concatenation.java | 22 +++- .../assertion/abnf/element/Dimension.java | 122 ++++++++++++++++++ .../assertion/abnf/element/Element.java | 7 +- .../abnf/element/NumericCharacter.java | 12 +- .../abnf/element/OptionalSequence.java | 13 +- .../assertion/abnf/element/RuleName.java | 4 + .../assertion/abnf/element/RuleReference.java | 13 +- .../assertion/abnf/element/SequenceGroup.java | 21 ++- .../abnf/element/SpecificRepetition.java | 20 ++- .../assertion/abnf/element/StringElement.java | 20 +-- .../abnf/element/ValidateableCodePoint.java | 107 +++++++++++++++ .../abnf/element/ValueRangeAlternatives.java | 2 +- .../abnf/element/VariableRepetition.java | 25 +++- .../abnf/reader/NumValExtractor.java | 5 +- .../format/assertion/abnf/CoreRulesTest.java | 42 +++++- .../abnf/element/AlternativeTest.java | 11 +- .../abnf/element/ConcatenationTest.java | 47 ++++++- .../assertion/abnf/element/DimensionTest.java | 83 ++++++++++++ .../assertion/abnf/element/ElementTest.java | 51 ++++++++ .../abnf/element/OptionalSequenceTest.java | 18 +++ .../abnf/element/RuleReferenceTest.java | 26 ++++ .../abnf/element/SequenceGroupTest.java | 45 +++++++ .../abnf/element/SpecificRepetitionTest.java | 48 +++++++ .../abnf/element/StringElementTest.java | 31 ++++- .../element/ValidateableCodePointTest.java | 59 +++++++++ .../element/ValueRangeAlternativesTest.java | 23 +++- .../abnf/element/VariableRepetitionTest.java | 50 +++++++ 29 files changed, 884 insertions(+), 77 deletions(-) create mode 100644 vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Dimension.java create mode 100644 vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePoint.java create mode 100644 vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/DimensionTest.java create mode 100644 vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ElementTest.java create mode 100644 vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePointTest.java diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRules.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRules.java index aae23cfd..0c9a0016 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRules.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRules.java @@ -26,12 +26,13 @@ import io.github.sebastiantoepfer.ddd.common.Media; 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.Dimension; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.Element; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.NumericCharacter; 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.ValidateableCodePoint; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.ValueRangeAlternatives; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.VariableRepetition; @@ -75,7 +76,7 @@ Element definition() { CRLF() { @Override Element definition() { - return Concatenation.of(RuleReference.of(CR.asRuleName()), RuleReference.of(LF.asRuleName())); + return Concatenation.of(CR, LF); } }, CTL() { @@ -134,14 +135,7 @@ Element definition() { LWSP() { @Override Element definition() { - return VariableRepetition.of( - SequenceGroup.of( - Concatenation.of( - Alternative.of(RuleReference.of(WSP.asRuleName()), RuleReference.of(CRLF.asRuleName())), - RuleReference.of(WSP.asRuleName()) - ) - ) - ); + return VariableRepetition.of(SequenceGroup.of(Concatenation.of(Alternative.of(WSP, CRLF), WSP))); } }, OCTET() { @@ -175,7 +169,7 @@ Element definition() { } }; - public RuleName asRuleName() { + public final RuleName asRuleName() { return RuleName.of(name()); } @@ -184,10 +178,19 @@ public final > T printOn(final T media) { return Rule.of(asRuleName(), definition()).printOn(media).withValue("type", "corerule"); } - @Override public final boolean isValidFor(final int codePoint) { + return isValidFor(ValidateableCodePoint.of(0, codePoint)); + } + + @Override + public final boolean isValidFor(final ValidateableCodePoint codePoint) { return definition().isValidFor(codePoint); } + @Override + public final Dimension dimension() { + return definition().dimension(); + } + abstract Element definition(); } diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Alternative.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Alternative.java index 13ec2721..87efed65 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Alternative.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Alternative.java @@ -56,10 +56,15 @@ public > T printOn(final T media) { } @Override - public boolean isValidFor(final int codePoint) { + public boolean isValidFor(final ValidateableCodePoint codePoint) { return alternatives.stream().anyMatch(e -> e.isValidFor(codePoint)); } + @Override + public Dimension dimension() { + return alternatives.stream().map(Element::dimension).sorted().reduce(Dimension::expandTo).orElseThrow(); + } + @Override public int hashCode() { int hash = 7; diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Concatenation.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Concatenation.java index 6aa48ec1..01512afd 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Concatenation.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Concatenation.java @@ -56,8 +56,26 @@ public > T printOn(final T media) { } @Override - public boolean isValidFor(final int codePoint) { - throw new UnsupportedOperationException("Not supported yet."); + public Dimension dimension() { + return concatenations.stream().map(Element::dimension).reduce(Dimension::plus).orElseThrow(); + } + + @Override + public boolean isValidFor(final ValidateableCodePoint codePoint) { + final boolean result; + if (dimension().isInRange(codePoint)) { + final Element first = concatenations.get(0); + if (first.dimension().isInRange(codePoint)) { + result = first.isValidFor(codePoint); + } else { + result = + of(concatenations.subList(1, concatenations.size())) + .isValidFor(codePoint.repositionBackBy(first.dimension())); + } + } else { + result = false; + } + return result; } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Dimension.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Dimension.java new file mode 100644 index 00000000..bcb9e197 --- /dev/null +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Dimension.java @@ -0,0 +1,122 @@ +/* + * 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 static java.util.Comparator.comparingLong; + +public final class Dimension implements Comparable { + + private static final Dimension ZERO = Dimension.of(0); + private static final Dimension ONE = Dimension.of(1); + + public static Dimension zero() { + return ZERO; + } + + public static Dimension one() { + return ONE; + } + + public static Dimension of(final long size) { + return of(size, size); + } + + public static Dimension of(final long minSize, final long maxSize) { + if (minSize < 0) { + throw new IllegalArgumentException("minSize must be greather or equals than 0!"); + } + if (maxSize < minSize) { + throw new IllegalArgumentException("MaxSize must be greater or equals minSize!"); + } + return new Dimension(minSize, maxSize); + } + + private final long minSize; + private final long maxSize; + + private Dimension(final long minSize, final long maxSize) { + this.minSize = minSize; + this.maxSize = maxSize; + } + + public boolean isInRange(final ValidateableCodePoint codepoint) { + return codepoint.position() < maxSize; + } + + Dimension expandTo(final Dimension newMax) { + return of(Math.min(minSize, newMax.minSize), Math.max(maxSize, newMax.maxSize)); + } + + Dimension plus(final Dimension toAdd) { + return of(minSize + toAdd.minSize, maxSize + toAdd.maxSize); + } + + Dimension multipliesBy(final int multiplier) { + return of(minSize * multiplier, maxSize * multiplier); + } + + @Override + public int compareTo(final Dimension t) { + return comparingLong(Dimension::length).thenComparing(comparingLong(Dimension::minSize)).compare(this, t); + } + + private long minSize() { + return minSize; + } + + long length() { + return maxSize; + } + + @Override + public String toString() { + return "Dimension{" + "minSize=" + minSize + ", maxSize=" + maxSize + '}'; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 53 * hash + (int) (this.minSize ^ (this.minSize >>> 32)); + hash = 53 * hash + (int) (this.maxSize ^ (this.maxSize >>> 32)); + 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 Dimension other = (Dimension) obj; + if (this.minSize != other.minSize) { + return false; + } + return this.maxSize == other.maxSize; + } +} diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Element.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Element.java index 8e84578e..efb83da4 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Element.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/Element.java @@ -26,6 +26,9 @@ import io.github.sebastiantoepfer.ddd.common.Printable; public interface Element extends Printable { - //no no, but let get start simple - boolean isValidFor(int codePoint); + boolean isValidFor(ValidateableCodePoint codePoint); + + default Dimension dimension() { + return Dimension.one(); + } } diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/NumericCharacter.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/NumericCharacter.java index d4e870e4..861f4ecb 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/NumericCharacter.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/NumericCharacter.java @@ -42,8 +42,8 @@ private NumericCharacter(final BASE base, final int value) { } @Override - public boolean isValidFor(final int codePoint) { - return value == codePoint; + public boolean isValidFor(final ValidateableCodePoint codePoint) { + return codePoint.isEqualsTo(value); } @Override @@ -51,12 +51,12 @@ public > T printOn(final T media) { return media.withValue("type", "num-val").withValue("base", base.name()).withValue("value", value); } - boolean lessThanOrEquals(final int codePoint) { - return value <= codePoint; + boolean lessThanOrEquals(final ValidateableCodePoint codePoint) { + return codePoint.isGreaterOrEqualsThan(value); } - boolean greatherThaneOrEquals(final int codePoint) { - return value >= codePoint; + boolean greatherThaneOrEquals(final ValidateableCodePoint codePoint) { + return codePoint.isLessOrEqualsThan(value); } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequence.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequence.java index 818c41cc..34de4c98 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequence.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequence.java @@ -50,8 +50,17 @@ public > T printOn(final T media) { } @Override - public boolean isValidFor(final int codePoint) { - throw new UnsupportedOperationException("Not supported yet."); + public boolean isValidFor(final ValidateableCodePoint codePoint) { + return true; + } + + @Override + public Dimension dimension() { + return Dimension + .zero() + .expandTo( + optionalElements.stream().map(Element::dimension).sorted().reduce(Dimension.zero(), Dimension::plus) + ); } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleName.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleName.java index 7117b4e1..24c7170f 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleName.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleName.java @@ -40,6 +40,10 @@ private RuleName(final String name) { this.name = Objects.requireNonNull(name); } + String name() { + return name; + } + @Override public > T printOn(final T media) { return media.withValue("name", name).withValue("type", "rulename"); diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReference.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReference.java index bcefab1b..6703388c 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReference.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReference.java @@ -39,8 +39,17 @@ private RuleReference(final RuleName name) { } @Override - public boolean isValidFor(final int codePoint) { - throw new UnsupportedOperationException("Not supported yet."); + public boolean isValidFor(final ValidateableCodePoint codePoint) { + return ruleNameAsStringElement().isValidFor(codePoint); + } + + @Override + public Dimension dimension() { + return ruleNameAsStringElement().dimension(); + } + + Element ruleNameAsStringElement() { + return StringElement.of(name.name()); } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroup.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroup.java index 44f9a82c..4518b89a 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroup.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroup.java @@ -60,8 +60,25 @@ public > T printOn(final T media) { } @Override - public boolean isValidFor(final int codePoint) { - throw new UnsupportedOperationException("Not supported yet."); + public boolean isValidFor(final ValidateableCodePoint codePoint) { + final boolean result; + if (dimension().isInRange(codePoint)) { + final Element first = elements.get(0); + if (first.dimension().isInRange(codePoint)) { + result = first.isValidFor(codePoint); + } else { + result = + of(elements.subList(1, elements.size())).isValidFor(codePoint.repositionBackBy(first.dimension())); + } + } else { + result = false; + } + return result; + } + + @Override + public Dimension dimension() { + return elements.stream().map(Element::dimension).reduce(Dimension.zero(), Dimension::plus); } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetition.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetition.java index fce29ab3..7b537758 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetition.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetition.java @@ -49,8 +49,24 @@ public > T printOn(final T media) { } @Override - public boolean isValidFor(final int codePoint) { - throw new UnsupportedOperationException("Not supported yet."); + public boolean isValidFor(final ValidateableCodePoint codePoint) { + final boolean result; + if (dimension().isInRange(codePoint)) { + if (elementToRepeat.dimension().isInRange(codePoint)) { + result = elementToRepeat.isValidFor(codePoint); + } else { + result = + of(elementToRepeat, occurences).isValidFor(codePoint.repositionBackBy(elementToRepeat.dimension())); + } + } else { + result = false; + } + return result; + } + + @Override + public Dimension dimension() { + return elementToRepeat.dimension().multipliesBy(occurences); } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElement.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElement.java index f3a156bd..6ef3cb5f 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElement.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElement.java @@ -40,14 +40,18 @@ private StringElement(final String value) { } @Override - public boolean isValidFor(final int codePoint) { - if (value.length() == 1) { - return ( - value.codePointAt(0) == Character.toUpperCase(codePoint) || - value.codePointAt(0) == Character.toLowerCase(codePoint) - ); - } - throw new UnsupportedOperationException("Not supported yet."); + public boolean isValidFor(final ValidateableCodePoint codePoint) { + return ( + dimension().isInRange(codePoint) && + (codePoint.isEqualsTo(value.codePointAt(codePoint.position())) || + codePoint.isUpperCaseOf(value.codePointAt(codePoint.position())) || + codePoint.isLowerCaseOf(value.codePointAt(codePoint.position()))) + ); + } + + @Override + public Dimension dimension() { + return Dimension.of(value.length()); } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePoint.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePoint.java new file mode 100644 index 00000000..4e34365a --- /dev/null +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePoint.java @@ -0,0 +1,107 @@ +/* + * 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; + +public final class ValidateableCodePoint { + + public static ValidateableCodePoint of(final int position, final int value) { + if (position < 0) { + throw new IllegalArgumentException("position must be greather than 0!"); + } + if (value < 0) { + throw new IllegalArgumentException("value must be greather than 0!"); + } + return new ValidateableCodePoint(position, value); + } + + private final int position; + private final int value; + + private ValidateableCodePoint(final int position, final int value) { + this.position = position; + this.value = value; + } + + public ValidateableCodePoint repositionBackBy(final Dimension before) { + return repositionTo(position - (int) before.length()); + } + + public ValidateableCodePoint repositionBackBy(final int offset) { + return repositionTo(position - offset); + } + + public ValidateableCodePoint repositionTo(final int newPosition) { + return of(newPosition, value); + } + + public int position() { + return position; + } + + public boolean isEqualsTo(final int codePoint) { + return codePoint == value; + } + + public boolean isUpperCaseOf(final int codePoint) { + return Character.toUpperCase(codePoint) == value; + } + + public boolean isLowerCaseOf(final int codePoint) { + return Character.toLowerCase(codePoint) == value; + } + + public boolean isGreaterOrEqualsThan(final int codePoint) { + return codePoint <= value; + } + + public boolean isLessOrEqualsThan(final int codePoint) { + return value <= codePoint; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 71 * hash + this.position; + hash = 71 * hash + this.value; + 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 ValidateableCodePoint other = (ValidateableCodePoint) obj; + if (this.position != other.position) { + return false; + } + return this.value == other.value; + } +} diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternatives.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternatives.java index c271c841..4538f367 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternatives.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternatives.java @@ -46,7 +46,7 @@ public > T printOn(final T media) { } @Override - public boolean isValidFor(final int codePoint) { + public boolean isValidFor(final ValidateableCodePoint codePoint) { return start.lessThanOrEquals(codePoint) && end.greatherThaneOrEquals(codePoint); } diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetition.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetition.java index 3cf86c23..ba998dc0 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetition.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetition.java @@ -74,8 +74,29 @@ public > T printOn(final T media) { } @Override - public boolean isValidFor(final int codePoint) { - throw new UnsupportedOperationException("Not supported yet."); + public boolean isValidFor(final ValidateableCodePoint codePoint) { + final boolean result; + if (dimension().isInRange(codePoint)) { + if (element.dimension().isInRange(codePoint)) { + result = element.isValidFor(codePoint); + } else { + final int newMinOccurrences = Math.min(minOccurrences, 1); + result = + ofBetween(element, newMinOccurrences, Math.max(newMinOccurrences, maxOccurrences - 1)) + .isValidFor(codePoint.repositionBackBy(element.dimension())); + } + } else { + result = false; + } + return result; + } + + @Override + public Dimension dimension() { + return element + .dimension() + .multipliesBy(minOccurrences) + .expandTo(element.dimension().multipliesBy(maxOccurrences)); } @Override diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/NumValExtractor.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/NumValExtractor.java index 4d99589c..888ab417 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/NumValExtractor.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/NumValExtractor.java @@ -25,6 +25,7 @@ import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.CoreRules; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.NumericCharacter; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.ValidateableCodePoint; import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.ValueRangeAlternatives; import java.util.Objects; @@ -85,7 +86,7 @@ public Extractor append(final int codePoint) { final Extractor result; if (codePoint == UsefulCodepoints.HYPHEN_MINUS) { result = new ValueRangeExtractor(owner, base, rule, value); - } else if (Character.isWhitespace(codePoint) || !rule.isValidFor(codePoint)) { + } else if (Character.isWhitespace(codePoint) || !rule.isValidFor(ValidateableCodePoint.of(0, codePoint))) { result = owner.imDone(asCreator()).append(codePoint); } else { result = new SpecificNumValExtractor(owner, base, rule, value.concat(Character.toString(codePoint))); @@ -142,7 +143,7 @@ private ValueRangeExtractor( @Override public Extractor append(final int codePoint) { final Extractor result; - if (Character.isWhitespace(codePoint) || !rule.isValidFor(codePoint)) { + if (Character.isWhitespace(codePoint) || !rule.isValidFor(ValidateableCodePoint.of(0, codePoint))) { result = owner.imDone(asCreator()).append(codePoint); } else { result = new ValueRangeExtractor(owner, base, rule, start, end.concat(Character.toString(codePoint))); diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRulesTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRulesTest.java index cf5ee8d7..829de2f8 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRulesTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/CoreRulesTest.java @@ -27,10 +27,11 @@ import static org.hamcrest.Matchers.allOf; 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.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 org.hamcrest.Matcher; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -153,8 +154,11 @@ void should_return_rulename() { } @Test - void should_nit_be_supported() { - assertThrows(UnsupportedOperationException.class, () -> CoreRules.CRLF.isValidFor(0x0D)); + void should_be_valid_for_crlf() { + final Element element = CoreRules.CRLF; + + assertThat(element.isValidFor(ValidateableCodePoint.of(0, '\r')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, '\n')), is(true)); } } @@ -316,8 +320,36 @@ void should_return_rulename() { } @Test - void should_nit_be_supported() { - assertThrows(UnsupportedOperationException.class, () -> CoreRules.LWSP.isValidFor(0x0D)); + void should_be_valid_for_sp_sp() { + final Element element = CoreRules.LWSP; + + assertThat(element.isValidFor(ValidateableCodePoint.of(0, 0x20)), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, 0x20)), is(true)); + } + + @Test + void should_be_valid_for_sp_htab() { + final Element element = CoreRules.LWSP; + + assertThat(element.isValidFor(ValidateableCodePoint.of(0, 0x20)), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, 0x09)), is(true)); + } + + @Test + void should_be_valid_for_htab_sp() { + final Element element = CoreRules.LWSP; + + assertThat(element.isValidFor(ValidateableCodePoint.of(0, 0x09)), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, 0x20)), is(true)); + } + + @Test + void should_be_valid_for_crlf_sp() { + final Element element = CoreRules.LWSP; + + assertThat(element.isValidFor(ValidateableCodePoint.of(0, '\r')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, '\n')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(2, 0x20)), is(true)); } } diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/AlternativeTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/AlternativeTest.java index 060ee140..12cea960 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/AlternativeTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/AlternativeTest.java @@ -24,12 +24,8 @@ package io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; -import java.util.List; import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.jupiter.api.Test; @@ -41,10 +37,7 @@ void equalsContract() { } @Test - void should_be_created_an_equals_instance() { - assertThat( - Alternative.of(List.of(StringElement.of("a"), StringElement.of("b"))), - both(is(Alternative.of(StringElement.of("a"), StringElement.of("b")))).and(not(nullValue())) - ); + void should_return_dimension_from_smallest_and_larges() { + assertThat(Alternative.of(StringElement.of("ab"), StringElement.of("cde")).dimension(), is(Dimension.of(2, 3))); } } diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ConcatenationTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ConcatenationTest.java index 95606799..f6911ea8 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ConcatenationTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ConcatenationTest.java @@ -25,15 +25,11 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; -import java.util.List; import nl.jqno.equalsverifier.EqualsVerifier; import org.hamcrest.Matcher; import org.junit.jupiter.api.Test; @@ -46,11 +42,48 @@ void equalsContract() { } @Test - void should_be_created_an_equals_instance() { + void should_return_dimension_as_sum() { assertThat( - Concatenation.of(List.of(StringElement.of("a"), StringElement.of("b"))), - both(is(Concatenation.of(StringElement.of("a"), StringElement.of("b")))).and(not(nullValue())) + Concatenation + .of( + Alternative.of(StringElement.of("ab"), StringElement.of("cde")), + Alternative.of(StringElement.of("x"), StringElement.of("yz")) + ) + .dimension(), + is(Dimension.of(3, 5)) + ); + } + + @Test + void should_be_valid_if_codepoint_is_equals_codepoint_at_position() { + final Concatenation concatenation = Concatenation.of( + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'b'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'c') + ); + assertThat(concatenation.isValidFor(ValidateableCodePoint.of(0, 'a')), is(true)); + assertThat(concatenation.isValidFor(ValidateableCodePoint.of(1, 'b')), is(true)); + assertThat(concatenation.isValidFor(ValidateableCodePoint.of(2, 'c')), is(true)); + } + + @Test + void should_be_invalid_if_codepoint_is_out_of_position() { + final Concatenation concatenation = Concatenation.of( + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'b'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'c') + ); + assertThat(concatenation.isValidFor(ValidateableCodePoint.of(3, 'c')), is(false)); + } + + @Test + void should_be_invalid_if_codepoint_is_notequals_codepoint_at_position() { + final Concatenation concatenation = Concatenation.of( + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'b'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'c') ); + assertThat(concatenation.isValidFor(ValidateableCodePoint.of(1, 'B')), is(false)); } @Test diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/DimensionTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/DimensionTest.java new file mode 100644 index 00000000..49d13bac --- /dev/null +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/DimensionTest.java @@ -0,0 +1,83 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; + +import java.util.List; +import java.util.TreeSet; +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +class DimensionTest { + + @Test + void should_equals_contract() { + EqualsVerifier.forClass(Dimension.class).verify(); + } + + @Test + void should_know_if_codepoint_is_in_range() { + assertThat(Dimension.of(1).isInRange(ValidateableCodePoint.of(0, 0x13)), is(true)); + } + + @Test + void should_know_if_codepoint_is_not_in_range() { + assertThat(Dimension.of(1).isInRange(ValidateableCodePoint.of(1, 0x13)), is(false)); + } + + @Test + void should_create_expanded_upper_bondary() { + assertThat(Dimension.of(2).expandTo(Dimension.of(3, 7)), is(Dimension.of(2, 7))); + } + + @Test + void should_create_expanded_lower_and_upper_bondary() { + assertThat(Dimension.of(2).expandTo(Dimension.of(1, 7)), is(Dimension.of(1, 7))); + } + + @Test + void should_create_expanded_lower_bondary() { + assertThat(Dimension.of(2, 8).expandTo(Dimension.of(1, 7)), is(Dimension.of(1, 8))); + } + + @Test + void should_be_sortable() { + assertThat( + new TreeSet<>( + List.of( + Dimension.of(6), + Dimension.of(2, 4), + Dimension.of(2), + Dimension.of(1, 7), + Dimension.of(2, 4), + Dimension.of(2, 6) + ) + ), + contains(Dimension.of(2), Dimension.of(2, 4), Dimension.of(2, 6), Dimension.of(6), Dimension.of(1, 7)) + ); + } +} diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ElementTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ElementTest.java new file mode 100644 index 00000000..2e335dee --- /dev/null +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ElementTest.java @@ -0,0 +1,51 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import io.github.sebastiantoepfer.ddd.common.Media; +import org.junit.jupiter.api.Test; + +class ElementTest { + + @Test + void should_had_dimension_of_one_by_default() { + assertThat(new TestElement().dimension(), is(Dimension.of(1))); + } + + private static class TestElement implements Element { + + @Override + public boolean isValidFor(ValidateableCodePoint codePoint) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public > T printOn(T media) { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequenceTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequenceTest.java index 4bd99697..500abb78 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequenceTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/OptionalSequenceTest.java @@ -49,6 +49,14 @@ void should_create_new_optionalsequence() { assertThat(OptionalSequence.of(StringElement.of(".")), is(not(nullValue()))); } + @Test + void should_has_dimension_from_zero_to_max() { + assertThat( + OptionalSequence.of(List.of(StringElement.of("a"), StringElement.of("b"))).dimension(), + is(Dimension.of(0, 2)) + ); + } + @Test void should_be_printable() { assertThat( @@ -65,4 +73,14 @@ void should_be_printable() { ) ); } + + @Test + void should_be_valid_for_every_codepoint() { + assertThat( + OptionalSequence + .of(List.of(StringElement.of("/"), StringElement.of(";"))) + .isValidFor(ValidateableCodePoint.of(0, ',')), + is(true) + ); + } } diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReferenceTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReferenceTest.java index 37411d8d..10478e86 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReferenceTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/RuleReferenceTest.java @@ -47,6 +47,11 @@ void equalsContract() { EqualsVerifier.forClass(RuleReference.class).verify(); } + @Test + void should_has_dimension_of_rulename_length() { + assertThat(RuleReference.of(RuleName.of("rule")).dimension(), is(Dimension.of(4))); + } + @Test void should_be_printable() { assertThat( @@ -60,4 +65,25 @@ void should_be_printable() { ) ); } + + @Test + void should_be_valid_if_codepoint_is_equals_codepoint_at_position() { + final Element element = RuleReference.of(RuleName.of("test")); + assertThat(element.isValidFor(ValidateableCodePoint.of(0, 't')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, 'e')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(2, 's')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(3, 't')), is(true)); + } + + @Test + void should_be_invalid_if_codepoint_is_not_equals_codepoint_at_position() { + final Element element = RuleReference.of(RuleName.of("test")); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, 't')), is(false)); + } + + @Test + void should_be_invalid_if_codepoint_is_out_of_position() { + final Element element = RuleReference.of(RuleName.of("test")); + assertThat(element.isValidFor(ValidateableCodePoint.of(4, 't')), is(false)); + } } diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroupTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroupTest.java index 9d758d8e..fdcd4ec8 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroupTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SequenceGroupTest.java @@ -55,6 +55,51 @@ void should_create() { ); } + @Test + void should_return_dimension_as_sum() { + assertThat( + SequenceGroup + .of( + Alternative.of(StringElement.of("ab"), StringElement.of("cde")), + Alternative.of(StringElement.of("x"), StringElement.of("yz")) + ) + .dimension(), + is(Dimension.of(3, 5)) + ); + } + + @Test + void should_be_valid_if_codepoint_is_equals_codepoint_at_position() { + final Element element = SequenceGroup.of( + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'b'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'c') + ); + assertThat(element.isValidFor(ValidateableCodePoint.of(0, 'a')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, 'b')), is(true)); + assertThat(element.isValidFor(ValidateableCodePoint.of(2, 'c')), is(true)); + } + + @Test + void should_be_invalid_if_codepoint_is_out_of_position() { + final Element element = SequenceGroup.of( + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'b'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'c') + ); + assertThat(element.isValidFor(ValidateableCodePoint.of(3, 'c')), is(false)); + } + + @Test + void should_be_invalid_if_codepoint_is_notequals_codepoint_at_position() { + final Element element = SequenceGroup.of( + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'b'), + NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'c') + ); + assertThat(element.isValidFor(ValidateableCodePoint.of(1, 'B')), is(false)); + } + @Test void should_be_printable() { assertThat( diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetitionTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetitionTest.java index f0b378c7..3c5f9cfd 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetitionTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/SpecificRepetitionTest.java @@ -47,6 +47,54 @@ void should_create_new_element() { assertThat(SpecificRepetition.of(StringElement.of("1"), 1), is(not(nullValue()))); } + @Test + void should_dimension_as_multimple_of() { + assertThat( + SpecificRepetition.of(Alternative.of(StringElement.of("ab"), StringElement.of("cde")), 2).dimension(), + is(Dimension.of(4, 6)) + ); + } + + @Test + void should_be_valid_if_codepoint_is_equals_codepoint_at_position_on_first_repeation() { + assertThat( + SpecificRepetition.of(StringElement.of("1"), 3).isValidFor(ValidateableCodePoint.of(0, '1')), + is(true) + ); + } + + @Test + void should_be_valid_if_codepoint_is_equals_codepoint_at_position_on_any_repeation() { + assertThat( + SpecificRepetition.of(StringElement.of("1"), 3).isValidFor(ValidateableCodePoint.of(1, '1')), + is(true) + ); + } + + @Test + void should_be_valid_if_codepoint_is_equals_codepoint_at_position_on_last_posible_repeation() { + assertThat( + SpecificRepetition.of(StringElement.of("1"), 3).isValidFor(ValidateableCodePoint.of(2, '1')), + is(true) + ); + } + + @Test + void should_be_invalid_if_codepoint_is_notequals_codepoint_at_position_on_any_posible_repeation() { + assertThat( + SpecificRepetition.of(StringElement.of("1"), 3).isValidFor(ValidateableCodePoint.of(1, '2')), + is(false) + ); + } + + @Test + void should_be_invalid_if_codepoint_is_out_of_position() { + assertThat( + SpecificRepetition.of(StringElement.of("1"), 3).isValidFor(ValidateableCodePoint.of(3, '1')), + is(false) + ); + } + @Test void should_be_printable() { assertThat( diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElementTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElementTest.java index f3ef17db..249ac865 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElementTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/StringElementTest.java @@ -27,7 +27,6 @@ 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 nl.jqno.equalsverifier.EqualsVerifier; import org.junit.jupiter.api.Test; @@ -45,23 +44,41 @@ void equalsContract() { } @Test - void should_throw_execption_if_string_has_more_than_one_character() { - final StringElement element = StringElement.of("invalid"); - assertThrows(UnsupportedOperationException.class, () -> element.isValidFor(0x01)); + void should_return_string_length_as_dimension() { + assertThat(StringElement.of("abc").dimension(), is(Dimension.of(3))); + } + + @Test + void should_be_invalid_if_codepoint_is_outside_the_dimension() { + assertThat(StringElement.of("abc").isValidFor(ValidateableCodePoint.of(3, 'a')), is(false)); + } + + @Test + void should_be_valid_if_codepoint_is_equals_codepoint_in_string_at_position() { + assertThat(StringElement.of("abc").isValidFor(ValidateableCodePoint.of(0, 'a')), is(true)); + assertThat(StringElement.of("abc").isValidFor(ValidateableCodePoint.of(1, 'b')), is(true)); + assertThat(StringElement.of("abc").isValidFor(ValidateableCodePoint.of(2, 'c')), is(true)); + } + + @Test + void should_be_invalid_if_codepoint_is_not_equals_codepoint_in_string_at_position() { + assertThat(StringElement.of("abc").isValidFor(ValidateableCodePoint.of(0, 'b')), is(false)); + assertThat(StringElement.of("abc").isValidFor(ValidateableCodePoint.of(1, 'a')), is(false)); + assertThat(StringElement.of("abc").isValidFor(ValidateableCodePoint.of(2, 'b')), is(false)); } @Test void should_be_valid_if_codePoint_is_lowercase_representation() { - assertThat(StringElement.of("A").isValidFor(0x61), is(true)); + assertThat(StringElement.of("A").isValidFor(ValidateableCodePoint.of(0, 0x61)), is(true)); } @Test void should_be_valid_if_codePoint_is_upercase_representation() { - assertThat(StringElement.of("A").isValidFor(0x41), is(true)); + assertThat(StringElement.of("A").isValidFor(ValidateableCodePoint.of(0, 0x41)), is(true)); } @Test void should_be_invalid_if_codePoint_is_neither_upercase_nor_lowercase_representation() { - assertThat(StringElement.of("A").isValidFor(0x42), is(false)); + assertThat(StringElement.of("A").isValidFor(ValidateableCodePoint.of(0, 0x42)), is(false)); } } diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePointTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePointTest.java new file mode 100644 index 00000000..cb7d8b90 --- /dev/null +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValidateableCodePointTest.java @@ -0,0 +1,59 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +class ValidateableCodePointTest { + + @Test + void should_equals_contract() { + EqualsVerifier.forClass(ValidateableCodePoint.class).verify(); + } + + @Test + void should_not_be_creatable_with_position_lower_zero() { + assertThrows(IllegalArgumentException.class, () -> ValidateableCodePoint.of(-1, 0x00)); + } + + @Test + void should_not_be_creatable_with_codepoint_lower_zero() { + assertThrows(IllegalArgumentException.class, () -> ValidateableCodePoint.of(0, -1)); + } + + @Test + void should_return_his_position() { + assertThat(ValidateableCodePoint.of(10, 0x13).position(), is(10)); + } + + @Test + void should_repositionable_by_offset() { + assertThat(ValidateableCodePoint.of(10, 0x13).repositionBackBy(9), is(ValidateableCodePoint.of(1, 0x13))); + } +} diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternativesTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternativesTest.java index a0fe1cfc..1675aabb 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternativesTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/ValueRangeAlternativesTest.java @@ -61,7 +61,7 @@ void should_be_invalid_if_value_too_small() { NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x02), NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x04) ) - .isValidFor(0x01), + .isValidFor(ValidateableCodePoint.of(0, 0x01)), is(false) ); } @@ -74,7 +74,7 @@ void should_be_invalid_if_value_too_big() { NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x02), NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x04) ) - .isValidFor(0x05), + .isValidFor(ValidateableCodePoint.of(0, 0x05)), is(false) ); } @@ -87,7 +87,7 @@ void should_be_valid_if_value_is_in_range() { NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x02), NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x04) ) - .isValidFor(0x03), + .isValidFor(ValidateableCodePoint.of(0, 0x03)), is(true) ); } @@ -100,7 +100,7 @@ void should_be_valid_if_value_is_minimum() { NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x02), NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x04) ) - .isValidFor(0x02), + .isValidFor(ValidateableCodePoint.of(0, 0x02)), is(true) ); } @@ -113,7 +113,7 @@ void should_be_valid_if_value_is_maximum() { NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x02), NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x04) ) - .isValidFor(0x04), + .isValidFor(ValidateableCodePoint.of(0, 0x04)), is(true) ); } @@ -137,4 +137,17 @@ void should_be_printable() { ) ); } + + @Test + void should_return_two_as_dimension() { + assertThat( + ValueRangeAlternatives + .of( + NumericCharacter.of(NumericCharacter.BASE.BINARY, 0b10101), + NumericCharacter.of(NumericCharacter.BASE.BINARY, 0b10111) + ) + .dimension(), + is(Dimension.of(1)) + ); + } } diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetitionTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetitionTest.java index 859f0146..8745067a 100644 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetitionTest.java +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/element/VariableRepetitionTest.java @@ -117,4 +117,54 @@ void should_be_printable_with_between() { ) ); } + + @Test + void should_dimension_as_multimple_of() { + assertThat( + VariableRepetition + .ofBetween(Alternative.of(StringElement.of("ab"), StringElement.of("cde")), 2, 4) + .dimension(), + is(Dimension.of(4, 12)) + ); + } + + @Test + void should_be_valid_if_codepoint_matches_codepoint_at_posion_of_first_repeation() { + assertThat( + VariableRepetition + .ofAtLeast(NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), 2) + .isValidFor(ValidateableCodePoint.of(0, 'a')), + is(true) + ); + } + + @Test + void should_be_valid_if_codepoint_matches_codepoint_at_posion_of_any_repeation() { + assertThat( + VariableRepetition + .ofAtLeast(NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), 2) + .isValidFor(ValidateableCodePoint.of(4, 'a')), + is(true) + ); + } + + @Test + void should_be_invalid_if_codepoint_not_equals_at_posion_for_min_repeation() { + assertThat( + VariableRepetition + .ofAtLeast(NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), 2) + .isValidFor(ValidateableCodePoint.of(1, 'b')), + is(false) + ); + } + + @Test + void should_be_invalod_if_codepoint_out_of_posion() { + assertThat( + VariableRepetition + .ofAtMost(NumericCharacter.of(NumericCharacter.BASE.DECIMAL, 'a'), 2) + .isValidFor(ValidateableCodePoint.of(3, 'a')), + is(false) + ); + } }