From 64b6f4d58b2e676b98233030aca74df92003aad8 Mon Sep 17 00:00:00 2001 From: Igor Foltin Date: Fri, 21 Apr 2017 17:06:37 +0200 Subject: [PATCH] YANG XPath functions - unit tests and bugfix Add more unit tests for YANG XPath functions in yang-data-jaxen. Fix deref function for leafrefs that reference a leaf-list node. Change-Id: I7bfe90a3a1a101b95a3b8ea3b1dd42963e5ea264 Signed-off-by: Igor Foltin (cherry picked from commit 8539503c13746b5b765c9aa9d249a85462f69d7f) --- .../yang/data/jaxen/YangFunctionContext.java | 62 +-- .../data/jaxen/BitIsSetXPathFunctionTest.java | 234 +++++++++++ .../data/jaxen/DerefXPathFunctionTest.java | 292 ++++++++++++++ .../jaxen/DerivedFromXPathFunctionTest.java | 307 +++++++++++++++ .../jaxen/EnumValueXPathFunctionTest.java | 203 ++++++++++ .../data/jaxen/ReMatchXPathFunctionTest.java | 76 ++++ .../data/jaxen/YangXPathFunctionsTest.java | 371 ------------------ .../bit-is-set-function/foo-invalid.yang | 21 + .../deref-function-leafref/foo.yang | 15 +- .../derived-from-function/bar-invalid.yang | 21 + .../enum-value-function/foo-invalid.yang | 21 + 11 files changed, 1227 insertions(+), 396 deletions(-) create mode 100644 yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/BitIsSetXPathFunctionTest.java create mode 100644 yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerefXPathFunctionTest.java create mode 100644 yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerivedFromXPathFunctionTest.java create mode 100644 yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/EnumValueXPathFunctionTest.java create mode 100644 yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/ReMatchXPathFunctionTest.java delete mode 100644 yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/YangXPathFunctionsTest.java create mode 100644 yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/bit-is-set-function/foo-invalid.yang create mode 100644 yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/derived-from-function/bar-invalid.yang create mode 100644 yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/enum-value-function/foo-invalid.yang diff --git a/yang/yang-data-jaxen/src/main/java/org/opendaylight/yangtools/yang/data/jaxen/YangFunctionContext.java b/yang/yang-data-jaxen/src/main/java/org/opendaylight/yangtools/yang/data/jaxen/YangFunctionContext.java index a335a5099f..429697d2f7 100644 --- a/yang/yang-data-jaxen/src/main/java/org/opendaylight/yangtools/yang/data/jaxen/YangFunctionContext.java +++ b/yang/yang-data-jaxen/src/main/java/org/opendaylight/yangtools/yang/data/jaxen/YangFunctionContext.java @@ -29,6 +29,8 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -113,19 +115,7 @@ final class YangFunctionContext implements FunctionContext { if (correspondingSchemaNode.getType() instanceof LeafrefTypeDefinition) { final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) correspondingSchemaNode.getType(); final RevisionAwareXPath xPath = leafrefType.getPathStatement(); - if (xPath.isAbsolute()) { - final NormalizedNode referencedNode = getNodeReferencedByAbsoluteLeafref( - xPath, currentNodeContext, schemaContext, correspondingSchemaNode); - if (referencedNode.getValue().equals(nodeValue)) { - return referencedNode; - } - } else { - final NormalizedNode referencedNode = getNodeReferencedByRelativeLeafref( - xPath, currentNodeContext, schemaContext, correspondingSchemaNode); - if (referencedNode.getValue().equals(nodeValue)) { - return referencedNode; - } - } + return getNodeReferencedByLeafref(xPath, currentNodeContext, schemaContext, correspondingSchemaNode, nodeValue); } return null; @@ -142,8 +132,24 @@ final class YangFunctionContext implements FunctionContext { if (possibleNode.isPresent()) { return possibleNode.get(); } + } + + return null; + } + + private static NormalizedNode getNodeReferencedByLeafref(final RevisionAwareXPath xPath, + final NormalizedNodeContext currentNodeContext, final SchemaContext schemaContext, + final TypedSchemaNode correspondingSchemaNode, final Object nodeValue) { + final NormalizedNode referencedNode = xPath.isAbsolute() ? getNodeReferencedByAbsoluteLeafref(xPath, + currentNodeContext, schemaContext, correspondingSchemaNode) : getNodeReferencedByRelativeLeafref(xPath, + currentNodeContext, schemaContext, correspondingSchemaNode); + + if (referencedNode instanceof LeafSetNode) { + return getReferencedLeafSetEntryNode((LeafSetNode) referencedNode, nodeValue); + } - return null; + if (referencedNode instanceof LeafNode && referencedNode.getValue().equals(nodeValue)) { + return referencedNode; } return null; @@ -163,8 +169,6 @@ final class YangFunctionContext implements FunctionContext { if (possibleNode.isPresent()) { return possibleNode.get(); } - - return null; } return null; @@ -195,6 +199,17 @@ final class YangFunctionContext implements FunctionContext { return null; } + private static LeafSetEntryNode getReferencedLeafSetEntryNode(final LeafSetNode referencedNode, + final Object currentNodeValue) { + for (final LeafSetEntryNode entryNode : referencedNode.getValue()) { + if (currentNodeValue.equals(entryNode.getValue())) { + return entryNode; + } + } + + return null; + } + // derived-from(node-set nodes, string identity) function as per https://tools.ietf.org/html/rfc7950#section-10.4.1 private static final Function DERIVED_FROM_FUNCTION = (context, args) -> { if (args == null || args.size() != 1) { @@ -313,7 +328,8 @@ final class YangFunctionContext implements FunctionContext { } } - throw new IllegalArgumentException("Cannot resolve prefix '%s' from identity '%s'."); + throw new IllegalArgumentException(String.format("Cannot resolve prefix '%s' from identity '%s'.", + identityPrefixAndName.get(0), identity)); } if (identityPrefixAndName.size() == 1) { // without prefix @@ -335,8 +351,6 @@ final class YangFunctionContext implements FunctionContext { " identity schema node in the module %s.", identityQName, module)); } - - // enum-value(node-set nodes) function as per https://tools.ietf.org/html/rfc7950#section-10.5.1 private static final Function ENUM_VALUE_FUNCTION = (context, args) -> { if (!args.isEmpty()) { @@ -350,16 +364,18 @@ final class YangFunctionContext implements FunctionContext { final TypedSchemaNode correspondingSchemaNode = getCorrespondingTypedSchemaNode(schemaContext, currentNodeContext); - if (!(correspondingSchemaNode.getType() instanceof EnumTypeDefinition)) { + final TypeDefinition nodeType = correspondingSchemaNode.getType(); + if (!(nodeType instanceof EnumTypeDefinition)) { return DOUBLE_NAN; } - if (!(currentNodeContext.getNode().getValue() instanceof String)) { + final Object nodeValue = currentNodeContext.getNode().getValue(); + if (!(nodeValue instanceof String)) { return DOUBLE_NAN; } - final EnumTypeDefinition enumerationType = (EnumTypeDefinition) correspondingSchemaNode.getType(); - final String enumName = (String) currentNodeContext.getNode().getValue(); + final EnumTypeDefinition enumerationType = (EnumTypeDefinition) nodeType; + final String enumName = (String) nodeValue; return getEnumValue(enumerationType, enumName); }; diff --git a/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/BitIsSetXPathFunctionTest.java b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/BitIsSetXPathFunctionTest.java new file mode 100644 index 0000000000..b654b378a2 --- /dev/null +++ b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/BitIsSetXPathFunctionTest.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.yangtools.yang.data.jaxen; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import java.net.URI; +import java.text.ParseException; +import java.util.Set; +import org.jaxen.Context; +import org.jaxen.Function; +import org.jaxen.FunctionCallException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathSchemaContext; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class BitIsSetXPathFunctionTest { + + private static JaxenSchemaContextFactory jaxenSchemaContextFactory; + + private static QNameModule fooModule; + private static QName myContainer; + private static QName myList; + private static QName flags; + private static QName ordinaryLeaf; + + @BeforeClass + public static void setup() throws ParseException { + jaxenSchemaContextFactory = new JaxenSchemaContextFactory(); + + fooModule = QNameModule.create(URI.create("foo-ns"), + SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); + myContainer = QName.create(fooModule, "my-container"); + myList = QName.create(fooModule, "my-list"); + flags = QName.create(fooModule, "flags"); + ordinaryLeaf = QName.create(fooModule, "ordinary-leaf"); + } + + @Test + public void testBitIsSetFunction() throws Exception { + final Set setOfBits = ImmutableSet.of("UP", "PROMISCUOUS"); + + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/bit-is-set-function/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(setOfBits)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToFlagsLeafNode(setOfBits)); + + final Function bitIsSetFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "bit-is-set"); + boolean bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("UP")); + assertTrue(bitIsSetResult); + bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("PROMISCUOUS")); + assertTrue(bitIsSetResult); + bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("DISABLED")); + assertFalse(bitIsSetResult); + } + + @Test + public void testInvalidTypeOfCorrespondingSchemaNode() throws Exception { + final Set setOfBits = ImmutableSet.of("UP", "PROMISCUOUS"); + + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/bit-is-set-function/foo-invalid.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(setOfBits)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToFlagsLeafNode(setOfBits)); + + final Function bitIsSetFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "bit-is-set"); + boolean bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("UP")); + assertFalse(bitIsSetResult); + } + + @Test + public void testInvalidNormalizedNodeValueType() throws Exception { + final String invalidNodeValueType = "value of invalid type"; + + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/bit-is-set-function/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(invalidNodeValueType)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToFlagsLeafNode(invalidNodeValueType)); + + final Function bitIsSetFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "bit-is-set"); + boolean bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("UP")); + assertFalse(bitIsSetResult); + } + + @Test + public void shouldFailOnUnknownBitArgument() throws Exception { + final Set setOfBits = ImmutableSet.of("UP", "PROMISCUOUS"); + + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/bit-is-set-function/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(setOfBits)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToFlagsLeafNode(setOfBits)); + + final Function bitIsSetFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "bit-is-set"); + try { + bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("UNKNOWN")); + fail("Function call should have failed on unknown bit-name argument"); + } catch (final IllegalStateException ex) { + assertTrue(ex.getMessage().startsWith("Bit UNKNOWN does not belong to bits")); + } + } + + @Test + public void shouldFailOnInvalidNumberOfArguments() throws Exception { + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function bitIsSetFunction = yangFunctionContext.getFunction(null, null, "bit-is-set"); + + final Context mockedContext = mock(Context.class); + + try { + bitIsSetFunction.call(mockedContext, ImmutableList.of("bit-a", "bit-b")); + fail("Function call should have failed on invalid number of arguments."); + } catch (final FunctionCallException ex) { + assertEquals("bit-is-set() takes two arguments: node-set nodes, string bit-name", ex.getMessage()); + } + } + + @Test + public void shouldFailOnInvalidTypeOfArgument() throws Exception { + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function bitIsSetFunction = yangFunctionContext.getFunction(null, null, "bit-is-set"); + + final Context mockedContext = mock(Context.class); + + try { + bitIsSetFunction.call(mockedContext, ImmutableList.of(100)); + fail("Function call should have failed on invalid type of the bit-name argument."); + } catch (final FunctionCallException ex) { + assertEquals("Argument bit-name of bit-is-set() function should be a String", ex.getMessage()); + } + } + + private static ContainerNode buildMyContainerNode(final Object keyLeafValue) { + final LeafNode ordinaryLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(ordinaryLeaf)) + .withValue("test-value").build(); + + final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) + .withChild(Builders.mapEntryBuilder().withNodeIdentifier( + new NodeIdentifierWithPredicates(myList, flags, keyLeafValue)) + .withChild(ordinaryLeafNode).build()).build(); + + final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myContainer)).withChild(myListNode).build(); + + return myContainerNode; + } + + private static YangInstanceIdentifier buildPathToFlagsLeafNode(final Object keyLeafValue) { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + final ImmutableMap keys = builder.put(flags, keyLeafValue).build(); + + final YangInstanceIdentifier path = YangInstanceIdentifier.of(myList) + .node(new NodeIdentifierWithPredicates(myList, keys)).node(flags); + return path; + } +} \ No newline at end of file diff --git a/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerefXPathFunctionTest.java b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerefXPathFunctionTest.java new file mode 100644 index 0000000000..539d9fc803 --- /dev/null +++ b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerefXPathFunctionTest.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.yangtools.yang.data.jaxen; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import java.net.URI; +import java.text.ParseException; +import java.util.Map; +import org.jaxen.Function; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathSchemaContext; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class DerefXPathFunctionTest { + + private static JaxenSchemaContextFactory jaxenSchemaContextFactory; + + private static QNameModule fooModule; + private static QName myContainer; + private static QName myInnerContainer; + private static QName myList; + private static QName keyLeafA; + private static QName keyLeafB; + private static QName iidLeaf; + private static QName referencedLeaf; + private static QName referencedLeafList; + private static QName absLeafrefLeaf; + private static QName relLeafrefLeaf; + private static QName leafListLeafrefLeaf; + private static QName ordinaryLeafA; + private static QName ordinaryLeafB; + + @BeforeClass + public static void setup() throws ParseException { + jaxenSchemaContextFactory = new JaxenSchemaContextFactory(); + + fooModule = QNameModule.create(URI.create("foo-ns"), + SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); + myContainer = QName.create(fooModule, "my-container"); + myInnerContainer = QName.create(fooModule, "my-inner-container"); + myList = QName.create(fooModule, "my-list"); + keyLeafA = QName.create(fooModule, "key-leaf-a"); + keyLeafB = QName.create(fooModule, "key-leaf-b"); + iidLeaf = QName.create(fooModule, "iid-leaf"); + referencedLeaf = QName.create(fooModule, "referenced-leaf"); + referencedLeafList = QName.create(fooModule, "referenced-leaf-list"); + absLeafrefLeaf = QName.create(fooModule, "abs-leafref-leaf"); + relLeafrefLeaf = QName.create(fooModule, "rel-leafref-leaf"); + leafListLeafrefLeaf = QName.create(fooModule, "leaf-list-leafref-leaf"); + ordinaryLeafA = QName.create(fooModule, "ordinary-leaf-a"); + ordinaryLeafB = QName.create(fooModule, "ordinary-leaf-b"); + } + + @Test + public void testDerefFunctionForInstanceIdentifier() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/deref-function-iid/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + + final LeafNode referencedLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(referencedLeaf)) + .withValue("referenced-leaf-node-value").build(); + + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNodeForIIdTest(referencedLeafNode)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToIIdLeafNode()); + + final Function derefFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "deref"); + final Object derefResult = derefFunction.call(normalizedNodeContext, ImmutableList.of()); + assertNotNull(derefResult); + assertTrue(derefResult instanceof NormalizedNode); + assertSame(referencedLeafNode, derefResult); + } + + @Test + public void testDerefFunctionForLeafref() throws Exception { + // tests absolute and relative leafref that references a leaf node + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/deref-function-leafref/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + + final LeafNode referencedLeafNode = Builders.leafBuilder().withNodeIdentifier( + new NodeIdentifier(referencedLeaf)).withValue("referenced-leaf-node-value").build(); + + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNodeForLeafrefTest( + referencedLeafNode)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final YangInstanceIdentifier absLeafrefPath = YangInstanceIdentifier.of(myInnerContainer).node(absLeafrefLeaf); + NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(absLeafrefPath); + + final Function derefFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "deref"); + Object derefResult = derefFunction.call(normalizedNodeContext, ImmutableList.of()); + assertNotNull(derefResult); + assertTrue(derefResult instanceof NormalizedNode); + assertSame(referencedLeafNode, derefResult); + + final YangInstanceIdentifier relLeafrefPath = YangInstanceIdentifier.of(myInnerContainer).node(relLeafrefLeaf); + normalizedNodeContext = normalizedNodeContextSupport.createContext(relLeafrefPath); + + derefResult = derefFunction.call(normalizedNodeContext, ImmutableList.of()); + assertNotNull(derefResult); + assertTrue(derefResult instanceof NormalizedNode); + assertSame(referencedLeafNode, derefResult); + } + + @Test + public void testDerefFunctionForLeafref2() throws Exception { + // tests leafref that references a leaf-list node + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/deref-function-leafref/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + + final LeafSetNode referencedLeafListNode = Builders.leafSetBuilder().withNodeIdentifier( + new NodeIdentifier(referencedLeafList)) + .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier( + new NodeWithValue<>(referencedLeafList, "referenced-node-entry-value-a")) + .withValue("referenced-node-entry-value-a").build()) + .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier( + new NodeWithValue<>(referencedLeafList, "referenced-node-entry-value-b")) + .withValue("referenced-node-entry-value-b").build()) + .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier( + new NodeWithValue<>(referencedLeafList, "referenced-node-entry-value-c")) + .withValue("referenced-node-entry-value-c").build()) + .build(); + + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNodeForLeafrefTest( + referencedLeafListNode)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final YangInstanceIdentifier leafListLeafrefPath = YangInstanceIdentifier.of(myInnerContainer) + .node(leafListLeafrefLeaf); + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport + .createContext(leafListLeafrefPath); + + final Function derefFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "deref"); + Object derefResult = derefFunction.call(normalizedNodeContext, ImmutableList.of()); + assertNotNull(derefResult); + assertTrue(derefResult instanceof NormalizedNode); + + final LeafSetEntryNode referencedLeafListNodeEntry = referencedLeafListNode.getChild( + new NodeWithValue<>(referencedLeafList, "referenced-node-entry-value-b")).get(); + assertSame(referencedLeafListNodeEntry, derefResult); + } + + private static ContainerNode buildMyContainerNodeForIIdTest(final LeafNode referencedLeafNode) { + final Map keyValues = ImmutableMap.of(keyLeafA, "key-value-a", keyLeafB, "key-value-b"); + final YangInstanceIdentifier iidPath = YangInstanceIdentifier.of(myContainer).node(myList) + .node(new NodeIdentifierWithPredicates(myList, keyValues)).node(referencedLeaf); + + final LeafNode iidLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(iidLeaf)) + .withValue(iidPath).build(); + + final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) + .withChild(Builders.mapEntryBuilder().withNodeIdentifier( + new NodeIdentifierWithPredicates(myList, keyValues)) + .withChild(iidLeafNode) + .withChild(referencedLeafNode).build()) + .build(); + + final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myContainer)).withChild(myListNode).build(); + return myContainerNode; + } + + private static YangInstanceIdentifier buildPathToIIdLeafNode() { + final Map keyValues = ImmutableMap.of(keyLeafA, "key-value-a", keyLeafB, "key-value-b"); + final YangInstanceIdentifier path = YangInstanceIdentifier.of(myList) + .node(new NodeIdentifierWithPredicates(myList, keyValues)).node(iidLeaf); + return path; + } + + // variant for a leafref that references a leaf + private static ContainerNode buildMyContainerNodeForLeafrefTest(final LeafNode referencedLeafNode) { + final Map keyValues = ImmutableMap.of(keyLeafA, "value-a", keyLeafB, "value-b"); + + final LeafNode absLeafrefNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(absLeafrefLeaf)) + .withValue("referenced-leaf-node-value").build(); + final LeafNode relLeafrefNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(relLeafrefLeaf)) + .withValue("referenced-leaf-node-value").build(); + final LeafNode ordinaryLeafANode = Builders.leafBuilder().withNodeIdentifier( + new NodeIdentifier(ordinaryLeafA)).withValue("value-a").build(); + final LeafNode ordinaryLeafBNode = Builders.leafBuilder().withNodeIdentifier( + new NodeIdentifier(ordinaryLeafB)).withValue("value-b").build(); + + final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) + .withChild(Builders.mapEntryBuilder().withNodeIdentifier( + new NodeIdentifierWithPredicates(myList, keyValues)) + .withChild(referencedLeafNode).build()) + .build(); + + final ContainerNode myInnerContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myInnerContainer)) + .withChild(absLeafrefNode) + .withChild(relLeafrefNode) + .withChild(ordinaryLeafANode) + .withChild(ordinaryLeafBNode).build(); + + final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myContainer)) + .withChild(myListNode) + .withChild(myInnerContainerNode).build(); + return myContainerNode; + } + + // variant for a leafref that references a leaf-list + private static ContainerNode buildMyContainerNodeForLeafrefTest(final LeafSetNode referencedLeafListNode) { + final LeafNode leafListLeafrefNode = Builders.leafBuilder().withNodeIdentifier( + new NodeIdentifier(leafListLeafrefLeaf)).withValue("referenced-node-entry-value-b").build(); + + final LeafNode ordinaryLeafANode = Builders.leafBuilder().withNodeIdentifier( + new NodeIdentifier(ordinaryLeafA)).withValue("value-a").build(); + final LeafNode ordinaryLeafBNode = Builders.leafBuilder().withNodeIdentifier( + new NodeIdentifier(ordinaryLeafB)).withValue("value-b").build(); + + final ContainerNode myInnerContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myInnerContainer)) + .withChild(leafListLeafrefNode) + .withChild(ordinaryLeafANode) + .withChild(ordinaryLeafBNode).build(); + + final Map keyValues = ImmutableMap.of(keyLeafA, "value-a", keyLeafB, "value-b"); + + final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) + .withChild(Builders.mapEntryBuilder().withNodeIdentifier( + new NodeIdentifierWithPredicates(myList, keyValues)) + .withChild(referencedLeafListNode).build()) + .build(); + + final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myContainer)) + .withChild(myListNode) + .withChild(myInnerContainerNode).build(); + return myContainerNode; + } +} \ No newline at end of file diff --git a/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerivedFromXPathFunctionTest.java b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerivedFromXPathFunctionTest.java new file mode 100644 index 0000000000..c08dd24dcf --- /dev/null +++ b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/DerivedFromXPathFunctionTest.java @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.yangtools.yang.data.jaxen; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import java.net.URI; +import java.text.ParseException; +import org.jaxen.Context; +import org.jaxen.Function; +import org.jaxen.FunctionCallException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathSchemaContext; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class DerivedFromXPathFunctionTest { + + private static JaxenSchemaContextFactory jaxenSchemaContextFactory; + + private static QNameModule barModule; + private static QName myContainer; + private static QName myList; + private static QName keyLeaf; + private static QName idrefLeaf; + private static QName idC2Identity; + + @BeforeClass + public static void setup() throws ParseException { + jaxenSchemaContextFactory = new JaxenSchemaContextFactory(); + + barModule = QNameModule.create(URI.create("bar-ns"), + SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); + myContainer = QName.create(barModule, "my-container"); + myList = QName.create(barModule, "my-list"); + keyLeaf = QName.create(barModule, "key-leaf"); + idrefLeaf = QName.create(barModule, "idref-leaf"); + idC2Identity = QName.create(barModule, "id-c2"); + } + + @Test + public void testDerivedFromFunction() throws Exception { + // also includes test for derived-from-or-self function + final SchemaContext schemaContext = YangParserTestUtils.parseYangSources(ImmutableList.of( + "/yang-xpath-functions-test/derived-from-function/foo.yang", + "/yang-xpath-functions-test/derived-from-function/bar.yang")); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("bar-prefix", barModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToIdrefLeafNode()); + + final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "derived-from"); + + assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3")); + assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a4")); + assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b2")); + assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-b3")); + assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "id-b4")); + + assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a1")); + assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a2")); + assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b1")); + assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-c1")); + assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-c2")); + + final Function derivedFromOrSelfFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "derived-from-or-self"); + assertTrue(getDerivedFromResult(derivedFromOrSelfFunction, normalizedNodeContext, "bar-prefix:id-c2")); + } + + @Test + public void testInvalidTypeOfCorrespondingSchemaNode() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/derived-from-function/bar-invalid.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("bar-prefix", barModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToIdrefLeafNode()); + + final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "derived-from"); + + assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "some-identity")); + } + + @Test + public void testInvalidNormalizedNodeValueType() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSources(ImmutableList.of( + "/yang-xpath-functions-test/derived-from-function/foo.yang", + "/yang-xpath-functions-test/derived-from-function/bar.yang")); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode("should be QName")); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("bar-prefix", barModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToIdrefLeafNode()); + + final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "derived-from"); + + assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3")); + } + + @Test + public void shouldFailOnUnknownPrefixOfIdentity() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSources(ImmutableList.of( + "/yang-xpath-functions-test/derived-from-function/foo.yang", + "/yang-xpath-functions-test/derived-from-function/bar.yang")); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("bar-prefix", barModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToIdrefLeafNode()); + + final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "derived-from"); + + try { + getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "unknown-prefix:id-a3"); + fail("Function call should have failed on unresolved prefix of the identity argument."); + } catch (IllegalArgumentException ex) { + assertEquals("Cannot resolve prefix 'unknown-prefix' from identity 'unknown-prefix:id-a3'.", ex.getMessage()); + } + } + + @Test + public void shouldFailOnMalformedIdentityArgument() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSources(ImmutableList.of( + "/yang-xpath-functions-test/derived-from-function/foo.yang", + "/yang-xpath-functions-test/derived-from-function/bar.yang")); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("bar-prefix", barModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToIdrefLeafNode()); + + final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "derived-from"); + + try { + getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo:bar:id-a3"); + fail("Function call should have failed on malformed identity argument."); + } catch (IllegalArgumentException ex) { + assertEquals("Malformed identity argument: foo:bar:id-a3.", ex.getMessage()); + } + } + + @Test + public void shouldFailOnUnknownIdentityArgument() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSources(ImmutableList.of( + "/yang-xpath-functions-test/derived-from-function/foo.yang", + "/yang-xpath-functions-test/derived-from-function/bar.yang")); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(idC2Identity)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("bar-prefix", barModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToIdrefLeafNode()); + + final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "derived-from"); + + try { + getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a333"); + fail("Function call should have failed on unknown identity argument."); + } catch (IllegalArgumentException ex) { + assertTrue(ex.getMessage().startsWith( + "Identity (foo-ns?revision=2017-04-03)id-a333 does not have a corresponding identity schema " + + "node in the module")); + } + } + + @Test + public void shouldFailOnInvalidNumberOfArguments() throws Exception { + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function derivedFromFunction = yangFunctionContext.getFunction(null, null, "derived-from"); + + final Context mockedContext = mock(Context.class); + + try { + derivedFromFunction.call(mockedContext, ImmutableList.of("some-identity", "should not be here")); + fail("Function call should have failed on invalid number of arguments."); + } catch (final FunctionCallException ex) { + assertEquals("derived-from() takes two arguments: node-set nodes, string identity.", ex.getMessage()); + } + } + + @Test + public void shouldFailOnInvalidTypeOfArgument() throws Exception { + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function bitIsSetFunction = yangFunctionContext.getFunction(null, null, "derived-from"); + + final Context mockedContext = mock(Context.class); + + try { + bitIsSetFunction.call(mockedContext, ImmutableList.of(100)); + fail("Function call should have failed on invalid type of the identity argument."); + } catch (final FunctionCallException ex) { + assertEquals("Argument 'identity' of derived-from() function should be a String.", ex.getMessage()); + } + } + + private static boolean getDerivedFromResult(final Function derivedFromFunction, final NormalizedNodeContext nnCtx, + final String identityArg) throws Exception { + return (boolean) derivedFromFunction.call(nnCtx, ImmutableList.of(identityArg)); + } + + private static ContainerNode buildMyContainerNode(final Object idrefLeafValue) { + final LeafNode idrefLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(idrefLeaf)) + .withValue(idrefLeafValue).build(); + + final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) + .withChild(Builders.mapEntryBuilder().withNodeIdentifier( + new NodeIdentifierWithPredicates(myList, keyLeaf, "key-value")) + .withChild(idrefLeafNode).build()).build(); + + final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myContainer)).withChild(myListNode).build(); + return myContainerNode; + } + + private static YangInstanceIdentifier buildPathToIdrefLeafNode() { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + final ImmutableMap keys = builder.put(keyLeaf, "key-value").build(); + + final YangInstanceIdentifier path = YangInstanceIdentifier.of(myList) + .node(new NodeIdentifierWithPredicates(myList, keys)).node(idrefLeaf); + return path; + } +} \ No newline at end of file diff --git a/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/EnumValueXPathFunctionTest.java b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/EnumValueXPathFunctionTest.java new file mode 100644 index 0000000000..0e42f875e5 --- /dev/null +++ b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/EnumValueXPathFunctionTest.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.yangtools.yang.data.jaxen; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import java.net.URI; +import java.text.ParseException; +import org.jaxen.Context; +import org.jaxen.Function; +import org.jaxen.FunctionCallException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument; +import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathSchemaContext; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class EnumValueXPathFunctionTest { + + private static JaxenSchemaContextFactory jaxenSchemaContextFactory; + + private static QNameModule fooModule; + private static QName myContainer; + private static QName alarm; + private static QName severity; + private static QName ordinaryLeaf; + + @BeforeClass + public static void setup() throws ParseException { + jaxenSchemaContextFactory = new JaxenSchemaContextFactory(); + + fooModule = QNameModule.create(URI.create("foo-ns"), + SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); + myContainer = QName.create(fooModule, "my-container"); + alarm = QName.create(fooModule, "alarm"); + severity = QName.create(fooModule, "severity"); + ordinaryLeaf = QName.create(fooModule, "ordinary-leaf"); + } + + @Test + public void testEnumValueFunction() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/enum-value-function/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode("major")); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToSeverityLeafNode("major")); + + final Function enumValueFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "enum-value"); + final int enumValueResult = (int) enumValueFunction.call(normalizedNodeContext, ImmutableList.of()); + assertEquals(5, enumValueResult); + } + + @Test + public void testInvalidTypeOfCorrespondingSchemaNode() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/enum-value-function/foo-invalid.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode("major")); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToSeverityLeafNode("major")); + + final Function enumValueFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "enum-value"); + final Double enumValueResult = (Double) enumValueFunction.call(normalizedNodeContext, ImmutableList.of()); + assertEquals(Double.NaN, enumValueResult, 0.001); + } + + @Test + public void testInvalidNormalizedNodeValueType() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/enum-value-function/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode(100)); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToSeverityLeafNode(100)); + + final Function enumValueFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "enum-value"); + final Double enumValueResult = (Double) enumValueFunction.call(normalizedNodeContext, ImmutableList.of()); + assertEquals(Double.NaN, enumValueResult, 0.001); + } + + @Test + public void shouldFailOnUnknownEnumNodeValue() throws Exception { + final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( + "/yang-xpath-functions-test/enum-value-function/foo.yang"); + assertNotNull(schemaContext); + + final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); + final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(buildMyContainerNode("unknown")); + + final BiMap converterBiMap = HashBiMap.create(); + converterBiMap.put("foo-prefix", fooModule); + + final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( + (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); + + final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext( + buildPathToSeverityLeafNode("unknown")); + + final Function enumValueFunction = normalizedNodeContextSupport.getFunctionContext() + .getFunction(null, null, "enum-value"); + try { + enumValueFunction.call(normalizedNodeContext, ImmutableList.of()); + fail("Function call should have failed on unknown enum node value"); + } catch (final IllegalStateException ex) { + assertTrue(ex.getMessage().startsWith("Enum unknown does not belong to enumeration")); + } + } + + @Test + public void shouldFailOnInvalidNumberOfArguments() throws Exception { + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function enumValueFunction = yangFunctionContext.getFunction(null, null, "enum-value"); + + final Context mockedContext = mock(Context.class); + + try { + enumValueFunction.call(mockedContext, ImmutableList.of("should not be here")); + fail("Function call should have failed on invalid number of arguments."); + } catch (final FunctionCallException ex) { + assertEquals("enum-value() takes one argument: node-set nodes.", ex.getMessage()); + } + } + + private static ContainerNode buildMyContainerNode(final Object keyLeafValue) { + final LeafNode ordinaryLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(ordinaryLeaf)) + .withValue("test-value").build(); + + final MapNode alarmListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(alarm)) + .withChild(Builders.mapEntryBuilder().withNodeIdentifier( + new NodeIdentifierWithPredicates(alarm, severity, keyLeafValue)) + .withChild(ordinaryLeafNode).build()).build(); + + final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( + new NodeIdentifier(myContainer)).withChild(alarmListNode).build(); + return myContainerNode; + } + + private static YangInstanceIdentifier buildPathToSeverityLeafNode(final Object keyLeafValue) { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + final ImmutableMap keys = builder.put(severity, keyLeafValue).build(); + + final YangInstanceIdentifier path = YangInstanceIdentifier.of(alarm) + .node(new NodeIdentifierWithPredicates(alarm, keys)).node(severity); + return path; + } +} \ No newline at end of file diff --git a/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/ReMatchXPathFunctionTest.java b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/ReMatchXPathFunctionTest.java new file mode 100644 index 0000000000..27dc7264cf --- /dev/null +++ b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/ReMatchXPathFunctionTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.yangtools.yang.data.jaxen; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import com.google.common.collect.ImmutableList; +import org.jaxen.Context; +import org.jaxen.Function; +import org.jaxen.FunctionCallException; +import org.junit.Test; + +public class ReMatchXPathFunctionTest { + + @Test + public void testRematchFunction() throws Exception { + // re-match() uses regex processing from yang-parser-impl which has been thoroughly tested within + // the Bug5410Test unit test class, so here is just a basic test + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function rematchFunction = yangFunctionContext.getFunction(null, null, "re-match"); + + final Context mockedContext = mock(Context.class); + + boolean rematchResult = (boolean) rematchFunction.call(mockedContext, ImmutableList.of("abbc", "[abc]{1,4}")); + assertTrue(rematchResult); + rematchResult = (boolean) rematchFunction.call(mockedContext, ImmutableList.of("abbcc", "[abc]{1,4}")); + assertFalse(rematchResult); + } + + @Test + public void shouldFailOnInvalidNumberOfArguments() throws Exception { + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function rematchFunction = yangFunctionContext.getFunction(null, null, "re-match"); + + final Context mockedContext = mock(Context.class); + + try { + rematchFunction.call(mockedContext, ImmutableList.of("abbc", "[abc]{1,4}", "should not be here")); + fail("Function call should have failed on invalid number of arguments."); + } catch (final FunctionCallException ex) { + assertEquals("re-match() takes two arguments: string subject, string pattern.", ex.getMessage()); + } + } + + @Test + public void shouldFailOnInvalidTypeOfArgument() throws Exception { + final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); + final Function rematchFunction = yangFunctionContext.getFunction(null, null, "re-match"); + + final Context mockedContext = mock(Context.class); + + try { + rematchFunction.call(mockedContext, ImmutableList.of(100, "[abc]{1,4}")); + fail("Function call should have failed on invalid type of the subject argument."); + } catch (final FunctionCallException ex) { + assertEquals("First argument of re-match() should be a String.", ex.getMessage()); + } + + try { + rematchFunction.call(mockedContext, ImmutableList.of("abbc", 100)); + fail("Function call should have failed on invalid type of the pattern argument."); + } catch (final FunctionCallException ex) { + assertEquals("Second argument of re-match() should be a String.", ex.getMessage()); + } + } +} \ No newline at end of file diff --git a/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/YangXPathFunctionsTest.java b/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/YangXPathFunctionsTest.java deleted file mode 100644 index a79ab0805d..0000000000 --- a/yang/yang-data-jaxen/src/test/java/org/opendaylight/yangtools/yang/data/jaxen/YangXPathFunctionsTest.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.yangtools.yang.data.jaxen; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; -import java.net.URI; -import java.util.Map; -import java.util.Set; -import org.jaxen.Context; -import org.jaxen.Function; -import org.junit.BeforeClass; -import org.junit.Test; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument; -import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathSchemaContext; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; - -public class YangXPathFunctionsTest { - - private static JaxenSchemaContextFactory jaxenSchemaContextFactory; - - @BeforeClass - public static void setup() { - jaxenSchemaContextFactory = new JaxenSchemaContextFactory(); - } - - @Test - public void testRematchFunction() throws Exception { - // re-match() uses regex processing from yang-parser-impl which has been thoroughly tested within - // the Bug5410Test unit test class, so here is just a basic test - final YangFunctionContext yangFunctionContext = YangFunctionContext.getInstance(); - final Function rematchFunction = yangFunctionContext.getFunction(null, null, "re-match"); - - final Context mockedContext = mock(Context.class); - - boolean rematchResult = (boolean) rematchFunction.call(mockedContext, ImmutableList.of("abbc", "[abc]{1,4}")); - assertTrue(rematchResult); - rematchResult = (boolean) rematchFunction.call(mockedContext, ImmutableList.of("abbcc", "[abc]{1,4}")); - assertFalse(rematchResult); - } - - @Test - public void testDerefFunctionForInstanceIdentifier() throws Exception { - final QNameModule fooModule = QNameModule.create(URI.create("foo-ns"), - SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); - final QName myContainer = QName.create(fooModule, "my-container"); - final QName myList = QName.create(fooModule, "my-list"); - final QName keyLeafA = QName.create(fooModule, "key-leaf-a"); - final QName keyLeafB = QName.create(fooModule, "key-leaf-b"); - final QName iidLeaf = QName.create(fooModule, "iid-leaf"); - final QName referencedLeaf = QName.create(fooModule, "referenced-leaf"); - - final Map keyValues = ImmutableMap.of(keyLeafA, "key-value-a", keyLeafB, "key-value-b"); - final YangInstanceIdentifier iidPath = YangInstanceIdentifier.of(myContainer).node(myList) - .node(new NodeIdentifierWithPredicates(myList, keyValues)).node(referencedLeaf); - - final LeafNode iidLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(iidLeaf)) - .withValue(iidPath).build(); - final LeafNode referencedLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(referencedLeaf)) - .withValue("referenced-leaf-node-value").build(); - - final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) - .withChild(Builders.mapEntryBuilder().withNodeIdentifier( - new NodeIdentifierWithPredicates(myList, keyValues)) - .withChild(iidLeafNode) - .withChild(referencedLeafNode).build()) - .build(); - - final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( - new NodeIdentifier(myContainer)).withChild(myListNode).build(); - - final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( - "/yang-xpath-functions-test/deref-function-iid/foo.yang"); - assertNotNull(schemaContext); - - final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); - final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(myContainerNode); - - final BiMap converterBiMap = HashBiMap.create(); - converterBiMap.put("foo-prefix", fooModule); - - final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( - (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); - - final YangInstanceIdentifier path = YangInstanceIdentifier.of(myList) - .node(new NodeIdentifierWithPredicates(myList, keyValues)).node(iidLeaf); - final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(path); - - final Function derefFunction = normalizedNodeContextSupport.getFunctionContext() - .getFunction(null, null, "deref"); - final Object derefResult = derefFunction.call(normalizedNodeContext, ImmutableList.of()); - assertNotNull(derefResult); - assertTrue(derefResult instanceof NormalizedNode); - assertSame(referencedLeafNode, derefResult); - } - - @Test - public void testDerefFunctionForLeafref() throws Exception { - final QNameModule fooModule = QNameModule.create(URI.create("foo-ns"), - SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); - final QName myContainer = QName.create(fooModule, "my-container"); - final QName myInnerContainer = QName.create(fooModule, "my-inner-container"); - final QName myList = QName.create(fooModule, "my-list"); - final QName keyLeafA = QName.create(fooModule, "key-leaf-a"); - final QName keyLeafB = QName.create(fooModule, "key-leaf-b"); - final QName absLeafrefLeaf = QName.create(fooModule, "abs-leafref-leaf"); - final QName relLeafrefLeaf = QName.create(fooModule, "rel-leafref-leaf"); - final QName ordinaryLeafA = QName.create(fooModule, "ordinary-leaf-a"); - final QName ordinaryLeafB = QName.create(fooModule, "ordinary-leaf-b"); - final QName referencedLeaf = QName.create(fooModule, "referenced-leaf"); - - final Map keyValues = ImmutableMap.of(keyLeafA, "value-a", keyLeafB, "value-b"); - - final LeafNode absLeafrefNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(absLeafrefLeaf)) - .withValue("referenced-leaf-node-value").build(); - final LeafNode relLeafrefNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(relLeafrefLeaf)) - .withValue("referenced-leaf-node-value").build(); - final LeafNode ordinaryLeafANode = Builders.leafBuilder().withNodeIdentifier( - new NodeIdentifier(ordinaryLeafA)).withValue("value-a").build(); - final LeafNode ordinaryLeafBNode = Builders.leafBuilder().withNodeIdentifier( - new NodeIdentifier(ordinaryLeafB)).withValue("value-b").build(); - - final LeafNode referencedLeafNode = Builders.leafBuilder().withNodeIdentifier( - new NodeIdentifier(referencedLeaf)).withValue("referenced-leaf-node-value").build(); - - final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) - .withChild(Builders.mapEntryBuilder().withNodeIdentifier( - new NodeIdentifierWithPredicates(myList, keyValues)) - .withChild(referencedLeafNode).build()) - .build(); - - final ContainerNode myInnerContainerNode = Builders.containerBuilder().withNodeIdentifier( - new NodeIdentifier(myInnerContainer)) - .withChild(absLeafrefNode) - .withChild(relLeafrefNode) - .withChild(ordinaryLeafANode) - .withChild(ordinaryLeafBNode).build(); - - final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( - new NodeIdentifier(myContainer)) - .withChild(myListNode) - .withChild(myInnerContainerNode).build(); - - final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( - "/yang-xpath-functions-test/deref-function-leafref/foo.yang"); - assertNotNull(schemaContext); - - final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); - final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(myContainerNode); - - final BiMap converterBiMap = HashBiMap.create(); - converterBiMap.put("foo-prefix", fooModule); - - final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( - (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); - - final YangInstanceIdentifier absLeafrefPath = YangInstanceIdentifier.of(myInnerContainer).node(absLeafrefLeaf); - NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(absLeafrefPath); - - final Function derefFunction = normalizedNodeContextSupport.getFunctionContext() - .getFunction(null, null, "deref"); - Object derefResult = derefFunction.call(normalizedNodeContext, ImmutableList.of()); - assertNotNull(derefResult); - assertTrue(derefResult instanceof NormalizedNode); - assertSame(referencedLeafNode, derefResult); - - final YangInstanceIdentifier relLeafrefPath = YangInstanceIdentifier.of(myInnerContainer).node(relLeafrefLeaf); - normalizedNodeContext = normalizedNodeContextSupport.createContext(relLeafrefPath); - - derefResult = derefFunction.call(normalizedNodeContext, ImmutableList.of()); - assertNotNull(derefResult); - assertTrue(derefResult instanceof NormalizedNode); - assertSame(referencedLeafNode, derefResult); - } - - @Test - public void testDerivedFromFunction() throws Exception { - // also includes test for derived-from-or-self function - final QNameModule barModule = QNameModule.create(URI.create("bar-ns"), - SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); - final QName myContainer = QName.create(barModule, "my-container"); - final QName myList = QName.create(barModule, "my-list"); - final QName keyLeaf = QName.create(barModule, "key-leaf"); - final QName idrefLeaf = QName.create(barModule, "idref-leaf"); - final QName idC2Identity = QName.create(barModule, "id-c2"); - - final LeafNode idrefLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(idrefLeaf)) - .withValue(idC2Identity).build(); - - final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) - .withChild(Builders.mapEntryBuilder().withNodeIdentifier( - new NodeIdentifierWithPredicates(myList, keyLeaf, "key-value")) - .withChild(idrefLeafNode).build()).build(); - - final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( - new NodeIdentifier(myContainer)).withChild(myListNode).build(); - - final SchemaContext schemaContext = YangParserTestUtils.parseYangSources( - "/yang-xpath-functions-test/derived-from-function"); - assertNotNull(schemaContext); - - final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); - final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(myContainerNode); - - final BiMap converterBiMap = HashBiMap.create(); - converterBiMap.put("bar-prefix", barModule); - - final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( - (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); - - final ImmutableMap.Builder builder = ImmutableMap.builder(); - final ImmutableMap keys = builder.put(keyLeaf, "key-value").build(); - - final YangInstanceIdentifier path = YangInstanceIdentifier.of(myList) - .node(new NodeIdentifierWithPredicates(myList, keys)).node(idrefLeaf); - final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(path); - - final Function derivedFromFunction = normalizedNodeContextSupport.getFunctionContext() - .getFunction(null, null, "derived-from"); - - assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a3")); - assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a4")); - assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b2")); - assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-b3")); - assertTrue(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "id-b4")); - - assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a1")); - assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-a2")); - assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-b1")); - assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "foo-prefix:id-c1")); - assertFalse(getDerivedFromResult(derivedFromFunction, normalizedNodeContext, "bar-prefix:id-c2")); - - final Function derivedFromOrSelfFunction = normalizedNodeContextSupport.getFunctionContext() - .getFunction(null, null, "derived-from-or-self"); - assertTrue(getDerivedFromResult(derivedFromOrSelfFunction, normalizedNodeContext, "bar-prefix:id-c2")); - } - - - - @Test - public void testEnumValueFunction() throws Exception { - final QNameModule fooModule = QNameModule.create(URI.create("foo-ns"), - SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); - final QName myContainer = QName.create(fooModule, "my-container"); - final QName alarm = QName.create(fooModule, "alarm"); - final QName severity = QName.create(fooModule, "severity"); - final QName ordinaryLeaf = QName.create(fooModule, "ordinary-leaf"); - - final LeafNode ordinaryLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(ordinaryLeaf)) - .withValue("test-value").build(); - - final MapNode alarmListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(alarm)) - .withChild(Builders.mapEntryBuilder().withNodeIdentifier( - new NodeIdentifierWithPredicates(alarm, severity, "major")) - .withChild(ordinaryLeafNode).build()).build(); - - final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( - new NodeIdentifier(myContainer)).withChild(alarmListNode).build(); - - final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( - "/yang-xpath-functions-test/enum-value-function/foo.yang"); - assertNotNull(schemaContext); - - final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); - final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(myContainerNode); - - final BiMap converterBiMap = HashBiMap.create(); - converterBiMap.put("foo-prefix", fooModule); - - final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( - (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); - - final ImmutableMap.Builder builder = ImmutableMap.builder(); - final ImmutableMap keys = builder.put(severity, "major").build(); - - final YangInstanceIdentifier path = YangInstanceIdentifier.of(alarm) - .node(new NodeIdentifierWithPredicates(alarm, keys)).node(severity); - final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(path); - - final Function enumValueFunction = normalizedNodeContextSupport.getFunctionContext() - .getFunction(null, null, "enum-value"); - final int enumValueResult = (int) enumValueFunction.call(normalizedNodeContext, ImmutableList.of()); - assertEquals(5, enumValueResult); - } - - @Test - public void testBitIsSetFunction() throws Exception { - final QNameModule fooModule = QNameModule.create(URI.create("foo-ns"), - SimpleDateFormatUtil.getRevisionFormat().parse("2017-04-03")); - final QName myContainer = QName.create(fooModule, "my-container"); - final QName myList = QName.create(fooModule, "my-list"); - final QName flags = QName.create(fooModule, "flags"); - final QName ordinaryLeaf = QName.create(fooModule, "ordinary-leaf"); - - final LeafNode ordinaryLeafNode = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(ordinaryLeaf)) - .withValue("test-value").build(); - - final Set setOfBits = ImmutableSet.of("UP", "PROMISCUOUS"); - - final MapNode myListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myList)) - .withChild(Builders.mapEntryBuilder().withNodeIdentifier( - new NodeIdentifierWithPredicates(myList, flags, setOfBits)) - .withChild(ordinaryLeafNode).build()).build(); - - final ContainerNode myContainerNode = Builders.containerBuilder().withNodeIdentifier( - new NodeIdentifier(myContainer)).withChild(myListNode).build(); - - final SchemaContext schemaContext = YangParserTestUtils.parseYangSource( - "/yang-xpath-functions-test/bit-is-set-function/foo.yang"); - assertNotNull(schemaContext); - - final XPathSchemaContext jaxenSchemaContext = jaxenSchemaContextFactory.createContext(schemaContext); - final XPathDocument jaxenDocument = jaxenSchemaContext.createDocument(myContainerNode); - - final BiMap converterBiMap = HashBiMap.create(); - converterBiMap.put("foo-prefix", fooModule); - - final NormalizedNodeContextSupport normalizedNodeContextSupport = NormalizedNodeContextSupport.create( - (JaxenDocument) jaxenDocument, Maps.asConverter(converterBiMap)); - - final ImmutableMap.Builder builder = ImmutableMap.builder(); - final ImmutableMap keys = builder.put(flags, setOfBits).build(); - - final YangInstanceIdentifier path = YangInstanceIdentifier.of(myList) - .node(new NodeIdentifierWithPredicates(myList, keys)).node(flags); - final NormalizedNodeContext normalizedNodeContext = normalizedNodeContextSupport.createContext(path); - - final Function bitIsSetFunction = normalizedNodeContextSupport.getFunctionContext() - .getFunction(null, null, "bit-is-set"); - boolean bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("UP")); - assertTrue(bitIsSetResult); - bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("PROMISCUOUS")); - assertTrue(bitIsSetResult); - bitIsSetResult = (boolean) bitIsSetFunction.call(normalizedNodeContext, ImmutableList.of("DISABLED")); - assertFalse(bitIsSetResult); - } - - private static boolean getDerivedFromResult(final Function derivedFromFunction, final NormalizedNodeContext nnCtx, - final String identityArg) throws Exception { - return (boolean) derivedFromFunction.call(nnCtx, ImmutableList.of(identityArg)); - } -} diff --git a/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/bit-is-set-function/foo-invalid.yang b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/bit-is-set-function/foo-invalid.yang new file mode 100644 index 0000000000..13e09e26f4 --- /dev/null +++ b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/bit-is-set-function/foo-invalid.yang @@ -0,0 +1,21 @@ +module foo-invalid { + namespace foo-ns; + prefix foo-prefix; + yang-version 1.1; + + revision 2017-04-03; + + container my-container { + list my-list { + key flags; + + leaf flags { + type int32; + } + + leaf ordinary-leaf { + type string; + } + } + } +} \ No newline at end of file diff --git a/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/deref-function-leafref/foo.yang b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/deref-function-leafref/foo.yang index a5c771af0d..4b12f546a6 100644 --- a/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/deref-function-leafref/foo.yang +++ b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/deref-function-leafref/foo.yang @@ -20,6 +20,10 @@ module foo { leaf referenced-leaf { type string; } + + leaf referenced-leaf-list { + type string; + } } container my-inner-container { @@ -32,8 +36,15 @@ module foo { leaf rel-leafref-leaf { type leafref { - path "../../my-list[key-leaf-a=current()/../ordinary-leaf-a]" + - "[key-leaf-b=current()/../ordinary-leaf-b]/referenced-leaf"; + path "../../foo-prefix:my-list[foo-prefix:key-leaf-a=current()/../ordinary-leaf-a]" + + "[key-leaf-b=current()/../ordinary-leaf-b]/foo-prefix:referenced-leaf"; + } + } + + leaf leaf-list-leafref-leaf { + type leafref { + path "/my-container/my-list[key-leaf-a=current()/../ordinary-leaf-a]" + + "[key-leaf-b=current()/../ordinary-leaf-b]/referenced-leaf-list"; } } diff --git a/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/derived-from-function/bar-invalid.yang b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/derived-from-function/bar-invalid.yang new file mode 100644 index 0000000000..c43fd47987 --- /dev/null +++ b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/derived-from-function/bar-invalid.yang @@ -0,0 +1,21 @@ +module bar-invalid { + namespace bar-ns; + prefix bar-prefix; + yang-version 1.1; + + revision 2017-04-03; + + container my-container { + list my-list { + key key-leaf; + + leaf key-leaf { + type string; + } + + leaf idref-leaf { + type int32; + } + } + } +} \ No newline at end of file diff --git a/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/enum-value-function/foo-invalid.yang b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/enum-value-function/foo-invalid.yang new file mode 100644 index 0000000000..aa238fe738 --- /dev/null +++ b/yang/yang-data-jaxen/src/test/resources/yang-xpath-functions-test/enum-value-function/foo-invalid.yang @@ -0,0 +1,21 @@ +module foo-invalid { + namespace foo-ns; + prefix foo-prefix; + yang-version 1.1; + + revision 2017-04-03; + + container my-container { + list alarm { + key severity; + + leaf ordinary-leaf { + type string; + } + + leaf severity { + type int32; + } + } + } +} \ No newline at end of file -- 2.36.6