59423ce3c2d473716f53bbf9ca97ce24fca14dd3
[mdsal.git] / binding / mdsal-binding-dom-codec / src / test / java / org / opendaylight / mdsal / binding / dom / codec / impl / NormalizedNodeSerializeDeserializeTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.mdsal.binding.dom.codec.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertThrows;
14 import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.top;
15 import static org.opendaylight.mdsal.binding.test.model.util.ListsBindingUtils.topLevelList;
16 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.choiceBuilder;
17 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder;
18 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafSetBuilder;
19 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafSetEntryBuilder;
20 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.mapBuilder;
21 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.orderedLeafSetBuilder;
22 import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.orderedMapBuilder;
23 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.leafNode;
24 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
25 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
26 import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
27
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.Set;
32 import org.junit.Test;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TopChoiceAugment1Builder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TopChoiceAugment2Builder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeLeafOnlyAugmentBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.top.choice.augment1.AugmentChoice1;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.top.choice.augment1.augment.choice1.Case1Builder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.top.choice.augment2.augment.choice2.Case11Builder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.top.choice.augment2.augment.choice2.case11.Case11ChoiceCaseContainerBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.ChoiceContainer;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.ChoiceContainerBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top1;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top1Builder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top2;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top2Builder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.TopBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.choice.identifier.ExtendedBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.choice.identifier.extended.ExtendedIdBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.top.level.list.NestedListBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.top.level.list.NestedListKey;
56 import org.opendaylight.yang.gen.v1.urn.test.foo4798.rev160101.Root;
57 import org.opendaylight.yangtools.yang.binding.Augmentation;
58 import org.opendaylight.yangtools.yang.binding.DataObject;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.QName;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
64 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
65 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
67
68 public class NormalizedNodeSerializeDeserializeTest extends AbstractBindingCodecTest {
69     public static final String TOP_LEVEL_LIST_FOO_KEY_VALUE = "foo";
70     public static final TopLevelListKey TOP_LEVEL_LIST_FOO_KEY = new TopLevelListKey(TOP_LEVEL_LIST_FOO_KEY_VALUE);
71
72     public static final QName TOP_QNAME = Top.QNAME;
73     public static final QName TOP_LEVEL_LIST_QNAME = QName.create(TOP_QNAME, "top-level-list");
74     public static final QName TOP_LEVEL_LIST_KEY_QNAME = QName.create(TOP_QNAME, "name");
75     public static final QName TOP_LEVEL_LEAF_LIST_QNAME = QName.create(TOP_QNAME, "top-level-leaf-list");
76     public static final QName TOP_LEVEL_ORDERED_LEAF_LIST_QNAME = QName.create(TOP_QNAME,
77         "top-level-ordered-leaf-list");
78     public static final QName NESTED_LIST_QNAME = QName.create(TOP_QNAME, "nested-list");
79     public static final QName NESTED_LIST_KEY_QNAME = QName.create(TOP_QNAME, "name");
80     public static final QName CHOICE_CONTAINER_QNAME = ChoiceContainer.QNAME;
81     public static final QName CHOICE_IDENTIFIER_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "identifier");
82     public static final QName CHOICE_IDENTIFIER_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "id");
83     public static final QName EXTENDED_ID_QNAME = QName.create(CHOICE_CONTAINER_QNAME, "extended-id");
84     private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value");
85
86     private static final InstanceIdentifier<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
87             .builder(Top.class).child(TopLevelList.class, TOP_LEVEL_LIST_FOO_KEY).build();
88
89     public static final YangInstanceIdentifier BI_TOP_PATH = YangInstanceIdentifier.of(TOP_QNAME);
90     public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_PATH = BI_TOP_PATH.node(TOP_LEVEL_LIST_QNAME);
91     public static final YangInstanceIdentifier BI_TOP_LEVEL_LIST_FOO_PATH = BI_TOP_LEVEL_LIST_PATH
92             .node(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME,
93                 TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE));
94     public static final YangInstanceIdentifier BI_CHOICE_CONTAINER_PATH = YangInstanceIdentifier.of(
95         CHOICE_CONTAINER_QNAME);
96
97     @Test
98     public void containerToNormalized() {
99         final var entry = codecContext.toNormalizedDataObject(InstanceIdentifier.create(Top.class), top());
100         assertEquals(getEmptyTop(), entry.node());
101     }
102
103     @Test
104     public void containerFromNormalized() {
105         final var entry = codecContext.fromNormalizedNode(BI_TOP_PATH, getEmptyTop());
106         assertEquals(top(), entry.getValue());
107     }
108
109     private static ContainerNode getEmptyTop() {
110         return containerBuilder().withNodeIdentifier(new NodeIdentifier(TOP_QNAME)).build();
111     }
112
113     private static final QName AGUMENT_STRING_Q = QName.create(TOP_QNAME, "augmented-string");
114     private static final String AUGMENT_STRING_VALUE = "testingEquals";
115     private static final QName AUGMENT_INT_Q = QName.create(TOP_QNAME, "augmented-int");
116     private static final int AUGMENT_INT_VALUE = 44;
117
118     @Test
119     public void equalsWithAugment() {
120         final ContainerNode topNormalizedWithAugments =
121             getNormalizedTopWithChildren(leafNode(AGUMENT_STRING_Q, AUGMENT_STRING_VALUE));
122         final ContainerNode topNormalized = getEmptyTop();
123
124         final var entry = codecContext.fromNormalizedNode(BI_TOP_PATH, topNormalized);
125         final var entryWithAugments = codecContext.fromNormalizedNode(BI_TOP_PATH, topNormalizedWithAugments);
126
127         // Equals on other with no augmentation should be false
128         assertNotEquals(top(), entryWithAugments.getValue());
129         // Equals on other(reversed) with no augmentation should be false
130         assertNotEquals(entryWithAugments.getValue(), top());
131         // Equals on other(lazy) with no augmentation should be false
132         assertNotEquals(entry.getValue(), entryWithAugments.getValue());
133         // Equals on other(lazy, reversed) with no augmentation should be false
134         assertNotEquals(entryWithAugments.getValue(), entry.getValue());
135
136         final Top topWithAugments = topWithAugments(
137             Map.of(Top1.class, new Top1Builder().setAugmentedString(AUGMENT_STRING_VALUE).build()));
138         // Equals other with same augment should be true
139         assertEquals(topWithAugments, entryWithAugments.getValue());
140         // Equals other with same augment should be true
141         assertEquals(entryWithAugments.getValue(), topWithAugments);
142         // Equals on self should be true
143         assertEquals(entryWithAugments.getValue(), entryWithAugments.getValue());
144
145         final Top topWithAugmentsDiffValue = topWithAugments(
146             Map.of(Top1.class, new Top1Builder().setAugmentedString("differentValue").build()));
147         assertNotEquals(topWithAugmentsDiffValue, entryWithAugments.getValue());
148         assertNotEquals(entryWithAugments.getValue(), topWithAugmentsDiffValue);
149     }
150
151     @Test
152     public void equalsWithMultipleAugments() {
153         final ContainerNode topNormalizedWithAugments = getNormalizedTopWithChildren(
154             leafNode(AGUMENT_STRING_Q, AUGMENT_STRING_VALUE),
155             leafNode(AUGMENT_INT_Q, AUGMENT_INT_VALUE));
156         final var entryWithAugments = codecContext.fromNormalizedNode(BI_TOP_PATH, topNormalizedWithAugments);
157         Top topWithAugments = topWithAugments(Map.of(
158             Top1.class, new Top1Builder().setAugmentedString(AUGMENT_STRING_VALUE).build(),
159             Top2.class, new Top2Builder().setAugmentedInt(AUGMENT_INT_VALUE).build()));
160
161         assertEquals(topWithAugments, entryWithAugments.getValue());
162         assertEquals(entryWithAugments.getValue(), topWithAugments);
163
164         topWithAugments = topWithAugments(Map.of(
165             Top1.class, new Top1Builder().setAugmentedString(AUGMENT_STRING_VALUE).build(),
166             Top2.class, new Top2Builder().setAugmentedInt(999).build()));
167
168         assertNotEquals(topWithAugments, entryWithAugments.getValue());
169         assertNotEquals(entryWithAugments.getValue(), topWithAugments);
170     }
171
172     private static ContainerNode getNormalizedTopWithChildren(final DataContainerChild... children) {
173         final var builder = containerBuilder();
174         for (DataContainerChild child : children) {
175             builder.withChild(child);
176         }
177         return builder.withNodeIdentifier(new NodeIdentifier(TOP_QNAME))
178                     .withChild(mapNodeBuilder(TOP_LEVEL_LIST_QNAME).build()).build();
179     }
180
181     private static Top topWithAugments(
182             final Map<Class<? extends Augmentation<Top>>, ? extends Augmentation<Top>> augments) {
183         final TopBuilder topBuilder = new TopBuilder();
184         for (Augmentation<Top> augment : augments.values()) {
185             topBuilder.addAugmentation(augment);
186         }
187         return topBuilder.build();
188     }
189
190     @Test
191     public void listWithKeysToNormalized() {
192         final var entry = codecContext.toNormalizedDataObject(BA_TOP_LEVEL_LIST, topLevelList(TOP_LEVEL_LIST_FOO_KEY));
193         assertEquals(mapEntryBuilder()
194             .withNodeIdentifier(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME,
195                 TOP_LEVEL_LIST_FOO_KEY_VALUE))
196             .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
197             .build(),
198             entry.node());
199     }
200
201     @Test
202     public void listWithKeysFromNormalized() {
203         final var entry = codecContext.fromNormalizedNode(BI_TOP_LEVEL_LIST_FOO_PATH, mapEntryBuilder()
204             .withNodeIdentifier(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME,
205                 TOP_LEVEL_LIST_FOO_KEY_VALUE))
206             .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
207             .build());
208         assertEquals(topLevelList(TOP_LEVEL_LIST_FOO_KEY), entry.getValue());
209     }
210
211     @Test
212     public void leafOnlyAugmentationToNormalized() {
213         final var entry = codecContext.toNormalizedDataObject(BA_TOP_LEVEL_LIST,
214             topLevelList(TOP_LEVEL_LIST_FOO_KEY,
215                 new TreeLeafOnlyAugmentBuilder().setSimpleValue("simpleValue").build()));
216         assertEquals(mapEntryBuilder()
217             .withNodeIdentifier(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME,
218                 TOP_LEVEL_LIST_FOO_KEY_VALUE))
219             .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
220             .withChild(leafNode(SIMPLE_VALUE_QNAME, "simpleValue")) // augmentation child
221             .build(),
222             entry.node());
223     }
224
225     @Test
226     public void leafOnlyAugmentationFromNormalized() {
227         final var entry = codecContext.fromNormalizedNode(BI_TOP_LEVEL_LIST_FOO_PATH, mapEntryBuilder()
228             .withNodeIdentifier(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME,
229                 TOP_LEVEL_LIST_FOO_KEY_VALUE))
230             .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
231             .withChild(leafNode(SIMPLE_VALUE_QNAME, "simpleValue")) // augmentation child
232             .build());
233         assertEquals(
234             topLevelList(TOP_LEVEL_LIST_FOO_KEY,
235                 new TreeLeafOnlyAugmentBuilder().setSimpleValue("simpleValue").build()),
236             entry.getValue());
237     }
238
239     @Test
240     public void orderedleafListToNormalized() {
241         final var entry = codecContext.toNormalizedDataObject(InstanceIdentifier.create(Top.class),
242             new TopBuilder().setTopLevelOrderedLeafList(List.of("foo")).build());
243         assertEquals(containerBuilder()
244             .withNodeIdentifier(new NodeIdentifier(TOP_QNAME))
245             .withChild(orderedLeafSetBuilder()
246                 .withNodeIdentifier(new NodeIdentifier(TOP_LEVEL_ORDERED_LEAF_LIST_QNAME))
247                 .withChild(leafSetEntryBuilder()
248                     .withNodeIdentifier(new NodeWithValue<>(TOP_LEVEL_ORDERED_LEAF_LIST_QNAME, "foo"))
249                     .withValue("foo")
250                     .build())
251                 .build())
252             .build(),
253             entry.node());
254     }
255
256     @Test
257     public void leafListToNormalized() {
258         final var entry = codecContext.toNormalizedDataObject(
259             InstanceIdentifier.create(Top.class), new TopBuilder().setTopLevelLeafList(Set.of("foo")).build());
260         assertEquals(containerBuilder()
261             .withNodeIdentifier(new NodeIdentifier(TOP_QNAME))
262             .withChild(leafSetBuilder()
263                 .withNodeIdentifier(new NodeIdentifier(TOP_LEVEL_LEAF_LIST_QNAME))
264                 .withChild(leafSetEntryBuilder()
265                     .withNodeIdentifier(new NodeWithValue<>(TOP_LEVEL_LEAF_LIST_QNAME, "foo"))
266                     .withValue("foo")
267                     .build())
268                 .build())
269             .build(),
270             entry.node());
271     }
272
273     @Test
274     public void leafListFromNormalized() {
275         final var entry = codecContext.fromNormalizedNode(BI_TOP_PATH, containerBuilder()
276             .withNodeIdentifier(new NodeIdentifier(TOP_QNAME))
277             .withChild(leafSetBuilder()
278                 .withNodeIdentifier(new NodeIdentifier(TOP_LEVEL_LEAF_LIST_QNAME))
279                 .withChild(leafSetEntryBuilder()
280                     .withNodeIdentifier(new NodeWithValue<>(TOP_LEVEL_LEAF_LIST_QNAME, "foo"))
281                     .withValue("foo")
282                     .build())
283                 .build())
284             .build());
285         assertEquals(new TopBuilder().setTopLevelLeafList(Set.of("foo")).build(), entry.getValue());
286     }
287
288     @Test
289     public void orderedLeafListFromNormalized() {
290         final var entry = codecContext.fromNormalizedNode(BI_TOP_PATH, containerBuilder()
291             .withNodeIdentifier(new NodeIdentifier(TOP_QNAME))
292             .withChild(orderedLeafSetBuilder()
293                 .withNodeIdentifier(new NodeIdentifier(TOP_LEVEL_ORDERED_LEAF_LIST_QNAME))
294                 .withChild(leafSetEntryBuilder()
295                     .withNodeIdentifier(new NodeWithValue<>(TOP_LEVEL_ORDERED_LEAF_LIST_QNAME, "foo"))
296                     .withValue("foo").build())
297                 .build())
298             .build());
299         assertEquals(new TopBuilder().setTopLevelOrderedLeafList(List.of("foo")).build(), entry.getValue());
300     }
301
302     @Test
303     public void choiceToNormalized() {
304         final var entry = codecContext.toNormalizedDataObject(InstanceIdentifier.create(ChoiceContainer.class),
305             new ChoiceContainerBuilder()
306                 .setIdentifier(new ExtendedBuilder()
307                     .setExtendedId(new ExtendedIdBuilder().setId("identifier_value").build())
308                     .build())
309                 .build());
310         assertEquals(containerBuilder()
311             .withNodeIdentifier(new NodeIdentifier(CHOICE_CONTAINER_QNAME))
312             .withChild(choiceBuilder()
313                 .withNodeIdentifier(new NodeIdentifier(CHOICE_IDENTIFIER_QNAME))
314                 .withChild(containerBuilder()
315                     .withNodeIdentifier(new NodeIdentifier(EXTENDED_ID_QNAME))
316                     .withChild(leafNode(CHOICE_IDENTIFIER_ID_QNAME, "identifier_value"))
317                     .build())
318                 .build())
319             .build(),
320             entry.node());
321     }
322
323     @Test
324     public void test4798() {
325         final QName containerIdentifierQname4798 = Root.QNAME;
326         final QName choiceIdentifierQname4798 = QName.create(containerIdentifierQname4798, "bug4798-choice");
327         final QName nestedListQname4798 = QName.create(containerIdentifierQname4798, "list-in-case");
328         final QName nestedListKeyQname4798 = QName.create(containerIdentifierQname4798, "test-leaf");
329         final QName nestedContainerValidQname = QName.create(containerIdentifierQname4798, "case-b-container");
330         final QName nestedContainerOuterQname = QName.create(containerIdentifierQname4798, "outer-container");
331         final QName nestedContainerLeafOuterQname = QName.create(containerIdentifierQname4798,
332                 "leaf-in-outer-container");
333
334         final YangInstanceIdentifier yangInstanceIdentifierOuter = YangInstanceIdentifier.of(
335             containerIdentifierQname4798);
336         final ContainerNode containerNodeOuter = containerBuilder()
337             .withNodeIdentifier(new NodeIdentifier(containerIdentifierQname4798))
338             .withChild(containerBuilder()
339                 .withNodeIdentifier(new NodeIdentifier(nestedContainerOuterQname))
340                 .withChild(leafNode(nestedContainerLeafOuterQname, "bar"))
341                 .build())
342             .build();
343         final Entry<InstanceIdentifier<?>, DataObject> entryContainer = codecContext.fromNormalizedNode(
344             yangInstanceIdentifierOuter, containerNodeOuter);
345         assertNotNull(entryContainer.getValue());
346         assertNotNull(entryContainer.getKey());
347
348         final NodeIdentifierWithPredicates nodeIdentifierWithPredicates4798 =
349                 NodeIdentifierWithPredicates.of(nestedListQname4798, nestedListKeyQname4798, "foo");
350         final YangInstanceIdentifier yangInstanceIdentifier4798 = YangInstanceIdentifier.of(
351             containerIdentifierQname4798)
352                 .node(choiceIdentifierQname4798)
353                 .node(nestedListQname4798)
354                 .node(nodeIdentifierWithPredicates4798);
355
356         final YangInstanceIdentifier yangInstanceIdentifierValid = YangInstanceIdentifier.of(
357             containerIdentifierQname4798)
358                 .node(choiceIdentifierQname4798)
359                 .node(nestedContainerValidQname)
360                 .node(nestedListQname4798)
361                 .node(nodeIdentifierWithPredicates4798);
362         final ContainerNode containerNodeValid = containerBuilder()
363             .withNodeIdentifier(new NodeIdentifier(containerIdentifierQname4798))
364             .withChild(choiceBuilder()
365                 .withNodeIdentifier(new NodeIdentifier(choiceIdentifierQname4798))
366                 .withChild(containerBuilder()
367                     .withNodeIdentifier(new NodeIdentifier(nestedContainerValidQname))
368                     .withChild(mapBuilder()
369                         .withNodeIdentifier(new NodeIdentifier(nestedListQname4798))
370                         .withChild(mapEntry(nestedListQname4798, nestedListKeyQname4798, "foo"))
371                         .withChild(mapEntry(nestedListQname4798, nestedListKeyQname4798, "bar"))
372                         .build())
373                     .build())
374                 .build())
375             .build();
376
377         var msg = assertThrows(IllegalArgumentException.class,
378             () -> codecContext.fromNormalizedNode(yangInstanceIdentifierValid, containerNodeValid))
379             .getMessage();
380         assertEquals("Expecting either a MapEntryNode or an UnkeyedListEntryNode, not ContainerNode", msg);
381
382         final ContainerNode containerNode4798 = containerBuilder()
383             .withNodeIdentifier(new NodeIdentifier(containerIdentifierQname4798))
384             .withChild(choiceBuilder()
385                 .withNodeIdentifier(new NodeIdentifier(choiceIdentifierQname4798))
386                 .withChild(mapBuilder()
387                     .withNodeIdentifier(new NodeIdentifier(nestedListQname4798))
388                     .withChild(mapEntry(nestedListQname4798, nestedListKeyQname4798, "foo"))
389                     .withChild(mapEntry(nestedListQname4798, nestedListKeyQname4798, "bar"))
390                     .build())
391                 .build())
392             .build();
393
394         msg = assertThrows(IllegalArgumentException.class,
395             () -> codecContext.fromNormalizedNode(yangInstanceIdentifier4798, containerNode4798))
396             .getMessage();
397         assertEquals("Expecting either a MapEntryNode or an UnkeyedListEntryNode, not ContainerNode", msg);
398     }
399
400     @Test
401     public void choiceFromNormalized() {
402         final ContainerNode choiceContainerBI = containerBuilder()
403             .withNodeIdentifier(new NodeIdentifier(CHOICE_CONTAINER_QNAME))
404             .withChild(choiceBuilder()
405                 .withNodeIdentifier(new NodeIdentifier(CHOICE_IDENTIFIER_QNAME))
406                 .withChild(containerBuilder()
407                     .withNodeIdentifier(new NodeIdentifier(EXTENDED_ID_QNAME))
408                     .withChild(leafNode(CHOICE_IDENTIFIER_ID_QNAME, "identifier_value"))
409                     .build())
410                 .build())
411             .build();
412         final Entry<InstanceIdentifier<?>, DataObject> entry = codecContext.fromNormalizedNode(BI_CHOICE_CONTAINER_PATH,
413             choiceContainerBI);
414         final ChoiceContainer choiceContainerBA = new ChoiceContainerBuilder().setIdentifier(new ExtendedBuilder()
415             .setExtendedId(new ExtendedIdBuilder().setId("identifier_value").build()).build()).build();
416         assertEquals(choiceContainerBA, entry.getValue());
417     }
418
419     @Test
420     public void orderedLisToNormalized() {
421         final var entry = codecContext.toNormalizedDataObject(BA_TOP_LEVEL_LIST, new TopLevelListBuilder()
422             .withKey(TOP_LEVEL_LIST_FOO_KEY)
423             .setNestedList(List.of(
424                 new NestedListBuilder().withKey(new NestedListKey("foo")).build(),
425                 new NestedListBuilder().withKey(new NestedListKey("bar")).build()))
426             .build());
427         assertEquals(mapEntryBuilder()
428             .withNodeIdentifier(NodeIdentifierWithPredicates.of(TOP_LEVEL_LIST_QNAME,
429                 TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
430             .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
431             .withChild(orderedMapBuilder()
432                 .withNodeIdentifier(new NodeIdentifier(NESTED_LIST_QNAME))
433                 .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "foo"))
434                 .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "bar"))
435                 .build())
436             .build(),
437             entry.node());
438     }
439
440     @Test
441     public void orderedLisFromNormalized() {
442         final var entry = codecContext.fromNormalizedNode(BI_TOP_LEVEL_LIST_FOO_PATH, mapEntryBuilder()
443             .withNodeIdentifier(NodeIdentifierWithPredicates.of(
444                 TOP_LEVEL_LIST_QNAME, TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
445             .withChild(leafNode(TOP_LEVEL_LIST_KEY_QNAME, TOP_LEVEL_LIST_FOO_KEY_VALUE))
446             .withChild(orderedMapBuilder()
447                 .withNodeIdentifier(new NodeIdentifier(NESTED_LIST_QNAME))
448                 .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "foo"))
449                 .withChild(mapEntry(NESTED_LIST_QNAME, NESTED_LIST_KEY_QNAME, "bar"))
450                 .build())
451             .build());
452         assertEquals(new TopLevelListBuilder()
453             .withKey(TOP_LEVEL_LIST_FOO_KEY)
454             .setNestedList(List.of(
455                 new NestedListBuilder().withKey(new NestedListKey("foo")).build(),
456                 new NestedListBuilder().withKey(new NestedListKey("bar")).build()))
457             .build(),
458             entry.getValue());
459     }
460
461     @Test
462     public void augmentMultipleChoices() {
463         final QName augmentChoice1QName = AugmentChoice1.QNAME;
464         final QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
465         final QName containerQName = QName.create(augmentChoice1QName, "case11-choice-case-container");
466         final QName leafQName = QName.create(augmentChoice1QName, "case11-choice-case-leaf");
467
468         final NodeIdentifier augmentChoice1Id = new NodeIdentifier(augmentChoice1QName);
469         final NodeIdentifier augmentChoice2Id = new NodeIdentifier(augmentChoice2QName);
470         final NodeIdentifier containerId = new NodeIdentifier(containerQName);
471
472         final Top top = new TopBuilder().addAugmentation(
473             // top is augmented with choice1 having case1
474             new TopChoiceAugment1Builder().setAugmentChoice1(
475                 new Case1Builder().addAugmentation(
476                     // case1 is augmented with choice2 having case11 (with container having leaf)
477                     new TopChoiceAugment2Builder().setAugmentChoice2(
478                         new Case11Builder().setCase11ChoiceCaseContainer(
479                                 new Case11ChoiceCaseContainerBuilder()
480                                         .setCase11ChoiceCaseLeaf("leaf-value").build()
481                         ).build()
482                     ).build()
483                 ).build()
484             ).build()
485         ).build();
486
487         final var biResult = codecContext.toNormalizedDataObject(InstanceIdentifier.create(Top.class), top);
488
489         final var topNormalized = containerBuilder()
490             .withNodeIdentifier(new NodeIdentifier(TOP_QNAME))
491             .withChild(choiceBuilder().withNodeIdentifier(augmentChoice1Id) // choice 1
492                 .withChild(choiceBuilder().withNodeIdentifier(augmentChoice2Id) // choice 2
493                     .withChild(containerBuilder().withNodeIdentifier(containerId)
494                         .withChild(leafNode(leafQName, "leaf-value")).build())
495                     .build())
496                 .build())
497             .build();
498
499         assertEquals(BI_TOP_PATH, biResult.path());
500         assertEquals(topNormalized, biResult.node());
501
502         final var baResult = codecContext.fromNormalizedNode(BI_TOP_PATH, topNormalized);
503
504         assertEquals(InstanceIdentifier.create(Top.class), baResult.getKey());
505         assertEquals(top, baResult.getValue());
506     }
507 }