Rename restconf-nb-rfc8040 to restconf-nb
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / rfc8040 / ApiPathTest.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.nb.rfc8040;
9
10 import static org.hamcrest.CoreMatchers.instanceOf;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertThrows;
14
15 import java.text.ParseException;
16 import java.util.Arrays;
17 import java.util.List;
18 import org.junit.Test;
19 import org.opendaylight.restconf.nb.rfc8040.ApiPath.ApiIdentifier;
20 import org.opendaylight.restconf.nb.rfc8040.ApiPath.ListInstance;
21 import org.opendaylight.restconf.nb.rfc8040.ApiPath.Step;
22 import org.opendaylight.yangtools.yang.common.UnresolvedQName;
23
24 public class ApiPathTest {
25     @Test
26     public void testNull() {
27         assertThrows(NullPointerException.class, () -> ApiPath.parse(null));
28     }
29
30     @Test
31     public void testEmpty() {
32         assertEquals(List.of(), parse("/"));
33     }
34
35     @Test
36     public void testSingleSlash() throws ParseException {
37         final var ex = assertThrows(ParseException.class, () -> ApiPath.parseUrl("/"));
38         assertEquals("Identifier may not be empty", ex.getMessage());
39         assertEquals(0, ex.getErrorOffset());
40     }
41
42     @Test
43     public void testTrailingSlash() throws ParseException {
44         final var ex = assertThrows(ParseException.class, () -> ApiPath.parseUrl("foo/"));
45         assertEquals("Identifier may not be empty", ex.getMessage());
46         assertEquals(4, ex.getErrorOffset());
47     }
48
49     @Test
50     public void testExample1() {
51         final var path = parse("/example-top:top/list1=key1,key2,key3/list2=key4,key5/X");
52         assertEquals(4, path.size());
53         assertApiIdentifier(path.get(0), "example-top", "top");
54         assertListInstance(path.get(1), null, "list1", "key1", "key2", "key3");
55         assertListInstance(path.get(2), null, "list2", "key4", "key5");
56         assertApiIdentifier(path.get(3), null, "X");
57     }
58
59     @Test
60     public void testExample2() {
61         final var path = parse("/example-top:top/Y=instance-value");
62         assertEquals(2, path.size());
63         assertApiIdentifier(path.get(0), "example-top", "top");
64         assertListInstance(path.get(1), null, "Y", "instance-value");
65     }
66
67     @Test
68     public void testExample3() {
69         final var path = parse("/example-top:top/list1=%2C%27\"%3A\"%20%2F,,foo");
70         assertEquals(2, path.size());
71         assertApiIdentifier(path.get(0), "example-top", "top");
72         assertListInstance(path.get(1), null, "list1", ",'\":\" /", "", "foo");
73     }
74
75     @Test
76     public void testEscapedColon() {
77         final var path = parse("/foo%3Afoo");
78         assertEquals(1, path.size());
79         assertApiIdentifier(path.get(0), "foo", "foo");
80     }
81
82     @Test
83     public void nonAsciiFirstIdentifier() {
84         final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("a%80"));
85         assertEquals("Expecting %00-%7F, not %80", ex.getMessage());
86         assertEquals(1, ex.getErrorOffset());
87     }
88
89     @Test
90     public void nonAsciiSecondIdentifier() {
91         final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("foo:a%80"));
92         assertEquals("Expecting %00-%7F, not %80", ex.getMessage());
93         assertEquals(5, ex.getErrorOffset());
94     }
95
96     @Test
97     public void testIllegalEscape() {
98         final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("foo:foo=%41%FF%42%FF%43"));
99         assertEquals("Invalid UTF-8 sequence 'A�B�C': Input length = 1", ex.getMessage());
100         assertEquals(8, ex.getErrorOffset());
101     }
102
103     private static void assertApiIdentifier(final Step step, final String module, final String identifier) {
104         assertThat(step, instanceOf(ApiIdentifier.class));
105         assertEquals(module, step.module());
106         assertEquals(UnresolvedQName.unqualified(identifier), step.identifier());
107     }
108
109     private static void assertListInstance(final Step step, final String module, final String identifier,
110             final String... keyValues) {
111         assertThat(step, instanceOf(ListInstance.class));
112         assertEquals(module, step.module());
113         assertEquals(UnresolvedQName.unqualified(identifier), step.identifier());
114         assertEquals(Arrays.asList(keyValues), ((ListInstance) step).keyValues());
115     }
116
117     private static List<Step> parse(final String str) {
118         final String toParse = str.substring(1);
119         try {
120             return ApiPath.parse(toParse).steps();
121         } catch (ParseException e) {
122             throw new AssertionError("Failed to parse \"" + toParse + "\"", e);
123         }
124     }
125 }