Remove RestconfError.ErrorTag
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / utils / parser / YangInstanceIdentifierDeserializerTest.java
1 /*
2  * Copyright (c) 2016 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.restconf.nb.rfc8040.utils.parser;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertThrows;
12 import static org.junit.Assert.assertTrue;
13
14 import com.google.common.collect.Iterables;
15 import com.google.common.collect.Sets;
16 import java.io.FileNotFoundException;
17 import java.util.Iterator;
18 import java.util.LinkedHashMap;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.Set;
22 import org.junit.AfterClass;
23 import org.junit.BeforeClass;
24 import org.junit.Test;
25 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
26 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
27 import org.opendaylight.yangtools.yang.common.ErrorTag;
28 import org.opendaylight.yangtools.yang.common.ErrorType;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.common.Revision;
31 import org.opendaylight.yangtools.yang.common.Uint8;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
38 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
39 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
40
41 /**
42  * Unit tests for {@link YangInstanceIdentifierDeserializer}.
43  */
44 public class YangInstanceIdentifierDeserializerTest {
45     // schema context
46     private static EffectiveModelContext SCHEMA_CONTEXT;
47
48     @BeforeClass
49     public static void beforeClass() throws FileNotFoundException {
50         SCHEMA_CONTEXT =
51                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/restconf/parser/deserializer"));
52     }
53
54     @AfterClass
55     public static void afterClass() {
56         SCHEMA_CONTEXT = null;
57     }
58
59     /**
60      * Test of deserialization <code>String</code> URI with container to
61      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
62      */
63     @Test
64     public void deserializeContainerTest() {
65         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
66                 .create(SCHEMA_CONTEXT, "deserializer-test:contA");
67
68         assertEquals("Result does not contains expected number of path arguments", 1, Iterables.size(result));
69         assertEquals("Not expected path argument",
70                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
71                 result.iterator().next());
72     }
73
74     /**
75      * Test of deserialization <code>String</code> URI with container containing leaf to
76      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
77      */
78     @Test
79     public void deserializeContainerWithLeafTest() {
80         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
81                 .create(SCHEMA_CONTEXT, "deserializer-test:contA/leaf-A");
82
83         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
84
85         final Iterator<PathArgument> iterator = result.iterator();
86         assertEquals("Not expected path argument",
87                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
88                 iterator.next());
89         assertEquals("Not expected path argument",
90                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "leaf-A")),
91                 iterator.next());
92     }
93
94     /**
95      * Test of deserialization <code>String</code> URI with container containing list with leaf list to
96      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
97      */
98     @Test
99     public void deserializeContainerWithListWithLeafListTest() {
100         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
101                 .create(SCHEMA_CONTEXT, "deserializer-test:contA/list-A=100/leaf-list-AA=instance");
102
103         assertEquals("Result does not contains expected number of path arguments", 5, Iterables.size(result));
104
105         final Iterator<PathArgument> iterator = result.iterator();
106
107         // container
108         assertEquals("Not expected path argument",
109                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
110                 iterator.next());
111
112         // list
113         final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
114         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
115         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(
116             list, QName.create(list, "list-key"), 100).toString(), iterator.next().toString());
117
118         // leaf list
119         final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-AA");
120         assertEquals("Not expected path argument", NodeIdentifier.create(leafList), iterator.next());
121         assertEquals("Not expected path argument", new NodeWithValue<>(leafList, "instance"), iterator.next());
122     }
123
124     /**
125      * Test of deserialization <code>String</code> URI with container containing list with Action to
126      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
127      */
128     @Test
129     public void deserializeContainerWithListWithActionTest() {
130         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
131             "example-actions:interfaces/interface=eth0/reset");
132         assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
133
134         final Iterator<PathArgument> iterator = result.iterator();
135
136         // container
137         assertEquals("Not expected path argument",
138             NodeIdentifier.create(QName.create("https://example.com/ns/example-actions", "2016-07-07", "interfaces")),
139             iterator.next());
140
141         // list
142         final QName list = QName.create("https://example.com/ns/example-actions", "2016-07-07", "interface");
143         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
144         assertEquals("Not expected path argument",
145             NodeIdentifierWithPredicates.of(list, QName.create(list, "name"), "eth0"), iterator.next());
146
147         // action QName
148         final QName action = QName.create("https://example.com/ns/example-actions", "2016-07-07", "reset");
149         assertEquals("Not expected path argument", NodeIdentifier.create(action),
150             iterator.next());
151     }
152
153     /**
154      * Test of deserialization <code>String</code> URI containing list with no keys to
155      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
156      */
157     @Test
158     public void deserializeListWithNoKeysTest() {
159         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
160             "deserializer-test:list-no-key");
161
162         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
163
164         final Iterator<PathArgument> iterator = result.iterator();
165         final QName list = QName.create("deserializer:test", "2016-06-06", "list-no-key");
166
167         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
168         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
169     }
170
171     /**
172      * Test of deserialization <code>String</code> URI containing list with one key to
173      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
174      */
175     @Test
176     public void deserializeListWithOneKeyTest() {
177         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
178             "deserializer-test:list-one-key=value");
179
180         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
181
182         final Iterator<PathArgument> iterator = result.iterator();
183         final QName list = QName.create("deserializer:test", "2016-06-06", "list-one-key");
184
185         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
186         assertEquals("Not expected path argument",
187             NodeIdentifierWithPredicates.of(list, QName.create(list, "name"), "value"), iterator.next());
188     }
189
190     /**
191      * Test of deserialization <code>String</code> URI containing list with multiple keys to
192      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
193      */
194     @Test
195     public void deserializeListWithMultipleKeysTest() {
196         final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
197         final Map<QName, Object> values = new LinkedHashMap<>();
198         values.put(QName.create(list, "name"), "value");
199         values.put(QName.create(list, "number"), 100);
200         values.put(QName.create(list, "enabled"), false);
201
202         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
203             "deserializer-test:list-multiple-keys=value,100,false");
204
205         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
206
207         final Iterator<PathArgument> iterator = result.iterator();
208
209         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
210         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(list, values).toString(),
211                 iterator.next().toString());
212     }
213
214     /**
215      * Test of deserialization <code>String</code> URI containing leaf list to
216      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
217      */
218     @Test
219     public void deserializeLeafListTest() {
220         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
221             "deserializer-test:leaf-list-0=true");
222
223         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
224
225         final Iterator<PathArgument> iterator = result.iterator();
226         final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-0");
227
228         assertEquals("Not expected path argument", new NodeIdentifier(leafList), iterator.next());
229         assertEquals("Not expected path argument",
230                 new NodeWithValue<>(leafList, true).toString(), iterator.next().toString());
231     }
232
233     /**
234      * Test when empty <code>String</code> is supplied as an input. Test is expected to return empty result.
235      */
236     @Test
237     public void deserializeEmptyDataTest() {
238         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "");
239         assertTrue("Empty result expected", Iterables.isEmpty(result));
240     }
241
242     /**
243      * Test of deserialization <code>String</code> URI with identifiers separated by multiple slashes to
244      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
245      */
246     @Test
247     public void deserializeMultipleSlashesTest() {
248         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
249                 .create(SCHEMA_CONTEXT, "deserializer-test:contA////list-A=40//list-key");
250
251         assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
252
253         final Iterator<PathArgument> iterator = result.iterator();
254
255         // container
256         assertEquals("Not expected path argument",
257                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
258                 iterator.next());
259
260         // list
261         final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
262         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
263         assertEquals("Not expected path argument",
264                 NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 40).toString(),
265                 iterator.next().toString());
266
267         // leaf
268         assertEquals("Not expected path argument",
269                 new NodeIdentifier(QName.create("deserializer:test", "2016-06-06", "list-key")), iterator.next());
270     }
271
272     /**
273      * Negative test when supplied <code>SchemaContext</code> is null. Test is expected to fail with
274      * <code>NullPointerException</code>.
275      */
276     @Test
277     public void deserializeNullSchemaContextNegativeTest() {
278         assertThrows(NullPointerException.class,
279             () -> YangInstanceIdentifierDeserializer.create(null, "deserializer-test:contA"));
280     }
281
282     /**
283      * Negative test when supplied <code>String</code> data to deserialize is null. Test is expected to fail with
284      * <code>NullPointerException</code>.
285      */
286     @Test
287     public void nullDataNegativeNegativeTest() {
288         assertThrows(NullPointerException.class,
289             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, null));
290     }
291
292     /**
293      * Negative test when identifier is not followed by slash or equals. Test is expected to fail with
294      * <code>RestconfDocumentedException</code>.
295      */
296     @Test
297     public void deserializeBadCharMissingSlashOrEqualNegativeTest() {
298         assertThrows(RestconfDocumentedException.class,
299             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:cont*leaf-A"));
300     }
301
302     /**
303      * Negative test of validating identifier when there is a slash after container without next identifier. Test
304      * is expected to fail with <code>RestconfDocumentedException</code>.
305      */
306     @Test
307     public void validArgIdentifierContainerEndsWithSlashNegativeTest() {
308         assertThrows(RestconfDocumentedException.class,
309             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:contA/"));
310     }
311
312     /**
313      * Negative test of validating identifier when there are multiple slashes after container without next identifier.
314      * Test is expected to fail with <code>RestconfDocumentedException</code>.
315      */
316     @Test
317     public void validArgIdentifierContainerEndsWithMultipleSlashesNegativeTest() {
318         assertThrows(RestconfDocumentedException.class,
319             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:contA///"));
320     }
321
322     /**
323      * Negative test of validating identifier when there is a slash after list key values without next identifier. Test
324      * is expected to fail with <code>RestconfDocumentedException</code>.
325      */
326     @Test
327     public void validArgIdentifierListEndsWithSlashLNegativeTest() {
328         assertThrows(RestconfDocumentedException.class,
329             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:list-one-key=value/"));
330     }
331
332     /**
333      * Negative test of validating identifier when there are multiple slashes after list key values without next
334      * identifier. Test is expected to fail with <code>RestconfDocumentedException</code>.
335      */
336     @Test
337     public void validArgIdentifierListEndsWithSlashesNegativeTest() {
338         assertThrows(RestconfDocumentedException.class,
339             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:list-one-key=value//"));
340     }
341
342     /**
343      * Negative test of creating <code>QName</code> when identifier is empty (example: '/'). Test is expected to fail
344      * with <code>RestconfDocumentedException</code>.
345      */
346     @Test
347     public void prepareQnameEmptyIdentifierNegativeTest() {
348         assertThrows(RestconfDocumentedException.class,
349             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "/"));
350     }
351
352     /**
353      * Negative test of creating <code>QName</code> when in identifier there is another sign than colon or equals.
354      * Test is expected to fail with <code>RestconfDocumentedException</code>.
355      */
356     @Test
357     public void prepareQnameBuildPathNegativeTest() {
358         assertThrows(RestconfDocumentedException.class,
359             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test*contA"));
360     }
361
362     /**
363      * Negative test of creating <code>QName</code> when it is not possible to find module for specified prefix. Test is
364      * expected to fail with <code>RestconfDocumentedException</code>.
365      */
366     @Test
367     public void prepareQnameNotExistingPrefixNegativeTest() {
368         assertThrows(RestconfDocumentedException.class,
369             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "not-existing:contA"));
370     }
371
372     /**
373      * Negative test of creating <code>QName</code> when after prefix and colon there is not parsable identifier as
374      * local name. Test is expected to fail with <code>RestconfDocumentedException</code>.
375      */
376     @Test
377     public void prepareQnameNotValidPrefixAndLocalNameNegativeTest() {
378         assertThrows(RestconfDocumentedException.class, () ->
379             YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:*not-parsable-identifier"));
380     }
381
382     /**
383      * Negative test of creating <code>QName</code> when data ends after prefix and colon. Test is expected to fail
384      * with <code>StringIndexOutOfBoundsException</code>.
385      */
386     @Test
387     public void prepareQnameErrorParsingNegativeTest() {
388         assertThrows(StringIndexOutOfBoundsException.class,
389             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:"));
390     }
391
392     /**
393      * Negative test of creating <code>QName</code> when after identifier and colon there is node name of unknown
394      * node in current container. Test is expected to fail with <code>RestconfDocumentedException</code> and error
395      * type, error tag and error status code are compared to expected values.
396      */
397     @Test
398     public void prepareQnameNotValidContainerNameNegativeTest() {
399         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
400             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:contA/leafB"));
401         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
402         assertEquals("Not expected error tag", ErrorTag.DATA_MISSING,
403             ex.getErrors().get(0).getErrorTag());
404     }
405
406     /**
407      * Negative test of creating <code>QName</code> when after identifier and equals there is node name of unknown
408      * node in current list. Test is expected to fail with <code>RestconfDocumentedException</code> and error
409      * type, error tag and error status code are compared to expected values.
410      */
411     @Test
412     public void prepareQnameNotValidListNameNegativeTest() {
413         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
414             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
415                 "deserializer-test:list-no-key/disabled=false"));
416         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
417         assertEquals("Not expected error tag", ErrorTag.DATA_MISSING,
418             ex.getErrors().get(0).getErrorTag());
419     }
420
421     /**
422      * Negative test of getting next identifier when current node is keyed entry. Test is expected to
423      * fail with <code>RestconfDocumentedException</code>.
424      */
425     @Test
426     public void prepareIdentifierNotKeyedEntryNegativeTest() {
427         assertThrows(RestconfDocumentedException.class,
428             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:list-one-key"));
429     }
430
431     /**
432      * Negative test when there is a comma also after the last key. Test is expected to fail with
433      * <code>RestconfDocumentedException</code>.
434      */
435     @Test
436     public void deserializeKeysEndsWithComaNegativeTest() {
437         assertThrows(RestconfDocumentedException.class, () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
438                 "deserializer-test:list-multiple-keys=value,100,false,"));
439     }
440
441     /**
442      * Positive when not all keys of list are encoded. The missing keys should be considered to has empty
443      * <code>String</code> values. Also value of next leaf must not be considered to be missing key value.
444      */
445     @Test
446     public void notAllListKeysEncodedPositiveTest() {
447         final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
448         final Map<QName, Object> values = new LinkedHashMap<>();
449         values.put(QName.create(list, "name"), ":foo");
450         values.put(QName.create(list, "number"), "");
451         values.put(QName.create(list, "enabled"), "");
452
453         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(
454                 SCHEMA_CONTEXT, "deserializer-test:list-multiple-keys=%3Afoo,,/string-value");
455
456         assertEquals("Result does not contains expected number of path arguments", 3, Iterables.size(result));
457
458         final Iterator<PathArgument> iterator = result.iterator();
459
460         // list
461         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
462         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(list, values).toString(),
463                 iterator.next().toString());
464
465         // leaf
466         assertEquals("Not expected path argument",
467                 new NodeIdentifier(QName.create("deserializer:test", "2016-06-06", "string-value")), iterator.next());
468     }
469
470     /**
471      * Negative test when not all keys of list are encoded and it is not possible to consider missing keys to be empty.
472      * Test is expected to fail with <code>RestconfDocumentedException</code> and error type, error tag and error
473      * status code are compared to expected values.
474      */
475     @Test
476     public void notAllListKeysEncodedNegativeTest() {
477         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
478             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
479                     "deserializer-test:list-multiple-keys=%3Afoo/string-value"));
480         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
481         assertEquals("Not expected error tag", ErrorTag.MISSING_ATTRIBUTE,
482             ex.getErrors().get(0).getErrorTag());
483     }
484
485     /**
486      * Test URI with list where key value starts with, ends with or contains percent encoded characters.The encoded
487      * value should be complete also with not percent-encoded parts.
488      */
489     @Test
490     public void percentEncodedKeyEndsWithNoPercentEncodedChars() {
491         final String URI = "deserializer-test:list-multiple-keys=%3Afoo,1,true";
492         final YangInstanceIdentifier result = YangInstanceIdentifier.create(
493                 YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, URI));
494
495         final Iterator<Entry<QName, Object>> resultListKeys =
496                 ((NodeIdentifierWithPredicates)result.getLastPathArgument()).entrySet().iterator();
497
498         assertEquals(":foo", resultListKeys.next().getValue());
499         assertEquals(Uint8.ONE, resultListKeys.next().getValue());
500         assertEquals(true, resultListKeys.next().getValue());
501     }
502
503     /**
504      * Positive test when all keys of list can be considered to be empty <code>String</code>.
505      */
506     @Test
507     public void deserializeAllKeysEmptyTest() {
508         final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
509         final Map<QName, Object> values = new LinkedHashMap<>();
510         values.put(QName.create(list, "name"), "");
511         values.put(QName.create(list, "number"), "");
512         values.put(QName.create(list, "enabled"), "");
513
514         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
515                 .create(SCHEMA_CONTEXT, "deserializer-test:list-multiple-keys=,,");
516
517         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
518
519         final Iterator<PathArgument> iterator = result.iterator();
520
521         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
522         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(list, values).toString(),
523                 iterator.next().toString());
524     }
525
526     /**
527      * Negative test of deserialization when for leaf list there is no specified instance value.
528      * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
529      * compared to expected values.
530      */
531     @Test
532     public void leafListMissingKeyNegativeTest() {
533         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
534             () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT, "deserializer-test:leaf-list-0="));
535         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
536         assertEquals("Not expected error tag", ErrorTag.MISSING_ATTRIBUTE,
537             ex.getErrors().get(0).getErrorTag());
538     }
539
540     /**
541      * Positive test of deserialization when parts of input URI <code>String</code> are defined in another module.
542      */
543     @Test
544     public void deserializePartInOtherModuleTest() {
545         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
546             "deserializer-test-included:augmented-list=100/augmented-leaf");
547
548         assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
549
550         final Iterator<PathArgument> iterator = result.iterator();
551         final QName list = QName.create("deserializer:test:included", "2016-06-06", "augmented-list");
552         final QName child = QName.create("deserializer:test", "2016-06-06", "augmented-leaf");
553
554         // list
555         assertEquals("Not expected path argument",
556                 NodeIdentifier.create(list),
557                 iterator.next());
558
559         assertEquals("Not expected path argument",
560                 NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100).toString(),
561                 iterator.next().toString());
562
563         // augmented leaf
564         assertEquals("Not expected path argument", new AugmentationIdentifier(Sets.newHashSet(child)), iterator.next());
565         assertEquals("Not expected path argument", NodeIdentifier.create(child), iterator.next());
566     }
567
568     /**
569      * Deserialization of path that contains list entry with key which value is described by leaflef to identityref.
570      */
571     @Test
572     public void deserializePathWithIdentityrefKeyValueTest() {
573         final Iterable<PathArgument> pathArgs = YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
574                 "refs/list-with-identityref=deserializer-test%3Aderived-identity/foo");
575         assertEquals(4, Iterables.size(pathArgs));
576         final Iterator<PathArgument> pathArgsIterator = pathArgs.iterator();
577
578         assertEquals("refs", pathArgsIterator.next().getNodeType().getLocalName());
579         assertEquals("list-with-identityref", pathArgsIterator.next().getNodeType().getLocalName());
580
581         final PathArgument listEntryArg = pathArgsIterator.next();
582         assertTrue(listEntryArg instanceof NodeIdentifierWithPredicates);
583         assertEquals("list-with-identityref", listEntryArg.getNodeType().getLocalName());
584         final Set<QName> keys = ((NodeIdentifierWithPredicates) listEntryArg).keySet();
585         assertEquals(1, keys.size());
586         assertEquals("id", keys.iterator().next().getLocalName());
587         final Object keyValue = ((NodeIdentifierWithPredicates) listEntryArg).values().iterator().next();
588         assertEquals(QName.create("deserializer:test", "derived-identity", Revision.of("2016-06-06")), keyValue);
589
590         assertEquals("foo", pathArgsIterator.next().getNodeType().getLocalName());
591     }
592
593     /**
594      * Identityref key value is not encoded correctly - ':' character must be encoded as '%3A'.
595      */
596     @Test
597     public void deserializePathWithInvalidIdentityrefKeyValueTest() {
598         assertThrows(RestconfDocumentedException.class, () -> YangInstanceIdentifierDeserializer.create(SCHEMA_CONTEXT,
599                 "refs/list-with-identityref=deserializer-test:derived-identity/foo"));
600     }
601 }