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 + " result = prime * result + obj.augmentations().hashCode();\n"
103 + " return result;\n"
104 + "}\n", genHashCode(mockAugment(mockGenType(TEST))).toString());
108 public void builderTemplateGenerateHashCodeWithPropertyWithAugmentTest() throws Exception {
109 assertXtendEquals("/**\n"
110 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
111 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
113 + " * results across all implementations.\n"
115 + " * @param obj Object for which to generate hashCode() result.\n"
116 + " * @return Hash code value of data modeled by this interface.\n"
117 + " * @throws NullPointerException if {@code obj} is null\n"
119 + "static int bindingHashCode(final test.@NonNull test obj) {\n"
120 + " final int prime = 31;\n"
121 + " int result = 1;\n"
122 + " result = prime * result + Objects.hashCode(obj.getTest());\n"
123 + " result = prime * result + obj.augmentations().hashCode();\n"
124 + " return result;\n"
125 + "}\n", genHashCode(mockAugment(mockGenType("get" + TEST))).toString());
129 public void builderTemplateGenerateHashCodeWithMorePropertiesWithAugmentTest() throws Exception {
130 assertXtendEquals("/**\n"
131 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
132 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
134 + " * results across all implementations.\n"
136 + " * @param obj Object for which to generate hashCode() result.\n"
137 + " * @return Hash code value of data modeled by this interface.\n"
138 + " * @throws NullPointerException if {@code obj} is null\n"
140 + "static int bindingHashCode(final test.@NonNull test obj) {\n"
141 + " final int prime = 31;\n"
142 + " int result = 1;\n"
143 + " result = prime * result + Objects.hashCode(obj.getTest1());\n"
144 + " result = prime * result + Objects.hashCode(obj.getTest2());\n"
145 + " result = prime * result + obj.augmentations().hashCode();\n"
146 + " return result;\n"
147 + "}\n", genHashCode(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
151 public void builderTemplateGenerateToStringWithPropertyTest() {
152 final GeneratedType genType = mockGenType("get" + TEST);
154 assertXtendEquals("/**\n"
155 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
156 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
157 + "\n * representations across all implementations.\n"
159 + " * @param obj Object for which to generate toString() result.\n"
160 + " * @return {@link String} value of data modeled by this interface.\n"
161 + " * @throws NullPointerException if {@code obj} is null\n"
163 + "static String bindingToString(final test.@NonNull test obj) {\n"
164 + " final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
165 + " CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
166 + " return helper.toString();\n"
167 + "}\n", genToString(genType).toString());
171 public void builderTemplateGenerateToStringWithoutAnyPropertyTest() throws Exception {
172 assertXtendEquals("/**\n"
173 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
174 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
175 + "\n * representations across all implementations.\n"
177 + " * @param obj Object for which to generate toString() result.\n"
178 + " * @return {@link String} value of data modeled by this interface.\n"
179 + " * @throws NullPointerException if {@code obj} is null\n"
181 + "static String bindingToString(final test.@NonNull test obj) {\n"
182 + " final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
183 + " return helper.toString();\n"
184 + "}\n", genToString(mockGenType(TEST)).toString());
188 public void builderTemplateGenerateToStringWithMorePropertiesTest() throws Exception {
189 assertXtendEquals("/**\n"
190 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
191 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
192 + "\n * representations across all implementations.\n"
194 + " * @param obj Object for which to generate toString() result.\n"
195 + " * @return {@link String} value of data modeled by this interface.\n"
196 + " * @throws NullPointerException if {@code obj} is null\n"
198 + "static String bindingToString(final test.@NonNull test obj) {\n"
199 + " final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
200 + " CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
201 + " CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
202 + " return helper.toString();\n"
203 + "}\n", genToString(mockGenTypeMoreMeth("get" + TEST)).toString());
207 public void builderTemplateGenerateToStringWithoutPropertyWithAugmentTest() throws Exception {
208 assertXtendEquals("/**\n"
209 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
210 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
211 + "\n * representations across all implementations.\n"
213 + " * @param obj Object for which to generate toString() result.\n"
214 + " * @return {@link String} value of data modeled by this interface.\n"
215 + " * @throws NullPointerException if {@code obj} is null\n"
217 + "static String bindingToString(final test.@NonNull test obj) {\n"
218 + " final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
219 + " CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
220 + " return helper.toString();\n"
221 + "}\n", genToString(mockAugment(mockGenType(TEST))).toString());
225 public void builderTemplateGenerateToStringWithPropertyWithAugmentTest() throws Exception {
226 assertXtendEquals("/**\n"
227 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
228 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
229 + "\n * representations across all implementations.\n"
231 + " * @param obj Object for which to generate toString() result.\n"
232 + " * @return {@link String} value of data modeled by this interface.\n"
233 + " * @throws NullPointerException if {@code obj} is null\n"
235 + "static String bindingToString(final test.@NonNull test obj) {\n"
236 + " final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
237 + " CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
238 + " CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
239 + " return helper.toString();\n"
240 + "}\n", genToString(mockAugment(mockGenType("get" + TEST))).toString());
244 public void builderTemplateGenerateToStringWithMorePropertiesWithAugmentTest() throws Exception {
245 assertXtendEquals("/**\n"
246 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
247 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
248 + "\n * representations across all implementations.\n"
250 + " * @param obj Object for which to generate toString() result.\n"
251 + " * @return {@link String} value of data modeled by this interface.\n"
252 + " * @throws NullPointerException if {@code obj} is null\n"
254 + "static String bindingToString(final test.@NonNull test obj) {\n"
255 + " final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
256 + " CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
257 + " CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
258 + " CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
259 + " return helper.toString();\n"
260 + "}\n", genToString(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
264 public void builderTemplateGenerateToEqualsComparingOrderTest() {
265 final EffectiveModelContext context = YangParserTestUtils.parseYangResource(
267 final List<GeneratedType> types = new DefaultBindingGenerator().generateTypes(context);
268 assertEquals(29, types.size());
270 final BuilderTemplate bt = BuilderGenerator.templateForType(
271 types.stream().filter(t -> t.getName().equals("Nodes")).findFirst().orElseThrow());
273 final List<String> sortedProperties = bt.properties.stream()
274 .sorted(ByTypeMemberComparator.getInstance())
275 .map(BuilderGeneratedProperty::getName)
276 .collect(Collectors.toList());
278 assertEquals(List.of(
279 // numeric types (boolean, byte, short, int, long, biginteger, bigdecimal), identityrefs, empty
280 "id16", "id16Def", "id32", "id32Def", "id64", "id64Def", "id8", "id8Def", "idBoolean", "idBooleanDef",
281 "idDecimal64", "idDecimal64Def","idEmpty", "idEmptyDef", "idIdentityref", "idIdentityrefDef",
282 "idLeafref", "idLeafrefDef", "idU16", "idU16Def", "idU32", "idU32Def", "idU64", "idU64Def", "idU8",
284 // string, binary, bits
285 "idBinary", "idBinaryDef", "idBits", "idBitsDef", "idGroupLeafString", "idLeafrefContainer1",
286 "idLeafrefContainer1Def", "idString", "idStringDef",
287 // instance identifier
288 "idInstanceIdentifier", "idInstanceIdentifierDef",
290 "idContainer1", "idContainer2", "idEnumeration", "idEnumerationDef",
291 "idGroupContainer", "idList", "idUnion", "idUnionDef"), sortedProperties);
294 private static GeneratedType mockAugment(final GeneratedType genType) {
295 final List<Type> impls = new ArrayList<>();
296 final Type impl = mock(Type.class);
297 doReturn("org.opendaylight.yangtools.yang.binding.Augmentable").when(impl).getFullyQualifiedName();
299 doReturn(impls).when(genType).getImplements();
303 private static GeneratedType mockGenTypeMoreMeth(final String methodeName) {
304 final GeneratedType genType = spy(GeneratedType.class);
305 doReturn(TYPE_NAME).when(genType).getIdentifier();
306 doReturn(TEST).when(genType).getName();
307 doReturn(TEST).when(genType).getPackageName();
309 final List<MethodSignature> listMethodSign = new ArrayList<>();
310 for (int i = 0; i < 2; i++) {
311 final MethodSignature methSign = mockMethSign(methodeName + (i + 1));
312 listMethodSign.add(methSign);
314 doReturn(listMethodSign).when(genType).getMethodDefinitions();
316 final List<Type> impls = new ArrayList<>();
317 doReturn(impls).when(genType).getImplements();
321 private static CharSequence genToString(final GeneratedType genType) {
322 return new InterfaceTemplate(genType).generateBindingToString();
325 private static CharSequence genHashCode(final GeneratedType genType) {
326 return new InterfaceTemplate(genType).generateBindingHashCode();
329 private static GeneratedType mockGenType(final String methodeName) {
330 final GeneratedType genType = spy(GeneratedType.class);
331 doReturn(TYPE_NAME).when(genType).getIdentifier();
332 doReturn(TEST).when(genType).getName();
333 doReturn(TEST).when(genType).getPackageName();
335 final List<MethodSignature> listMethodSign = new ArrayList<>();
336 final MethodSignature methSign = mockMethSign(methodeName);
337 listMethodSign.add(methSign);
338 doReturn(listMethodSign).when(genType).getMethodDefinitions();
340 final List<Type> impls = new ArrayList<>();
341 doReturn(impls).when(genType).getImplements();
345 private static MethodSignature mockMethSign(final String methodeName) {
346 final MethodSignature methSign = mock(MethodSignature.class);
347 doReturn(methodeName).when(methSign).getName();
348 final Type methType = mock(Type.class);
349 doCallRealMethod().when(methType).getFullyQualifiedName();
350 doReturn(TYPE_NAME).when(methType).getIdentifier();
351 doReturn(TEST).when(methType).getName();
352 doReturn(methType).when(methSign).getReturnType();
353 doReturn(ValueMechanics.NORMAL).when(methSign).getMechanics();
357 // Xtend's StringConcatenation is using runtime-configured line separator, which can change between runs, notably
358 // it has a different value on Windows. Make sure we account for that.
359 private static void assertXtendEquals(final String expected, final String actual) {
360 assertEquals(expected.replace("\n", StringConcatenation.DEFAULT_LINE_DELIMITER), actual);