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
index 481bd924770946c4df975573a3d3e4ebef768814..3e9b7b6cdbdb0cb6ab745ba0d716635b3b542d01 100644 (file)
@@ -11,21 +11,22 @@ import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
-import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
+import java.util.stream.Collectors;
 import org.junit.Test;
-import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
+import org.opendaylight.mdsal.binding.generator.impl.DefaultBindingGenerator;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
 import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
 public class BuilderGeneratorTest {
-
-    private static final String PROPERTIES_FIELD_NAME = "properties";
     private static final String TEST = "test";
     private static final JavaTypeName TYPE_NAME = JavaTypeName.create(TEST, TEST);
 
@@ -34,69 +35,256 @@ public class BuilderGeneratorTest {
         assertEquals("", new BuilderGenerator().generate(mock(Type.class)));
     }
 
+    @Test
+    public void builderTemplateGenerateHashcodeWithPropertyTest() {
+        final GeneratedType genType = mockGenType("get" + TEST);
+
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent"
+                + " hashing\n"
+                + " * results across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate hashCode() result.\n"
+                + " * @return Hash code value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static int bindingHashCode(final test.@NonNull test obj) {\n"
+                + "    final int prime = 31;\n"
+                + "    int result = 1;\n"
+                + "    result = prime * result + Objects.hashCode(obj.getTest());\n"
+                + "    return result;\n"
+                + "}\n", genHashCode(genType).toString());
+    }
+
+    @Test
+    public void builderTemplateGenerateHashCodeWithoutAnyPropertyTest() throws Exception {
+        assertEquals("", genHashCode(mockGenType(TEST)).toString());
+    }
+
+    @Test
+    public void builderTemplateGenerateHashCodeWithMorePropertiesTest() throws Exception {
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent"
+                + " hashing\n"
+                + " * results across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate hashCode() result.\n"
+                + " * @return Hash code value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static int bindingHashCode(final test.@NonNull test obj) {\n"
+                + "    final int prime = 31;\n"
+                + "    int result = 1;\n"
+                + "    result = prime * result + Objects.hashCode(obj.getTest1());\n"
+                + "    result = prime * result + Objects.hashCode(obj.getTest2());\n"
+                + "    return result;\n"
+                + "}\n", genHashCode(mockGenTypeMoreMeth("get" + TEST)).toString());
+    }
+
+    @Test
+    public void builderTemplateGenerateHashCodeWithoutPropertyWithAugmentTest() throws Exception {
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent"
+                + " hashing\n"
+                + " * results across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate hashCode() result.\n"
+                + " * @return Hash code value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static int bindingHashCode(final test.@NonNull test obj) {\n"
+                + "    final int prime = 31;\n"
+                + "    int result = 1;\n"
+                + "    result = prime * result + obj.augmentations().hashCode();\n"
+                + "    return result;\n"
+                + "}\n", genHashCode(mockAugment(mockGenType(TEST))).toString());
+    }
+
+    @Test
+    public void builderTemplateGenerateHashCodeWithPropertyWithAugmentTest() throws Exception {
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent"
+                + " hashing\n"
+                + " * results across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate hashCode() result.\n"
+                + " * @return Hash code value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static int bindingHashCode(final test.@NonNull test obj) {\n"
+                + "    final int prime = 31;\n"
+                + "    int result = 1;\n"
+                + "    result = prime * result + Objects.hashCode(obj.getTest());\n"
+                + "    result = prime * result + obj.augmentations().hashCode();\n"
+                + "    return result;\n"
+                + "}\n", genHashCode(mockAugment(mockGenType("get" + TEST))).toString());
+    }
+
+    @Test
+    public void builderTemplateGenerateHashCodeWithMorePropertiesWithAugmentTest() throws Exception {
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#hashCode()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent"
+                + " hashing\n"
+                + " * results across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate hashCode() result.\n"
+                + " * @return Hash code value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static int bindingHashCode(final test.@NonNull test obj) {\n"
+                + "    final int prime = 31;\n"
+                + "    int result = 1;\n"
+                + "    result = prime * result + Objects.hashCode(obj.getTest1());\n"
+                + "    result = prime * result + Objects.hashCode(obj.getTest2());\n"
+                + "    result = prime * result + obj.augmentations().hashCode();\n"
+                + "    return result;\n"
+                + "}\n", genHashCode(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
+    }
+
     @Test
     public void builderTemplateGenerateToStringWithPropertyTest() {
         final GeneratedType genType = mockGenType("get" + TEST);
 
-        assertEquals("@Override\n" +
-                "public java.lang.String toString() {\n" +
-                "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
-                "    CodeHelpers.appendValue(helper, \"_test\", _test);\n" +
-                "    return helper.toString();\n" +
-                "}\n", genToString(genType).toString());
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
+                + "\n * representations across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate toString() result.\n"
+                + " * @return {@link String} value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static String bindingToString(final test.@NonNull test obj) {\n"
+                + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
+                + "    CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
+                + "    return helper.toString();\n"
+                + "}\n", genToString(genType).toString());
     }
 
     @Test
     public void builderTemplateGenerateToStringWithoutAnyPropertyTest() throws Exception {
-        assertEquals("@Override\n" +
-                "public java.lang.String toString() {\n" +
-                "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
-                "    return helper.toString();\n" +
-                "}\n", genToString(mockGenType(TEST)).toString());
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
+                + "\n * representations across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate toString() result.\n"
+                + " * @return {@link String} value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static String bindingToString(final test.@NonNull test obj) {\n"
+                + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
+                + "    return helper.toString();\n"
+                + "}\n", genToString(mockGenType(TEST)).toString());
     }
 
     @Test
     public void builderTemplateGenerateToStringWithMorePropertiesTest() throws Exception {
-        assertEquals("@Override\n" +
-                "public java.lang.String toString() {\n" +
-                "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
-                "    CodeHelpers.appendValue(helper, \"_test1\", _test1);\n" +
-                "    CodeHelpers.appendValue(helper, \"_test2\", _test2);\n" +
-                "    return helper.toString();\n" +
-                "}\n", genToString(mockGenTypeMoreMeth("get" + TEST)).toString());
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
+                + "\n * representations across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate toString() result.\n"
+                + " * @return {@link String} value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static String bindingToString(final test.@NonNull test obj) {\n"
+                + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
+                + "    CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
+                + "    CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
+                + "    return helper.toString();\n"
+                + "}\n", genToString(mockGenTypeMoreMeth("get" + TEST)).toString());
     }
 
     @Test
     public void builderTemplateGenerateToStringWithoutPropertyWithAugmentTest() throws Exception {
-        assertEquals("@Override\n" +
-                "public java.lang.String toString() {\n" +
-                "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
-                "    CodeHelpers.appendValue(helper, \"augmentation\", augmentation.values());\n" +
-                "    return helper.toString();\n" +
-                "}\n", genToString(mockAugment(mockGenType(TEST))).toString());
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
+                + "\n * representations across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate toString() result.\n"
+                + " * @return {@link String} value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static String bindingToString(final test.@NonNull test obj) {\n"
+                + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
+                + "    CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
+                + "    return helper.toString();\n"
+                + "}\n", genToString(mockAugment(mockGenType(TEST))).toString());
     }
 
     @Test
     public void builderTemplateGenerateToStringWithPropertyWithAugmentTest() throws Exception {
-        assertEquals("@Override\n" +
-                "public java.lang.String toString() {\n" +
-                "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
-                "    CodeHelpers.appendValue(helper, \"_test\", _test);\n" +
-                "    CodeHelpers.appendValue(helper, \"augmentation\", augmentation.values());\n" +
-                "    return helper.toString();\n" +
-                "}\n", genToString(mockAugment(mockGenType("get" + TEST))).toString());
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
+                + "\n * representations across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate toString() result.\n"
+                + " * @return {@link String} value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static String bindingToString(final test.@NonNull test obj) {\n"
+                + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
+                + "    CodeHelpers.appendValue(helper, \"test\", obj.gettest());\n"
+                + "    CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
+                + "    return helper.toString();\n"
+                + "}\n", genToString(mockAugment(mockGenType("get" + TEST))).toString());
     }
 
     @Test
     public void builderTemplateGenerateToStringWithMorePropertiesWithAugmentTest() throws Exception {
-        assertEquals("@Override\n" +
-                "public java.lang.String toString() {\n" +
-                "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
-                "    CodeHelpers.appendValue(helper, \"_test1\", _test1);\n" +
-                "    CodeHelpers.appendValue(helper, \"_test2\", _test2);\n" +
-                "    CodeHelpers.appendValue(helper, \"augmentation\", augmentation.values());\n" +
-                "    return helper.toString();\n" +
-                "}\n", genToString(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
+        assertEquals("/**\n"
+                + " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+                + " * Implementations of this interface are encouraged to defer to this method to get consistent string"
+                + "\n * representations across all implementations.\n"
+                + " *\n"
+                + " * @param obj Object for which to generate toString() result.\n"
+                + " * @return {@link String} value of data modeled by this interface.\n"
+                + " * @throws NullPointerException if {@code obj} is null\n"
+                + " */\n"
+                + "static String bindingToString(final test.@NonNull test obj) {\n"
+                + "    final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n"
+                + "    CodeHelpers.appendValue(helper, \"test1\", obj.gettest1());\n"
+                + "    CodeHelpers.appendValue(helper, \"test2\", obj.gettest2());\n"
+                + "    CodeHelpers.appendValue(helper, \"augmentation\", obj.augmentations().values());\n"
+                + "    return helper.toString();\n"
+                + "}\n", genToString(mockAugment(mockGenTypeMoreMeth("get" + TEST))).toString());
+    }
+
+    @Test
+    public void builderTemplateGenerateToEqualsComparingOrderTest() {
+        final EffectiveModelContext context = YangParserTestUtils.parseYangResource(
+                "/test-types.yang");
+        final List<Type> types = new DefaultBindingGenerator().generateTypes(context);
+        final BuilderTemplate bt = BuilderGenerator.templateForType((GeneratedType) types.get(19));
+
+        final List<String> sortedProperties = bt.properties.stream()
+                .sorted(ByTypeMemberComparator.getInstance())
+                .map(BuilderGeneratedProperty::getName)
+                .collect(Collectors.toList());
+
+        assertEquals(List.of(
+                // numeric types (boolean, byte, short, int, long, biginteger, bigdecimal), identityrefs, empty
+                "id16", "id16Def", "id32", "id32Def", "id64", "id64Def", "id8", "id8Def", "idBoolean", "idBooleanDef",
+                "idDecimal64", "idDecimal64Def","idEmpty", "idEmptyDef", "idIdentityref", "idIdentityrefDef",
+                "idLeafref", "idLeafrefDef", "idU16", "idU16Def", "idU32", "idU32Def", "idU64", "idU64Def", "idU8",
+                "idU8Def",
+                // string, binary, bits
+                "idBinary", "idBinaryDef", "idBits", "idBitsDef", "idGroupLeafString", "idLeafrefContainer1",
+                "idLeafrefContainer1Def", "idString", "idStringDef",
+                // instance identifier
+                "idInstanceIdentifier", "idInstanceIdentifierDef",
+                // other types
+                "idContainer1", "idContainer2", "idEnumeration", "idEnumerationDef",
+                "idGroupContainer", "idList", "idUnion", "idUnionDef"), sortedProperties);
     }
 
     private static GeneratedType mockAugment(final GeneratedType genType) {
@@ -126,16 +314,12 @@ public class BuilderGeneratorTest {
         return genType;
     }
 
-    @SuppressWarnings("unchecked")
     private static CharSequence genToString(final GeneratedType genType) {
-        try {
-            final BuilderTemplate bt = new BuilderTemplate(genType);
-            final Field propertiesField = bt.getClass().getDeclaredField(PROPERTIES_FIELD_NAME);
-            propertiesField.setAccessible(true);
-            return bt.generateToString((Collection<GeneratedProperty>) propertiesField.get(bt));
-        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
-            throw new RuntimeException(e);
-        }
+        return new InterfaceTemplate(genType).generateBindingToString();
+    }
+
+    private static CharSequence genHashCode(final GeneratedType genType) {
+        return new InterfaceTemplate(genType).generateBindingHashCode();
     }
 
     private static GeneratedType mockGenType(final String methodeName) {
@@ -158,8 +342,11 @@ public class BuilderGeneratorTest {
         final MethodSignature methSign = mock(MethodSignature.class);
         doReturn(methodeName).when(methSign).getName();
         final Type methType = mock(Type.class);
+        when(methType.getFullyQualifiedName()).thenCallRealMethod();
         doReturn(TYPE_NAME).when(methType).getIdentifier();
+        doReturn(TEST).when(methType).getName();
         doReturn(methType).when(methSign).getReturnType();
+        doReturn(ValueMechanics.NORMAL).when(methSign).getMechanics();
         return methSign;
     }
 }