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