Improve SchemaInferenceStack error reporting
[yangtools.git] / model / yang-model-util / src / test / java / org / opendaylight / yangtools / yang / model / util / LeafrefStaticAnalysisTest.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.model.util;
9
10 import static org.hamcrest.CoreMatchers.instanceOf;
11 import static org.hamcrest.CoreMatchers.startsWith;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.hamcrest.Matchers.isA;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertThrows;
16
17 import org.junit.BeforeClass;
18 import org.junit.Test;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
22 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
23 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.Module;
26 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
28 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
29
30 public class LeafrefStaticAnalysisTest {
31     private static final QName FOO = QName.create("leafrefs", "foo");
32
33     private static EffectiveModelContext context;
34     private static GroupingDefinition grp;
35     private static ListSchemaNode foo;
36     private static ContainerSchemaNode bar;
37     private static Module module;
38
39     @BeforeClass
40     public static void beforeClass() {
41         context = YangParserTestUtils.parseYangResource("/leafrefs.yang");
42         module = context.getModules().iterator().next();
43
44         foo = (ListSchemaNode) module.findDataChildByName(FOO).get();
45         bar = (ContainerSchemaNode) foo.findDataChildByName(QName.create(FOO, "bar")).get();
46         grp = module.getGroupings().iterator().next();
47     }
48
49     @Test
50     public void testGrpOuterId() {
51         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(QName.create(FOO, "outer-id")).get();
52         // Cannot be found as the reference goes outside of the grouping
53         final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
54         stack.enterGrouping(grp.getQName());
55         stack.enterSchemaTree(QName.create(FOO, "outer-id"));
56         assertThrowsInvalidPath(stack, leaf);
57     }
58
59     @Test
60     public void testFooOuterId() {
61         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(QName.create(FOO, "outer-id")).get();
62         final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
63         stack.enterSchemaTree(QName.create(FOO, "outer-id"));
64         final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
65                 .getPathStatement());
66
67         assertThat(found, isA(LeafSchemaNode.class));
68         assertEquals(QName.create(FOO, "id"), found.getQName());
69     }
70
71     @Test
72     public void testGrpOuterIndirectProp() {
73         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(
74             QName.create(FOO, "outer-indirect-prop")).get();
75         final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
76         stack.enterGrouping(grp.getQName());
77         stack.enterSchemaTree(QName.create(FOO, "outer-indirect-prop"));
78         // Cannot resolve deref outer-id
79         assertThrowsInvalidPath(stack, leaf);
80     }
81
82     @Test
83     public void testFooOuterIndirectProp() {
84         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
85             QName.create(FOO, "outer-indirect-prop")).get();
86         final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
87         stack.enterSchemaTree(QName.create(FOO, "outer-indirect-prop"));
88         final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
89                 .getPathStatement());
90
91         assertThat(found, isA(LeafSchemaNode.class));
92         assertEquals(QName.create(FOO, "prop"), found.getQName());
93     }
94
95     @Test
96     public void testGrpIndirect() {
97         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(QName.create(FOO, "indirect")).get();
98         final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
99         stack.enterGrouping(grp.getQName());
100         stack.enterSchemaTree(QName.create(FOO, "indirect"));
101         final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
102                 .getPathStatement());
103
104         assertThat(found, isA(LeafSchemaNode.class));
105         assertEquals(QName.create(FOO, "prop"), found.getQName());
106     }
107
108     @Test
109     public void testFooIndirect() {
110         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(QName.create(FOO, "indirect")).get();
111         final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
112         stack.enterSchemaTree(QName.create(FOO, "indirect"));
113         final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
114                 .getPathStatement());
115
116         assertThat(found, isA(LeafSchemaNode.class));
117         assertEquals(QName.create(FOO, "prop"), found.getQName());
118     }
119
120     @Test
121     public void testGrpDerefNonExistent() {
122         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(
123             QName.create(FOO, "deref-non-existent")).get();
124         final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
125         stack.enterGrouping(grp.getQName());
126         stack.enterSchemaTree(QName.create(FOO, "deref-non-existent"));
127         assertThrowsMissingXyzzy(stack, leaf, "grouping (leafrefs)grp");
128     }
129
130     @Test
131     public void testFooDerefNonExistent() {
132         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
133             QName.create(FOO, "deref-non-existent")).get();
134         final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
135         stack.enterSchemaTree(QName.create(FOO, "deref-non-existent"));
136         assertThrowsMissingXyzzy(stack, leaf, "schema parent (leafrefs)bar");
137     }
138
139     @Test
140     public void testGrpNonExistentDeref() {
141         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(
142             QName.create(FOO, "non-existent-deref")).get();
143         final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
144         stack.enterGrouping(grp.getQName());
145         stack.enterSchemaTree(QName.create(FOO, "non-existent-deref"));
146         assertThrowsMissingXyzzy(stack, leaf, "schema parent (leafrefs)foo");
147     }
148
149     @Test
150     public void testFooNonExistentDeref() {
151         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
152             QName.create(FOO, "non-existent-deref")).get();
153         final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
154         stack.enterSchemaTree(QName.create(FOO, "non-existent-deref"));
155         assertThrowsMissingXyzzy(stack, leaf, "schema parent (leafrefs)foo");
156     }
157
158     @Test
159     public void testNonExistentRelativeXpath() {
160         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
161                 QName.create(FOO, "indirect-with-current")).get();
162         final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context,
163             foo.getQName(), bar.getQName(), QName.create(FOO, "indirect-with-current"));
164         assertThrowsMissingChild(stack, leaf, "(leafrefs)n", "module (leafrefs)leafrefs");
165     }
166
167     private static void assertThrowsInvalidPath(final SchemaInferenceStack stack, final LeafSchemaNode leaf) {
168         final IllegalArgumentException ex = assertThrowsIAE(stack, leaf);
169         assertThat(ex.getMessage(), startsWith("Illegal parent access in "));
170         final Throwable cause = ex.getCause();
171         assertThat(cause, instanceOf(IllegalStateException.class));
172         assertEquals("Unexpected current GroupingEffectiveStatementImpl[qname=(leafrefs)grp]", cause.getMessage());
173     }
174
175     private static void assertThrowsMissingXyzzy(final SchemaInferenceStack stack, final LeafSchemaNode leaf,
176             final String parentDesc) {
177         assertThrowsMissingChild(stack, leaf, "(leafrefs)xyzzy", parentDesc);
178     }
179
180     private static void assertThrowsMissingChild(final SchemaInferenceStack stack, final LeafSchemaNode leaf,
181             final String childName, final String parentDesc) {
182         assertEquals("Data tree child " + childName + " not present in " + parentDesc,
183             assertThrowsIAE(stack, leaf).getMessage());
184     }
185
186     private static IllegalArgumentException assertThrowsIAE(final SchemaInferenceStack stack,
187             final LeafSchemaNode leaf) {
188         return assertThrows(IllegalArgumentException.class,
189             () -> stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
190     }
191 }