Fix parsing of union values
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / server / spi / NC1265Test.java
1 /*
2  * Copyright (c) 2024 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.server.spi;
9
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertThrows;
12
13 import java.text.ParseException;
14 import org.junit.jupiter.api.Test;
15 import org.opendaylight.restconf.api.ApiPath;
16 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
17 import org.opendaylight.restconf.common.errors.RestconfError;
18 import org.opendaylight.restconf.server.api.DatabindContext;
19 import org.opendaylight.yangtools.yang.common.ErrorTag;
20 import org.opendaylight.yangtools.yang.common.ErrorType;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.common.Uint8;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
24 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
25
26 class NC1265Test {
27     private static final ApiPathNormalizer NORMALIZER = new ApiPathNormalizer(DatabindContext.ofModel(
28         YangParserTestUtils.parseYangResource("/nc1265.yang")));
29     private static final QName FOO = QName.create("nc1265", "foo");
30     private static final QName BAR = QName.create("nc1265", "bar");
31     private static final QName BAZ = QName.create("nc1265", "baz");
32     private static final QName KEY = QName.create("nc1265", "key");
33     private static final QName XYZZY = QName.create("nc1265", "xyzzy");
34
35     @Test
36     void uintKey() {
37         assertNormalized(YangInstanceIdentifier.builder()
38             .node(FOO)
39             .nodeWithKey(FOO, KEY, Uint8.valueOf(123))
40             .build(), "nc1265:foo=123");
41     }
42
43     @Test
44     void leafrefKey() {
45         assertNormalized(YangInstanceIdentifier.builder()
46             .node(BAZ)
47             .nodeWithKey(BAZ, KEY, Uint8.valueOf(123))
48             .build(), "nc1265:baz=123");
49     }
50
51     @Test
52     void instanceIdentifierKey() {
53         assertNormalized(YangInstanceIdentifier.builder()
54             .node(BAR)
55             .nodeWithKey(BAR, KEY, YangInstanceIdentifier.builder()
56                 .node(BAZ)
57                 .nodeWithKey(BAZ, KEY, Uint8.valueOf(123))
58                 .build())
59             .build(), "nc1265:bar=%2Fnc1265:baz=123");
60     }
61
62     @Test
63     void unionKeyInstanceIdentifier() {
64         assertNormalized(YangInstanceIdentifier.builder()
65             .node(XYZZY)
66             .nodeWithKey(XYZZY, KEY, YangInstanceIdentifier.builder()
67                 .node(BAZ)
68                 .nodeWithKey(BAZ, KEY, Uint8.valueOf(123))
69                 .build())
70             .build(), "nc1265:xyzzy=%2Fnc1265:baz=123");
71     }
72
73     @Test
74     void unionKeyIdentityref() {
75         assertNormalized(YangInstanceIdentifier.builder()
76             .node(XYZZY)
77             .nodeWithKey(XYZZY, KEY, QName.create("nc1265", "base-id"))
78             .build(), "nc1265:xyzzy=nc1265:base-id");
79     }
80
81     @Test
82     void unionKeyLeafref() {
83         assertNormalized(YangInstanceIdentifier.builder()
84             .node(XYZZY)
85             .nodeWithKey(XYZZY, KEY, Uint8.valueOf(123))
86             .build(), "nc1265:xyzzy=123");
87     }
88
89     @Test
90     void unionKeyString() {
91         assertNormalized(YangInstanceIdentifier.builder()
92             .node(XYZZY)
93             .nodeWithKey(XYZZY, KEY, "abc")
94             .build(), "nc1265:xyzzy=abc");
95     }
96
97     @Test
98     void noslashInstanceIdentifierKey() {
99         final var error = assertRestconfError("nc1265:bar=nc1265:baz=123");
100         assertEquals(ErrorType.PROTOCOL, error.getErrorType());
101         assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag());
102         assertEquals("Invalid value 'nc1265:baz=123' for (nc1265)key", error.getErrorMessage());
103         assertEquals(null, error.getErrorInfo());
104     }
105
106     @Test
107     void malformedInstanceIdentifierKey() {
108         final var error = assertRestconfError("nc1265:bar=%2Fnc1265:baz=abc");
109         assertEquals(ErrorType.PROTOCOL, error.getErrorType());
110         assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag());
111         assertEquals("Invalid value '/nc1265:baz=abc' for (nc1265)key", error.getErrorMessage());
112         assertEquals("""
113             errors: [RestconfError [error-type: protocol, error-tag: invalid-value, error-message: Invalid value 'abc' \
114             for (nc1265)key, error-info: Incorrect lexical representation of integer value: abc.
115             An integer value can be defined as:
116               - a decimal number,
117               - a hexadecimal number (prefix 0x),%n  - an octal number (prefix 0).
118             Signed values are allowed. Spaces between digits are NOT allowed.]]""", error.getErrorInfo());
119     }
120
121     private static void assertNormalized(final YangInstanceIdentifier expected, final String apiPath) {
122         assertEquals(expected, NORMALIZER.normalizeDataPath(assertApiPath(apiPath)).instance());
123     }
124
125     private static RestconfError assertRestconfError(final String apiPath) {
126         final var parsed = assertApiPath(apiPath);
127
128         final var ex = assertThrows(RestconfDocumentedException.class, () -> NORMALIZER.normalizeDataPath(parsed));
129         final var errors = ex.getErrors();
130         assertEquals(1, errors.size());
131         return errors.get(0);
132     }
133
134     private static ApiPath assertApiPath(final String apiPath) {
135         try {
136             return ApiPath.parse(apiPath);
137         } catch (ParseException e) {
138             throw new AssertionError(e);
139         }
140     }
141 }