2 * Copyright (c) 2017 Cisco Systems, Inc. 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.data.jaxen;
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;
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 org.jaxen.Context;
23 import org.jaxen.Function;
24 import org.jaxen.FunctionCallException;
25 import org.junit.Test;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.common.QNameModule;
28 import org.opendaylight.yangtools.yang.common.Revision;
29 import org.opendaylight.yangtools.yang.common.XMLNamespace;
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.SystemMapNode;
36 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
37 import org.opendaylight.yangtools.yang.data.jaxen.api.XPathDocument;
38 import org.opendaylight.yangtools.yang.data.jaxen.api.XPathSchemaContext;
39 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
40 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
42 public class DerivedFromXPathFunctionTest {
44 private static final JaxenSchemaContextFactory SCHEMA_CONTEXT_FACTORY = new JaxenSchemaContextFactory();
45 private static final QNameModule BAR_MODULE =
46 QNameModule.create(XMLNamespace.of("bar-ns"), Revision.of("2017-04-03"));
47 private static final QName MY_CONTAINER = QName.create(BAR_MODULE, "my-container");
48 private static final QName MY_LIST = QName.create(BAR_MODULE, "my-list");
49 private static final QName KEY_LEAF = QName.create(BAR_MODULE, "key-leaf");
50 private static final QName IDREF_LEAF = QName.create(BAR_MODULE, "idref-leaf");
51 private static final QName ID_C2_IDENTITY = QName.create(BAR_MODULE, "id-c2");
54 public void testDerivedFromFunction() throws Exception {
55 // also includes test for derived-from-or-self function
56 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYangResources(
57 DerivedFromXPathFunctionTest.class,
58 "/yang-xpath-functions-test/derived-from-function/foo.yang",
59 "/yang-xpath-functions-test/derived-from-function/bar.yang");
60 assertNotNull(schemaContext);
62 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
63 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
65 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
66 converterBiMap.put("bar-prefix", BAR_MODULE);
68 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
69 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
71 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
72 buildPathToIdrefLeafNode());
74 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
75 .getFunction(null, null, "derived-from");
77 assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3"));
78 assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a4"));
79 assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b2"));
80 assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-b3"));
81 assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "id-b4"));
83 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a1"));
84 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a2"));
85 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b1"));
86 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-c1"));
87 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-c2"));
89 final Function derivedFromOrSelfFunction = normalizedNodeContextSupport.getFunctionContext()
90 .getFunction(null, null, "derived-from-or-self");
91 assertTrue(getDerivedFromResult(derivedFromOrSelfFunction, normalizedNodeContext, "bar-prefix:id-c2"));
95 public void testInvalidTypeOfCorrespondingSchemaNode() throws Exception {
96 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYangResources(
97 DerivedFromXPathFunctionTest.class, "/yang-xpath-functions-test/derived-from-function/bar-invalid.yang");
98 assertNotNull(schemaContext);
100 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
101 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
103 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
104 converterBiMap.put("bar-prefix", BAR_MODULE);
106 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
107 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
109 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
110 buildPathToIdrefLeafNode());
112 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
113 .getFunction(null, null, "derived-from");
115 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "some-identity"));
119 public void testInvalidNormalizedNodeValueType() throws Exception {
120 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYangResources(
121 DerivedFromXPathFunctionTest.class,
122 "/yang-xpath-functions-test/derived-from-function/foo.yang",
123 "/yang-xpath-functions-test/derived-from-function/bar.yang");
124 assertNotNull(schemaContext);
126 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
127 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode("should be QName"));
129 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
130 converterBiMap.put("bar-prefix", BAR_MODULE);
132 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
133 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
135 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
136 buildPathToIdrefLeafNode());
138 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
139 .getFunction(null, null, "derived-from");
141 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3"));
145 public void shouldFailOnUnknownPrefixOfIdentity() throws Exception {
146 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYangResources(
147 DerivedFromXPathFunctionTest.class,
148 "/yang-xpath-functions-test/derived-from-function/foo.yang",
149 "/yang-xpath-functions-test/derived-from-function/bar.yang");
150 assertNotNull(schemaContext);
152 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
153 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
155 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
156 converterBiMap.put("bar-prefix", BAR_MODULE);
158 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
159 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
161 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
162 buildPathToIdrefLeafNode());
164 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
165 .getFunction(null, null, "derived-from");
168 getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "unknown-prefix:id-a3");
169 fail("Function call should have failed on unresolved prefix of the identity argument.");
170 } catch (IllegalArgumentException ex) {
171 assertEquals("Cannot resolve prefix 'unknown-prefix' from identity 'unknown-prefix:id-a3'.",
177 public void shouldFailOnMalformedIdentityArgument() throws Exception {
178 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYangResources(
179 DerivedFromXPathFunctionTest.class,
180 "/yang-xpath-functions-test/derived-from-function/foo.yang",
181 "/yang-xpath-functions-test/derived-from-function/bar.yang");
182 assertNotNull(schemaContext);
184 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
185 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
187 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
188 converterBiMap.put("bar-prefix", BAR_MODULE);
190 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
191 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
193 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
194 buildPathToIdrefLeafNode());
196 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
197 .getFunction(null, null, "derived-from");
200 getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo:bar:id-a3");
201 fail("Function call should have failed on malformed identity argument.");
202 } catch (IllegalArgumentException ex) {
203 assertEquals("Malformed identity argument: foo:bar:id-a3.", ex.getMessage());
208 public void shouldFailOnUnknownIdentityArgument() throws Exception {
209 final EffectiveModelContext schemaContext = YangParserTestUtils.parseYangResources(
210 DerivedFromXPathFunctionTest.class,
211 "/yang-xpath-functions-test/derived-from-function/foo.yang",
212 "/yang-xpath-functions-test/derived-from-function/bar.yang");
213 assertNotNull(schemaContext);
215 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
216 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
218 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
219 converterBiMap.put("bar-prefix", BAR_MODULE);
221 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
222 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
224 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
225 buildPathToIdrefLeafNode());
227 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
228 .getFunction(null, null, "derived-from");
231 getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a333");
232 fail("Function call should have failed on unknown identity argument.");
233 } catch (IllegalArgumentException ex) {
234 assertTrue(ex.getMessage().startsWith(
235 "Identity (foo-ns?revision=2017-04-03)id-a333 does not have a corresponding identity schema "
236 + "node in the module"));
241 public void shouldFailOnInvalidNumberOfArguments() throws Exception {
242 final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance();
243 final Function derivedFromFunction = yangFunctionContext.getFunction(null, null, "derived-from");
245 final Context mockedContext = mock(Context.class);
248 derivedFromFunction.call(mockedContext, ImmutableList.of("some-identity", "should not be here"));
249 fail("Function call should have failed on invalid number of arguments.");
250 } catch (final FunctionCallException ex) {
251 assertEquals("derived-from() takes two arguments: node-set nodes, string identity", ex.getMessage());
256 public void shouldFailOnInvalidTypeOfArgument() throws Exception {
257 final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance();
258 final Function bitIsSetFunction = yangFunctionContext.getFunction(null, null, "derived-from");
260 final Context mockedContext = mock(Context.class);
263 bitIsSetFunction.call(mockedContext, ImmutableList.of(100));
264 fail("Function call should have failed on invalid type of the identity argument.");
265 } catch (final FunctionCallException ex) {
266 assertEquals("Argument 'identity' of derived-from() function should be a String.", ex.getMessage());
270 private static boolean getDerivedFromResult(final Function derivedFromFunction, final NormalizedNodeContext nnCtx,
271 final String identityArg) throws Exception {
272 return (boolean) derivedFromFunction.call(nnCtx, ImmutableList.of(identityArg));
275 private static ContainerNode buildMyContainerNode(final Object idrefLeafValue) {
276 final LeafNode<?> idrefLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(IDREF_LEAF))
277 .withValue(idrefLeafValue).build();
279 final SystemMapNode myListNode = Builders.mapBuilder()
280 .withNodeIdentifier(new NodeIdentifier(MY_LIST))
281 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
282 NodeIdentifierWithPredicates.of(MY_LIST, KEY_LEAF, "key-value"))
283 .withChild(idrefLeafNode).build()).build();
285 final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier(
286 new NodeIdentifier(MY_CONTAINER)).withChild(myListNode).build();
287 return myContainerNode;
290 private static YangInstanceIdentifier buildPathToIdrefLeafNode() {
291 final ImmutableMap.Builder<QName, Object> builder = ImmutableMap.builder();
292 final ImmutableMap<QName, Object> keys = builder.put(KEY_LEAF, "key-value").build();
294 final YangInstanceIdentifier path = YangInstanceIdentifier.of(MY_LIST)
295 .node(NodeIdentifierWithPredicates.of(MY_LIST, keys)).node(IDREF_LEAF);