2 * Copyright (c) 2022 PANTHEON.tech, s.r.o. 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.codec.xml;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
12 import static org.mockito.Mockito.verify;
14 import javax.xml.stream.XMLStreamWriter;
15 import org.junit.jupiter.api.AfterAll;
16 import org.junit.jupiter.api.BeforeAll;
17 import org.junit.jupiter.api.Disabled;
18 import org.junit.jupiter.api.Test;
19 import org.junit.jupiter.api.extension.ExtendWith;
20 import org.mockito.ArgumentCaptor;
21 import org.mockito.Captor;
22 import org.mockito.Mock;
23 import org.mockito.junit.jupiter.MockitoExtension;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
29 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
32 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
34 @ExtendWith(MockitoExtension.class)
35 public class YT1473Test {
37 private static final String FOO_NS = "foons"; // namespace for prefix 'foo'
38 private static final QName FOO_FOO = QName.create(FOO_NS, "foo"); // list with key 'str'
39 private static final QName FOO_BAR = QName.create(FOO_NS, "bar"); // list with key 'qname'
40 private static final QName FOO_BAZ = QName.create(FOO_NS, "baz"); // list with key 'id'
41 private static final QName FOO_ONE = QName.create(FOO_NS, "one"); // identity
42 private static final QName FOO_STR = QName.create(FOO_NS, "str"); // key of type 'string'
43 private static final QName FOO_QNAME = QName.create(FOO_NS, "qname"); // key of type 'one' based
44 private static final QName FOO_ID = QName.create(FOO_NS, "id"); // key of type 'instance-identifier'
46 private static final String BAR_NS = "barns"; // namespace for prefix 'bar'
47 private static final QName BAR_FOO = QName.create(BAR_NS, "foo"); // leaf of type 'foo:one' based
48 private static final QName BAR_BAR = QName.create(BAR_NS, "bar"); // leaf of type 'instance-identifier'
49 private static final QName BAR_TWO = QName.create(BAR_NS, "two"); // identity inheriting 'foo:one'
51 private static XmlCodec<YangInstanceIdentifier> CODEC;
54 private XMLStreamWriter writer;
56 private ArgumentCaptor<String> captor;
59 public static void beforeAll() {
60 final var modelContext = YangParserTestUtils.parseYangResourceDirectory("/yt1473");
61 final var baz = modelContext.getDataChildByName(FOO_BAZ);
62 assertTrue(baz instanceof ListSchemaNode);
63 final var id = ((ListSchemaNode) baz).getDataChildByName(FOO_ID);
64 assertTrue(id instanceof LeafSchemaNode);
65 final var type = ((LeafSchemaNode) id).getType();
66 assertTrue(type instanceof InstanceIdentifierTypeDefinition);
67 CODEC = (XmlStringInstanceIdentifierCodec) XmlCodecFactory.create(modelContext)
68 .instanceIdentifierCodec((InstanceIdentifierTypeDefinition) type);
72 public static void afterAll() {
77 public void testSerializeSimple() throws Exception {
78 // No escaping needed, use single quotes
79 assertEquals("/foo:foo[foo:str='str\"']", write(buildYangInstanceIdentifier(FOO_FOO, FOO_STR, "str\"")));
83 @Disabled("YT-1473: string escaping needs to work")
84 public void testSerializeEscaped() throws Exception {
85 // Escaping is needed, use double quotes and escape
86 assertEquals("/foo:foo[foo:str=\"str'\\\"\"]", write(buildYangInstanceIdentifier(FOO_FOO, FOO_STR, "str'\"")));
90 @Disabled("YT-1473: QName values need to be recognized and properly encoded via identity codec")
91 public void testSerializeIdentityRefSame() throws Exception {
92 // TODO: an improvement is to use just 'one' as the namespace is the same as the leaf (see RFC7951 section 6.8)
93 assertEquals("/foo:bar[qname='one']", write(buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, FOO_ONE)));
97 @Disabled("YT-1473: QName values need to be recognized and properly encoded via identity codec")
98 public void testSerializeIdentityRefOther() throws Exception {
99 // No escaping is needed, use double quotes and escape
100 assertEquals("/foo:bar[qname='bar:two']", write(buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, BAR_TWO)));
104 @Disabled("YT-1473: Instance-identifier values need to be recognized and properly encoded and escaped")
105 public void testSerializeInstanceIdentifierRef() throws Exception {
106 assertEquals("/foo:baz[id=\"/foo:bar[qname='bar:two']\"]", write(
107 buildYangInstanceIdentifier(FOO_BAZ, FOO_ID, buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, BAR_TWO)))
112 @Disabled("YT-1473: QName values need to be recognized and properly encoded via identity codec")
113 public void testSerializeIdentityValue() throws Exception {
114 assertEquals("/bar:foo[.='foo:one']", write(buildYangInstanceIdentifier(BAR_FOO, FOO_ONE)));
118 @Disabled("YT-1473: Instance-identifier values need to be recognized and properly encoded and escaped")
119 public void testSerializeInstanceIdentifierValue() throws Exception {
120 assertEquals("/bar:bar[.=\"/foo:bar/bar[qname='bar:two'\"]']",
121 write(buildYangInstanceIdentifier(BAR_BAR, buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, BAR_TWO))));
124 private static YangInstanceIdentifier buildYangInstanceIdentifier(final QName node, final QName key,
125 final Object value) {
126 return YangInstanceIdentifier.create(
127 new NodeIdentifier(node), NodeIdentifierWithPredicates.of(node, key, value));
130 private static YangInstanceIdentifier buildYangInstanceIdentifier(final QName node, final Object value) {
131 return YangInstanceIdentifier.create(new NodeWithValue<>(node, value));
134 private String write(final YangInstanceIdentifier yangInstanceIdentifier) throws Exception {
135 CODEC.writeValue(writer, yangInstanceIdentifier);
136 verify(writer).writeCharacters(captor.capture());
137 return captor.getValue();