From: Robert Varga Date: Thu, 16 Aug 2018 12:30:11 +0000 (+0200) Subject: Fix unique argument parser X-Git-Tag: v2.0.6.2~4 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=yangtools.git;a=commitdiff_plain;h=5eda1057f1a1ada0b154c8029debf0effbb269e9 Fix unique argument parser Unique argument can use horizontal tabs and line-breaks as separators in addition to spaces. Deal with them instead of rejecting input. Change-Id: I5fb6137b9b73c5c844a05cc59fb9261868834a24 JIRA: YANGTOOLS-893 Signed-off-by: Robert Varga (cherry picked from commit 68de00c780737c1844f7d045d6f1ecfd0e83f957) --- diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/unique/UniqueStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/unique/UniqueStatementSupport.java index 1ecada93c6..1030e4a39a 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/unique/UniqueStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/unique/UniqueStatementSupport.java @@ -7,11 +7,13 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.unique; +import com.google.common.base.CharMatcher; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import java.util.Collection; import java.util.HashSet; import java.util.Set; +import java.util.regex.Pattern; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; @@ -23,10 +25,16 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; -public final class UniqueStatementSupport - extends AbstractStatementSupport, UniqueStatement, - EffectiveStatement, UniqueStatement>> { - private static final Splitter SPACE_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults(); +public final class UniqueStatementSupport extends AbstractStatementSupport, UniqueStatement, + EffectiveStatement, UniqueStatement>> { + /** + * Support 'sep' ABNF rule in RFC7950 section 14. CRLF pattern is used to squash line-break from CRLF to LF form + * and then we use SEP_SPLITTER, which can operate on single characters. + */ + private static final Pattern CRLF_PATTERN = Pattern.compile("\r\n", Pattern.LITERAL); + private static final Splitter SEP_SPLITTER = Splitter.on(CharMatcher.anyOf(" \t\n").precomputed()) + .omitEmptyStrings(); + private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder( YangStmtMapping.UNIQUE) .build(); @@ -41,8 +49,7 @@ public final class UniqueStatementSupport } @Override - public Collection parseArgumentValue(final StmtContext ctx, - final String value) { + public Collection parseArgumentValue(final StmtContext ctx, final String value) { final Collection uniqueConstraints = parseUniqueConstraintArgument(ctx, value); SourceException.throwIf(uniqueConstraints.isEmpty(), ctx.getStatementSourceReference(), "Invalid argument value '%s' of unique statement. The value must contains at least " @@ -57,8 +64,8 @@ public final class UniqueStatementSupport @Override public EffectiveStatement, UniqueStatement> createEffective( - final StmtContext, UniqueStatement, - EffectiveStatement, UniqueStatement>> ctx) { + final StmtContext, UniqueStatement, EffectiveStatement, + UniqueStatement>> ctx) { return new UniqueEffectiveStatementImpl(ctx); } @@ -67,15 +74,18 @@ public final class UniqueStatementSupport return SUBSTATEMENT_VALIDATOR; } - private static Collection parseUniqueConstraintArgument( - final StmtContext ctx, final String argumentValue) { - final Set uniqueConstraintNodes = new HashSet<>(); - for (final String uniqueArgToken : SPACE_SPLITTER.split(argumentValue)) { + private static Collection parseUniqueConstraintArgument(final StmtContext ctx, + final String argumentValue) { + // deal with 'line-break' rule, which is either "\n" or "\r\n", but not "\r" + final String nocrlf = CRLF_PATTERN.matcher(argumentValue).replaceAll("\n"); + + final Set uniqueConstraintNodes = new HashSet<>(); + for (final String uniqueArgToken : SEP_SPLITTER.split(nocrlf)) { final SchemaNodeIdentifier nodeIdentifier = ArgumentUtils.nodeIdentifierFromPath(ctx, uniqueArgToken); SourceException.throwIf(nodeIdentifier.isAbsolute(), ctx.getStatementSourceReference(), "Unique statement argument '%s' contains schema node identifier '%s' " + "which is not in the descendant node identifier form.", argumentValue, uniqueArgToken); - uniqueConstraintNodes.add((SchemaNodeIdentifier.Relative) nodeIdentifier); + uniqueConstraintNodes.add((Relative) nodeIdentifier); } return ImmutableSet.copyOf(uniqueConstraintNodes); } diff --git a/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT893Test.java b/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT893Test.java new file mode 100644 index 0000000000..4c40428fee --- /dev/null +++ b/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT893Test.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.stmt; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.opendaylight.yangtools.yang.parser.spi.meta.SomeModifiersUnresolvedException; + +public class YT893Test { + @Test(expected = SomeModifiersUnresolvedException.class) + public void testCR() throws Exception { + StmtTestUtils.parseYangSource("/bugs/YT893/cr.yang"); + } + + @Test + public void testCRLF() throws Exception { + assertNotNull(StmtTestUtils.parseYangSource("/bugs/YT893/crlf.yang")); + } + + @Test + public void testHTAB() throws Exception { + assertNotNull(StmtTestUtils.parseYangSource("/bugs/YT893/ht.yang")); + } + + @Test + public void testLF() throws Exception { + assertNotNull(StmtTestUtils.parseYangSource("/bugs/YT893/lf.yang")); + } +} diff --git a/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/cr.yang b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/cr.yang new file mode 100644 index 0000000000..ed724ac806 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/cr.yang @@ -0,0 +1,15 @@ +module cr { + namespace "urn:cr"; + prefix cr; + + list foo { + unique "a b"; + + leaf a { + type string; + } + leaf b { + type string; + } + } +} diff --git a/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/crlf.yang b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/crlf.yang new file mode 100644 index 0000000000..063f54abec --- /dev/null +++ b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/crlf.yang @@ -0,0 +1,16 @@ +module crlf { + namespace "urn:crlf"; + prefix crlf; + + list foo { + unique "a + b"; + + leaf a { + type string; + } + leaf b { + type string; + } + } +} diff --git a/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/ht.yang b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/ht.yang new file mode 100644 index 0000000000..8e035feef6 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/ht.yang @@ -0,0 +1,15 @@ +module ht { + namespace "urn:ht"; + prefix ht; + + list foo { + unique "a b"; + + leaf a { + type string; + } + leaf b { + type string; + } + } +} diff --git a/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/lf.yang b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/lf.yang new file mode 100644 index 0000000000..b1d559f658 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/test/resources/bugs/YT893/lf.yang @@ -0,0 +1,16 @@ +module lf { + namespace "urn:lf"; + prefix lf; + + list foo { + unique "a + b"; + + leaf a { + type string; + } + leaf b { + type string; + } + } +}