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;
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;
42 public class DerivedFromXPathFunctionTest {
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");
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);
60 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
61 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
63 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
64 converterBiMap.put("bar-prefix", BAR_MODULE);
66 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
67 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
69 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
70 buildPathToIdrefLeafNode());
72 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
73 .getFunction(null, null, "derived-from");
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"));
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"));
87 final Function derivedFromOrSelfFunction = normalizedNodeContextSupport.getFunctionContext()
88 .getFunction(null, null, "derived-from-or-self");
89 assertTrue(getDerivedFromResult(derivedFromOrSelfFunction, normalizedNodeContext, "bar-prefix:id-c2"));
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);
98 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
99 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
101 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
102 converterBiMap.put("bar-prefix", BAR_MODULE);
104 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
105 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
107 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
108 buildPathToIdrefLeafNode());
110 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
111 .getFunction(null, null, "derived-from");
113 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "some-identity"));
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);
123 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
124 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode("should be QName"));
126 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
127 converterBiMap.put("bar-prefix", BAR_MODULE);
129 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
130 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
132 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
133 buildPathToIdrefLeafNode());
135 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
136 .getFunction(null, null, "derived-from");
138 assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3"));
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);
148 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
149 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
151 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
152 converterBiMap.put("bar-prefix", BAR_MODULE);
154 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
155 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
157 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
158 buildPathToIdrefLeafNode());
160 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
161 .getFunction(null, null, "derived-from");
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'.",
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);
179 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
180 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
182 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
183 converterBiMap.put("bar-prefix", BAR_MODULE);
185 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
186 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
188 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
189 buildPathToIdrefLeafNode());
191 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
192 .getFunction(null, null, "derived-from");
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());
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);
209 final XPathSchemaContext jaxenSchemaContext = SCHEMA_CONTEXT_FACTORY.createContext(schemaContext);
210 final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(ID_C2_IDENTITY));
212 final BiMap<String, QNameModule> converterBiMap = HashBiMap.create();
213 converterBiMap.put("bar-prefix", BAR_MODULE);
215 final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create(
216 (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap));
218 final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(
219 buildPathToIdrefLeafNode());
221 final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext()
222 .getFunction(null, null, "derived-from");
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"));
235 public void shouldFailOnInvalidNumberOfArguments() throws Exception {
236 final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance();
237 final Function derivedFromFunction = yangFunctionContext.getFunction(null, null, "derived-from");
239 final Context mockedContext = mock(Context.class);
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());
250 public void shouldFailOnInvalidTypeOfArgument() throws Exception {
251 final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance();
252 final Function bitIsSetFunction = yangFunctionContext.getFunction(null, null, "derived-from");
254 final Context mockedContext = mock(Context.class);
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());
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));
269 private static ContainerNode buildMyContainerNode(final Object idrefLeafValue) {
270 final LeafNode<?> idrefLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(IDREF_LEAF))
271 .withValue(idrefLeafValue).build();
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();
278 final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier(
279 new NodeIdentifier(MY_CONTAINER)).withChild(myListNode).build();
280 return myContainerNode;
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();
287 final YangInstanceIdentifier path = YangInstanceIdentifier.of(MY_LIST)
288 .node(NodeIdentifierWithPredicates.of(MY_LIST, keys)).node(IDREF_LEAF);