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