BUG-4688: switch revisions from Date to Revision
[yangtools.git] / yang / yang-data-jaxen / src / test / java / org / opendaylight / yangtools / yang / data / jaxen / DerivedFromXPathFunctionTest.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. 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
9 package org.opendaylight.yangtools.yang.data.jaxen;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.mockito.Mockito.mock;
17
18 import com.google.common.collect.BiMap;
19 import com.google.common.collect.HashBiMap;
20 import com.google.common.collect.ImmutableList;
21 import com.google.common.collect.ImmutableMap;
22 import com.google.common.collect.Maps;
23 import java.net.URI;
24 import org.jaxen.Context;
25 import org.jaxen.Function;
26 import org.jaxen.FunctionCallException;
27 import org.junit.BeforeClass;
28 import org.junit.Test;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.common.QNameModule;
31 import org.opendaylight.yangtools.yang.common.Revision;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
35 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument;
39 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathSchemaContext;
40 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
43
44 public class DerivedFromXPathFunctionTest {
45
46     private static JaxenSchemaContextFactory jaxenSchemaContextFactory;
47
48     private static QNameModule barModule;
49     private static QName myContainer;
50     private static QName myList;
51     private static QName keyLeaf;
52     private static QName idrefLeaf;
53     private static QName idC2Identity;
54
55     @BeforeClass
56     public static void setup() {
57         jaxenSchemaContextFactory = new JaxenSchemaContextFactory();
58
59         barModule = QNameModule.create(URI.create("bar-ns"), Revision.valueOf("2017-04-03"));
60         myContainer = QName.create(barModule, "my-container");
61         myList = QName.create(barModule, "my-list");
62         keyLeaf = QName.create(barModule, "key-leaf");
63         idrefLeaf = QName.create(barModule, "idref-leaf");
64         idC2Identity = QName.create(barModule, "id-c2");
65     }
66
67     @Test
68     public void testDerivedFromFunction() throws Exception {
69         // also includes test for derived-from-or-self function
70         final SchemaContext schemaContext = YangParserTestUtils.parseYangResources(DerivedFromXPathFunctionTest.class,
71                 "/yang-xpath-functions-test/derived-from-function/foo.yang",
72                 "/yang-xpath-functions-test/derived-from-function/bar.yang");
73         assertNotNull(schemaContext);
74
75         final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext);
76         final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity));
77
78         final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
79         converterBiMap.put("bar-prefix", barModule);
80
81         final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
82                 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
83
84         final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
85                 buildPathToIdrefLeafNode());
86
87         final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
88                 .getFunction(null, null, "derived-from");
89
90         assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3"));
91         assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a4"));
92         assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b2"));
93         assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-b3"));
94         assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "id-b4"));
95
96         assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a1"));
97         assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a2"));
98         assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b1"));
99         assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-c1"));
100         assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-c2"));
101
102         final Function derivedFromOrSelfFunction = normalizedNodeContextSupport.getFunctionContext()
103                 .getFunction(null, null, "derived-from-or-self");
104         assertTrue(getDerivedFromResult(derivedFromOrSelfFunction, normalizedNodeContext, "bar-prefix:id-c2"));
105     }
106
107     @Test
108     public void testInvalidTypeOfCorrespondingSchemaNode() throws Exception {
109         final SchemaContext schemaContext = YangParserTestUtils.parseYangResources(DerivedFromXPathFunctionTest.class,
110                 "/yang-xpath-functions-test/derived-from-function/bar-invalid.yang");
111         assertNotNull(schemaContext);
112
113         final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext);
114         final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity));
115
116         final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
117         converterBiMap.put("bar-prefix", barModule);
118
119         final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
120                 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
121
122         final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
123                 buildPathToIdrefLeafNode());
124
125         final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
126                 .getFunction(null, null, "derived-from");
127
128         assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "some-identity"));
129     }
130
131     @Test
132     public void testInvalidNormalizedNodeValueType() throws Exception {
133         final SchemaContext schemaContext = YangParserTestUtils.parseYangResources(DerivedFromXPathFunctionTest.class,
134                 "/yang-xpath-functions-test/derived-from-function/foo.yang",
135                 "/yang-xpath-functions-test/derived-from-function/bar.yang");
136         assertNotNull(schemaContext);
137
138         final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext);
139         final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode("should be QName"));
140
141         final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
142         converterBiMap.put("bar-prefix", barModule);
143
144         final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
145                 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
146
147         final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
148                 buildPathToIdrefLeafNode());
149
150         final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
151                 .getFunction(null, null, "derived-from");
152
153         assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3"));
154     }
155
156     @Test
157     public void shouldFailOnUnknownPrefixOfIdentity() throws Exception {
158         final SchemaContext schemaContext = YangParserTestUtils.parseYangResources(DerivedFromXPathFunctionTest.class,
159                 "/yang-xpath-functions-test/derived-from-function/foo.yang",
160                 "/yang-xpath-functions-test/derived-from-function/bar.yang");
161         assertNotNull(schemaContext);
162
163         final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext);
164         final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity));
165
166         final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
167         converterBiMap.put("bar-prefix", barModule);
168
169         final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
170                 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
171
172         final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
173                 buildPathToIdrefLeafNode());
174
175         final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
176                 .getFunction(null, null, "derived-from");
177
178         try {
179             getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "unknown-prefix:id-a3");
180             fail("Function call should have failed on unresolved prefix of the identity argument.");
181         } catch (IllegalArgumentException ex) {
182             assertEquals("Cannot resolve prefix 'unknown-prefix' from identity 'unknown-prefix:id-a3'.",
183                 ex.getMessage());
184         }
185     }
186
187     @Test
188     public void shouldFailOnMalformedIdentityArgument() throws Exception {
189         final SchemaContext schemaContext = YangParserTestUtils.parseYangResources(DerivedFromXPathFunctionTest.class,
190                 "/yang-xpath-functions-test/derived-from-function/foo.yang",
191                 "/yang-xpath-functions-test/derived-from-function/bar.yang");
192         assertNotNull(schemaContext);
193
194         final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext);
195         final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity));
196
197         final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
198         converterBiMap.put("bar-prefix", barModule);
199
200         final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
201                 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
202
203         final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
204                 buildPathToIdrefLeafNode());
205
206         final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
207                 .getFunction(null, null, "derived-from");
208
209         try {
210             getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo:bar:id-a3");
211             fail("Function call should have failed on malformed identity argument.");
212         } catch (IllegalArgumentException ex) {
213             assertEquals("Malformed identity argument: foo:bar:id-a3.", ex.getMessage());
214         }
215     }
216
217     @Test
218     public void shouldFailOnUnknownIdentityArgument() throws Exception {
219         final SchemaContext schemaContext = YangParserTestUtils.parseYangResources(DerivedFromXPathFunctionTest.class,
220                 "/yang-xpath-functions-test/derived-from-function/foo.yang",
221                 "/yang-xpath-functions-test/derived-from-function/bar.yang");
222         assertNotNull(schemaContext);
223
224         final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext);
225         final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity));
226
227         final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
228         converterBiMap.put("bar-prefix", barModule);
229
230         final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
231                 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
232
233         final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
234                 buildPathToIdrefLeafNode());
235
236         final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
237                 .getFunction(null, null, "derived-from");
238
239         try {
240             getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a333");
241             fail("Function call should have failed on unknown identity argument.");
242         } catch (IllegalArgumentException ex) {
243             assertTrue(ex.getMessage().startsWith(
244                     "Identity (foo-ns?revision=2017-04-03)id-a333 does not have a corresponding identity schema "
245                     + "node in the module"));
246         }
247     }
248
249     @Test
250     public void shouldFailOnInvalidNumberOfArguments() throws Exception {
251         final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance();
252         final Function derivedFromFunction = yangFunctionContext.getFunction(null, null, "derived-from");
253
254         final Context mockedContext = mock(Context.class);
255
256         try {
257             derivedFromFunction.call(mockedContext, ImmutableList.of("some-identity", "should not be here"));
258             fail("Function call should have failed on invalid number of arguments.");
259         } catch (final FunctionCallException ex) {
260             assertEquals("derived-from() takes two arguments: node-set nodes, string identity.", ex.getMessage());
261         }
262     }
263
264     @Test
265     public void shouldFailOnInvalidTypeOfArgument() throws Exception {
266         final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance();
267         final Function bitIsSetFunction = yangFunctionContext.getFunction(null, null, "derived-from");
268
269         final Context mockedContext = mock(Context.class);
270
271         try {
272             bitIsSetFunction.call(mockedContext, ImmutableList.of(100));
273             fail("Function call should have failed on invalid type of the identity argument.");
274         } catch (final FunctionCallException ex) {
275             assertEquals("Argument 'identity' of derived-from() function should be a String.", ex.getMessage());
276         }
277     }
278
279     private static boolean getDerivedFromResult(final Function derivedFromFunction, final NormalizedNodeContext nnCtx,
280             final String identityArg) throws Exception {
281         return (boolean) derivedFromFunction.call(nnCtx, ImmutableList.of(identityArg));
282     }
283
284     private static ContainerNode buildMyContainerNode(final Object idrefLeafValue) {
285         final LeafNode<?> idrefLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(idrefLeaf))
286                 .withValue(idrefLeafValue).build();
287
288         final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList))
289                 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
290                         new NodeIdentifierWithPredicates(myList, keyLeaf, "key-value"))
291                         .withChild(idrefLeafNode).build()).build();
292
293         final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier(
294                 new NodeIdentifier(myContainer)).withChild(myListNode).build();
295         return myContainerNode;
296     }
297
298     private static YangInstanceIdentifier buildPathToIdrefLeafNode() {
299         final ImmutableMap.Builder<QName, Object> builder = ImmutableMap.builder();
300         final ImmutableMap<QName, Object> keys = builder.put(keyLeaf, "key-value").build();
301
302         final YangInstanceIdentifier path = YangInstanceIdentifier.of(myList)
303                 .node(new NodeIdentifierWithPredicates(myList, keys)).node(idrefLeaf);
304         return path;
305     }
306 }