From: Robert Varga Date: Mon, 24 Jun 2019 16:01:16 +0000 (+0200) Subject: Allow Errata 5617 expressions in leafref X-Git-Tag: v4.0.4~18 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=2788395b6edecb26c9c2e59b2ab94275e8276987;p=yangtools.git Allow Errata 5617 expressions in leafref This updates PathExpression interface to allow expressing leafref paths which start with a deref(...) function call, as proposed by https://www.rfc-editor.org/errata/eid5617. This unfortunately necessitates breaking the API contract of this interface, as the original object model could not express these. JIRA: YANGTOOLS-968 Change-Id: I3a193d338de5a82b95d2dd6cc5200e77032e67d9 Signed-off-by: Robert Varga Signed-off-by: Peter Suna --- diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/PathExpression.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/PathExpression.java index fef07e744d..5673a24117 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/PathExpression.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/PathExpression.java @@ -7,13 +7,20 @@ */ package org.opendaylight.yangtools.yang.model.api; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.base.MoreObjects.ToStringHelper; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator; import org.opendaylight.yangtools.yang.xpath.api.YangFunction; import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Relative; +import org.opendaylight.yangtools.yang.xpath.api.YangPathExpr; import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis; import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression; @@ -39,6 +46,103 @@ import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression; @Beta @NonNullByDefault public interface PathExpression extends Immutable { + /** + * Abstract base class for expressing steps of a PathExpression. + */ + abstract class Steps { + Steps() { + // Prevent external subclassing + } + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(@Nullable Object obj); + + @Override + public final String toString() { + return addToStringAttributes(MoreObjects.toStringHelper(this)).toString(); + } + + abstract ToStringHelper addToStringAttributes(ToStringHelper helper); + } + + /** + * Steps of a PathExpression which is a LocationPath, corresponding to RFC7950 base specification. + */ + final class LocationPathSteps extends Steps { + private final YangLocationPath locationPath; + + public LocationPathSteps(final YangLocationPath locationPath) { + this.locationPath = requireNonNull(locationPath); + } + + public YangLocationPath getLocationPath() { + return locationPath; + } + + @Override + public int hashCode() { + return locationPath.hashCode(); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj + || obj instanceof LocationPathSteps && locationPath.equals(((LocationPathSteps) obj).locationPath); + } + + @Override + ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return helper.add("locationPath", locationPath); + } + } + + /** + * Steps of a PathExpression which is a combination of {@code deref()} function call and a relative path, + * corresponding to Errata 5617. + */ + final class DerefSteps extends Steps { + private final Relative derefArgument; + private final Relative relativePath; + + public DerefSteps(final Relative derefArgument, final Relative relativePath) { + this.derefArgument = requireNonNull(derefArgument); + this.relativePath = requireNonNull(relativePath); + } + + public Relative getDerefArgument() { + return derefArgument; + } + + public Relative getRelativePath() { + return relativePath; + } + + @Override + public int hashCode() { + return 31 * derefArgument.hashCode() + relativePath.hashCode(); + } + + @Override + public boolean equals(@Nullable final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof DerefSteps)) { + return false; + } + final DerefSteps other = (DerefSteps) obj; + return derefArgument.equals(other.derefArgument) && relativePath.equals(other.relativePath); + } + + @Override + ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return helper.add("derefArgument", derefArgument).add("relativePath", relativePath); + } + } + /** * Returns the path expression formatted string as is defined in model. For example: * {@code /prefix:container/prefix:container::cond[when()=foo]/prefix:leaf} @@ -48,13 +152,14 @@ public interface PathExpression extends Immutable { String getOriginalString(); /** - * Return the {@link YangLocationPath} of this expression. + * Return the path of this expression, which can either be a {@link YangLocationPath} (compliant to RFC7950) or + * a {@link YangPathExpr} with filter being an invocation of {@link YangFunction#DEREF}. * - * @return The location path + * @return The path's steps * @throws UnsupportedOperationException if the implementation has not parsed the string. Implementations are * strongly encouraged to perform proper parsing. */ - YangLocationPath getLocation(); + Steps getSteps(); /** * Returns true if the XPapth starts in root of YANG model, otherwise returns false. @@ -62,6 +167,7 @@ public interface PathExpression extends Immutable { * @return true if the XPapth starts in root of YANG model, otherwise returns false */ default boolean isAbsolute() { - return getLocation().isAbsolute(); + final Steps steps = getSteps(); + return steps instanceof LocationPathSteps && ((LocationPathSteps) steps).getLocationPath().isAbsolute(); } } diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PathExpressionImpl.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PathExpressionImpl.java index ca35335b2d..70782bdd1e 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PathExpressionImpl.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PathExpressionImpl.java @@ -7,11 +7,12 @@ */ package org.opendaylight.yangtools.yang.model.util; +import static java.util.Objects.requireNonNull; + import com.google.common.base.MoreObjects.ToStringHelper; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; /** * A simple XPathExpression implementation. @@ -22,20 +23,21 @@ import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; @Deprecated @NonNullByDefault public final class PathExpressionImpl extends AbstractPathExpression { - private final @Nullable YangLocationPath location; + private final @Nullable Steps steps; private final boolean absolute; @SuppressFBWarnings(value = "NP_STORE_INTO_NONNULL_FIELD", justification = "Non-grok on SpotBugs part") public PathExpressionImpl(final String xpath, final boolean absolute) { super(xpath); this.absolute = absolute; - this.location = null; + this.steps = null; } - public PathExpressionImpl(final String xpath, final YangLocationPath location) { + public PathExpressionImpl(final String xpath, final Steps steps) { super(xpath); - this.absolute = location.isAbsolute(); - this.location = location; + this.steps = requireNonNull(steps); + this.absolute = steps instanceof LocationPathSteps + && ((LocationPathSteps) steps).getLocationPath().isAbsolute(); } @Override @@ -44,16 +46,16 @@ public final class PathExpressionImpl extends AbstractPathExpression { } @Override - public YangLocationPath getLocation() { - final YangLocationPath loc = location; + public Steps getSteps() { + final Steps loc = steps; if (loc == null) { - throw new UnsupportedOperationException("Location has not been provided"); + throw new UnsupportedOperationException("Steps have not been provided"); } return loc; } @Override protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { - return super.addToStringAttributes(helper.add("absolute", absolute).add("location", location)); + return super.addToStringAttributes(helper.add("absolute", absolute).add("steps", steps)); } } diff --git a/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathLexer.g4 b/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathLexer.g4 index 3d63ee9eea..7b88efe352 100644 --- a/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathLexer.g4 +++ b/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathLexer.g4 @@ -10,6 +10,7 @@ LEFT_PARENTHESIS : '(' ; RIGHT_PARENTHESIS : ')' ; CURRENT_KEYWORD : 'current'; +DEREF_KEYWORD : 'deref'; SEP: [ \n\r\t]+ ; IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_\-.]*; diff --git a/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathParser.g4 b/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathParser.g4 index 1ae7f9ef67..816f638f04 100644 --- a/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathParser.g4 +++ b/yang/yang-parser-rfc7950/src/main/antlr4/org/opendaylight/yangtools/antlrv4/code/gen/LeafRefPathParser.g4 @@ -4,7 +4,11 @@ options { tokenVocab = LeafRefPathLexer; } -path_arg : (absolute_path | relative_path) EOF; +path_arg : (deref_expr | path_str) EOF; + +deref_expr : deref_function_invocation SEP? SLASH SEP? relative_path; + +path_str : absolute_path | relative_path; absolute_path : (SLASH node_identifier (path_predicate)*)+; @@ -24,7 +28,9 @@ node_identifier : (prefix COLON)? identifier; current_function_invocation : CURRENT_KEYWORD SEP? LEFT_PARENTHESIS SEP? RIGHT_PARENTHESIS; +deref_function_invocation : DEREF_KEYWORD SEP? LEFT_PARENTHESIS SEP? relative_path SEP? RIGHT_PARENTHESIS; + prefix : identifier; -identifier: IDENTIFIER | CURRENT_KEYWORD; +identifier: IDENTIFIER | CURRENT_KEYWORD | DEREF_KEYWORD; diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/ParsedPathExpression.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/ParsedPathExpression.java index 21ee7f757f..6c482a6254 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/ParsedPathExpression.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/ParsedPathExpression.java @@ -10,25 +10,25 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.path; import static java.util.Objects.requireNonNull; import com.google.common.base.MoreObjects.ToStringHelper; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.opendaylight.yangtools.yang.model.util.AbstractPathExpression; -import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; +@NonNullByDefault final class ParsedPathExpression extends AbstractPathExpression { - private final @NonNull YangLocationPath location; + private final Steps steps; - ParsedPathExpression(final YangLocationPath location, final String originalString) { + ParsedPathExpression(final Steps steps, final String originalString) { super(originalString); - this.location = requireNonNull(location); + this.steps = requireNonNull(steps); } @Override - public YangLocationPath getLocation() { - return location; + public Steps getSteps() { + return steps; } @Override protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { - return super.addToStringAttributes(helper.add("location", location)); + return super.addToStringAttributes(helper.add("steps", steps)); } } diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParser.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParser.java index e02e6fce25..83d3d122ee 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParser.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParser.java @@ -20,17 +20,23 @@ import org.antlr.v4.runtime.tree.TerminalNode; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathLexer; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Absolute_pathContext; +import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Deref_exprContext; +import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Deref_function_invocationContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Descendant_pathContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Node_identifierContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Path_argContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Path_equality_exprContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Path_key_exprContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Path_predicateContext; +import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Path_strContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Rel_path_keyexprContext; import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Relative_pathContext; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.UnqualifiedQName; import org.opendaylight.yangtools.yang.model.api.PathExpression; +import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps; +import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps; +import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps; import org.opendaylight.yangtools.yang.parser.rfc7950.antlr.SourceExceptionParser; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; @@ -76,16 +82,30 @@ class PathExpressionParser { ctx.getStatementSourceReference()); final ParseTree childPath = path.getChild(0); - final YangLocationPath location; + final Steps steps; + if (childPath instanceof Path_strContext) { + steps = new LocationPathSteps(parsePathStr(ctx, pathArg, (Path_strContext) childPath)); + } else if (childPath instanceof Deref_exprContext) { + final Deref_exprContext deref = (Deref_exprContext) childPath; + steps = new DerefSteps(parseRelative(ctx, pathArg, + getChild(deref, 0, Deref_function_invocationContext.class).getChild(Relative_pathContext.class, 0)), + parseRelative(ctx, pathArg, getChild(deref, deref.getChildCount() - 1, Relative_pathContext.class))); + } else { + throw new IllegalStateException("Unsupported child " + childPath); + } + return new ParsedPathExpression(steps, pathArg); + } + + private static YangLocationPath parsePathStr(final StmtContext ctx, final String pathArg, + final Path_strContext path) { + final ParseTree childPath = path.getChild(0); if (childPath instanceof Absolute_pathContext) { - location = parseAbsolute(ctx, pathArg, (Absolute_pathContext) childPath); + return parseAbsolute(ctx, pathArg, (Absolute_pathContext) childPath); } else if (childPath instanceof Relative_pathContext) { - location = parseRelative(ctx, pathArg, (Relative_pathContext) childPath); + return parseRelative(ctx, pathArg, (Relative_pathContext) childPath); } else { throw new IllegalStateException("Unsupported child " + childPath); } - - return new ParsedPathExpression(location, pathArg); } private static Absolute parseAbsolute(final StmtContext ctx, final String pathArg, @@ -97,14 +117,20 @@ class PathExpressionParser { private static Relative parseRelative(final StmtContext ctx, final String pathArg, final Relative_pathContext relative) { - final List steps = new ArrayList<>(); - final int relativeChildren = relative.getChildCount(); verify(relativeChildren % 2 != 0, "Unexpected child count %s", relativeChildren); - for (int i = 0; i < relativeChildren / 2; ++i) { + + final int stepCount = relativeChildren / 2; + final List steps = new ArrayList<>(stepCount); + for (int i = 0; i < stepCount; ++i) { steps.add(YangXPathAxis.PARENT.asStep()); } + return parseRelative(ctx, pathArg, relative, steps); + } + private static Relative parseRelative(final StmtContext ctx, final String pathArg, + final Relative_pathContext relative, final List steps) { + final int relativeChildren = relative.getChildCount(); final Descendant_pathContext descendant = getChild(relative, relativeChildren - 1, Descendant_pathContext.class); final Node_identifierContext qname = getChild(descendant, 0, Node_identifierContext.class); diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/UnparsedPathExpression.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/UnparsedPathExpression.java index 643691d933..1f363a8687 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/UnparsedPathExpression.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/UnparsedPathExpression.java @@ -12,7 +12,6 @@ import static java.util.Objects.requireNonNull; import com.google.common.base.MoreObjects.ToStringHelper; import org.opendaylight.yangtools.yang.model.util.AbstractPathExpression; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.ArgumentUtils; -import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; final class UnparsedPathExpression extends AbstractPathExpression { private final RuntimeException cause; @@ -30,7 +29,7 @@ final class UnparsedPathExpression extends AbstractPathExpression { } @Override - public YangLocationPath getLocation() { + public Steps getSteps() { throw new UnsupportedOperationException("Expression '" + getOriginalString() + "' was not parsed", cause); } diff --git a/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParserTest.java b/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParserTest.java index 07ee8c3486..b1d4d6471c 100644 --- a/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParserTest.java +++ b/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/path/PathExpressionParserTest.java @@ -8,7 +8,9 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.path; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.isA; import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @@ -19,9 +21,15 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.opendaylight.yangtools.yang.common.UnqualifiedQName; +import org.opendaylight.yangtools.yang.model.api.PathExpression; +import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps; +import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath; +import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis; @RunWith(MockitoJUnitRunner.StrictStubs.class) public class PathExpressionParserTest { @@ -29,6 +37,7 @@ public class PathExpressionParserTest { private StmtContext ctx; @Mock private StatementSourceReference ref; + private final PathExpressionParser parser = new PathExpressionParser(); @Before public void before() { @@ -37,21 +46,23 @@ public class PathExpressionParserTest { @Test public void testDerefPath() { - try { - // deref() is not valid as per RFC7950, but YANGTOOLS-968 would allow it - new PathExpressionParser().parseExpression(ctx, "deref(../id)/../type"); - fail("SourceException should have been thrown"); - } catch (SourceException e) { - assertSame(ref, e.getSourceReference()); - assertThat(e.getMessage(), startsWith("mismatched input '(' expecting ")); - assertThat(e.getMessage(), containsString(" at 1:5 [at ")); - } + // deref() is not valid as per RFC7950, but we tolarate it. + final PathExpression deref = parser.parseExpression(ctx, "deref(../id)/../type"); + + final Steps steps = deref.getSteps(); + assertThat(steps, isA(DerefSteps.class)); + + final DerefSteps derefSteps = (DerefSteps) steps; + assertEquals(YangLocationPath.relative(YangXPathAxis.PARENT.asStep(), + YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("type"))), derefSteps.getRelativePath()); + assertEquals(YangLocationPath.relative(YangXPathAxis.PARENT.asStep(), + YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("id"))), derefSteps.getDerefArgument()); } @Test public void testInvalidLeftParent() { try { - new PathExpressionParser().parseExpression(ctx, "foo("); + parser.parseExpression(ctx, "foo("); fail("SourceException should have been thrown"); } catch (SourceException e) { assertSame(ref, e.getSourceReference()); @@ -63,7 +74,7 @@ public class PathExpressionParserTest { @Test public void testInvalidRightParent() { try { - new PathExpressionParser().parseExpression(ctx, "foo)"); + parser.parseExpression(ctx, "foo)"); fail("SourceException should have been thrown"); } catch (SourceException e) { assertSame(ref, e.getSourceReference()); @@ -75,7 +86,7 @@ public class PathExpressionParserTest { @Test public void testInvalidIdentifier() { try { - new PathExpressionParser().parseExpression(ctx, "foo%"); + parser.parseExpression(ctx, "foo%"); fail("SourceException should have been thrown"); } catch (SourceException e) { assertSame(ref, e.getSourceReference()); diff --git a/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/EffectiveStatementTypeTest.java b/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/EffectiveStatementTypeTest.java index 75c31dcb8c..ee76fdc092 100644 --- a/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/EffectiveStatementTypeTest.java +++ b/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/EffectiveStatementTypeTest.java @@ -321,6 +321,34 @@ public class EffectiveStatementTypeTest { assertTrue(leafrefEff.equals(leafrefEff)); } + @Test + public void testLeafrefWithDeref() { + currentLeaf = (LeafSchemaNode) types.getDataChildByName(QName + .create(types.getQNameModule(), "leaf-leafref-deref")); + assertNotNull(currentLeaf.getType()); + + final LeafrefTypeDefinition leafrefEff = ((LeafrefSpecificationEffectiveStatement) + ((LeafEffectiveStatement) currentLeaf).effectiveSubstatements().iterator().next()) + .getTypeDefinition(); + + assertEquals("deref(../container-test)/leaf-test", + leafrefEff.getPathStatement().getOriginalString()); + assertNull(leafrefEff.getBaseType()); + assertEquals(Optional.empty(), leafrefEff.getUnits()); + assertEquals(Optional.empty(), leafrefEff.getDefaultValue()); + assertNotNull(leafrefEff.toString()); + assertEquals("leafref", leafrefEff.getQName().getLocalName()); + assertEquals(Status.CURRENT, leafrefEff.getStatus()); + assertNotNull(leafrefEff.getUnknownSchemaNodes()); + assertEquals("leafref", leafrefEff.getPath().getLastComponent().getLocalName()); + assertFalse(leafrefEff.getDescription().isPresent()); + assertFalse(leafrefEff.getReference().isPresent()); + assertNotNull(leafrefEff.hashCode()); + assertFalse(leafrefEff.equals(null)); + assertFalse(leafrefEff.equals("test")); + assertTrue(leafrefEff.equals(leafrefEff)); + } + @Test public void testIntAll() { currentLeaf = (LeafSchemaNode) types.getDataChildByName(QName.create(types.getQNameModule(), "leaf-int8")); diff --git a/yang/yang-parser-rfc7950/src/test/resources/type-tests/types.yang b/yang/yang-parser-rfc7950/src/test/resources/type-tests/types.yang index 7f8ed0cc96..4e62f014a5 100644 --- a/yang/yang-parser-rfc7950/src/test/resources/type-tests/types.yang +++ b/yang/yang-parser-rfc7950/src/test/resources/type-tests/types.yang @@ -135,6 +135,12 @@ module types { } } + leaf leaf-leafref-deref { + type leafref { + path "deref(../container-test)/leaf-test"; + } + } + container container-test { leaf leaf-test { type int8; diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java index df27ca2c57..2049c805fc 100644 --- a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java @@ -54,6 +54,10 @@ public class YangFunctionCallExpr implements YangExpr { return new YangFunctionCallExpr(name); } + public static YangFunctionCallExpr of(final QName name, final YangExpr argument) { + return new WithArgs(name, ImmutableList.of(argument)); + } + public static YangFunctionCallExpr of(final QName name, final List arguments) { return arguments.isEmpty() ? of(name) : new WithArgs(name, arguments); }