Specialize relative leafref types during instantiation
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / test / java / org / opendaylight / mdsal / binding / java / api / generator / test / SpecializingLeafrefTest.java
1 /*
2  * Copyright (c) 2020 Pantheon Technologies, s.r.o.  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.test;
9
10 import static org.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.CoreMatchers.instanceOf;
12 import static org.hamcrest.CoreMatchers.not;
13 import static org.hamcrest.MatcherAssert.assertThat;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertNotNull;
16 import static org.opendaylight.mdsal.binding.java.api.generator.test.FileSearchUtil.DOUBLE_TAB;
17 import static org.opendaylight.mdsal.binding.java.api.generator.test.FileSearchUtil.TAB;
18 import static org.opendaylight.mdsal.binding.java.api.generator.test.FileSearchUtil.TRIPLE_TAB;
19 import static org.opendaylight.mdsal.binding.java.api.generator.test.FileSearchUtil.doubleTab;
20 import static org.opendaylight.mdsal.binding.java.api.generator.test.FileSearchUtil.getFiles;
21 import static org.opendaylight.mdsal.binding.java.api.generator.test.FileSearchUtil.tab;
22 import static org.opendaylight.mdsal.binding.java.api.generator.test.FileSearchUtil.tripleTab;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.net.URISyntaxException;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.util.List;
30 import java.util.Map;
31 import org.junit.After;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
35 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
36 import org.opendaylight.mdsal.binding.model.api.Type;
37 import org.opendaylight.mdsal.binding.model.util.Types;
38
39 public class SpecializingLeafrefTest extends BaseCompilationTest {
40     private static final Type LIST_STRING_TYPE  = Types.listTypeFor(Types.STRING);
41
42     public static final String BAR_CONT = "BarCont";
43     public static final String BOOLEAN_CONT = "BooleanCont";
44
45     private static final String BAR_LST = "BarLst";
46     private static final String BAZ_GRP = "BazGrp";
47     private static final String FOO_GRP = "FooGrp";
48     private static final String RESOLVED_LEAF_GRP = "ResolvedLeafGrp";
49     private static final String RESOLVED_LEAFLIST_GRP = "ResolvedLeafListGrp";
50     private static final String TRANSITIVE_GROUP = "TransitiveGroup";
51     private static final String UNRESOLVED_GROUPING = "UnresolvedGrouping";
52
53     private static final String GET_LEAF1_NAME = "getLeaf1";
54     private static final String GET_LEAFLIST1_NAME = "getLeafList1";
55     private static final String IS_LEAF1_NAME = "isLeaf1";
56
57     private static final String GET_LEAF1_TYPE_OBJECT = "    Object getLeaf1();";
58     private static final String GET_LEAF1_TYPE_STRING = "    String getLeaf1();";
59     private static final String GET_LEAFLIST1_WILDCARD = "    @Nullable List<?> getLeafList1();";
60     private static final String GET_LEAFLIST1_STRING = "    @Nullable List<String> getLeafList1();";
61     private static final String GET_LEAFLIST1_DECLARATION = " getLeafList1();";
62     private static final String GET_LEAF1_DECLARATION = " getLeaf1();";
63     private static final String IS_LEAF1_BOOLEAN = "    Boolean isLeaf1();";
64
65     private static final char CLOSING_METHOD_BRACE = '}';
66     private static final String TAB_CLOSING_METHOD_BRACE = TAB + CLOSING_METHOD_BRACE;
67     private static final String DTAB_CLOSING_METHOD_BRACE = DOUBLE_TAB + CLOSING_METHOD_BRACE;
68
69     private static final String FOO_GRP_REF = "org.opendaylight.yang.gen.v1.mdsal426.norev.FooGrp";
70     private static final String RESOLVED_LEAF_GRP_REF = "org.opendaylight.yang.gen.v1.mdsal426.norev.ResolvedLeafGrp";
71
72     private static final String UNRESOLVED_GROUPING_REF =
73             "org.opendaylight.yang.gen.v1.mdsal426.norev.UnresolvedGrouping";
74
75     private static final String ARG_AS_FOO_GRP = "((" + FOO_GRP_REF + ")arg)";
76
77     private static final String LEAF2_ASSIGNMENT = "this._leaf2 = arg.getLeaf2();";
78
79     private static final String TAB_FIELDS_FROM_SIGNATURE = TAB + "public void fieldsFrom(DataObject arg) {";
80     private static final String TTAB_SET_IS_VALID_ARG_TRUE = TRIPLE_TAB + "isValidArg = true;";
81     private static final String DTAB_INIT_IS_VALID_ARG_FALSE = DOUBLE_TAB + "boolean isValidArg = false;";
82
83     private File sourcesOutputDir;
84     private File compiledOutputDir;
85     private List<Type> types;
86     private Map<String, File> files;
87
88     @Before
89     public void before() throws IOException, URISyntaxException {
90         sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal426");
91         compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal426");
92         types = generateTestSources("/compilation/mdsal426", sourcesOutputDir);
93         CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
94         files = getFiles(sourcesOutputDir);
95     }
96
97     @After
98     public void after() {
99         CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
100     }
101
102     @Test
103     public void testGroupingWithUnresolvedLeafRefs() throws IOException {
104         verifyReturnType(FOO_GRP, GET_LEAF1_NAME, Types.objectType());
105         verifyReturnType(FOO_GRP, GET_LEAFLIST1_NAME, Types.listTypeWildcard());
106
107         final String content = getFileContent(FOO_GRP);
108
109         assertThat(content, containsString(GET_LEAF1_TYPE_OBJECT));
110         assertThat(content, containsString(GET_LEAFLIST1_WILDCARD));
111     }
112
113     @Test
114     public void testLeafLeafrefPointsLeaf() throws IOException {
115         verifyReturnType(RESOLVED_LEAF_GRP, GET_LEAF1_NAME, Types.STRING);
116
117         final String content = getFileContent(RESOLVED_LEAF_GRP);
118
119         assertThat(content, containsString(GET_LEAF1_TYPE_STRING));
120     }
121
122     @Test
123     public void testLeafLeafrefPointsLeafList() throws IOException {
124         verifyReturnType(RESOLVED_LEAFLIST_GRP, GET_LEAF1_NAME, Types.STRING);
125
126         final String content = getFileContent(RESOLVED_LEAF_GRP);
127
128         assertThat(content, containsString(GET_LEAF1_TYPE_STRING));
129     }
130
131     @Test
132     public void testLeafListLeafrefPointsLeaf() throws IOException {
133         verifyReturnType(RESOLVED_LEAF_GRP, GET_LEAFLIST1_NAME, LIST_STRING_TYPE);
134
135         final String content = getFileContent(RESOLVED_LEAF_GRP);
136
137         assertOverriddenGetter(content, GET_LEAFLIST1_STRING);
138     }
139
140     @Test
141     public void testLeafListLeafrefPointsLeafList() throws IOException {
142         verifyReturnType(RESOLVED_LEAFLIST_GRP, GET_LEAFLIST1_NAME, LIST_STRING_TYPE);
143
144         final String content = getFileContent(RESOLVED_LEAFLIST_GRP);
145
146         assertOverriddenGetter(content, GET_LEAFLIST1_STRING);
147     }
148
149     @Test
150     public void testGroupingWhichInheritUnresolvedLeafrefAndDoesNotDefineIt() throws IOException {
151         verifyMethodAbsence(TRANSITIVE_GROUP, GET_LEAF1_NAME);
152         verifyMethodAbsence(TRANSITIVE_GROUP, GET_LEAFLIST1_NAME);
153
154         final String content = getFileContent(TRANSITIVE_GROUP);
155
156         assertThat(content, not(containsString(GET_LEAF1_DECLARATION)));
157         assertThat(content, not(containsString(GET_LEAFLIST1_DECLARATION)));
158     }
159
160     @Test
161     public void testLeafrefWhichPointsBoolean() throws IOException {
162         verifyReturnType(UNRESOLVED_GROUPING, GET_LEAF1_NAME, Types.objectType());
163         verifyReturnType(BOOLEAN_CONT, GET_LEAF1_NAME, Types.BOOLEAN);
164         verifyReturnType(BOOLEAN_CONT, IS_LEAF1_NAME, Types.BOOLEAN);
165
166         final String unresolvedGrouping = getFileContent(UNRESOLVED_GROUPING);
167         final String booleanCont = getFileContent(BOOLEAN_CONT);
168
169         assertNotOverriddenGetter(unresolvedGrouping, GET_LEAF1_TYPE_OBJECT);
170         assertThat(booleanCont, containsString(GET_LEAF1_DECLARATION));
171     }
172
173     @Test
174     public void testGroupingsUsageWhereLeafrefAlreadyResolved() throws IOException {
175         leafList1AndLeaf1Absence(BAR_CONT);
176         leafList1AndLeaf1Absence(BAR_LST);
177         leafList1AndLeaf1Absence(BAZ_GRP);
178     }
179
180     private void leafList1AndLeaf1Absence(final String typeName) throws IOException {
181         verifyMethodAbsence(typeName, GET_LEAF1_NAME);
182         verifyMethodAbsence(typeName, GET_LEAFLIST1_NAME);
183
184         final String content = getFileContent(typeName);
185
186         assertThat(content, not(containsString(GET_LEAF1_DECLARATION)));
187         assertThat(content, not(containsString(GET_LEAFLIST1_DECLARATION)));
188     }
189
190     private static void assertNotOverriddenGetter(final String fileContent, final String getterString) {
191         assertThat(fileContent, not(containsString("@Override" + System.lineSeparator() + getterString)));
192         assertThat(fileContent, containsString(getterString));
193     }
194
195     private static void assertOverriddenGetter(final String fileContent, final String getterString) {
196         assertThat(fileContent, containsString("@Override" + System.lineSeparator() + getterString));
197     }
198
199     @Test
200     public void barContBuilderDataObjectTest() throws IOException {
201         final File file = files.get(getJavaBuilderFileName(BAR_CONT));
202         final String content = Files.readString(file.toPath());
203
204         barContBuilderConstructorResolvedLeafGrpTest(file, content);
205         barContBuilderConstructorFooGrpTest(file, content);
206         barContBuilderFieldsFromTest(file, content);
207     }
208
209     private static void barContBuilderConstructorResolvedLeafGrpTest(final File file, final String content) {
210         FileSearchUtil.assertFileContainsConsecutiveLines(file, content,
211                 tab("public BarContBuilder(" + RESOLVED_LEAF_GRP_REF + " arg) {"),
212                 doubleTab("this._leaf1 = arg.getLeaf1();"),
213                 doubleTab("this._leafList1 = arg.getLeafList1();"),
214                 doubleTab("this._name = arg.getName();"),
215                 doubleTab(LEAF2_ASSIGNMENT),
216                 TAB_CLOSING_METHOD_BRACE);
217     }
218
219     private static void barContBuilderFieldsFromTest(final File file, final String content) {
220         FileSearchUtil.assertFileContainsConsecutiveLines(file, content,
221                 TAB_FIELDS_FROM_SIGNATURE,
222                 DTAB_INIT_IS_VALID_ARG_FALSE,
223                 doubleTab("if (arg instanceof " + FOO_GRP_REF + ") {"),
224                 tripleTab("this._leaf1 = CodeHelpers.checkFieldCast(java.lang.String.class, \"leaf1\", "
225                     + ARG_AS_FOO_GRP + ".getLeaf1());"),
226                 tripleTab("this._leafList1 = CodeHelpers.checkListFieldCast(java.lang.String.class, \"leafList1\", "
227                     + ARG_AS_FOO_GRP + ".getLeafList1());"),
228                 tripleTab("this._leaf2 = " + ARG_AS_FOO_GRP + ".getLeaf2();"),
229                 TTAB_SET_IS_VALID_ARG_TRUE,
230                 DTAB_CLOSING_METHOD_BRACE,
231                 doubleTab("if (arg instanceof " + RESOLVED_LEAF_GRP_REF + ") {"),
232                 tripleTab("this._name = ((" + RESOLVED_LEAF_GRP_REF + ")arg).getName();"),
233                 TTAB_SET_IS_VALID_ARG_TRUE,
234                 DTAB_CLOSING_METHOD_BRACE,
235                 doubleTab("CodeHelpers.validValue(isValidArg, arg, \"[" + FOO_GRP_REF + ", " + RESOLVED_LEAF_GRP_REF
236                     + "]\");"),
237                 TAB_CLOSING_METHOD_BRACE);
238     }
239
240     private static void barContBuilderConstructorFooGrpTest(final File file, final String content) {
241         FileSearchUtil.assertFileContainsConsecutiveLines(file, content,
242                 tab("public BarContBuilder(" + FOO_GRP_REF + " arg) {"),
243                 doubleTab("this._leaf1 = CodeHelpers.checkFieldCast(java.lang.String.class, \"leaf1\", "
244                     + "arg.getLeaf1());"),
245                 doubleTab("this._leafList1 = CodeHelpers.checkListFieldCast(java.lang.String.class, \"leafList1\", "
246                     + "arg.getLeafList1());"),
247                 doubleTab(LEAF2_ASSIGNMENT),
248                 TAB_CLOSING_METHOD_BRACE);
249     }
250
251     @Test
252     public void booleanContBuilderDataObjectTest() throws IOException {
253         final File file = files.get(getJavaBuilderFileName(BOOLEAN_CONT));
254         final String content = Files.readString(file.toPath());
255
256         booleanContBuilderFieldsFromTest(file, content);
257         booleanContBuilderConstructorTest(file, content);
258     }
259
260     private static void booleanContBuilderFieldsFromTest(final File file, final String content) {
261         FileSearchUtil.assertFileContainsConsecutiveLines(file, content,
262                 TAB_FIELDS_FROM_SIGNATURE,
263                 DTAB_INIT_IS_VALID_ARG_FALSE,
264                 doubleTab("if (arg instanceof " + UNRESOLVED_GROUPING_REF + ") {"),
265                 tripleTab("this._leaf1 = CodeHelpers.checkFieldCast(java.lang.Boolean.class, \"leaf1\", (("
266                     + UNRESOLVED_GROUPING_REF + ")arg).getLeaf1());"),
267                 TTAB_SET_IS_VALID_ARG_TRUE,
268                 DTAB_CLOSING_METHOD_BRACE,
269                 doubleTab("CodeHelpers.validValue(isValidArg, arg, \"[" + UNRESOLVED_GROUPING_REF + "]\");"),
270                 TAB_CLOSING_METHOD_BRACE);
271     }
272
273     private static void booleanContBuilderConstructorTest(final File file, final String content) {
274         FileSearchUtil.assertFileContainsConsecutiveLines(file, content,
275                 tab("public BooleanContBuilder(" + UNRESOLVED_GROUPING_REF + " arg) {"),
276                 doubleTab("this._leaf1 = CodeHelpers.checkFieldCast(java.lang.Boolean.class, \"leaf1\", "
277                     + "arg.getLeaf1());"),
278                 TAB_CLOSING_METHOD_BRACE);
279     }
280
281     private static String getJavaFileName(final String name) {
282         return name + ".java";
283     }
284
285     private static String getJavaBuilderFileName(final String name) {
286         return getJavaFileName(name + "Builder");
287     }
288
289     private String getFileContent(final String fileName) throws IOException {
290         final File file = files.get(getJavaFileName(fileName));
291         assertNotNull(Files.lines(file.toPath()).findFirst());
292         final String content = Files.readString(Path.of(file.getAbsolutePath()));
293         assertNotNull(content);
294         return content;
295     }
296
297     private void verifyMethodAbsence(final String typeName, final String getterName) {
298         verifyReturnType(typeName, getterName, null);
299     }
300
301     private void verifyReturnType(final String typeName, final String getterName, final Type returnType) {
302         final Type type = typeByName(types, typeName);
303         assertThat(type, instanceOf(GeneratedType.class));
304         final GeneratedType generated = (GeneratedType)type;
305         assertEquals(returnType, returnTypeByMethodName(generated, getterName));
306     }
307
308     private static Type typeByName(final List<Type> types, final String name) {
309         for (final Type type : types) {
310             if (type.getName().equals(name)) {
311                 return type;
312             }
313         }
314         return null;
315     }
316
317     private static Type returnTypeByMethodName(final GeneratedType type, final String name) {
318         for (final MethodSignature m : type.getMethodDefinitions()) {
319             if (m.getName().equals(name)) {
320                 return m.getReturnType();
321             }
322         }
323         return null;
324     }
325 }