From 23c5adb741f55ee37ab59a5bdb2562b1de9b7381 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Thu, 16 Nov 2023 22:15:42 +0100 Subject: [PATCH] add support to read abnf from stream --- .../format/assertion/abnf/reader/ABNF.java | 2 +- .../format/assertion/abnf/reader/ABNFs.java | 46 ++ .../abnf/reader/StreambasedABNF.java | 70 ++++ .../assertion/abnf/reader/TextABNF.java | 7 +- .../assertion/abnf/reader/ABNFsTest.java | 393 ++++++++++++++++++ .../abnf/reader/StreambasedABNFTest.java | 58 +++ .../assertion/abnf/reader/TextABNFTest.java | 388 ----------------- .../src/test/resources/ABNFspec.txt | 25 ++ 8 files changed, 599 insertions(+), 390 deletions(-) create mode 100644 vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFs.java create mode 100644 vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNF.java create mode 100644 vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFsTest.java create mode 100644 vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNFTest.java delete mode 100644 vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNFTest.java create mode 100644 vocabulary-format-assertion/src/test/resources/ABNFspec.txt diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNF.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNF.java index 3b2d3f30..0b72a9a2 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNF.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNF.java @@ -25,6 +25,6 @@ import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.RuleList; -public interface ABNF { +public interface ABNF extends AutoCloseable { RuleList rules(); } diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFs.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFs.java new file mode 100644 index 00000000..32cbc47e --- /dev/null +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFs.java @@ -0,0 +1,46 @@ +/* + * 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 java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +public final class ABNFs { + + public static ABNF of(final CharSequence sequence) { + return TextABNF.of(sequence); + } + + public static ABNF of(final InputStream is, final Charset cs) { + return of(new InputStreamReader(is, cs)); + } + + public static ABNF of(final Reader input) { + return StreambasedABNF.of(input); + } + + private ABNFs() {} +} diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNF.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNF.java new file mode 100644 index 00000000..1f8c2214 --- /dev/null +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNF.java @@ -0,0 +1,70 @@ +/* + * 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.RuleList; +import java.io.IOException; +import java.io.Reader; +import java.util.Objects; +import java.util.logging.Logger; + +final class StreambasedABNF implements ABNF { + + public static ABNF of(final Reader reader) { + return new StreambasedABNF(reader); + } + + private static final Logger LOG = Logger.getLogger(StreambasedABNF.class.getName()); + + private final Reader reader; + + private StreambasedABNF(final Reader reader) { + this.reader = Objects.requireNonNull(reader); + } + + @Override + public void close() throws IOException { + reader.close(); + } + + @Override + public RuleList rules() { + LOG.entering(StreambasedABNF.class.getName(), "rules"); + final RuleList result; + try { + Extractor extractor = RuleListExtractor.of(); + int codePoint; + while ((codePoint = reader.read()) != -1) { + extractor = extractor.append(codePoint); + } + result = extractor.finish().createAs(RuleList.class); + } catch (IOException ex) { + final IllegalArgumentException thrown = new IllegalArgumentException(ex); + LOG.throwing(StreambasedABNF.class.getName(), "rules", thrown); + throw thrown; + } + LOG.exiting(TextABNF.class.getName(), "rules", result); + return result; + } +} diff --git a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNF.java b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNF.java index ab57fa23..d4d4b85f 100644 --- a/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNF.java +++ b/vocabulary-format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNF.java @@ -26,7 +26,7 @@ import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.RuleList; import java.util.logging.Logger; -public final class TextABNF implements ABNF { +final class TextABNF implements ABNF { private static final Logger LOG = Logger.getLogger(TextABNF.class.getName()); @@ -40,6 +40,11 @@ private TextABNF(final CharSequence rules) { this.rules = rules; } + @Override + public void close() { + //nothing to do! + } + @Override public RuleList rules() { LOG.entering(TextABNF.class.getName(), "rules"); diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFsTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFsTest.java new file mode 100644 index 00000000..ebf254d8 --- /dev/null +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/ABNFsTest.java @@ -0,0 +1,393 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.CoreRules; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.Rule; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.RuleList; +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.NumericCharacter; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.OptionalSequence; +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.ValueRangeAlternatives; +import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.VariableRepetition; +import java.nio.charset.StandardCharsets; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.Test; + +class ABNFsTest { + + @Test + void should_create_abnf_rules_from_string() { + //Note: a rule MUST end with crlf!! see rfc5234. lf is already set by the formatting :) + assertThat( + ABNFs + .of( + """ + rulelist = 1*( rule / (*c-wsp c-nl) )\r + rule = rulename defined-as elements c-nl\r + rulename = ALPHA *(ALPHA / DIGIT / "-")\r + defined-as = *c-wsp ("=" / "=/") *c-wsp\r + elements = alternation *c-wsp\r + c-wsp = WSP / (c-nl WSP)\r + c-nl = comment / CRLF\r + comment = ";" *(WSP / VCHAR) CRLF\r + alternation = concatenation\r + *(*c-wsp "/" *c-wsp concatenation)\r + concatenation = repetition *(1*c-wsp repetition)\r + repetition = [repeat] element\r + repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)\r + element = rulename / group / option /\r + char-val / num-val / prose-val\r + group = "(" *c-wsp alternation *c-wsp ")"\r + option = "[" *c-wsp alternation *c-wsp "]"\r + char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE\r + num-val = "%" (bin-val / dec-val / hex-val)\r + bin-val = "b" 1*BIT\r + [ 1*("." 1*BIT) / ("-" 1*BIT) ]\r + dec-val = "d" 1*DIGIT\r + [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]\r + hex-val = "x" 1*HEXDIG\r + [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]\r + """ + ) + .rules(), + isAbnfSpecAsRuleList() + ); + } + + @Test + void should_create_abnf_rules_from_inputstream() { + assertThat( + ABNFs.of(ABNFs.class.getClassLoader().getResourceAsStream("ABNFspec.txt"), StandardCharsets.UTF_8).rules(), + isAbnfSpecAsRuleList() + ); + } + + private static Matcher isAbnfSpecAsRuleList() { + return is( + RuleList.of( + Rule.of( + RuleName.of("rulelist"), + VariableRepetition.ofAtLeast( + SequenceGroup.of( + Alternative.of( + RuleReference.of(RuleName.of("rule")), + SequenceGroup.of( + Concatenation.of( + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + RuleReference.of(RuleName.of("c-nl")) + ) + ) + ) + ), + 1 + ) + ), + Rule.of( + RuleName.of("rule"), + Concatenation.of( + RuleReference.of(RuleName.of("rulename")), + RuleReference.of(RuleName.of("defined-as")), + RuleReference.of(RuleName.of("elements")), + RuleReference.of(RuleName.of("c-nl")) + ) + ), + Rule.of( + RuleName.of("rulename"), + Concatenation.of( + RuleReference.of(CoreRules.ALPHA.asRuleName()), + VariableRepetition.of( + SequenceGroup.of( + Alternative.of( + RuleReference.of(CoreRules.ALPHA.asRuleName()), + RuleReference.of(CoreRules.DIGIT.asRuleName()), + StringElement.of("-") + ) + ) + ) + ) + ), + Rule.of( + RuleName.of("defined-as"), + Concatenation.of( + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + SequenceGroup.of(Alternative.of(StringElement.of("="), StringElement.of("=/"))), + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))) + ) + ), + Rule.of( + RuleName.of("elements"), + Concatenation.of( + RuleReference.of(RuleName.of("alternation")), + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))) + ) + ), + Rule.of( + RuleName.of("c-wsp"), + Alternative.of( + RuleReference.of(RuleName.of("WSP")), + SequenceGroup.of( + Concatenation.of( + RuleReference.of(RuleName.of("c-nl")), + RuleReference.of(CoreRules.WSP.asRuleName()) + ) + ) + ) + ), + Rule.of( + RuleName.of("c-nl"), + Alternative.of( + RuleReference.of(RuleName.of("comment")), + RuleReference.of(CoreRules.CRLF.asRuleName()) + ) + ), + Rule.of( + RuleName.of("comment"), + Concatenation.of( + StringElement.of(";"), + VariableRepetition.of( + SequenceGroup.of( + Alternative.of( + RuleReference.of(CoreRules.WSP.asRuleName()), + RuleReference.of(CoreRules.VCHAR.asRuleName()) + ) + ) + ), + RuleReference.of(CoreRules.CRLF.asRuleName()) + ) + ), + Rule.of( + RuleName.of("alternation"), + Concatenation.of( + RuleReference.of(RuleName.of("concatenation")), + VariableRepetition.of( + SequenceGroup.of( + Concatenation.of( + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + StringElement.of("/"), + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + RuleReference.of(RuleName.of("concatenation")) + ) + ) + ) + ) + ), + Rule.of( + RuleName.of("concatenation"), + Concatenation.of( + RuleReference.of(RuleName.of("repetition")), + VariableRepetition.of( + SequenceGroup.of( + Concatenation.of( + VariableRepetition.ofAtLeast(RuleReference.of(RuleName.of("c-wsp")), 1), + RuleReference.of(RuleName.of("repetition")) + ) + ) + ) + ) + ), + Rule.of( + RuleName.of("repetition"), + Concatenation.of( + OptionalSequence.of(RuleReference.of(RuleName.of("repeat"))), + RuleReference.of(RuleName.of("element")) + ) + ), + Rule.of( + RuleName.of("repeat"), + Alternative.of( + VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.DIGIT.asRuleName()), 1), + SequenceGroup.of( + Concatenation.of( + VariableRepetition.of(RuleReference.of(CoreRules.DIGIT.asRuleName())), + StringElement.of("*"), + VariableRepetition.of(RuleReference.of(CoreRules.DIGIT.asRuleName())) + ) + ) + ) + ), + Rule.of( + RuleName.of("element"), + Alternative.of( + RuleReference.of(RuleName.of("rulename")), + RuleReference.of(RuleName.of("group")), + RuleReference.of(RuleName.of("option")), + RuleReference.of(RuleName.of("char-val")), + RuleReference.of(RuleName.of("num-val")), + RuleReference.of(RuleName.of("prose-val")) + ) + ), + Rule.of( + RuleName.of("group"), + Concatenation.of( + StringElement.of("("), + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + RuleReference.of(RuleName.of("alternation")), + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + StringElement.of(")") + ) + ), + Rule.of( + RuleName.of("option"), + Concatenation.of( + StringElement.of("["), + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + RuleReference.of(RuleName.of("alternation")), + VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), + StringElement.of("]") + ) + ), + Rule.of( + RuleName.of("char-val"), + Concatenation.of( + RuleReference.of(CoreRules.DQUOTE.asRuleName()), + VariableRepetition.of( + SequenceGroup.of( + Alternative.of( + ValueRangeAlternatives.of( + NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x20), + NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x21) + ), + ValueRangeAlternatives.of( + NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x23), + NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x7E) + ) + ) + ) + ), + RuleReference.of(CoreRules.DQUOTE.asRuleName()) + ) + ), + Rule.of( + RuleName.of("num-val"), + Concatenation.of( + StringElement.of("%"), + SequenceGroup.of( + Alternative.of( + RuleReference.of(RuleName.of("bin-val")), + RuleReference.of(RuleName.of("dec-val")), + RuleReference.of(RuleName.of("hex-val")) + ) + ) + ) + ), + Rule.of( + RuleName.of("bin-val"), + Concatenation.of( + StringElement.of("b"), + VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.BIT.asRuleName()), 1), + OptionalSequence.of( + Alternative.of( + VariableRepetition.ofAtLeast( + SequenceGroup.of( + Concatenation.of( + StringElement.of("."), + VariableRepetition.ofAtLeast( + RuleReference.of(CoreRules.BIT.asRuleName()), + 1 + ) + ) + ), + 1 + ), + SequenceGroup.of( + Concatenation.of( + StringElement.of("-"), + VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.BIT.asRuleName()), 1) + ) + ) + ) + ) + ) + ), + Rule.of( + RuleName.of("dec-val"), + Concatenation.of( + StringElement.of("d"), + VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.DIGIT.asRuleName()), 1), + OptionalSequence.of( + Alternative.of( + VariableRepetition.ofAtLeast( + SequenceGroup.of( + Concatenation.of( + StringElement.of("."), + VariableRepetition.ofAtLeast( + RuleReference.of(CoreRules.DIGIT.asRuleName()), + 1 + ) + ) + ), + 1 + ), + SequenceGroup.of( + Concatenation.of( + StringElement.of("-"), + VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.DIGIT.asRuleName()), 1) + ) + ) + ) + ) + ) + ), + Rule.of( + RuleName.of("hex-val"), + Concatenation.of( + StringElement.of("x"), + VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.HEXDIG.asRuleName()), 1), + OptionalSequence.of( + Alternative.of( + VariableRepetition.ofAtLeast( + SequenceGroup.of( + Concatenation.of( + StringElement.of("."), + VariableRepetition.ofAtLeast( + RuleReference.of(CoreRules.HEXDIG.asRuleName()), + 1 + ) + ) + ), + 1 + ), + SequenceGroup.of( + Concatenation.of( + StringElement.of("-"), + VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.HEXDIG.asRuleName()), 1) + ) + ) + ) + ) + ) + ) + ) + ); + } +} diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNFTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNFTest.java new file mode 100644 index 00000000..0c70f651 --- /dev/null +++ b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/StreambasedABNFTest.java @@ -0,0 +1,58 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.io.Reader; +import org.junit.jupiter.api.Test; + +class StreambasedABNFTest { + + @Test + void should_close_underlining_reader() throws Exception { + final ReaderImpl r = new ReaderImpl(); + + StreambasedABNF.of(r).close(); + + assertThat(r.isClosed, is(true)); + } + + private class ReaderImpl extends Reader { + + boolean isClosed = false; + + @Override + public int read(char[] chars, int i, int i1) throws IOException { + return -1; + } + + @Override + public void close() throws IOException { + isClosed = true; + } + } +} diff --git a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNFTest.java b/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNFTest.java deleted file mode 100644 index 13ee520c..00000000 --- a/vocabulary-format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/format/assertion/abnf/reader/TextABNFTest.java +++ /dev/null @@ -1,388 +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 static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.CoreRules; -import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.Rule; -import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.RuleList; -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.NumericCharacter; -import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.OptionalSequence; -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.ValueRangeAlternatives; -import io.github.sebastiantoepfer.jsonschema.vocabulary.format.assertion.abnf.element.VariableRepetition; -import org.junit.jupiter.api.Test; - -class TextABNFTest { - - @Test - void should_create_abnf_rules_from_string() { - //Note: a rule MUST end with crlf!! see rfc5234. lf is already set by the formatting :) - assertThat( - TextABNF - .of( - """ - rulelist = 1*( rule / (*c-wsp c-nl) )\r - rule = rulename defined-as elements c-nl\r - rulename = ALPHA *(ALPHA / DIGIT / "-")\r - defined-as = *c-wsp ("=" / "=/") *c-wsp\r - elements = alternation *c-wsp\r - c-wsp = WSP / (c-nl WSP)\r - c-nl = comment / CRLF\r - comment = ";" *(WSP / VCHAR) CRLF\r - alternation = concatenation\r - *(*c-wsp "/" *c-wsp concatenation)\r - concatenation = repetition *(1*c-wsp repetition)\r - repetition = [repeat] element\r - repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)\r - element = rulename / group / option /\r - char-val / num-val / prose-val\r - group = "(" *c-wsp alternation *c-wsp ")"\r - option = "[" *c-wsp alternation *c-wsp "]"\r - char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE\r - num-val = "%" (bin-val / dec-val / hex-val)\r - bin-val = "b" 1*BIT\r - [ 1*("." 1*BIT) / ("-" 1*BIT) ]\r - dec-val = "d" 1*DIGIT\r - [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]\r - hex-val = "x" 1*HEXDIG\r - [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]\r - """ - ) - .rules(), - is( - RuleList.of( - Rule.of( - RuleName.of("rulelist"), - VariableRepetition.ofAtLeast( - SequenceGroup.of( - Alternative.of( - RuleReference.of(RuleName.of("rule")), - SequenceGroup.of( - Concatenation.of( - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - RuleReference.of(RuleName.of("c-nl")) - ) - ) - ) - ), - 1 - ) - ), - Rule.of( - RuleName.of("rule"), - Concatenation.of( - RuleReference.of(RuleName.of("rulename")), - RuleReference.of(RuleName.of("defined-as")), - RuleReference.of(RuleName.of("elements")), - RuleReference.of(RuleName.of("c-nl")) - ) - ), - Rule.of( - RuleName.of("rulename"), - Concatenation.of( - RuleReference.of(CoreRules.ALPHA.asRuleName()), - VariableRepetition.of( - SequenceGroup.of( - Alternative.of( - RuleReference.of(CoreRules.ALPHA.asRuleName()), - RuleReference.of(CoreRules.DIGIT.asRuleName()), - StringElement.of("-") - ) - ) - ) - ) - ), - Rule.of( - RuleName.of("defined-as"), - Concatenation.of( - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - SequenceGroup.of(Alternative.of(StringElement.of("="), StringElement.of("=/"))), - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))) - ) - ), - Rule.of( - RuleName.of("elements"), - Concatenation.of( - RuleReference.of(RuleName.of("alternation")), - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))) - ) - ), - Rule.of( - RuleName.of("c-wsp"), - Alternative.of( - RuleReference.of(RuleName.of("WSP")), - SequenceGroup.of( - Concatenation.of( - RuleReference.of(RuleName.of("c-nl")), - RuleReference.of(CoreRules.WSP.asRuleName()) - ) - ) - ) - ), - Rule.of( - RuleName.of("c-nl"), - Alternative.of( - RuleReference.of(RuleName.of("comment")), - RuleReference.of(CoreRules.CRLF.asRuleName()) - ) - ), - Rule.of( - RuleName.of("comment"), - Concatenation.of( - StringElement.of(";"), - VariableRepetition.of( - SequenceGroup.of( - Alternative.of( - RuleReference.of(CoreRules.WSP.asRuleName()), - RuleReference.of(CoreRules.VCHAR.asRuleName()) - ) - ) - ), - RuleReference.of(CoreRules.CRLF.asRuleName()) - ) - ), - Rule.of( - RuleName.of("alternation"), - Concatenation.of( - RuleReference.of(RuleName.of("concatenation")), - VariableRepetition.of( - SequenceGroup.of( - Concatenation.of( - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - StringElement.of("/"), - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - RuleReference.of(RuleName.of("concatenation")) - ) - ) - ) - ) - ), - Rule.of( - RuleName.of("concatenation"), - Concatenation.of( - RuleReference.of(RuleName.of("repetition")), - VariableRepetition.of( - SequenceGroup.of( - Concatenation.of( - VariableRepetition.ofAtLeast(RuleReference.of(RuleName.of("c-wsp")), 1), - RuleReference.of(RuleName.of("repetition")) - ) - ) - ) - ) - ), - Rule.of( - RuleName.of("repetition"), - Concatenation.of( - OptionalSequence.of(RuleReference.of(RuleName.of("repeat"))), - RuleReference.of(RuleName.of("element")) - ) - ), - Rule.of( - RuleName.of("repeat"), - Alternative.of( - VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.DIGIT.asRuleName()), 1), - SequenceGroup.of( - Concatenation.of( - VariableRepetition.of(RuleReference.of(CoreRules.DIGIT.asRuleName())), - StringElement.of("*"), - VariableRepetition.of(RuleReference.of(CoreRules.DIGIT.asRuleName())) - ) - ) - ) - ), - Rule.of( - RuleName.of("element"), - Alternative.of( - RuleReference.of(RuleName.of("rulename")), - RuleReference.of(RuleName.of("group")), - RuleReference.of(RuleName.of("option")), - RuleReference.of(RuleName.of("char-val")), - RuleReference.of(RuleName.of("num-val")), - RuleReference.of(RuleName.of("prose-val")) - ) - ), - Rule.of( - RuleName.of("group"), - Concatenation.of( - StringElement.of("("), - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - RuleReference.of(RuleName.of("alternation")), - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - StringElement.of(")") - ) - ), - Rule.of( - RuleName.of("option"), - Concatenation.of( - StringElement.of("["), - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - RuleReference.of(RuleName.of("alternation")), - VariableRepetition.of(RuleReference.of(RuleName.of("c-wsp"))), - StringElement.of("]") - ) - ), - Rule.of( - RuleName.of("char-val"), - Concatenation.of( - RuleReference.of(CoreRules.DQUOTE.asRuleName()), - VariableRepetition.of( - SequenceGroup.of( - Alternative.of( - ValueRangeAlternatives.of( - NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x20), - NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x21) - ), - ValueRangeAlternatives.of( - NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x23), - NumericCharacter.of(NumericCharacter.BASE.HEXADECIMAL, 0x7E) - ) - ) - ) - ), - RuleReference.of(CoreRules.DQUOTE.asRuleName()) - ) - ), - Rule.of( - RuleName.of("num-val"), - Concatenation.of( - StringElement.of("%"), - SequenceGroup.of( - Alternative.of( - RuleReference.of(RuleName.of("bin-val")), - RuleReference.of(RuleName.of("dec-val")), - RuleReference.of(RuleName.of("hex-val")) - ) - ) - ) - ), - Rule.of( - RuleName.of("bin-val"), - Concatenation.of( - StringElement.of("b"), - VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.BIT.asRuleName()), 1), - OptionalSequence.of( - Alternative.of( - VariableRepetition.ofAtLeast( - SequenceGroup.of( - Concatenation.of( - StringElement.of("."), - VariableRepetition.ofAtLeast( - RuleReference.of(CoreRules.BIT.asRuleName()), - 1 - ) - ) - ), - 1 - ), - SequenceGroup.of( - Concatenation.of( - StringElement.of("-"), - VariableRepetition.ofAtLeast( - RuleReference.of(CoreRules.BIT.asRuleName()), - 1 - ) - ) - ) - ) - ) - ) - ), - Rule.of( - RuleName.of("dec-val"), - Concatenation.of( - StringElement.of("d"), - VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.DIGIT.asRuleName()), 1), - OptionalSequence.of( - Alternative.of( - VariableRepetition.ofAtLeast( - SequenceGroup.of( - Concatenation.of( - StringElement.of("."), - VariableRepetition.ofAtLeast( - RuleReference.of(CoreRules.DIGIT.asRuleName()), - 1 - ) - ) - ), - 1 - ), - SequenceGroup.of( - Concatenation.of( - StringElement.of("-"), - VariableRepetition.ofAtLeast( - RuleReference.of(CoreRules.DIGIT.asRuleName()), - 1 - ) - ) - ) - ) - ) - ) - ), - Rule.of( - RuleName.of("hex-val"), - Concatenation.of( - StringElement.of("x"), - VariableRepetition.ofAtLeast(RuleReference.of(CoreRules.HEXDIG.asRuleName()), 1), - OptionalSequence.of( - Alternative.of( - VariableRepetition.ofAtLeast( - SequenceGroup.of( - Concatenation.of( - StringElement.of("."), - VariableRepetition.ofAtLeast( - RuleReference.of(CoreRules.HEXDIG.asRuleName()), - 1 - ) - ) - ), - 1 - ), - SequenceGroup.of( - Concatenation.of( - StringElement.of("-"), - VariableRepetition.ofAtLeast( - RuleReference.of(CoreRules.HEXDIG.asRuleName()), - 1 - ) - ) - ) - ) - ) - ) - ) - ) - ) - ); - } -} diff --git a/vocabulary-format-assertion/src/test/resources/ABNFspec.txt b/vocabulary-format-assertion/src/test/resources/ABNFspec.txt new file mode 100644 index 00000000..3a5ffd54 --- /dev/null +++ b/vocabulary-format-assertion/src/test/resources/ABNFspec.txt @@ -0,0 +1,25 @@ +rulelist = 1*( rule / (*c-wsp c-nl) ) +rule = rulename defined-as elements c-nl +rulename = ALPHA *(ALPHA / DIGIT / "-") +defined-as = *c-wsp ("=" / "=/") *c-wsp +elements = alternation *c-wsp +c-wsp = WSP / (c-nl WSP) +c-nl = comment / CRLF +comment = ";" *(WSP / VCHAR) CRLF +alternation = concatenation + *(*c-wsp "/" *c-wsp concatenation) +concatenation = repetition *(1*c-wsp repetition) +repetition = [repeat] element +repeat = 1*DIGIT / (*DIGIT "*" *DIGIT) +element = rulename / group / option / + char-val / num-val / prose-val +group = "(" *c-wsp alternation *c-wsp ")" +option = "[" *c-wsp alternation *c-wsp "]" +char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE +num-val = "%" (bin-val / dec-val / hex-val) +bin-val = "b" 1*BIT + [ 1*("." 1*BIT) / ("-" 1*BIT) ] +dec-val = "d" 1*DIGIT + [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ] +hex-val = "x" 1*HEXDIG + [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]