2 * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.restconf.nb.rfc8040;
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;
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.UnqualifiedQName;
24 public class ApiPathTest {
26 public void testNull() {
27 assertThrows(NullPointerException.class, () -> ApiPath.parse(null));
31 public void testEmpty() {
32 assertEquals(List.of(), parse("/"));
36 public void testSingleSlash() throws ParseException {
37 final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("/"));
38 assertEquals("Identifier may not be empty", ex.getMessage());
39 assertEquals(0, ex.getErrorOffset());
41 assertEquals(ApiPath.empty(), ApiPath.parseUrl("/"));
45 public void testTrailingSlash() throws ParseException {
46 final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("foo/"));
47 assertEquals("Identifier may not be empty", ex.getMessage());
48 assertEquals(4, ex.getErrorOffset());
50 final var path = ApiPath.parseUrl("foo/").steps();
51 assertEquals(1, path.size());
52 assertApiIdentifier(path.get(0), null, "foo");
56 public void testExample1() {
57 final var path = parse("/example-top:top/list1=key1,key2,key3/list2=key4,key5/X");
58 assertEquals(4, path.size());
59 assertApiIdentifier(path.get(0), "example-top", "top");
60 assertListInstance(path.get(1), null, "list1", "key1", "key2", "key3");
61 assertListInstance(path.get(2), null, "list2", "key4", "key5");
62 assertApiIdentifier(path.get(3), null, "X");
66 public void testExample2() {
67 final var path = parse("/example-top:top/Y=instance-value");
68 assertEquals(2, path.size());
69 assertApiIdentifier(path.get(0), "example-top", "top");
70 assertListInstance(path.get(1), null, "Y", "instance-value");
74 public void testExample3() {
75 final var path = parse("/example-top:top/list1=%2C%27\"%3A\"%20%2F,,foo");
76 assertEquals(2, path.size());
77 assertApiIdentifier(path.get(0), "example-top", "top");
78 assertListInstance(path.get(1), null, "list1", ",'\":\" /", "", "foo");
82 public void testEscapedColon() {
83 final var path = parse("/foo%3Afoo");
84 assertEquals(1, path.size());
85 assertApiIdentifier(path.get(0), "foo", "foo");
89 public void nonAsciiFirstIdentifier() {
90 final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("a%80"));
91 assertEquals("Expecting %00-%7F, not %80", ex.getMessage());
92 assertEquals(1, ex.getErrorOffset());
96 public void nonAsciiSecondIdentifier() {
97 final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("foo:a%80"));
98 assertEquals("Expecting %00-%7F, not %80", ex.getMessage());
99 assertEquals(5, ex.getErrorOffset());
103 public void testIllegalEscape() {
104 final var ex = assertThrows(ParseException.class, () -> ApiPath.parse("foo:foo=%41%FF%42%FF%43"));
105 assertEquals("Invalid UTF-8 sequence 'A�B�C': Input length = 1", ex.getMessage());
106 assertEquals(8, ex.getErrorOffset());
109 private static void assertApiIdentifier(final Step step, final String module, final String identifier) {
110 assertThat(step, instanceOf(ApiIdentifier.class));
111 assertEquals(module, step.module());
112 assertEquals(UnqualifiedQName.of(identifier), step.identifier());
115 private static void assertListInstance(final Step step, final String module, final String identifier,
116 final String... keyValues) {
117 assertThat(step, instanceOf(ListInstance.class));
118 assertEquals(module, step.module());
119 assertEquals(UnqualifiedQName.of(identifier), step.identifier());
120 assertEquals(Arrays.asList(keyValues), ((ListInstance) step).keyValues());
123 private static List<Step> parse(final String str) {
124 final String toParse = str.substring(1);
126 return ApiPath.parse(toParse).steps();
127 } catch (ParseException e) {
128 throw new AssertionError("Failed to parse \"" + toParse + "\"", e);