Disconnect JSONCodec from JsonWriter
[yangtools.git] / codec / yang-data-codec-gson / src / test / java / org / opendaylight / yangtools / yang / data / codec / gson / YT1473Test.java
1 /*
2  * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.codec.gson;
9
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.doNothing;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.verify;
16
17 import com.google.common.collect.ImmutableSet;
18 import org.junit.jupiter.api.AfterAll;
19 import org.junit.jupiter.api.BeforeAll;
20 import org.junit.jupiter.api.Test;
21 import org.mockito.ArgumentCaptor;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
27 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
30 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
31
32 class YT1473Test {
33     private static final String FOO_NS = "foons"; // namespace for prefix 'foo'
34     private static final QName FOO_FOO = QName.create(FOO_NS, "foo"); // list with key 'str'
35     private static final QName FOO_BAR = QName.create(FOO_NS, "bar"); // list with key 'qname'
36     private static final QName FOO_BAZ = QName.create(FOO_NS, "baz"); // list with key 'id'
37     private static final QName FOO_BEE = QName.create(FOO_NS, "bee"); // list with key 'bts'
38     private static final QName FOO_ONE = QName.create(FOO_NS, "one"); // identity
39     private static final QName FOO_STR = QName.create(FOO_NS, "str"); // key of type 'string'
40     private static final QName FOO_QNAME = QName.create(FOO_NS, "qname"); // key of type 'one' based
41     private static final QName FOO_ID = QName.create(FOO_NS, "id"); // key of type 'instance-identifier'
42     private static final QName FOO_BTS = QName.create(FOO_NS, "bts"); // key of type 'bts' (bits)
43
44     private static final String BAR_NS = "barns"; // namespace for prefix 'bar'
45     private static final QName BAR_STR = QName.create(BAR_NS, "str"); // leaf-list of type 'string'
46     private static final QName BAR_FOO = QName.create(BAR_NS, "foo"); // leaf-list of type 'foo:one' based
47     private static final QName BAR_BAR = QName.create(BAR_NS, "bar"); // leaf-list of type 'instance-identifier'
48     private static final QName BAR_BEE = QName.create(BAR_NS, "bee"); // leaf-list of type 'foo:bts' (bits)
49     private static final QName BAR_TWO = QName.create(BAR_NS, "two"); // identity inheriting 'foo:one'
50
51     private static JSONCodec<YangInstanceIdentifier> CODEC;
52
53     @BeforeAll
54     static void beforeAll() {
55         final var modelContext = YangParserTestUtils.parseYang("""
56             module bar {
57               namespace barns;
58               prefix bar;
59               import foo { prefix foo; }
60
61               identity two {
62                 base foo:one;
63               }
64
65               leaf-list str {
66                 type string;
67               }
68
69               leaf-list foo {
70                 type identityref {
71                   base foo:one;
72                 }
73               }
74
75               leaf-list bar {
76                 type instance-identifier;
77               }
78
79               leaf-list bee {
80                 type foo:bitz;
81               }
82
83               leaf baz {
84                 type instance-identifier;
85               }
86             }""", """
87             module foo {
88               namespace foons;
89               prefix foo;
90               identity one;
91
92               typedef bitz {
93                 type bits {
94                   bit one;
95                   bit two;
96                   bit three;
97                 }
98               }
99
100               list foo {
101                 key str;
102                 leaf str {
103                   type string;
104                 }
105               }
106
107               list bar {
108                 key qname;
109                 leaf qname {
110                   type identityref {
111                     base one;
112                   }
113                 }
114               }
115
116               list baz {
117                 key id;
118                 leaf id {
119                   type instance-identifier;
120                 }
121               }
122
123               list bee {
124                 key bts;
125                 leaf bts {
126                   type bitz;
127                 }
128               }
129             }""");
130         final var baz = assertInstanceOf(ListSchemaNode.class, modelContext.getDataChildByName(FOO_BAZ));
131         final var id = assertInstanceOf(LeafSchemaNode.class, baz.getDataChildByName(FOO_ID));
132         final var type = assertInstanceOf(InstanceIdentifierTypeDefinition.class, id.getType());
133         CODEC = JSONCodecFactorySupplier.RFC7951.getShared(modelContext).instanceIdentifierCodec(type);
134     }
135
136     @AfterAll
137     static void afterAll() {
138         CODEC = null;
139     }
140
141     @Test
142     void testSerializeSimple() throws Exception {
143         // No escaping needed, use single quotes
144         assertSerdes("/bar:str[.='str\"']", buildYangInstanceIdentifier(BAR_STR, "str\""));
145         assertSerdes("/bar:str[.='str\\']", buildYangInstanceIdentifier(BAR_STR, "str\\"));
146         assertSerdes("/bar:str[.='str\r']", buildYangInstanceIdentifier(BAR_STR, "str\r"));
147         assertSerdes("/bar:str[.='str\n']", buildYangInstanceIdentifier(BAR_STR, "str\n"));
148         assertSerdes("/bar:str[.='str\t']", buildYangInstanceIdentifier(BAR_STR, "str\t"));
149
150         assertSerdes("/foo:foo[str='str\"\\']", buildYangInstanceIdentifier(FOO_FOO, FOO_STR, "str\"\\"));
151         assertSerdes("/foo:foo[str='str\r\n\t']", buildYangInstanceIdentifier(FOO_FOO, FOO_STR, "str\r\n\t"));
152     }
153
154     @Test
155     void testSerializeEscaped() throws Exception {
156         // Escaping is needed, use double quotes and escape
157         assertSerdes("/bar:str[.=\"str'\\\"\"]", buildYangInstanceIdentifier(BAR_STR, "str'\""));
158         assertSerdes("/bar:str[.=\"str'\\n\"]", buildYangInstanceIdentifier(BAR_STR, "str'\n"));
159         assertSerdes("/bar:str[.=\"str'\\t\"]", buildYangInstanceIdentifier(BAR_STR, "str'\t"));
160         assertSerdes("/bar:str[.=\"str'\r\"]", buildYangInstanceIdentifier(BAR_STR, "str'\r"));
161
162         assertSerdes("/foo:foo[str=\"str'\\\"\\n\"]", buildYangInstanceIdentifier(FOO_FOO, FOO_STR, "str'\"\n"));
163         assertSerdes("/foo:foo[str=\"str'\\t\r\"]", buildYangInstanceIdentifier(FOO_FOO, FOO_STR, "str'\t\r"));
164     }
165
166     @Test
167     void testSerializeIdentityRefSame() throws Exception {
168         assertSerdes("/foo:bar[qname='one']", buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, FOO_ONE));
169     }
170
171     @Test
172     void testSerializeIdentityRefOther() throws Exception {
173         // No escaping is needed, use double quotes and escape
174         assertSerdes("/foo:bar[qname='bar:two']", buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, BAR_TWO));
175     }
176
177     @Test
178     void testSerializeInstanceIdentifierRef() throws Exception {
179         assertSerdes("/foo:baz[id=\"/foo:bar[qname='bar:two']\"]",
180             buildYangInstanceIdentifier(FOO_BAZ, FOO_ID, buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, BAR_TWO)));
181     }
182
183     @Test
184     void testSerializeIdentityValue() throws Exception {
185         assertSerdes("/bar:foo[.='foo:one']", buildYangInstanceIdentifier(BAR_FOO, FOO_ONE));
186         assertSerdes("/bar:foo[.='two']", buildYangInstanceIdentifier(BAR_FOO, BAR_TWO));
187     }
188
189     @Test
190     void testSerializeInstanceIdentifierValue() throws Exception {
191         assertSerdes("/bar:bar[.=\"/foo:bar[qname='bar:two']\"]",
192             buildYangInstanceIdentifier(BAR_BAR, buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, BAR_TWO)));
193         assertSerdes("/bar:bar[.=\"/foo:bar[qname='one']\"]",
194             buildYangInstanceIdentifier(BAR_BAR, buildYangInstanceIdentifier(FOO_BAR, FOO_QNAME, FOO_ONE)));
195     }
196
197     @Test
198     void testSerializeBits() throws Exception {
199         assertSerdes("/foo:bee[bts='']", buildYangInstanceIdentifier(FOO_BEE, FOO_BTS, ImmutableSet.of()));
200         assertSerdes("/foo:bee[bts='one']", buildYangInstanceIdentifier(FOO_BEE, FOO_BTS, ImmutableSet.of("one")));
201         assertSerdes("/foo:bee[bts='two three']",
202             buildYangInstanceIdentifier(FOO_BEE, FOO_BTS, ImmutableSet.of("two", "three")));
203     }
204
205     @Test
206     void testSerializeBitsValue() throws Exception {
207         assertSerdes("/bar:bee[.='']", buildYangInstanceIdentifier(BAR_BEE, ImmutableSet.of()));
208         assertSerdes("/bar:bee[.='one']", buildYangInstanceIdentifier(BAR_BEE, ImmutableSet.of("one")));
209         assertSerdes("/bar:bee[.='two three']", buildYangInstanceIdentifier(BAR_BEE, ImmutableSet.of("two", "three")));
210     }
211
212     private static void assertSerdes(final String expected, final YangInstanceIdentifier id) throws Exception {
213         final var writer = mock(JSONValueWriter.class);
214         doNothing().when(writer).writeString(any());
215         CODEC.writeValue(writer, id);
216
217         final var captor = ArgumentCaptor.forClass(String.class);
218         verify(writer).writeString(captor.capture());
219
220         assertEquals(expected, captor.getValue());
221         assertEquals(id, CODEC.parseValue(expected));
222     }
223
224     private static YangInstanceIdentifier buildYangInstanceIdentifier(final QName node, final QName key,
225             final Object value) {
226         return YangInstanceIdentifier.of(new NodeIdentifier(node), NodeIdentifierWithPredicates.of(node, key, value));
227     }
228
229     private static YangInstanceIdentifier buildYangInstanceIdentifier(final QName node, final Object value) {
230         return YangInstanceIdentifier.of(new NodeIdentifier(node), new NodeWithValue<>(node, value));
231     }
232 }