Skip bindingHashCode() generation on properties' absence
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / test / java / org / opendaylight / mdsal / binding / java / api / generator / BuilderGeneratorTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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.mdsal.binding.java.api.generator;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.Mockito.doReturn;
12 import static org.mockito.Mockito.mock;
13 import static org.mockito.Mockito.spy;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.stream.Collectors;
18 import org.junit.Test;
19 import org.opendaylight.mdsal.binding.generator.impl.DefaultBindingGenerator;
20 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
21 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
22 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
23 import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
24 import org.opendaylight.mdsal.binding.model.api.Type;
25 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
26 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
27
28 public class BuilderGeneratorTest {
29     private static final String TEST = "test";
30     private static final JavaTypeName TYPE_NAME = JavaTypeName.create(TEST, TEST);
31
32     @Test
33     public void basicTest() {
34         assertEquals("", new BuilderGenerator().generate(mock(Type.class)));
35     }
36
37     @Test
38     public void builderTemplateGenerateHashcodeWithPropertyTest() {
39         final GeneratedType genType = mockGenType("get" + TEST);
40
41         assertEquals("/**\n"
42                 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
43                 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
44                 + " hashing\n"
45                 + " * results across all implementations.\n"
46                 + " *\n"
47                 + " * @param obj Object for which to generate hashCode() result.\n"
48                 + " * @return Hash code value of data modeled by this interface.\n"
49                 + " * @throws NullPointerException if {@code obj} is null\n"
50                 + " */\n"
51                 + "static int bindingHashCode(final test.test obj) {\n"
52                 + "    final int prime = 31;\n"
53                 + "    int result = 1;\n"
54                 + "    result = prime * result + Objects.hashCode(obj.getTest());\n"
55                 + "    return result;\n"
56                 + "}\n", genHashCode(genType).toString());
57     }
58
59     @Test
60     public void builderTemplateGenerateHashCodeWithoutAnyPropertyTest() throws Exception {
61         assertEquals("", genHashCode(mockGenType(TEST)).toString());
62     }
63
64     @Test
65     public void builderTemplateGenerateHashCodeWithMorePropertiesTest() throws Exception {
66         assertEquals("/**\n"
67                 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
68                 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
69                 + " hashing\n"
70                 + " * results across all implementations.\n"
71                 + " *\n"
72                 + " * @param obj Object for which to generate hashCode() result.\n"
73                 + " * @return Hash code value of data modeled by this interface.\n"
74                 + " * @throws NullPointerException if {@code obj} is null\n"
75                 + " */\n"
76                 + "static int bindingHashCode(final test.test obj) {\n"
77                 + "    final int prime = 31;\n"
78                 + "    int result = 1;\n"
79                 + "    result = prime * result + Objects.hashCode(obj.getTest1());\n"
80                 + "    result = prime * result + Objects.hashCode(obj.getTest2());\n"
81                 + "    return result;\n"
82                 + "}\n", genHashCode(mockGenTypeMoreMeth("get" + TEST)).toString());
83     }
84
85     @Test
86     public void builderTemplateGenerateHashCodeWithoutPropertyWithAugmentTest() throws Exception {
87         assertEquals("/**\n"
88                 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
89                 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
90                 + " hashing\n"
91                 + " * results across all implementations.\n"
92                 + " *\n"
93                 + " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
94                 + " *              contract.\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"
98                 + " */\n"
99                 + "static <T$$ extends test.test & AugmentationHolder<?>> int bindingHashCode(final @NonNull T$$ obj) {"
100                 + "\n"
101                 + "    final int prime = 31;\n"
102                 + "    int result = 1;\n"
103                 + "    result = prime * result + CodeHelpers.hashAugmentations(obj);\n"
104                 + "    return result;\n"
105                 + "}\n", genHashCode(mockAugment(mockGenType(TEST))).toString());
106     }
107
108     @Test
109     public void builderTemplateGenerateHashCodeWithPropertyWithAugmentTest() throws Exception {
110         assertEquals("/**\n"
111                 + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
112                 + " * Implementations of this interface are encouraged to defer to this method to get consistent"
113                 + " hashing\n"
114                 + " * results across all implementations.\n"
115                 + " *\n"
116                 + " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
117                 + " *              contract.\n"
118                 + " * @param obj Object for which to generate hashCode() result.\n"
119                 + " * @return Hash code value of data modeled by this interface.\n"
120                 + " * @throws NullPointerException if {@code obj} is null\n"
121                 + " */\n"
122                 + "static <T$$ extends test.test & AugmentationHolder<?>> int bindingHashCode(final @NonNull T$$ obj) {"
123                 + "\n"
124                 + "    final int prime = 31;\n"
125                 + "    int result = 1;\n"
126                 + "    result = prime * result + Objects.hashCode(obj.getTest());\n"
127                 + "    result = prime * result + CodeHelpers.hashAugmentations(obj);\n"
128                 + "    return result;\n"
129                 + "}\n", genHashCode(mockAugment(mockGenType("get" + TEST))).toString());
130     }
131
132     @Test
133     public void builderTemplateGenerateHashCodeWithMorePropertiesWithAugmentTest() throws Exception {
134         assertEquals("/**\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"
137                 + " hashing\n"
138                 + " * results across all implementations.\n"
139                 + " *\n"
140                 + " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
141                 + " *              contract.\n"
142                 + " * @param obj Object for which to generate hashCode() result.\n"
143                 + " * @return Hash code value of data modeled by this interface.\n"
144                 + " * @throws NullPointerException if {@code obj} is null\n"
145                 + " */\n"
146                 + "static <T$$ extends test.test & AugmentationHolder<?>> int bindingHashCode(final @NonNull T$$ obj) {"
147                 + "\n"
148                 + "    final int prime = 31;\n"
149                 + "    int result = 1;\n"
150                 + "    result = prime * result + Objects.hashCode(obj.getTest1());\n"
151                 + "    result = prime * result + Objects.hashCode(obj.getTest2());\n"
152                 + "    result = prime * result + CodeHelpers.hashAugmentations(obj);\n"
153                 + "    return result;\n"
154                 + "}\n", genHashCode(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
155     }
156
157     @Test
158     public void builderTemplateGenerateToStringWithPropertyTest() {
159         final GeneratedType genType = mockGenType("get" + TEST);
160
161         assertEquals("/**\n"
162                 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
163                 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
164                 + "\n * representations across all implementations.\n"
165                 + " *\n"
166                 + " * @param obj Object for which to generate toString() result.\n"
167                 + " * @return {@link String} value of data modeled by this interface.\n"
168                 + " * @throws NullPointerException if {@code obj} is null\n"
169                 + " */\n"
170                 + "static String bindingToString(final test.test obj) {\n"
171                 + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
172                 + "    CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
173                 + "    return helper.toString();\n"
174                 + "}\n", genToString(genType).toString());
175     }
176
177     @Test
178     public void builderTemplateGenerateToStringWithoutAnyPropertyTest() throws Exception {
179         assertEquals("/**\n"
180                 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
181                 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
182                 + "\n * representations across all implementations.\n"
183                 + " *\n"
184                 + " * @param obj Object for which to generate toString() result.\n"
185                 + " * @return {@link String} value of data modeled by this interface.\n"
186                 + " * @throws NullPointerException if {@code obj} is null\n"
187                 + " */\n"
188                 + "static String bindingToString(final test.test obj) {\n"
189                 + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
190                 + "    return helper.toString();\n"
191                 + "}\n", genToString(mockGenType(TEST)).toString());
192     }
193
194     @Test
195     public void builderTemplateGenerateToStringWithMorePropertiesTest() throws Exception {
196         assertEquals("/**\n"
197                 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
198                 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
199                 + "\n * representations across all implementations.\n"
200                 + " *\n"
201                 + " * @param obj Object for which to generate toString() result.\n"
202                 + " * @return {@link String} value of data modeled by this interface.\n"
203                 + " * @throws NullPointerException if {@code obj} is null\n"
204                 + " */\n"
205                 + "static String bindingToString(final test.test obj) {\n"
206                 + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
207                 + "    CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
208                 + "    CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
209                 + "    return helper.toString();\n"
210                 + "}\n", genToString(mockGenTypeMoreMeth("get" + TEST)).toString());
211     }
212
213     @Test
214     public void builderTemplateGenerateToStringWithoutPropertyWithAugmentTest() throws Exception {
215         assertEquals("/**\n"
216                 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
217                 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
218                 + "\n * representations across all implementations.\n"
219                 + " *\n"
220                 + " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
221                 + " *              contract.\n"
222                 + " * @param obj Object for which to generate toString() result.\n"
223                 + " * @return {@link String} value of data modeled by this interface.\n"
224                 + " * @throws NullPointerException if {@code obj} is null\n"
225                 + " */\n"
226                 + "static <T$$ extends test.test & AugmentationHolder<test.test>> String bindingToString(final @NonNull"
227                 + " T$$ obj) {\n"
228                 + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
229                 + "    CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
230                 + "    return helper.toString();\n"
231                 + "}\n", genToString(mockAugment(mockGenType(TEST))).toString());
232     }
233
234     @Test
235     public void builderTemplateGenerateToStringWithPropertyWithAugmentTest() throws Exception {
236         assertEquals("/**\n"
237                 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
238                 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
239                 + "\n * representations across all implementations.\n"
240                 + " *\n"
241                 + " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
242                 + " *              contract.\n"
243                 + " * @param obj Object for which to generate toString() result.\n"
244                 + " * @return {@link String} value of data modeled by this interface.\n"
245                 + " * @throws NullPointerException if {@code obj} is null\n"
246                 + " */\n"
247                 + "static <T$$ extends test.test & AugmentationHolder<test.test>> String bindingToString(final @NonNull"
248                 + " T$$ obj) {\n"
249                 + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
250                 + "    CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
251                 + "    CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
252                 + "    return helper.toString();\n"
253                 + "}\n", genToString(mockAugment(mockGenType("get" + TEST))).toString());
254     }
255
256     @Test
257     public void builderTemplateGenerateToStringWithMorePropertiesWithAugmentTest() throws Exception {
258         assertEquals("/**\n"
259                 + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
260                 + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
261                 + "\n * representations across all implementations.\n"
262                 + " *\n"
263                 + " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
264                 + " *              contract.\n"
265                 + " * @param obj Object for which to generate toString() result.\n"
266                 + " * @return {@link String} value of data modeled by this interface.\n"
267                 + " * @throws NullPointerException if {@code obj} is null\n"
268                 + " */\n"
269                 + "static <T$$ extends test.test & AugmentationHolder<test.test>> String bindingToString(final @NonNull"
270                 + " T$$ obj) {\n"
271                 + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
272                 + "    CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
273                 + "    CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
274                 + "    CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
275                 + "    return helper.toString();\n"
276                 + "}\n", genToString(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
277     }
278
279     @Test
280     public void builderTemplateGenerateToEqualsComparingOrderTest() {
281         final EffectiveModelContext context = YangParserTestUtils.parseYangResource(
282                 "/test-types.yang");
283         final List<Type> types = new DefaultBindingGenerator().generateTypes(context);
284         final BuilderTemplate bt = BuilderGenerator.templateForType((GeneratedType) types.get(19));
285
286         final List<String> sortedProperties = bt.properties.stream()
287                 .sorted(ByTypeMemberComparator.getInstance())
288                 .map(BuilderGeneratedProperty::getName)
289                 .collect(Collectors.toList());
290
291         assertEquals(List.of(
292                 // numeric types (boolean, byte, short, int, long, biginteger, bigdecimal), identityrefs, empty
293                 "id16", "id16Def", "id32", "id32Def", "id64", "id64Def", "id8", "id8Def", "idBoolean", "idBooleanDef",
294                 "idDecimal64", "idDecimal64Def","idEmpty", "idEmptyDef", "idIdentityref", "idIdentityrefDef",
295                 "idLeafref", "idLeafrefDef", "idU16", "idU16Def", "idU32", "idU32Def", "idU64", "idU64Def", "idU8",
296                 "idU8Def",
297                 // string, binary, bits
298                 "idBinary", "idBinaryDef", "idBits", "idBitsDef", "idGroupLeafString", "idLeafrefContainer1",
299                 "idLeafrefContainer1Def", "idString", "idStringDef",
300                 // instance identifier
301                 "idInstanceIdentifier", "idInstanceIdentifierDef",
302                 // other types
303                 "idContainer1", "idContainer2", "idEnumeration", "idEnumerationDef",
304                 "idGroupContainer", "idList", "idUnion", "idUnionDef"), sortedProperties);
305     }
306
307     private static GeneratedType mockAugment(final GeneratedType genType) {
308         final List<Type> impls = new ArrayList<>();
309         final Type impl = mock(Type.class);
310         doReturn("org.opendaylight.yangtools.yang.binding.Augmentable").when(impl).getFullyQualifiedName();
311         impls.add(impl);
312         doReturn(impls).when(genType).getImplements();
313         return genType;
314     }
315
316     private static GeneratedType mockGenTypeMoreMeth(final String methodeName) {
317         final GeneratedType genType = spy(GeneratedType.class);
318         doReturn(TYPE_NAME).when(genType).getIdentifier();
319         doReturn(TEST).when(genType).getName();
320         doReturn(TEST).when(genType).getPackageName();
321
322         final List<MethodSignature> listMethodSign = new ArrayList<>();
323         for (int i = 0; i < 2; i++) {
324             final MethodSignature methSign = mockMethSign(methodeName + (i + 1));
325             listMethodSign.add(methSign);
326         }
327         doReturn(listMethodSign).when(genType).getMethodDefinitions();
328
329         final List<Type> impls = new ArrayList<>();
330         doReturn(impls).when(genType).getImplements();
331         return genType;
332     }
333
334     private static CharSequence genToString(final GeneratedType genType) {
335         return new InterfaceTemplate(genType).generateBindingToString();
336     }
337
338     private static CharSequence genHashCode(final GeneratedType genType) {
339         return new InterfaceTemplate(genType).generateBindingHashCode();
340     }
341
342     private static GeneratedType mockGenType(final String methodeName) {
343         final GeneratedType genType = spy(GeneratedType.class);
344         doReturn(TYPE_NAME).when(genType).getIdentifier();
345         doReturn(TEST).when(genType).getName();
346         doReturn(TEST).when(genType).getPackageName();
347
348         final List<MethodSignature> listMethodSign = new ArrayList<>();
349         final MethodSignature methSign = mockMethSign(methodeName);
350         listMethodSign.add(methSign);
351         doReturn(listMethodSign).when(genType).getMethodDefinitions();
352
353         final List<Type> impls = new ArrayList<>();
354         doReturn(impls).when(genType).getImplements();
355         return genType;
356     }
357
358     private static MethodSignature mockMethSign(final String methodeName) {
359         final MethodSignature methSign = mock(MethodSignature.class);
360         doReturn(methodeName).when(methSign).getName();
361         final Type methType = mock(Type.class);
362         doReturn(TYPE_NAME).when(methType).getIdentifier();
363         doReturn(TEST).when(methType).getName();
364         doReturn(methType).when(methSign).getReturnType();
365         doReturn(ValueMechanics.NORMAL).when(methSign).getMechanics();
366         return methSign;
367     }
368 }