2 * Copyright (c) 2016 Cisco Systems, Inc. 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.mdsal.binding.java.api.generator;
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.Mockito.doCallRealMethod;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.mock;
14 import static org.mockito.Mockito.spy;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.stream.Collectors;
19 import org.eclipse.xtend2.lib.StringConcatenation;
20 import org.junit.Test;
21 import org.opendaylight.mdsal.binding.generator.impl.DefaultBindingGenerator;
22 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
23 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
24 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
25 import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
26 import org.opendaylight.mdsal.binding.model.api.Type;
27 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
28 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
30 public class BuilderGeneratorTest {
31 private static final String TEST = "test";
32 private static final JavaTypeName TYPE_NAME = JavaTypeName.create(TEST, TEST);
35 public void basicTest() {
36 assertEquals("", new BuilderGenerator().generate(mock(Type.class)));
40 public void builderTemplateGenerateHashcodeWithPropertyTest() {
41 final GeneratedType genType = mockGenType("get" + TEST);
43 assertXtendEquals("/**\n"
44 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
45 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
47 + " * results across all implementations.\n"
49 + " * @param obj Object for which to generate hashCode() result.\n"
50 + " * @return Hash code value of data modeled by this interface.\n"
51 + " * @throws NullPointerException if {@code obj} is null\n"
53 + "static int bindingHashCode(final test.@NonNull test obj) {\n"
54 + " final int prime = 31;\n"
55 + " int result = 1;\n"
56 + " result = prime * result + Objects.hashCode(obj.getTest());\n"
58 + "}\n", genHashCode(genType).toString());
62 public void builderTemplateGenerateHashCodeWithoutAnyPropertyTest() throws Exception {
63 assertEquals("", genHashCode(mockGenType(TEST)).toString());
67 public void builderTemplateGenerateHashCodeWithMorePropertiesTest() throws Exception {
68 assertXtendEquals("/**\n"
69 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
70 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
72 + " * results across all implementations.\n"
74 + " * @param obj Object for which to generate hashCode() result.\n"
75 + " * @return Hash code value of data modeled by this interface.\n"
76 + " * @throws NullPointerException if {@code obj} is null\n"
78 + "static int bindingHashCode(final test.@NonNull test obj) {\n"
79 + " final int prime = 31;\n"
80 + " int result = 1;\n"
81 + " result = prime * result + Objects.hashCode(obj.getTest1());\n"
82 + " result = prime * result + Objects.hashCode(obj.getTest2());\n"
84 + "}\n", genHashCode(mockGenTypeMoreMeth("get" + TEST)).toString());
88 public void builderTemplateGenerateHashCodeWithoutPropertyWithAugmentTest() throws Exception {
89 assertXtendEquals("/**\n"
90 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
91 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
93 + " * results across all implementations.\n"
95 + " * @param obj Object for which to generate hashCode() result.\n"
96 + " * @return Hash code value of data modeled by this interface.\n"
97 + " * @throws NullPointerException if {@code obj} is null\n"
99 + "static int bindingHashCode(final test.@NonNull test obj) {\n"
100 + " final int prime = 31;\n"
101 + " int result = 1;\n"
102 + " for (var augmentation : obj.augmentations().values()) {\n"
103 + " result += augmentation.hashCode();\n"
105 + " return result;\n"
106 + "}\n", genHashCode(mockAugment(mockGenType(TEST))).toString());
110 public void builderTemplateGenerateHashCodeWithPropertyWithAugmentTest() throws Exception {
111 assertXtendEquals("/**\n"
112 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
113 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
115 + " * results across all implementations.\n"
117 + " * @param obj Object for which to generate hashCode() result.\n"
118 + " * @return Hash code value of data modeled by this interface.\n"
119 + " * @throws NullPointerException if {@code obj} is null\n"
121 + "static int bindingHashCode(final test.@NonNull test obj) {\n"
122 + " final int prime = 31;\n"
123 + " int result = 1;\n"
124 + " result = prime * result + Objects.hashCode(obj.getTest());\n"
125 + " for (var augmentation : obj.augmentations().values()) {\n"
126 + " result += augmentation.hashCode();\n"
128 + " return result;\n"
129 + "}\n", genHashCode(mockAugment(mockGenType("get" + TEST))).toString());
133 public void builderTemplateGenerateHashCodeWithMorePropertiesWithAugmentTest() throws Exception {
134 assertXtendEquals("/**\n"
135 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
136 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
138 + " * results across all implementations.\n"
140 + " * @param obj Object for which to generate hashCode() result.\n"
141 + " * @return Hash code value of data modeled by this interface.\n"
142 + " * @throws NullPointerException if {@code obj} is null\n"
144 + "static int bindingHashCode(final test.@NonNull test obj) {\n"
145 + " final int prime = 31;\n"
146 + " int result = 1;\n"
147 + " result = prime * result + Objects.hashCode(obj.getTest1());\n"
148 + " result = prime * result + Objects.hashCode(obj.getTest2());\n"
149 + " for (var augmentation : obj.augmentations().values()) {\n"
150 + " result += augmentation.hashCode();\n"
152 + " return result;\n"
153 + "}\n", genHashCode(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
157 public void builderTemplateGenerateToStringWithPropertyTest() {
158 final GeneratedType genType = mockGenType("get" + TEST);
160 assertXtendEquals("/**\n"
161 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
162 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
163 + "\n * representations across all implementations.\n"
165 + " * @param obj Object for which to generate toString() result.\n"
166 + " * @return {@link String} value of data modeled by this interface.\n"
167 + " * @throws NullPointerException if {@code obj} is null\n"
169 + "static String bindingToString(final test.@NonNull test obj) {\n"
170 + " final var helper = MoreObjects.toStringHelper(\"test\");\n"
171 + " CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
172 + " return helper.toString();\n"
173 + "}\n", genToString(genType).toString());
177 public void builderTemplateGenerateToStringWithoutAnyPropertyTest() throws Exception {
178 assertXtendEquals("/**\n"
179 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
180 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
181 + "\n * representations across all implementations.\n"
183 + " * @param obj Object for which to generate toString() result.\n"
184 + " * @return {@link String} value of data modeled by this interface.\n"
185 + " * @throws NullPointerException if {@code obj} is null\n"
187 + "static String bindingToString(final test.@NonNull test obj) {\n"
188 + " final var helper = MoreObjects.toStringHelper(\"test\");\n"
189 + " return helper.toString();\n"
190 + "}\n", genToString(mockGenType(TEST)).toString());
194 public void builderTemplateGenerateToStringWithMorePropertiesTest() throws Exception {
195 assertXtendEquals("/**\n"
196 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
197 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
198 + "\n * representations across all implementations.\n"
200 + " * @param obj Object for which to generate toString() result.\n"
201 + " * @return {@link String} value of data modeled by this interface.\n"
202 + " * @throws NullPointerException if {@code obj} is null\n"
204 + "static String bindingToString(final test.@NonNull test obj) {\n"
205 + " final var helper = MoreObjects.toStringHelper(\"test\");\n"
206 + " CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
207 + " CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
208 + " return helper.toString();\n"
209 + "}\n", genToString(mockGenTypeMoreMeth("get" + TEST)).toString());
213 public void builderTemplateGenerateToStringWithoutPropertyWithAugmentTest() throws Exception {
214 assertXtendEquals("/**\n"
215 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
216 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
217 + "\n * representations across all implementations.\n"
219 + " * @param obj Object for which to generate toString() result.\n"
220 + " * @return {@link String} value of data modeled by this interface.\n"
221 + " * @throws NullPointerException if {@code obj} is null\n"
223 + "static String bindingToString(final test.@NonNull test obj) {\n"
224 + " final var helper = MoreObjects.toStringHelper(\"test\");\n"
225 + " CodeHelpers.appendAugmentations(helper, \"augmentation\", obj);\n"
226 + " return helper.toString();\n"
227 + "}\n", genToString(mockAugment(mockGenType(TEST))).toString());
231 public void builderTemplateGenerateToStringWithPropertyWithAugmentTest() throws Exception {
232 assertXtendEquals("/**\n"
233 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
234 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
235 + "\n * representations across all implementations.\n"
237 + " * @param obj Object for which to generate toString() result.\n"
238 + " * @return {@link String} value of data modeled by this interface.\n"
239 + " * @throws NullPointerException if {@code obj} is null\n"
241 + "static String bindingToString(final test.@NonNull test obj) {\n"
242 + " final var helper = MoreObjects.toStringHelper(\"test\");\n"
243 + " CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
244 + " CodeHelpers.appendAugmentations(helper, \"augmentation\", obj);\n"
245 + " return helper.toString();\n"
246 + "}\n", genToString(mockAugment(mockGenType("get" + TEST))).toString());
250 public void builderTemplateGenerateToStringWithMorePropertiesWithAugmentTest() throws Exception {
251 assertXtendEquals("/**\n"
252 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
253 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
254 + "\n * representations across all implementations.\n"
256 + " * @param obj Object for which to generate toString() result.\n"
257 + " * @return {@link String} value of data modeled by this interface.\n"
258 + " * @throws NullPointerException if {@code obj} is null\n"
260 + "static String bindingToString(final test.@NonNull test obj) {\n"
261 + " final var helper = MoreObjects.toStringHelper(\"test\");\n"
262 + " CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
263 + " CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
264 + " CodeHelpers.appendAugmentations(helper, \"augmentation\", obj);\n"
265 + " return helper.toString();\n"
266 + "}\n", genToString(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
270 public void builderTemplateGenerateToEqualsComparingOrderTest() {
271 final EffectiveModelContext context = YangParserTestUtils.parseYangResource(
273 final List<GeneratedType> types = new DefaultBindingGenerator().generateTypes(context);
274 assertEquals(29, types.size());
276 final BuilderTemplate bt = BuilderGenerator.templateForType(
277 types.stream().filter(t -> t.getName().equals("Nodes")).findFirst().orElseThrow());
279 final List<String> sortedProperties = bt.properties.stream()
280 .sorted(ByTypeMemberComparator.getInstance())
281 .map(BuilderGeneratedProperty::getName)
282 .collect(Collectors.toList());
284 assertEquals(List.of(
285 // numeric types (boolean, byte, short, int, long, biginteger, bigdecimal), identityrefs, empty
286 "id16", "id16Def", "id32", "id32Def", "id64", "id64Def", "id8", "id8Def", "idBoolean", "idBooleanDef",
287 "idDecimal64", "idDecimal64Def","idEmpty", "idEmptyDef", "idIdentityref", "idIdentityrefDef",
288 "idLeafref", "idLeafrefDef", "idU16", "idU16Def", "idU32", "idU32Def", "idU64", "idU64Def", "idU8",
290 // string, binary, bits
291 "idBinary", "idBinaryDef", "idBits", "idBitsDef", "idGroupLeafString", "idLeafrefContainer1",
292 "idLeafrefContainer1Def", "idString", "idStringDef",
293 // instance identifier
294 "idInstanceIdentifier", "idInstanceIdentifierDef",
296 "idContainer1", "idContainer2", "idEnumeration", "idEnumerationDef",
297 "idGroupContainer", "idList", "idUnion", "idUnionDef"), sortedProperties);
300 private static GeneratedType mockAugment(final GeneratedType genType) {
301 final List<Type> impls = new ArrayList<>();
302 final Type impl = mock(Type.class);
303 doReturn("org.opendaylight.yangtools.yang.binding.Augmentable").when(impl).getFullyQualifiedName();
305 doReturn(impls).when(genType).getImplements();
309 private static GeneratedType mockGenTypeMoreMeth(final String methodeName) {
310 final GeneratedType genType = spy(GeneratedType.class);
311 doReturn(TYPE_NAME).when(genType).getIdentifier();
312 doReturn(TEST).when(genType).getName();
313 doReturn(TEST).when(genType).getPackageName();
315 final List<MethodSignature> listMethodSign = new ArrayList<>();
316 for (int i = 0; i < 2; i++) {
317 final MethodSignature methSign = mockMethSign(methodeName + (i + 1));
318 listMethodSign.add(methSign);
320 doReturn(listMethodSign).when(genType).getMethodDefinitions();
322 final List<Type> impls = new ArrayList<>();
323 doReturn(impls).when(genType).getImplements();
327 private static CharSequence genToString(final GeneratedType genType) {
328 return new InterfaceTemplate(genType).generateBindingToString();
331 private static CharSequence genHashCode(final GeneratedType genType) {
332 return new InterfaceTemplate(genType).generateBindingHashCode();
335 private static GeneratedType mockGenType(final String methodeName) {
336 final GeneratedType genType = spy(GeneratedType.class);
337 doReturn(TYPE_NAME).when(genType).getIdentifier();
338 doReturn(TEST).when(genType).getName();
339 doReturn(TEST).when(genType).getPackageName();
341 final List<MethodSignature> listMethodSign = new ArrayList<>();
342 final MethodSignature methSign = mockMethSign(methodeName);
343 listMethodSign.add(methSign);
344 doReturn(listMethodSign).when(genType).getMethodDefinitions();
346 final List<Type> impls = new ArrayList<>();
347 doReturn(impls).when(genType).getImplements();
351 private static MethodSignature mockMethSign(final String methodeName) {
352 final MethodSignature methSign = mock(MethodSignature.class);
353 doReturn(methodeName).when(methSign).getName();
354 final Type methType = mock(Type.class);
355 doCallRealMethod().when(methType).getFullyQualifiedName();
356 doReturn(TYPE_NAME).when(methType).getIdentifier();
357 doReturn(TEST).when(methType).getName();
358 doReturn(methType).when(methSign).getReturnType();
359 doReturn(ValueMechanics.NORMAL).when(methSign).getMechanics();
363 // Xtend's StringConcatenation is using runtime-configured line separator, which can change between runs, notably
364 // it has a different value on Windows. Make sure we account for that.
365 private static void assertXtendEquals(final String expected, final String actual) {
366 assertEquals(expected.replace("\n", StringConcatenation.DEFAULT_LINE_DELIMITER), actual);