2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.model.util;
10 import static org.hamcrest.CoreMatchers.startsWith;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.jupiter.api.Assertions.assertEquals;
13 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
14 import static org.junit.jupiter.api.Assertions.assertThrows;
16 import org.junit.jupiter.api.BeforeAll;
17 import org.junit.jupiter.api.Test;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
21 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
22 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.Module;
25 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
26 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
28 class LeafrefStaticAnalysisTest {
29 private static final QName FOO = QName.create("leafrefs", "foo");
31 private static EffectiveModelContext context;
32 private static GroupingDefinition grp;
33 private static ListSchemaNode foo;
34 private static ContainerSchemaNode bar;
35 private static Module module;
38 static void beforeClass() {
39 context = YangParserTestUtils.parseYangResource("/leafrefs.yang");
40 module = context.getModules().iterator().next();
42 foo = assertInstanceOf(ListSchemaNode.class, module.getDataChildByName(FOO));
43 bar = assertInstanceOf(ContainerSchemaNode.class, foo.getDataChildByName(QName.create(FOO, "bar")));
44 grp = module.getGroupings().iterator().next();
48 void testGrpOuterId() {
49 final var leaf = assertInstanceOf(LeafSchemaNode.class, grp.getDataChildByName(QName.create(FOO, "outer-id")));
50 // Cannot be found as the reference goes outside of the grouping
51 final var stack = SchemaInferenceStack.of(context);
52 stack.enterGrouping(grp.getQName());
53 stack.enterSchemaTree(QName.create(FOO, "outer-id"));
54 assertThrowsInvalidPath(stack, leaf);
58 void testFooOuterId() {
59 final var leaf = assertInstanceOf(LeafSchemaNode.class, bar.getDataChildByName(QName.create(FOO, "outer-id")));
60 final var leafType = assertInstanceOf(LeafrefTypeDefinition.class, leaf.getType());
61 final var stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
62 stack.enterSchemaTree(QName.create(FOO, "outer-id"));
63 final var found = assertInstanceOf(LeafSchemaNode.class,
64 stack.resolvePathExpression(leafType.getPathStatement()));
65 assertEquals(QName.create(FOO, "id"), found.getQName());
69 void testGrpOuterIndirectProp() {
70 final var leaf = assertInstanceOf(LeafSchemaNode.class,
71 grp.getDataChildByName(QName.create(FOO, "outer-indirect-prop")));
72 final var stack = SchemaInferenceStack.of(context);
73 stack.enterGrouping(grp.getQName());
74 stack.enterSchemaTree(QName.create(FOO, "outer-indirect-prop"));
75 // Cannot resolve deref outer-id
76 assertThrowsInvalidPath(stack, leaf);
80 void testFooOuterIndirectProp() {
81 final var leaf = assertInstanceOf(LeafSchemaNode.class,
82 bar.getDataChildByName(QName.create(FOO, "outer-indirect-prop")));
83 final var leafType = assertInstanceOf(LeafrefTypeDefinition.class, leaf.getType());
84 final var stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
85 stack.enterSchemaTree(QName.create(FOO, "outer-indirect-prop"));
86 final var found = assertInstanceOf(LeafSchemaNode.class,
87 stack.resolvePathExpression(leafType.getPathStatement()));
88 assertEquals(QName.create(FOO, "prop"), found.getQName());
92 void testGrpIndirect() {
93 final var leaf = assertInstanceOf(LeafSchemaNode.class, grp.getDataChildByName(QName.create(FOO, "indirect")));
94 final var leafType = assertInstanceOf(LeafrefTypeDefinition.class, leaf.getType());
95 final var stack = SchemaInferenceStack.of(context);
96 stack.enterGrouping(grp.getQName());
97 stack.enterSchemaTree(QName.create(FOO, "indirect"));
98 final var found = assertInstanceOf(LeafSchemaNode.class,
99 stack.resolvePathExpression(leafType.getPathStatement()));
100 assertEquals(QName.create(FOO, "prop"), found.getQName());
104 void testFooIndirect() {
105 final var leaf = assertInstanceOf(LeafSchemaNode.class, bar.getDataChildByName(QName.create(FOO, "indirect")));
106 final var leafType = assertInstanceOf(LeafrefTypeDefinition.class, leaf.getType());
107 final var stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
108 stack.enterSchemaTree(QName.create(FOO, "indirect"));
109 final var found = assertInstanceOf(LeafSchemaNode.class,
110 stack.resolvePathExpression(leafType.getPathStatement()));
111 assertEquals(QName.create(FOO, "prop"), found.getQName());
115 void testGrpDerefNonExistent() {
116 final var leaf = assertInstanceOf(LeafSchemaNode.class,
117 grp.getDataChildByName(QName.create(FOO, "deref-non-existent")));
118 final var stack = SchemaInferenceStack.of(context);
119 stack.enterGrouping(grp.getQName());
120 stack.enterSchemaTree(QName.create(FOO, "deref-non-existent"));
121 assertThrowsMissingXyzzy(stack, leaf, "grouping (leafrefs)grp");
125 void testFooDerefNonExistent() {
126 final var leaf = assertInstanceOf(LeafSchemaNode.class,
127 bar.getDataChildByName(QName.create(FOO, "deref-non-existent")));
128 final var stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
129 stack.enterSchemaTree(QName.create(FOO, "deref-non-existent"));
130 assertThrowsMissingXyzzy(stack, leaf, "schema parent (leafrefs)bar");
134 void testGrpNonExistentDeref() {
135 final var leaf = assertInstanceOf(LeafSchemaNode.class,
136 grp.getDataChildByName(QName.create(FOO, "non-existent-deref")));
137 final var stack = SchemaInferenceStack.of(context);
138 stack.enterGrouping(grp.getQName());
139 stack.enterSchemaTree(QName.create(FOO, "non-existent-deref"));
140 assertThrowsMissingXyzzy(stack, leaf, "schema parent (leafrefs)foo");
144 void testFooNonExistentDeref() {
145 final var leaf = assertInstanceOf(LeafSchemaNode.class,
146 bar.getDataChildByName(QName.create(FOO, "non-existent-deref")));
147 final var stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
148 stack.enterSchemaTree(QName.create(FOO, "non-existent-deref"));
149 assertThrowsMissingXyzzy(stack, leaf, "schema parent (leafrefs)foo");
153 void testNonExistentRelativeXpath() {
154 final var leaf = assertInstanceOf(LeafSchemaNode.class,
155 bar.getDataChildByName(QName.create(FOO, "indirect-with-current")));
156 final var stack = SchemaInferenceStack.ofDataTreePath(context,
157 foo.getQName(), bar.getQName(), QName.create(FOO, "indirect-with-current"));
158 assertThrowsMissingChild(stack, leaf, "(leafrefs)n", "module (leafrefs)leafrefs");
161 private static void assertThrowsInvalidPath(final SchemaInferenceStack stack, final LeafSchemaNode leaf) {
162 final var ex = assertThrowsIAE(stack, leaf);
163 assertThat(ex.getMessage(), startsWith("Illegal parent access in "));
164 final var cause = assertInstanceOf(IllegalStateException.class, ex.getCause());
165 assertEquals("Unexpected current EmptyGroupingEffectiveStatement{argument=(leafrefs)grp}", cause.getMessage());
168 private static void assertThrowsMissingXyzzy(final SchemaInferenceStack stack, final LeafSchemaNode leaf,
169 final String parentDesc) {
170 assertThrowsMissingChild(stack, leaf, "(leafrefs)xyzzy", parentDesc);
173 private static void assertThrowsMissingChild(final SchemaInferenceStack stack, final LeafSchemaNode leaf,
174 final String childName, final String parentDesc) {
175 assertEquals("Data tree child " + childName + " not present in " + parentDesc,
176 assertThrowsIAE(stack, leaf).getMessage());
179 private static IllegalArgumentException assertThrowsIAE(final SchemaInferenceStack stack,
180 final LeafSchemaNode leaf) {
181 return assertThrows(IllegalArgumentException.class, () -> stack.resolvePathExpression(
182 assertInstanceOf(LeafrefTypeDefinition.class, leaf.getType()).getPathStatement()));