2 * Copyright (c) 2022 PANTHEON.tech s.r.o. 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.mdsal.binding.generator.impl;
10 import static org.hamcrest.MatcherAssert.assertThat;
11 import static org.hamcrest.Matchers.in;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertTrue;
16 import com.google.common.collect.ImmutableMap;
17 import java.util.List;
20 import java.util.stream.Collectors;
21 import org.junit.Test;
22 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
23 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
24 import org.opendaylight.mdsal.binding.model.api.Type;
25 import org.opendaylight.mdsal.binding.model.ri.BaseYangTypes;
26 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
27 import org.opendaylight.mdsal.binding.model.ri.Types;
28 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
30 public class Mdsal675Test {
31 private static final String PACKAGE = "org.opendaylight.yang.gen.v1.urn.test.yang.data.demo.norev.";
32 private static final String PACKAGE2 = "org.opendaylight.yang.gen.v1.urn.test.yang.data.naming.norev.";
33 private static final String MODULE_CLASS_NAME = PACKAGE + "YangDataDemoData";
34 private static final String ROOT_CONTAINER_CLASS_NAME = PACKAGE + "RootContainer";
35 private static final Map<String, Type> INTERFACE_METHODS =
36 Map.of("implementedInterface", Types.typeForClass(Class.class));
39 public void yangDataGen() {
40 final List<GeneratedType> allGenTypes = DefaultBindingGenerator.generateFor(
41 YangParserTestUtils.parseYangResources(Mdsal675Test.class,
42 "/yang-data-models/ietf-restconf.yang", "/yang-data-models/yang-data-demo.yang"));
43 assertNotNull(allGenTypes);
44 assertEquals(29, allGenTypes.size());
45 final Map<String, GeneratedType> genTypesMap = allGenTypes.stream()
46 .collect(ImmutableMap.toImmutableMap(type -> type.getIdentifier().toString(), type -> type));
48 // ensure generated yang-data classes contain getters for inner structure types
50 // yang-data > container
51 assertYangDataGenType(
52 assertGenType(genTypesMap, PACKAGE + "YangDataWithContainer"),
53 assertGenType(genTypesMap, PACKAGE + "yang.data.with.container.ContainerFromYangData"),
54 List.of("getContainerFromYangData", "nonnullContainerFromYangData"));
56 assertYangDataGenType(
57 assertGenType(genTypesMap, PACKAGE + "YangDataWithList"),
58 Types.listTypeFor(assertGenType(genTypesMap, PACKAGE + "yang.data.with.list.ListFromYangData")),
59 List.of("getListFromYangData", "nonnullListFromYangData"));
61 assertYangDataGenType(
62 assertGenType(genTypesMap, PACKAGE + "YangDataWithLeaf"),
63 BaseYangTypes.STRING_TYPE,
64 List.of("getLeafFromYangData", "requireLeafFromYangData"));
65 // yang-data > leaf-list
66 assertYangDataGenType(
67 assertGenType(genTypesMap, PACKAGE + "YangDataWithLeafList"),
68 Types.setTypeFor(BaseYangTypes.STRING_TYPE),
69 List.of("getLeafListFromYangData", "requireLeafListFromYangData"));
70 // yang-data > anydata
71 assertYangDataGenType(
72 assertGenType(genTypesMap, PACKAGE + "YangDataWithAnydata"),
73 assertGenType(genTypesMap, PACKAGE + "yang.data.with.anydata.AnydataFromYangData"),
74 List.of("getAnydataFromYangData", "requireAnydataFromYangData"));
76 assertYangDataGenType(
77 assertGenType(genTypesMap, PACKAGE + "YangDataWithAnyxml"),
78 assertGenType(genTypesMap, PACKAGE + "yang.data.with.anyxml.AnyxmlFromYangData"),
79 List.of("getAnyxmlFromYangData", "requireAnyxmlFromYangData"));
81 // ensure generated yang-data classes extending inner group so group content is reachable
83 // yang-data > uses > group > container
84 assertYangDataGenType(
85 assertGenType(genTypesMap, PACKAGE + "YangDataWithContainerFromGroup"),
86 assertGenType(genTypesMap, PACKAGE + "GrpForContainer"),
87 assertGenType(genTypesMap, PACKAGE + "grp._for.container.ContainerFromGroup"),
88 List.of("getContainerFromGroup", "nonnullContainerFromGroup"));
89 // yang-data > uses > group > list
90 assertYangDataGenType(
91 assertGenType(genTypesMap, PACKAGE + "YangDataWithListFromGroup"),
92 assertGenType(genTypesMap, PACKAGE + "GrpForList"),
93 Types.listTypeFor(assertGenType(genTypesMap, PACKAGE + "grp._for.list.ListFromGroup")),
94 List.of("getListFromGroup", "nonnullListFromGroup")
96 // yang-data > uses > group > leaf
97 assertYangDataGenType(
98 assertGenType(genTypesMap, PACKAGE + "YangDataWithLeafFromGroup"),
99 assertGenType(genTypesMap, PACKAGE + "GrpForLeaf"),
100 BaseYangTypes.UINT32_TYPE,
101 List.of("getLeafFromGroup", "requireLeafFromGroup"));
102 // yang-data > uses > group > leaf-list
103 assertYangDataGenType(
104 assertGenType(genTypesMap, PACKAGE + "YangDataWithLeafListFromGroup"),
105 assertGenType(genTypesMap, PACKAGE + "GrpForLeafList"),
106 Types.setTypeFor(BaseYangTypes.UINT32_TYPE),
107 List.of("getLeafListFromGroup", "requireLeafListFromGroup"));
108 // yang-data > uses > group > anydata
109 assertYangDataGenType(
110 assertGenType(genTypesMap, PACKAGE + "YangDataWithAnydataFromGroup"),
111 assertGenType(genTypesMap, PACKAGE + "GrpForAnydata"),
112 assertGenType(genTypesMap, PACKAGE + "grp._for.anydata.AnydataFromGroup"),
113 List.of("getAnydataFromGroup", "requireAnydataFromGroup"));
114 // yang-data > uses > group > anyxml
115 assertYangDataGenType(
116 assertGenType(genTypesMap, PACKAGE + "YangDataWithAnyxmlFromGroup"),
117 assertGenType(genTypesMap, PACKAGE + "GrpForAnyxml"),
118 assertGenType(genTypesMap, PACKAGE + "grp._for.anyxml.AnyxmlFromGroup"),
119 List.of("getAnyxmlFromGroup", "requireAnyxmlFromGroup"));
121 // ensure module class has only getter for root container
122 final GeneratedType moduleType = assertGenType(genTypesMap, MODULE_CLASS_NAME);
123 assertNotNull(moduleType.getMethodDefinitions());
124 assertEquals(List.of("getRootContainer"),
125 moduleType.getMethodDefinitions().stream().map(MethodSignature::getName)
126 .filter(methodName -> methodName.startsWith("get")).toList());
128 // ensure yang-data at non-top level is ignored (no getters in parent container)
129 GeneratedType rootContainerType = assertGenType(genTypesMap, ROOT_CONTAINER_CLASS_NAME);
130 assertNotNull(rootContainerType.getMethodDefinitions());
131 assertTrue(rootContainerType.getMethodDefinitions().stream()
132 .filter(method -> method.getName().startsWith("get"))
133 .findFirst().isEmpty());
137 public void yangDataNamingStrategy() {
138 final List<GeneratedType> allGenTypes = DefaultBindingGenerator.generateFor(
139 YangParserTestUtils.parseYangResources(Mdsal675Test.class,
140 "/yang-data-models/ietf-restconf.yang", "/yang-data-models/yang-data-naming.yang"));
141 assertNotNull(allGenTypes);
142 assertEquals(22, allGenTypes.size());
143 final Set<String> genTypeNames =
144 allGenTypes.stream().map(type -> type.getIdentifier().toString()).collect(Collectors.toSet());
146 // template name is not compliant to YANG identifier -> char encoding used, name starts with $ char
147 // a) latin1, but not a valid Java identifier
148 assertTrue(genTypeNames.contains(PACKAGE2 + "$ľaľa$20$ho$2C$$20$papľuha$2C$$20$ogrcal$20$mi$20$krpce$21$"));
149 // b) cyrillic, but a valid Java identifier
150 assertTrue(genTypeNames.contains(PACKAGE2 + "привет"));
152 // template name is compliant to yang identifier -> camel-case used
153 assertTrue(genTypeNames.contains(PACKAGE2 + "IdentifierCompliantName"));
155 // name collision with a typedef
156 assertTrue(genTypeNames.contains(PACKAGE2 + "Collision1$T"));
157 assertTrue(genTypeNames.contains(PACKAGE2 + "collision1.Collision1"));
158 assertTrue(genTypeNames.contains(PACKAGE2 + "Collision1$YD"));
160 // name collision with top level container
161 assertTrue(genTypeNames.contains(PACKAGE2 + "Collision2"));
162 assertTrue(genTypeNames.contains(PACKAGE2 + "Collision2$YD"));
164 // name collision with group used
165 assertTrue(genTypeNames.contains(PACKAGE2 + "Collision3$G"));
166 assertTrue(genTypeNames.contains(PACKAGE2 + "Collision3$YD"));
169 assertTrue(genTypeNames.contains(PACKAGE2 + "$$2E$$2D$$2F$$23$"));
170 assertTrue(genTypeNames.contains(PACKAGE2 + "$$2e$$2d$$2f$$23$$.Foo"));
173 assertTrue(genTypeNames.contains(PACKAGE2 + "$$2D$$2E$$2F$$23$"));
174 assertTrue(genTypeNames.contains(PACKAGE2 + "$$2d$$2e$$2f$$23$$.Foo"));
177 private static GeneratedType assertGenType(final Map<String, GeneratedType> genTypesMap, final String className) {
178 final var ret = genTypesMap.get(className);
179 assertNotNull("no type generated: " + className, ret);
183 private static void assertYangDataGenType(final GeneratedType yangDataType, final Type contentType,
184 final List<String> getterMethods) {
185 assertImplements(yangDataType, BindingTypes.yangData(yangDataType));
186 INTERFACE_METHODS.forEach((name, type) -> assertHasMethod(yangDataType, name, type));
187 for (final String methodName : getterMethods) {
188 assertHasMethod(yangDataType, methodName, contentType);
192 private static void assertYangDataGenType(final GeneratedType yangDataType, final GeneratedType groupType,
193 final Type contentType, final List<String> getterMethods) {
194 assertImplements(yangDataType, BindingTypes.yangData(yangDataType));
195 assertImplements(yangDataType, groupType);
196 INTERFACE_METHODS.forEach((name, type) -> assertHasMethod(yangDataType, name, type));
197 for (final String methodName : getterMethods) {
198 assertHasMethod(groupType, methodName, contentType);
202 private static void assertHasMethod(final GeneratedType genType, final String methodName,
203 final Type returnType) {
204 assertTrue("no expected method " + methodName + " returning " + returnType,
205 genType.getMethodDefinitions().stream().anyMatch(
206 method -> methodName.equals(method.getName()) && returnType.equals(method.getReturnType())));
209 private static void assertImplements(final GeneratedType genType, final Type implementedType) {
210 assertThat(implementedType, in(genType.getImplements()));