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