Merge changes I38344133,Ib209ceed,I3f643034,I2f4ed366
[controller.git] / opendaylight / md-sal / sal-common-impl / src / test / java / org / opendaylight / controller / md / sal / common / impl / util / compat / DataNormalizerTest.java
1 /*
2  * Copyright (c) 2014 Brocade Communications 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.controller.md.sal.common.impl.util.compat;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15
16 import com.google.common.collect.ImmutableList;
17 import com.google.common.collect.Lists;
18 import com.google.common.collect.Maps;
19 import com.google.common.collect.Sets;
20
21 import java.util.AbstractMap;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.Set;
30
31 import org.junit.Test;
32 import org.opendaylight.yangtools.yang.common.QName;
33 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
34 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
38 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
39 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
40 import org.opendaylight.yangtools.yang.data.api.Node;
41 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
47 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
49 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
50 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
51 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
56 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
57 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
58 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
59 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
60 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
61 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
62 import org.opendaylight.yangtools.yang.model.api.Module;
63 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
64 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
65
66 public class DataNormalizerTest {
67
68     static class NormalizedNodeData {
69         PathArgument nodeID;
70         Class<?> nodeClass;
71         Object nodeData; // List for a container, value Object for a leaf
72
73         NormalizedNodeData(final PathArgument nodeID, final Class<?> nodeClass, final Object nodeData) {
74             this.nodeID = nodeID;
75             this.nodeClass = nodeClass;
76             this.nodeData = nodeData;
77         }
78     }
79
80     static class LegacyNodeData {
81         QName nodeKey;
82         Object nodeData; // List for a CompositeNode, value Object for a
83         // SimpeNode
84
85         LegacyNodeData(final QName nodeKey, final Object nodeData) {
86             this.nodeKey = nodeKey;
87             this.nodeData = nodeData;
88         }
89
90         @Override
91         public String toString() {
92             return nodeKey.toString();
93         }
94     }
95
96     static final QName TEST_QNAME = QName.create(
97             "urn:opendaylight:params:xml:ns:yang:controller:md:sal:normalization:test", "2014-03-13", "test");
98     static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list");
99     static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list");
100     static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice");
101     static final QName ID_QNAME = QName.create(TEST_QNAME, "id");
102     static final QName NAME_QNAME = QName.create(TEST_QNAME, "name");
103     static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value");
104
105     static final InstanceIdentifier TEST_PATH = InstanceIdentifier.of(TEST_QNAME);
106     static final InstanceIdentifier OUTER_LIST_PATH = InstanceIdentifier.builder(TEST_PATH).node(OUTER_LIST_QNAME)
107             .build();
108     static final QName ONE_QNAME = QName.create(TEST_QNAME, "one");
109     static final QName TWO_QNAME = QName.create(TEST_QNAME, "two");
110     static final QName THREE_QNAME = QName.create(TEST_QNAME, "three");
111
112     static final QName ANY_XML_DATA_QNAME = QName.create(TEST_QNAME, "any-xml-data");
113     static final QName OUTER_CONTAINER_QNAME = QName.create(TEST_QNAME, "outer-container");
114     static final QName AUGMENTED_LEAF_QNAME = QName.create(TEST_QNAME, "augmented-leaf");
115     static final QName UNKEYED_LIST_QNAME = QName.create(TEST_QNAME, "unkeyed-list");
116     static final QName UNORDERED_LEAF_LIST_QNAME = QName.create(TEST_QNAME, "unordered-leaf-list");
117     static final QName ORDERED_LEAF_LIST_QNAME = QName.create(TEST_QNAME, "ordered-leaf-list");
118
119     static final Short OUTER_LIST_ID = (short) 10;
120
121     static final InstanceIdentifier OUTER_LIST_PATH_LEGACY = InstanceIdentifier.builder(TEST_QNAME)
122             .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID).build();
123
124     static final InstanceIdentifier LEAF_TWO_PATH_LEGACY = InstanceIdentifier.builder(OUTER_LIST_PATH_LEGACY)
125             .node(TWO_QNAME).build();
126
127     static final QName ANY_XML_LEAF_QNAME = QName.create(TEST_QNAME, "leaf");;
128     static final QName ANY_XML_INNER_QNAME = QName.create(TEST_QNAME, "inner");
129     static final QName ANY_XML_INNER_LEAF_QNAME = QName.create(TEST_QNAME, "inner-leaf");
130
131     SchemaContext createTestContext() {
132         YangParserImpl parser = new YangParserImpl();
133         Set<Module> modules = parser.parseYangModelsFromStreams(Collections.singletonList(DataNormalizerTest.class
134                 .getResourceAsStream("/normalization-test.yang")));
135         return parser.resolveSchemaContext(modules);
136     }
137
138     @Test
139     public void testToNormalizedInstanceIdentifier() {
140         SchemaContext testCtx = createTestContext();
141         DataNormalizer normalizer = new DataNormalizer(testCtx);
142
143         InstanceIdentifier normalizedPath = normalizer.toNormalized(LEAF_TWO_PATH_LEGACY);
144
145         verifyNormalizedInstanceIdentifier(normalizedPath, TEST_QNAME, OUTER_LIST_QNAME, new Object[] {
146                 OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID }, OUTER_CHOICE_QNAME, TWO_QNAME);
147     }
148
149     private void verifyNormalizedInstanceIdentifier(final InstanceIdentifier actual, final Object... expPath) {
150
151         assertNotNull("Actual InstanceIdentifier is null", actual);
152         assertEquals("InstanceIdentifier path length", expPath.length, actual.getPath().size());
153
154         for (int i = 0; i < expPath.length; i++) {
155             PathArgument actualArg = actual.getPath().get(i);
156             if (expPath[i] instanceof Object[]) { // NodeIdentifierWithPredicates
157                 Object[] exp = (Object[]) expPath[i];
158                 assertEquals("Actual path arg " + (i + 1) + " class", NodeIdentifierWithPredicates.class,
159                         actualArg.getClass());
160                 NodeIdentifierWithPredicates actualNode = (NodeIdentifierWithPredicates) actualArg;
161                 assertEquals("Actual path arg " + (i + 1) + " node type", exp[0], actualNode.getNodeType());
162                 assertEquals("Actual path arg " + (i + 1) + " key values map size", 1, actualNode.getKeyValues().size());
163                 Entry<QName, Object> keyValuesEntry = actualNode.getKeyValues().entrySet().iterator().next();
164                 assertEquals("Actual path arg " + (i + 1) + " key values map key", exp[1], keyValuesEntry.getKey());
165                 assertEquals("Actual path arg " + (i + 1) + " key values map value", exp[2], keyValuesEntry.getValue());
166             } else if (expPath[i] instanceof Set) { // AugmentationIdentifier
167                 assertEquals("Actual path arg " + (i + 1) + " class", AugmentationIdentifier.class,
168                         actualArg.getClass());
169                 AugmentationIdentifier actualNode = (AugmentationIdentifier) actualArg;
170                 assertEquals("Actual path arg " + (i + 1) + " PossibleChildNames", expPath[i],
171                         actualNode.getPossibleChildNames());
172             } else {
173                 assertEquals("Actual path arg " + (i + 1) + " node type", expPath[i], actualArg.getNodeType());
174             }
175         }
176     }
177
178     @Test
179     public void testToLegacyInstanceIdentifier() throws DataNormalizationException {
180
181         DataNormalizer normalizer = new DataNormalizer(createTestContext());
182
183         InstanceIdentifier normalized = InstanceIdentifier.builder().node(TEST_QNAME).node(OUTER_LIST_QNAME)
184                 .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID).node(OUTER_CHOICE_QNAME).node(TWO_QNAME)
185                 .build();
186
187         InstanceIdentifier legacy = normalizer.toLegacy(normalized);
188
189         assertEquals("Legacy InstanceIdentifier", LEAF_TWO_PATH_LEGACY, legacy);
190     }
191
192     @Test
193     public void testToLegacyNormalizedNode() {
194
195         ChoiceNode choiceNode1 = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(OUTER_CHOICE_QNAME))
196                 .withChild(ImmutableNodes.leafNode(TWO_QNAME, "two"))
197                 .withChild(ImmutableNodes.leafNode(THREE_QNAME, "three")).build();
198
199         MapEntryNode innerListEntryNode1 = Builders.mapEntryBuilder()
200                 .withNodeIdentifier(new NodeIdentifierWithPredicates(INNER_LIST_QNAME, NAME_QNAME, "inner-name1"))
201                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "inner-name1"))
202                 .withChild(ImmutableNodes.leafNode(VALUE_QNAME, "inner-value1")).build();
203
204         MapEntryNode innerListEntryNode2 = Builders.mapEntryBuilder()
205                 .withNodeIdentifier(new NodeIdentifierWithPredicates(INNER_LIST_QNAME, NAME_QNAME, "inner-name2"))
206                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "inner-name2"))
207                 .withChild(ImmutableNodes.leafNode(VALUE_QNAME, "inner-value2")).build();
208
209         OrderedMapNode innerListNode = Builders.orderedMapBuilder()
210                 .withNodeIdentifier(new NodeIdentifier(INNER_LIST_QNAME)).withChild(innerListEntryNode1)
211                 .withChild(innerListEntryNode2).build();
212
213         Short outerListID1 = Short.valueOf((short) 10);
214         MapEntryNode outerListEntryNode1 = Builders.mapEntryBuilder()
215                 .withNodeIdentifier(new NodeIdentifierWithPredicates(OUTER_LIST_QNAME, ID_QNAME, outerListID1))
216                 .withChild(ImmutableNodes.leafNode(ID_QNAME, outerListID1)).withChild(choiceNode1)
217                 .withChild(innerListNode).build();
218
219         ChoiceNode choiceNode2 = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(OUTER_CHOICE_QNAME))
220                 .withChild(ImmutableNodes.leafNode(ONE_QNAME, "one")).build();
221
222         Short outerListID2 = Short.valueOf((short) 20);
223         MapEntryNode outerListEntryNode2 = Builders.mapEntryBuilder()
224                 .withNodeIdentifier(new NodeIdentifierWithPredicates(OUTER_LIST_QNAME, ID_QNAME, outerListID2))
225                 .withChild(ImmutableNodes.leafNode(ID_QNAME, outerListID2)).withChild(choiceNode2).build();
226
227         MapNode outerListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(OUTER_LIST_QNAME))
228                 .withChild(outerListEntryNode1).withChild(outerListEntryNode2).build();
229
230         UnkeyedListEntryNode unkeyedListEntryNode1 = Builders.unkeyedListEntryBuilder()
231                 .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME))
232                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "unkeyed1")).build();
233
234         UnkeyedListEntryNode unkeyedListEntryNode2 = Builders.unkeyedListEntryBuilder()
235                 .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME))
236                 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "unkeyed2")).build();
237
238         UnkeyedListNode unkeyedListNode = Builders.unkeyedListBuilder()
239                 .withNodeIdentifier(new NodeIdentifier(UNKEYED_LIST_QNAME)).withChild(unkeyedListEntryNode1)
240                 .withChild(unkeyedListEntryNode2).build();
241
242         ContainerNode testContainerNode = Builders.containerBuilder()
243                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(outerListNode).withChild(unkeyedListNode)
244                 .build();
245
246         Node<?> legacyNode = DataNormalizer.toLegacy(testContainerNode);
247
248         verifyLegacyNode(
249                 legacyNode,
250                 expectCompositeNode(
251                         TEST_QNAME,
252                         expectCompositeNode(
253                                 OUTER_LIST_QNAME,
254                                 expectSimpleNode(ID_QNAME, outerListID1),
255                                 expectSimpleNode(TWO_QNAME, "two"),
256                                 expectSimpleNode(THREE_QNAME, "three"),
257
258                                 expectCompositeNode(INNER_LIST_QNAME, expectSimpleNode(NAME_QNAME, "inner-name1"),
259                                         expectSimpleNode(VALUE_QNAME, "inner-value1")),
260
261                                         expectCompositeNode(INNER_LIST_QNAME, expectSimpleNode(NAME_QNAME, "inner-name2"),
262                                                 expectSimpleNode(VALUE_QNAME, "inner-value2"))),
263                                                 expectCompositeNode(OUTER_LIST_QNAME, expectSimpleNode(ID_QNAME, outerListID2),
264                                                         expectSimpleNode(ONE_QNAME, "one")),
265                                                         expectCompositeNode(UNKEYED_LIST_QNAME, expectSimpleNode(NAME_QNAME, "unkeyed1")),
266                                                         expectCompositeNode(UNKEYED_LIST_QNAME, expectSimpleNode(NAME_QNAME, "unkeyed2"))));
267
268         // Conversion of Mixin type nodes is not supported.
269
270         assertNull("Expected null returned for Mixin type node", DataNormalizer.toLegacy(outerListNode));
271     }
272
273     /**
274      * Following data are constructed: <any-xml-data> <inner>
275      * <inner-leaf>inner-leaf-value</inner-leaf> </inner>
276      * <leaf>leaf-value</leaf> <any-xml-data>
277      */
278     @Test
279     public void testToLegacyNormalizedNodeWithAnyXml() {
280
281         Node<?> innerLeafChild = NodeFactory.createImmutableSimpleNode(ANY_XML_INNER_LEAF_QNAME, null,
282                 "inner-leaf-value");
283         CompositeNode innerContainer = NodeFactory.createImmutableCompositeNode(ANY_XML_INNER_QNAME, null,
284                 Collections.<Node<?>> singletonList(innerLeafChild));
285
286         Node<?> leafChild = NodeFactory.createImmutableSimpleNode(ANY_XML_LEAF_QNAME, null, "leaf-value");
287         CompositeNode anyXmlNodeValue = NodeFactory.createImmutableCompositeNode(ANY_XML_DATA_QNAME, null,
288                 Arrays.asList(leafChild, innerContainer));
289
290         AnyXmlNode testAnyXmlNode = Builders.anyXmlBuilder().withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
291                 .withValue(anyXmlNodeValue).build();
292
293         ContainerNode testContainerNode = Builders.containerBuilder()
294                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(testAnyXmlNode).build();
295
296         DataNormalizer normalizer = new DataNormalizer(createTestContext());
297         Node<?> legacyNode = normalizer.toLegacy(InstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
298
299         verifyLegacyNode(
300                 legacyNode,
301                 expectCompositeNode(
302                         TEST_QNAME,
303                         expectCompositeNode(
304                                 ANY_XML_DATA_QNAME,
305                                 expectSimpleNode(ANY_XML_LEAF_QNAME, "leaf-value"),
306                                 expectCompositeNode(ANY_XML_INNER_QNAME,
307                                         expectSimpleNode(ANY_XML_INNER_LEAF_QNAME, "inner-leaf-value")))));
308     }
309
310     @Test
311     public void testToLegacyNormalizedNodeWithLeafLists() {
312
313         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
314         testBuilder.setQName(TEST_QNAME);
315
316         ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders.leafSetBuilder()
317                 .withNodeIdentifier(new NodeIdentifier(UNORDERED_LEAF_LIST_QNAME));
318         for (int i = 1; i <= 3; i++) {
319             leafSetBuilder.withChildValue("unordered-value" + i);
320         }
321
322         ListNodeBuilder<Object, LeafSetEntryNode<Object>> orderedLeafSetBuilder = Builders.orderedLeafSetBuilder()
323                 .withNodeIdentifier(new NodeIdentifier(ORDERED_LEAF_LIST_QNAME));
324         for (int i = 3; i > 0; i--) {
325             orderedLeafSetBuilder.withChildValue("ordered-value" + i);
326         }
327
328         ContainerNode testContainerNode = Builders.containerBuilder()
329                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(leafSetBuilder.build())
330                 .withChild(orderedLeafSetBuilder.build()).build();
331
332         DataNormalizer normalizer = new DataNormalizer(createTestContext());
333
334         Node<?> legacyNode = normalizer.toLegacy(InstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
335
336         verifyLegacyNode(
337                 legacyNode,
338                 expectCompositeNode(TEST_QNAME, expectSimpleNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value1"),
339                         expectSimpleNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value2"),
340                         expectSimpleNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value3"),
341                         expectSimpleNode(ORDERED_LEAF_LIST_QNAME, "ordered-value3"),
342                         expectSimpleNode(ORDERED_LEAF_LIST_QNAME, "ordered-value2"),
343                         expectSimpleNode(ORDERED_LEAF_LIST_QNAME, "ordered-value1")));
344     }
345
346     @Test
347     public void testToLegacyNormalizedNodeWithAugmentation() {
348
349         AugmentationNode augmentationNode = Builders.augmentationBuilder()
350                 .withNodeIdentifier(new AugmentationIdentifier(Sets.newHashSet(AUGMENTED_LEAF_QNAME)))
351                 .withChild(ImmutableNodes.leafNode(AUGMENTED_LEAF_QNAME, "augmented-value")).build();
352
353         ContainerNode outerContainerNode = Builders.containerBuilder()
354                 .withNodeIdentifier(new NodeIdentifier(OUTER_CONTAINER_QNAME)).withChild(augmentationNode).build();
355
356         ContainerNode testContainerNode = Builders.containerBuilder()
357                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(outerContainerNode).build();
358
359         DataNormalizer normalizer = new DataNormalizer(createTestContext());
360
361         Node<?> legacyNode = normalizer.toLegacy(InstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
362
363         verifyLegacyNode(
364                 legacyNode,
365                 expectCompositeNode(
366                         TEST_QNAME,
367                         expectCompositeNode(OUTER_CONTAINER_QNAME,
368                                 expectSimpleNode(AUGMENTED_LEAF_QNAME, "augmented-value"))));
369     }
370
371     private boolean isOrdered(final QName nodeName) {
372         return ORDERED_LEAF_LIST_QNAME.equals(nodeName) || INNER_LIST_QNAME.equals(nodeName);
373     }
374
375     @SuppressWarnings("unchecked")
376     private void verifyLegacyNode(final Node<?> actual, final LegacyNodeData expNodeData) {
377
378         assertNotNull("Actual Node is null", actual);
379         assertTrue("Expected CompositeNode instance", actual instanceof CompositeNode);
380         CompositeNode actualCN = (CompositeNode) actual;
381         assertEquals("Node key", expNodeData.nodeKey, actualCN.getKey());
382
383         List<LegacyNodeData> expChildData = Lists.newArrayList();
384         List<LegacyNodeData> unorderdChildData = Lists.newArrayList();
385         for (LegacyNodeData data : (List<LegacyNodeData>) expNodeData.nodeData) {
386             if (isOrdered(data.nodeKey)) {
387                 expChildData.add(data);
388             } else {
389                 unorderdChildData.add(data);
390             }
391         }
392
393         Collections.sort(unorderdChildData, new Comparator<LegacyNodeData>() {
394             @Override
395             public int compare(final LegacyNodeData arg1, final LegacyNodeData arg2) {
396                 if (!(arg1.nodeData instanceof List) && !(arg2.nodeData instanceof List)) {
397                     // if neither is a list, just compare them
398                     String str1 = arg1.nodeKey.getLocalName() + arg1.nodeData;
399                     String str2 = arg2.nodeKey.getLocalName() + arg2.nodeData;
400                     return str1.compareTo(str2);
401                 } else if (arg1.nodeData instanceof List && arg2.nodeData instanceof List) {
402                     // if both are lists, first check their local name
403                     String str1 = arg1.nodeKey.getLocalName();
404                     String str2 = arg2.nodeKey.getLocalName();
405                     if (!str1.equals(str2)) {
406                         return str1.compareTo(str2);
407                     } else {
408                         // if local names are the same, then look at the list contents
409                         List<LegacyNodeData> l1 = (List<LegacyNodeData>) arg1.nodeData;
410                         List<LegacyNodeData> l2 = (List<LegacyNodeData>) arg2.nodeData;
411
412                         if (l1.size() != l2.size()) {
413                             // if the sizes are different, use that
414                             return l2.size() - l1.size();
415                         } else {
416                             // lastly sort and recursively check the list contents
417                             Collections.sort(l1, this);
418                             Collections.sort(l2, this);
419
420                             for (int i = 0 ; i < l1.size() ; i++) {
421                                 int diff = this.compare(l1.get(i), l2.get(i));
422                                 if (diff != 0) {
423                                     return diff;
424                                 }
425                             }
426                             return 0;
427                         }
428                     }
429                 } else if( arg1.nodeData instanceof List ) {
430                     return -1;
431                 } else{
432                     return 1;
433                 }
434             }
435         });
436
437         expChildData.addAll(unorderdChildData);
438
439         List<Node<?>> actualChildNodes = Lists.newArrayList();
440         List<Node<?>> unorderedChildNodes = Lists.newArrayList();
441         for (Node<?> node : actualCN.getValue()) {
442             if (isOrdered(node.getKey())) {
443                 actualChildNodes.add(node);
444             } else {
445                 unorderedChildNodes.add(node);
446             }
447         }
448
449         Collections.sort(unorderedChildNodes, new Comparator<Node<?>>() {
450             @Override
451             public int compare(final Node<?> n1, final Node<?> n2) {
452                 if (n1 instanceof SimpleNode && n2 instanceof SimpleNode) {
453                     // if they're SimpleNodes just compare their strings
454                     String str1 = n1.getKey().getLocalName() + ((SimpleNode<?>)n1).getValue();
455                     String str2 = n2.getKey().getLocalName() + ((SimpleNode<?>)n2).getValue();
456                     return str1.compareTo(str2);
457                 } else if (n1 instanceof CompositeNode && n2 instanceof CompositeNode) {
458                     // if they're CompositeNodes, things are more interesting
459                     String str1 = n1.getKey().getLocalName();
460                     String str2 = n2.getKey().getLocalName();
461                     if (!str1.equals(str2)) {
462                         // if their local names differ, return that difference
463                         return str1.compareTo(str2);
464                     } else {
465                         // otherwise, we need to look at their contents
466                         ArrayList<Node<?>> l1 = new ArrayList<Node<?>>( ((CompositeNode)n1).getValue() );
467                         ArrayList<Node<?>> l2 = new ArrayList<Node<?>>( ((CompositeNode)n2).getValue() );
468
469                         if (l1.size() != l2.size()) {
470                             // if they have different numbers of things in them return that
471                             return l2.size() - l1.size();
472                         } else {
473                             // otherwise, compare the individual elements, first sort them
474                             Collections.sort(l1, this);
475                             Collections.sort(l2, this);
476
477                             // then compare them individually
478                             for(int i = 0 ; i < l2.size() ; i++) {
479                                 int diff = this.compare(l1.get(i), l2.get(i));
480                                 if(diff != 0){
481                                     return diff;
482                                 }
483                             }
484                             return 0;
485                         }
486                     }
487                 } else if (n1 instanceof CompositeNode && n2 instanceof SimpleNode) {
488                     return -1;
489                 } else if (n2 instanceof CompositeNode && n1 instanceof SimpleNode) {
490                     return 1;
491                 } else {
492                     assertTrue("Expected either SimpleNodes CompositeNodes", false);
493                     return 0;
494                 }
495             }
496         });
497
498         actualChildNodes.addAll(unorderedChildNodes);
499
500         for (Node<?> actualChild : actualChildNodes) {
501             LegacyNodeData expData = expChildData.isEmpty() ? null : expChildData.remove(0);
502             assertNotNull("Unexpected child node with key " + actualChild.getKey(), expData);
503             assertEquals("Child node QName", expData.nodeKey, actualChild.getKey());
504
505             if (expData.nodeData instanceof List) { // List represents a
506                 // composite node
507                 verifyLegacyNode(actualChild, expData);
508             } else { // else a simple node
509                 assertTrue("Expected SimpleNode instance", actualChild instanceof SimpleNode);
510                 assertEquals("Child node value with key " + actualChild.getKey(), expData.nodeData,
511                         ((SimpleNode<?>) actualChild).getValue());
512             }
513         }
514
515         if (!expChildData.isEmpty()) {
516             fail("Missing child nodes: " + expChildData);
517         }
518     }
519
520     private LegacyNodeData expectCompositeNode(final QName key, final LegacyNodeData... childData) {
521         return new LegacyNodeData(key, Lists.newArrayList(childData));
522     }
523
524     private LegacyNodeData expectSimpleNode(final QName key, final Object value) {
525         return new LegacyNodeData(key, value);
526     }
527
528     @Test
529     public void testToNormalizedCompositeNode() {
530         SchemaContext testCtx = createTestContext();
531         DataNormalizer normalizer = new DataNormalizer(testCtx);
532
533         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
534         testBuilder.setQName(TEST_QNAME);
535
536         CompositeNodeBuilder<ImmutableCompositeNode> outerListBuilder = ImmutableCompositeNode.builder();
537         outerListBuilder.setQName(OUTER_LIST_QNAME);
538         outerListBuilder.addLeaf(ID_QNAME, 10);
539         outerListBuilder.addLeaf(ONE_QNAME, "one");
540
541         for (int i = 3; i > 0; i--) {
542             CompositeNodeBuilder<ImmutableCompositeNode> innerListBuilder = ImmutableCompositeNode.builder();
543             innerListBuilder.setQName(INNER_LIST_QNAME);
544             innerListBuilder.addLeaf(NAME_QNAME, "inner-name" + i);
545             innerListBuilder.addLeaf(VALUE_QNAME, "inner-value" + i);
546             outerListBuilder.add(innerListBuilder.toInstance());
547         }
548
549         testBuilder.add(outerListBuilder.toInstance());
550
551         outerListBuilder = ImmutableCompositeNode.builder();
552         outerListBuilder.setQName(OUTER_LIST_QNAME);
553         outerListBuilder.addLeaf(ID_QNAME, 20);
554         outerListBuilder.addLeaf(TWO_QNAME, "two");
555         outerListBuilder.addLeaf(THREE_QNAME, "three");
556         testBuilder.add(outerListBuilder.toInstance());
557
558         for (int i = 1; i <= 2; i++) {
559             CompositeNodeBuilder<ImmutableCompositeNode> unkeyedListBuilder = ImmutableCompositeNode.builder();
560             unkeyedListBuilder.setQName(UNKEYED_LIST_QNAME);
561             unkeyedListBuilder.addLeaf(NAME_QNAME, "unkeyed-name" + i);
562             testBuilder.add(unkeyedListBuilder.toInstance());
563         }
564
565         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
566                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(InstanceIdentifier.create(
567                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
568
569         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
570
571         verifyNormalizedNode(
572                 normalizedNodeEntry.getValue(),
573                 expectContainerNode(
574                         TEST_QNAME,
575                         expectMapNode(
576                                 OUTER_LIST_QNAME,
577                                 expectMapEntryNode(
578                                         OUTER_LIST_QNAME,
579                                         ID_QNAME,
580                                         10,
581                                         expectLeafNode(ID_QNAME, 10),
582                                         expectChoiceNode(OUTER_CHOICE_QNAME, expectLeafNode(ONE_QNAME, "one")),
583                                         expectOrderedMapNode(
584                                                 INNER_LIST_QNAME,
585                                                 expectMapEntryNode(INNER_LIST_QNAME, NAME_QNAME, "inner-name3",
586                                                         expectLeafNode(NAME_QNAME, "inner-name3"),
587                                                         expectLeafNode(VALUE_QNAME, "inner-value3")),
588                                                         expectMapEntryNode(INNER_LIST_QNAME, NAME_QNAME, "inner-name2",
589                                                                 expectLeafNode(NAME_QNAME, "inner-name2"),
590                                                                 expectLeafNode(VALUE_QNAME, "inner-value2")),
591                                                                 expectMapEntryNode(INNER_LIST_QNAME, NAME_QNAME, "inner-name1",
592                                                                         expectLeafNode(NAME_QNAME, "inner-name1"),
593                                                                         expectLeafNode(VALUE_QNAME, "inner-value1")))),
594                                                                         expectMapEntryNode(
595                                                                                 OUTER_LIST_QNAME,
596                                                                                 ID_QNAME,
597                                                                                 20,
598                                                                                 expectLeafNode(ID_QNAME, 20),
599                                                                                 expectChoiceNode(OUTER_CHOICE_QNAME, expectLeafNode(TWO_QNAME, "two"),
600                                                                                         expectLeafNode(THREE_QNAME, "three")))),
601                                                                                         expectUnkeyedListNode(
602                                                                                                 UNKEYED_LIST_QNAME,
603                                                                                                 expectUnkeyedListEntryNode(UNKEYED_LIST_QNAME,
604                                                                                                         expectLeafNode(NAME_QNAME, "unkeyed-name1")),
605                                                                                                         expectUnkeyedListEntryNode(UNKEYED_LIST_QNAME,
606                                                                                                                 expectLeafNode(NAME_QNAME, "unkeyed-name2")))));
607     }
608
609     @Test
610     public void testToNormalizedCompositeNodeWithAnyXml() {
611         SchemaContext testCtx = createTestContext();
612         DataNormalizer normalizer = new DataNormalizer(testCtx);
613
614         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
615         testBuilder.setQName(TEST_QNAME);
616
617         CompositeNodeBuilder<ImmutableCompositeNode> anyXmlBuilder = ImmutableCompositeNode.builder();
618         anyXmlBuilder.setQName(ANY_XML_DATA_QNAME);
619         anyXmlBuilder.addLeaf(ANY_XML_LEAF_QNAME, "leaf-value");
620
621         CompositeNodeBuilder<ImmutableCompositeNode> innerBuilder = ImmutableCompositeNode.builder();
622         innerBuilder.setQName(ANY_XML_INNER_QNAME);
623         innerBuilder.addLeaf(ANY_XML_INNER_LEAF_QNAME, "inner-leaf-value");
624
625         anyXmlBuilder.add(innerBuilder.toInstance());
626         CompositeNode anyXmlLegacy = anyXmlBuilder.toInstance();
627         testBuilder.add(anyXmlLegacy);
628
629         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
630                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(InstanceIdentifier.create(
631                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
632
633         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
634
635         verifyNormalizedNode(normalizedNodeEntry.getValue(),
636                 expectContainerNode(TEST_QNAME, expectAnyXmlNode(ANY_XML_DATA_QNAME, anyXmlLegacy)));
637     }
638
639     @Test
640     public void testToNormalizedCompositeNodeWithAugmentation() {
641         SchemaContext testCtx = createTestContext();
642         DataNormalizer normalizer = new DataNormalizer(testCtx);
643
644         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
645         testBuilder.setQName(TEST_QNAME);
646
647         CompositeNodeBuilder<ImmutableCompositeNode> outerContBuilder = ImmutableCompositeNode.builder();
648         outerContBuilder.setQName(OUTER_CONTAINER_QNAME);
649         outerContBuilder.addLeaf(AUGMENTED_LEAF_QNAME, "augmented-value");
650
651         testBuilder.add(outerContBuilder.toInstance());
652
653         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
654                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(InstanceIdentifier.create(
655                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
656
657         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
658
659         NormalizedNodeData expAugmentation = expectAugmentation(AUGMENTED_LEAF_QNAME,
660                 expectLeafNode(AUGMENTED_LEAF_QNAME, "augmented-value"));
661
662         verifyNormalizedNode(normalizedNodeEntry.getValue(),
663                 expectContainerNode(TEST_QNAME, expectContainerNode(OUTER_CONTAINER_QNAME, expAugmentation)));
664
665         normalizedNodeEntry = normalizer.toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(
666                 InstanceIdentifier.create(Lists.newArrayList(new NodeIdentifier(TEST_QNAME), new NodeIdentifier(
667                         OUTER_CONTAINER_QNAME))), outerContBuilder.toInstance()));
668
669         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME, OUTER_CONTAINER_QNAME,
670                 Sets.newHashSet(AUGMENTED_LEAF_QNAME));
671
672         verifyNormalizedNode(normalizedNodeEntry.getValue(), expAugmentation);
673     }
674
675     @Test
676     public void testToNormalizedCompositeNodeWithLeafLists() {
677         SchemaContext testCtx = createTestContext();
678         DataNormalizer normalizer = new DataNormalizer(testCtx);
679
680         CompositeNodeBuilder<ImmutableCompositeNode> testBuilder = ImmutableCompositeNode.builder();
681         testBuilder.setQName(TEST_QNAME);
682
683         for (int i = 1; i <= 3; i++) {
684             testBuilder.addLeaf(UNORDERED_LEAF_LIST_QNAME, "unordered-value" + i);
685         }
686
687         for (int i = 3; i > 0; i--) {
688             testBuilder.addLeaf(ORDERED_LEAF_LIST_QNAME, "ordered-value" + i);
689         }
690
691         Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = normalizer
692                 .toNormalized(new AbstractMap.SimpleEntry<InstanceIdentifier, CompositeNode>(InstanceIdentifier.create(
693                         ImmutableList.<PathArgument> of(new NodeIdentifier(TEST_QNAME))), testBuilder.toInstance()));
694
695         verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME);
696
697         verifyNormalizedNode(
698                 normalizedNodeEntry.getValue(),
699                 expectContainerNode(
700                         TEST_QNAME,
701                         expectLeafSetNode(UNORDERED_LEAF_LIST_QNAME,
702                                 expectLeafSetEntryNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value1"),
703                                 expectLeafSetEntryNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value2"),
704                                 expectLeafSetEntryNode(UNORDERED_LEAF_LIST_QNAME, "unordered-value3")),
705                                 expectOrderedLeafSetNode(ORDERED_LEAF_LIST_QNAME,
706                                         expectLeafSetEntryNode(ORDERED_LEAF_LIST_QNAME, "ordered-value3"),
707                                         expectLeafSetEntryNode(ORDERED_LEAF_LIST_QNAME, "ordered-value2"),
708                                         expectLeafSetEntryNode(ORDERED_LEAF_LIST_QNAME, "ordered-value1"))));
709     }
710
711     @SuppressWarnings("unchecked")
712     private void verifyNormalizedNode(final NormalizedNode<?, ?> actual, final NormalizedNodeData expNodeData) {
713
714         Class<?> expNodeClass = expNodeData.nodeClass;
715         PathArgument expNodeID = expNodeData.nodeID;
716
717         assertNotNull("Actual NormalizedNode is null", actual);
718         assertTrue("NormalizedNode instance " + actual.getClass() + " is not derived from " + expNodeClass,
719                 expNodeClass.isAssignableFrom(actual.getClass()));
720         assertEquals("NormalizedNode identifier", expNodeID, actual.getIdentifier());
721
722         if (expNodeData.nodeData instanceof List) {
723             Map<PathArgument, Integer> orderingMap = null;
724             if (expNodeClass.equals(OrderedMapNode.class) || expNodeClass.equals(OrderedLeafSetNode.class)) {
725                 orderingMap = Maps.newHashMap();
726             }
727
728             int i = 1;
729             Map<PathArgument, NormalizedNodeData> expChildDataMap = Maps.newHashMap();
730             List<NormalizedNodeData> expChildDataList = (List<NormalizedNodeData>) expNodeData.nodeData;
731             for (NormalizedNodeData data : expChildDataList) {
732                 expChildDataMap.put(data.nodeID, data);
733
734                 if (orderingMap != null) {
735                     orderingMap.put(data.nodeID, i++);
736                 }
737             }
738
739             assertNotNull("Actual value is null for node " + actual.getIdentifier(), actual.getValue());
740             assertTrue("Expected value instance Iterable for node " + actual.getIdentifier(),
741                     Iterable.class.isAssignableFrom(actual.getValue().getClass()));
742
743             i = 1;
744             for (NormalizedNode<?, ?> actualChild : (Iterable<NormalizedNode<?, ?>>) actual.getValue()) {
745                 NormalizedNodeData expChildData = expNodeClass.equals(UnkeyedListNode.class) ? expChildDataList
746                         .remove(0) : expChildDataMap.remove(actualChild.getIdentifier());
747
748                         assertNotNull(
749                                 "Unexpected child node " + actualChild.getClass() + " with identifier "
750                                         + actualChild.getIdentifier() + " for parent node " + actual.getClass()
751                                         + " with identifier " + actual.getIdentifier(), expChildData);
752
753                         if (orderingMap != null) {
754                             assertEquals("Order index for child node " + actualChild.getIdentifier(),
755                                     orderingMap.get(actualChild.getIdentifier()), Integer.valueOf(i));
756                         }
757
758                         verifyNormalizedNode(actualChild, expChildData);
759                         i++;
760             }
761
762             if (expNodeClass.equals(UnkeyedListNode.class)) {
763                 if (expChildDataList.size() > 0) {
764                     fail("Missing " + expChildDataList.size() + " child nodes for parent " + actual.getIdentifier());
765                 }
766             } else {
767                 if (!expChildDataMap.isEmpty()) {
768                     fail("Missing child nodes for parent " + actual.getIdentifier() + ": " + expChildDataMap.keySet());
769                 }
770             }
771         } else {
772             assertEquals("Leaf value for node " + actual.getIdentifier(), expNodeData.nodeData, actual.getValue());
773         }
774     }
775
776     private NormalizedNodeData expectOrderedLeafSetNode(final QName nodeName, final NormalizedNodeData... childData) {
777         return new NormalizedNodeData(new NodeIdentifier(nodeName), OrderedLeafSetNode.class,
778                 Lists.newArrayList(childData));
779     }
780
781     private NormalizedNodeData expectLeafSetNode(final QName nodeName, final NormalizedNodeData... childData) {
782         return new NormalizedNodeData(new NodeIdentifier(nodeName), LeafSetNode.class, Lists.newArrayList(childData));
783     }
784
785     private NormalizedNodeData expectLeafSetEntryNode(final QName nodeName, final Object value) {
786         return new NormalizedNodeData(new NodeWithValue(nodeName, value), LeafSetEntryNode.class, value);
787     }
788
789     private NormalizedNodeData expectUnkeyedListNode(final QName nodeName, final NormalizedNodeData... childData) {
790         return new NormalizedNodeData(new NodeIdentifier(nodeName), UnkeyedListNode.class,
791                 Lists.newArrayList(childData));
792     }
793
794     private NormalizedNodeData expectUnkeyedListEntryNode(final QName nodeName, final NormalizedNodeData... childData) {
795         return new NormalizedNodeData(new NodeIdentifier(nodeName), UnkeyedListEntryNode.class,
796                 Lists.newArrayList(childData));
797     }
798
799     private NormalizedNodeData expectAugmentation(final QName augmentedNodeName, final NormalizedNodeData... childData) {
800         return new NormalizedNodeData(new AugmentationIdentifier(Sets.newHashSet(augmentedNodeName)),
801                 AugmentationNode.class, Lists.newArrayList(childData));
802     }
803
804     private NormalizedNodeData expectAnyXmlNode(final QName nodeName, final Object value) {
805         return new NormalizedNodeData(new NodeIdentifier(nodeName), AnyXmlNode.class, value);
806     }
807
808     private NormalizedNodeData expectContainerNode(final QName nodeName, final NormalizedNodeData... childData) {
809         return new NormalizedNodeData(new NodeIdentifier(nodeName), ContainerNode.class, Lists.newArrayList(childData));
810     }
811
812     private NormalizedNodeData expectChoiceNode(final QName nodeName, final NormalizedNodeData... childData) {
813         return new NormalizedNodeData(new NodeIdentifier(nodeName), ChoiceNode.class, Lists.newArrayList(childData));
814     }
815
816     private NormalizedNodeData expectLeafNode(final QName nodeName, final Object value) {
817         return new NormalizedNodeData(new NodeIdentifier(nodeName), LeafNode.class, value);
818
819     }
820
821     private NormalizedNodeData expectMapEntryNode(final QName nodeName, final QName key, final Object value,
822             final NormalizedNodeData... childData) {
823         return new NormalizedNodeData(new NodeIdentifierWithPredicates(nodeName, key, value), MapEntryNode.class,
824                 Lists.newArrayList(childData));
825     }
826
827     private NormalizedNodeData expectMapNode(final QName key, final NormalizedNodeData... childData) {
828         return new NormalizedNodeData(new NodeIdentifier(key), MapNode.class, Lists.newArrayList(childData));
829     }
830
831     private NormalizedNodeData expectOrderedMapNode(final QName key, final NormalizedNodeData... childData) {
832         return new NormalizedNodeData(new NodeIdentifier(key), OrderedMapNode.class, Lists.newArrayList(childData));
833     }
834 }