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.test.util.YangParserTestUtils;
29 public class BuilderGeneratorTest {
30 private static final String TEST = "test";
31 private static final JavaTypeName TYPE_NAME = JavaTypeName.create(TEST, TEST);
34 public void basicTest() {
35 assertEquals("", new BuilderGenerator().generate(mock(Type.class)));
39 public void builderTemplateGenerateHashcodeWithPropertyTest() {
40 final GeneratedType genType = mockGenType("get" + TEST);
44 * Default implementation of {@link Object#hashCode()} contract for this interface.
45 * Implementations of this interface are encouraged to defer to this method to get consistent\
47 * results across all implementations.
49 * @param obj Object for which to generate hashCode() result.
50 * @return Hash code value of data modeled by this interface.
51 * @throws NullPointerException if {@code obj} is {@code null}
53 static int bindingHashCode(final test.@NonNull test obj) {
56 result = prime * result + Objects.hashCode(obj.getTest());
59 """, genHashCode(genType).toString());
63 public void builderTemplateGenerateHashCodeWithoutAnyPropertyTest() throws Exception {
64 assertEquals("", genHashCode(mockGenType(TEST)).toString());
68 public void builderTemplateGenerateHashCodeWithMorePropertiesTest() throws Exception {
71 * Default implementation of {@link Object#hashCode()} contract for this interface.
72 * Implementations of this interface are encouraged to defer to this method to get consistent\
74 * results across all implementations.
76 * @param obj Object for which to generate hashCode() result.
77 * @return Hash code value of data modeled by this interface.
78 * @throws NullPointerException if {@code obj} is {@code null}
80 static int bindingHashCode(final test.@NonNull test obj) {
83 result = prime * result + Objects.hashCode(obj.getTest1());
84 result = prime * result + Objects.hashCode(obj.getTest2());
87 """, genHashCode(mockGenTypeMoreMeth("get" + TEST)).toString());
91 public void builderTemplateGenerateHashCodeWithoutPropertyWithAugmentTest() throws Exception {
94 * Default implementation of {@link Object#hashCode()} contract for this interface.
95 * Implementations of this interface are encouraged to defer to this method to get consistent\
97 * results across all implementations.
99 * @param obj Object for which to generate hashCode() result.
100 * @return Hash code value of data modeled by this interface.
101 * @throws NullPointerException if {@code obj} is {@code null}
103 static int bindingHashCode(final test.@NonNull test obj) {
104 final int prime = 31;
106 for (var augmentation : obj.augmentations().values()) {
107 result += augmentation.hashCode();
111 """, genHashCode(mockAugment(mockGenType(TEST))).toString());
115 public void builderTemplateGenerateHashCodeWithPropertyWithAugmentTest() throws Exception {
116 assertXtendEquals("""
118 * Default implementation of {@link Object#hashCode()} contract for this interface.
119 * Implementations of this interface are encouraged to defer to this method to get consistent\
121 * results across all implementations.
123 * @param obj Object for which to generate hashCode() result.
124 * @return Hash code value of data modeled by this interface.
125 * @throws NullPointerException if {@code obj} is {@code null}
127 static int bindingHashCode(final test.@NonNull test obj) {
128 final int prime = 31;
130 result = prime * result + Objects.hashCode(obj.getTest());
131 for (var augmentation : obj.augmentations().values()) {
132 result += augmentation.hashCode();
136 """, genHashCode(mockAugment(mockGenType("get" + TEST))).toString());
140 public void builderTemplateGenerateHashCodeWithMorePropertiesWithAugmentTest() throws Exception {
141 assertXtendEquals("""
143 * Default implementation of {@link Object#hashCode()} contract for this interface.
144 * Implementations of this interface are encouraged to defer to this method to get consistent\
146 * results across all implementations.
148 * @param obj Object for which to generate hashCode() result.
149 * @return Hash code value of data modeled by this interface.
150 * @throws NullPointerException if {@code obj} is {@code null}
152 static int bindingHashCode(final test.@NonNull test obj) {
153 final int prime = 31;
155 result = prime * result + Objects.hashCode(obj.getTest1());
156 result = prime * result + Objects.hashCode(obj.getTest2());
157 for (var augmentation : obj.augmentations().values()) {
158 result += augmentation.hashCode();
162 """, genHashCode(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
166 public void builderTemplateGenerateToStringWithPropertyTest() {
167 final GeneratedType genType = mockGenType("get" + TEST);
169 assertXtendEquals("""
171 * Default implementation of {@link Object#toString()} contract for this interface.
172 * Implementations of this interface are encouraged to defer to this method to get consistent string\
174 * representations across all implementations.
176 * @param obj Object for which to generate toString() result.
177 * @return {@link String} value of data modeled by this interface.
178 * @throws NullPointerException if {@code obj} is {@code null}
180 static String bindingToString(final test.@NonNull test obj) {
181 final var helper = MoreObjects.toStringHelper("test");
182 CodeHelpers.appendValue(helper, "test", obj.gettest());
183 return helper.toString();
185 """, genToString(genType).toString());
189 public void builderTemplateGenerateToStringWithoutAnyPropertyTest() throws Exception {
190 assertXtendEquals("""
192 * Default implementation of {@link Object#toString()} contract for this interface.
193 * Implementations of this interface are encouraged to defer to this method to get consistent string\
195 * representations across all implementations.
197 * @param obj Object for which to generate toString() result.
198 * @return {@link String} value of data modeled by this interface.
199 * @throws NullPointerException if {@code obj} is {@code null}
201 static String bindingToString(final test.@NonNull test obj) {
202 final var helper = MoreObjects.toStringHelper("test");
203 return helper.toString();
205 """, genToString(mockGenType(TEST)).toString());
209 public void builderTemplateGenerateToStringWithMorePropertiesTest() throws Exception {
210 assertXtendEquals("""
212 * Default implementation of {@link Object#toString()} contract for this interface.
213 * Implementations of this interface are encouraged to defer to this method to get consistent string\
215 * representations across all implementations.
217 * @param obj Object for which to generate toString() result.
218 * @return {@link String} value of data modeled by this interface.
219 * @throws NullPointerException if {@code obj} is {@code null}
221 static String bindingToString(final test.@NonNull test obj) {
222 final var helper = MoreObjects.toStringHelper("test");
223 CodeHelpers.appendValue(helper, "test1", obj.gettest1());
224 CodeHelpers.appendValue(helper, "test2", obj.gettest2());
225 return helper.toString();
227 """, genToString(mockGenTypeMoreMeth("get" + TEST)).toString());
231 public void builderTemplateGenerateToStringWithoutPropertyWithAugmentTest() throws Exception {
232 assertXtendEquals("""
234 * Default implementation of {@link Object#toString()} contract for this interface.
235 * Implementations of this interface are encouraged to defer to this method to get consistent string\
237 * representations across all implementations.
239 * @param obj Object for which to generate toString() result.
240 * @return {@link String} value of data modeled by this interface.
241 * @throws NullPointerException if {@code obj} is {@code null}
243 static String bindingToString(final test.@NonNull test obj) {
244 final var helper = MoreObjects.toStringHelper("test");
245 CodeHelpers.appendAugmentations(helper, "augmentation", obj);
246 return helper.toString();
248 """, genToString(mockAugment(mockGenType(TEST))).toString());
252 public void builderTemplateGenerateToStringWithPropertyWithAugmentTest() throws Exception {
253 assertXtendEquals("""
255 * Default implementation of {@link Object#toString()} contract for this interface.
256 * Implementations of this interface are encouraged to defer to this method to get consistent string\
258 * representations across all implementations.
260 * @param obj Object for which to generate toString() result.
261 * @return {@link String} value of data modeled by this interface.
262 * @throws NullPointerException if {@code obj} is {@code null}
264 static String bindingToString(final test.@NonNull test obj) {
265 final var helper = MoreObjects.toStringHelper("test");
266 CodeHelpers.appendValue(helper, "test", obj.gettest());
267 CodeHelpers.appendAugmentations(helper, "augmentation", obj);
268 return helper.toString();
270 """, genToString(mockAugment(mockGenType("get" + TEST))).toString());
274 public void builderTemplateGenerateToStringWithMorePropertiesWithAugmentTest() throws Exception {
275 assertXtendEquals("""
277 * Default implementation of {@link Object#toString()} contract for this interface.
278 * Implementations of this interface are encouraged to defer to this method to get consistent string\
280 * representations across all implementations.
282 * @param obj Object for which to generate toString() result.
283 * @return {@link String} value of data modeled by this interface.
284 * @throws NullPointerException if {@code obj} is {@code null}
286 static String bindingToString(final test.@NonNull test obj) {
287 final var helper = MoreObjects.toStringHelper("test");
288 CodeHelpers.appendValue(helper, "test1", obj.gettest1());
289 CodeHelpers.appendValue(helper, "test2", obj.gettest2());
290 CodeHelpers.appendAugmentations(helper, "augmentation", obj);
291 return helper.toString();
293 """, genToString(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
297 public void builderTemplateGenerateToEqualsComparingOrderTest() {
298 final var context = YangParserTestUtils.parseYangResource("/test-types.yang");
299 final var types = new DefaultBindingGenerator().generateTypes(context);
300 assertEquals(27, types.size());
302 final BuilderTemplate bt = BuilderGenerator.templateForType(
303 types.stream().filter(t -> t.getName().equals("Nodes")).findFirst().orElseThrow());
305 final List<String> sortedProperties = bt.properties.stream()
306 .sorted(ByTypeMemberComparator.getInstance())
307 .map(BuilderGeneratedProperty::getName)
308 .collect(Collectors.toList());
310 assertEquals(List.of(
311 // numeric types (boolean, byte, short, int, long, biginteger, bigdecimal), identityrefs, empty
312 "id16", "id16Def", "id32", "id32Def", "id64", "id64Def", "id8", "id8Def", "idBoolean", "idBooleanDef",
313 "idDecimal64", "idDecimal64Def","idEmpty", "idEmptyDef", "idIdentityref", "idIdentityrefDef",
314 "idLeafref", "idLeafrefDef", "idU16", "idU16Def", "idU32", "idU32Def", "idU64", "idU64Def", "idU8",
316 // string, binary, bits
317 "idBinary", "idBinaryDef", "idBits", "idBitsDef", "idGroupLeafString", "idLeafrefContainer1",
318 "idLeafrefContainer1Def", "idString", "idStringDef",
319 // instance identifier
320 "idInstanceIdentifier", "idInstanceIdentifierDef",
322 "idContainer1", "idContainer2", "idEnumeration", "idEnumerationDef",
323 "idGroupContainer", "idList", "idUnion", "idUnionDef"), sortedProperties);
326 private static GeneratedType mockAugment(final GeneratedType genType) {
327 final List<Type> impls = new ArrayList<>();
328 final Type impl = mock(Type.class);
329 doReturn("org.opendaylight.yangtools.yang.binding.Augmentable").when(impl).getFullyQualifiedName();
331 doReturn(impls).when(genType).getImplements();
335 private static GeneratedType mockGenTypeMoreMeth(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 for (int i = 0; i < 2; i++) {
343 final MethodSignature methSign = mockMethSign(methodeName + (i + 1));
344 listMethodSign.add(methSign);
346 doReturn(listMethodSign).when(genType).getMethodDefinitions();
348 final List<Type> impls = new ArrayList<>();
349 doReturn(impls).when(genType).getImplements();
353 private static CharSequence genToString(final GeneratedType genType) {
354 return new InterfaceTemplate(genType).generateBindingToString();
357 private static CharSequence genHashCode(final GeneratedType genType) {
358 return new InterfaceTemplate(genType).generateBindingHashCode();
361 private static GeneratedType mockGenType(final String methodeName) {
362 final GeneratedType genType = spy(GeneratedType.class);
363 doReturn(TYPE_NAME).when(genType).getIdentifier();
364 doReturn(TEST).when(genType).getName();
365 doReturn(TEST).when(genType).getPackageName();
367 final List<MethodSignature> listMethodSign = new ArrayList<>();
368 final MethodSignature methSign = mockMethSign(methodeName);
369 listMethodSign.add(methSign);
370 doReturn(listMethodSign).when(genType).getMethodDefinitions();
372 final List<Type> impls = new ArrayList<>();
373 doReturn(impls).when(genType).getImplements();
377 private static MethodSignature mockMethSign(final String methodeName) {
378 final MethodSignature methSign = mock(MethodSignature.class);
379 doReturn(methodeName).when(methSign).getName();
380 final Type methType = mock(Type.class);
381 doCallRealMethod().when(methType).getFullyQualifiedName();
382 doReturn(TYPE_NAME).when(methType).getIdentifier();
383 doReturn(TEST).when(methType).getName();
384 doReturn(methType).when(methSign).getReturnType();
385 doReturn(ValueMechanics.NORMAL).when(methSign).getMechanics();
389 // Xtend's StringConcatenation is using runtime-configured line separator, which can change between runs, notably
390 // it has a different value on Windows. Make sure we account for that.
391 private static void assertXtendEquals(final String expected, final String actual) {
392 assertEquals(expected.replace("\n", StringConcatenation.DEFAULT_LINE_DELIMITER), actual);