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.hamcrest.CoreMatchers.startsWith;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertThrows;
15 import static org.junit.Assert.assertTrue;
17 import com.google.common.collect.Collections2;
18 import com.google.common.collect.ImmutableList;
19 import com.google.common.collect.ImmutableSet;
20 import com.google.common.collect.Range;
22 import java.io.IOException;
23 import java.lang.annotation.Annotation;
24 import java.lang.reflect.Field;
25 import java.lang.reflect.Method;
26 import java.lang.reflect.Modifier;
27 import java.lang.reflect.ParameterizedType;
28 import java.lang.reflect.Type;
29 import java.lang.reflect.WildcardType;
30 import java.net.URISyntaxException;
32 import java.net.URLClassLoader;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.HexFormat;
37 import java.util.List;
38 import java.util.stream.Collectors;
39 import org.junit.Test;
40 import org.opendaylight.mdsal.binding.model.ri.TypeConstants;
41 import org.opendaylight.yangtools.yang.binding.ChildOf;
42 import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
43 import org.opendaylight.yangtools.yang.common.Decimal64;
44 import org.opendaylight.yangtools.yang.common.Empty;
45 import org.opendaylight.yangtools.yang.common.Uint16;
46 import org.opendaylight.yangtools.yang.common.Uint32;
47 import org.opendaylight.yangtools.yang.common.Uint64;
48 import org.opendaylight.yangtools.yang.common.Uint8;
51 * Test correct code generation.
54 public class CompilationTest extends BaseCompilationTest {
57 * Java 8 allows JaCoCo to hook onto interfaces, as well as
58 * generating a default implementation. We only want to check
61 private static Collection<Method> abstractMethods(final Class<?> clazz) {
63 return Collections2.filter(Arrays.asList(clazz.getDeclaredMethods()),
64 input -> Modifier.isAbstract(input.getModifiers()));
68 public void testListGeneration() throws Exception {
69 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("list-gen");
70 final File compiledOutputDir = CompilationTestUtils.compilerOutput("list-gen");
71 generateTestSources("/compilation/list-gen", sourcesOutputDir);
73 // Test if all sources are generated
74 File parent = new File(sourcesOutputDir, CompilationTestUtils.NS_TEST);
75 final File keyArgs = new File(parent, "KeyArgs.java");
76 final File links = new File(parent, "Links.java");
77 final File linksBuilder = new File(parent, "LinksBuilder.java");
78 final File linksKey = new File(parent, "LinksKey.java");
79 final File testData = new File(parent, "TestData.java");
80 assertTrue(keyArgs.exists());
81 assertTrue(links.exists());
82 assertTrue(linksBuilder.exists());
83 assertTrue(linksKey.exists());
84 assertTrue(testData.exists());
85 CompilationTestUtils.assertFilesCount(parent, 6);
86 final File svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_TEST);
87 CompilationTestUtils.assertFilesCount(svcParent, 1);
89 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_TEST + CompilationTestUtils.FS + "links");
90 final File level = new File(parent, "Level.java");
91 final File linkGroup = new File(parent, "LinkGroup.java");
92 final File node = new File(parent, "Node.java");
93 final File nodeBuilder = new File(parent, "NodeBuilder.java");
94 final File nodeList = new File(parent, "NodeList.java");
95 final File nodeListBuilder = new File(parent, "NodeListBuilder.java");
96 final File nodesType = new File(parent, "NodesType.java");
97 assertTrue(level.exists());
98 assertTrue(linkGroup.exists());
99 assertTrue(node.exists());
100 assertTrue(nodeBuilder.exists());
101 assertTrue(nodeList.exists());
102 assertTrue(nodeListBuilder.exists());
103 assertTrue(nodesType.exists());
104 CompilationTestUtils.assertFilesCount(parent, 8);
106 // Test if sources are compilable
107 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
109 final ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
110 final Class<?> keyArgsClass = Class.forName(CompilationTestUtils.BASE_PKG
111 + ".urn.opendaylight.test.rev131008.KeyArgs", true, loader);
112 final Class<?> linksClass = Class.forName(CompilationTestUtils.BASE_PKG
113 + ".urn.opendaylight.test.rev131008.Links", true, loader);
114 final Class<?> linksKeyClass = Class.forName(CompilationTestUtils.BASE_PKG
115 + ".urn.opendaylight.test.rev131008.LinksKey", true, loader);
117 // Test generated 'grouping key-args'
118 assertTrue(keyArgsClass.isInterface());
119 CompilationTestUtils.assertContainsMethod(keyArgsClass, String.class, "getName");
120 CompilationTestUtils.assertContainsMethod(keyArgsClass, Integer.class, "getSize");
121 assertEquals(3, abstractMethods(keyArgsClass).size());
123 // Test generated 'list links'
124 assertTrue(linksClass.isInterface());
125 CompilationTestUtils.assertImplementsIfc(linksClass, keyArgsClass);
126 assertEquals(8, abstractMethods(linksClass).size());
127 CompilationTestUtils.assertContainsMethod(linksClass,
128 "org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.links.Text", "getText", loader);
129 CompilationTestUtils.assertContainsMethod(linksClass,
130 "org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.links.Text", "requireText", loader);
132 // Test list key constructor arguments ordering
133 CompilationTestUtils.assertContainsConstructor(linksKeyClass, Byte.class, String.class, Integer.class);
134 // Test serialVersionUID generation
135 final Field suid = CompilationTestUtils.assertContainsField(linksKeyClass, "serialVersionUID", Long.TYPE);
136 suid.setAccessible(true);
137 assertEquals(-8290985055387641395L, suid.getLong(null));
139 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
143 * Test that nonnull getter method is generated for non-presence containers only.
145 * @throws Exception when any exception occurs during the test
148 public void testContainerGettersGeneration() throws Exception {
149 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("containers-gen");
150 final File compiledOutputDir = CompilationTestUtils.compilerOutput("containers-gen");
151 generateTestSources("/compilation/containers-gen", sourcesOutputDir);
153 // Test if all sources were generated from 'module containers'
154 File parent = new File(sourcesOutputDir, CompilationTestUtils.NS_TEST);
155 assertTrue(new File(parent, "RootContainer.java").exists());
156 assertTrue(new File(parent, "rootcontainer/PresenceContainer.java").exists());
157 assertTrue(new File(parent, "rootcontainer/NonPresenceContainer.java").exists());
158 CompilationTestUtils.assertFilesCount(parent, 4);
159 File svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_TEST);
160 CompilationTestUtils.assertFilesCount(svcParent, 1);
162 // Test if sources are compilable
163 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
165 final ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
166 final Class<?> rootClass = Class.forName(CompilationTestUtils.BASE_PKG
167 + ".urn.opendaylight.test.rev131008.RootContainer", true, loader);
169 // Test generated 'container root'
170 assertTrue(rootClass.isInterface());
171 assertEquals(3, abstractMethods(rootClass).size());
173 // Test generated getter and not-generated nonnull method for presence container
174 CompilationTestUtils.assertContainsMethod(rootClass,
175 "org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.rootcontainer.PresenceContainer",
176 "getPresenceContainer", loader);
177 final var error = assertThrows(AssertionError.class, () ->
178 CompilationTestUtils.assertContainsMethod(rootClass,
179 "org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.rootcontainer.PresenceContainer",
180 "nonnullPresenceContainer", loader));
181 assertTrue(error.getCause() instanceof NoSuchMethodException);
183 // Test generated getter and nonnull methods for non-presence container
184 CompilationTestUtils.assertContainsMethod(rootClass,
185 "org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.rootcontainer.NonPresenceContainer",
186 "getNonPresenceContainer", loader);
187 CompilationTestUtils.assertContainsMethod(rootClass,
188 "org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.rootcontainer.NonPresenceContainer",
189 "nonnullNonPresenceContainer", loader);
191 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
195 public void testAugmentUnderUsesGeneration() throws Exception {
196 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("augment-under-uses");
197 final File compiledOutputDir = CompilationTestUtils.compilerOutput("augment-under-uses");
198 generateTestSources("/compilation/augment-under-uses", sourcesOutputDir);
200 // Test if all sources were generated from 'module foo'
201 File parent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO);
202 assertTrue(new File(parent, "Object.java").exists());
203 assertTrue(new File(parent, "ClosedObject.java").exists());
204 assertTrue(new File(parent, "OpenObject.java").exists());
205 assertTrue(new File(parent, "ExplicitRouteObject.java").exists());
206 assertTrue(new File(parent, "PathKeySubobject.java").exists());
207 assertTrue(new File(parent, "FooData.java").exists());
208 CompilationTestUtils.assertFilesCount(parent, 10);
209 File svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_FOO);
210 CompilationTestUtils.assertFilesCount(svcParent, 1);
212 parent = new File(parent, "object");
213 assertTrue(new File(parent, "Nodes.java").exists());
214 assertTrue(new File(parent, "NodesBuilder.java").exists());
215 CompilationTestUtils.assertFilesCount(parent, 2);
217 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO + CompilationTestUtils.FS + "closed");
218 CompilationTestUtils.assertFilesCount(parent, 1);
220 parent = new File(parent, "object");
221 assertTrue(new File(parent, "Link1.java").exists());
222 assertTrue(new File(parent, "Link1Builder.java").exists());
223 CompilationTestUtils.assertFilesCount(parent, 2);
225 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO + CompilationTestUtils.FS + "open");
226 CompilationTestUtils.assertFilesCount(parent, 1);
228 parent = new File(parent, "object");
229 assertTrue(new File(parent, "Nodes1.java").exists());
230 assertTrue(new File(parent, "Nodes1Builder.java").exists());
231 CompilationTestUtils.assertFilesCount(parent, 3);
233 parent = new File(parent, "nodes");
234 assertTrue(new File(parent, "Links.java").exists());
235 assertTrue(new File(parent, "LinksBuilder.java").exists());
236 CompilationTestUtils.assertFilesCount(parent, 2);
238 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO + CompilationTestUtils.FS + "explicit");
239 CompilationTestUtils.assertFilesCount(parent, 1);
240 parent = new File(parent, "route");
241 CompilationTestUtils.assertFilesCount(parent, 1);
242 parent = new File(parent, "object");
243 assertTrue(new File(parent, "Subobjects.java").exists());
244 assertTrue(new File(parent, "SubobjectsBuilder.java").exists());
245 CompilationTestUtils.assertFilesCount(parent, 3);
247 parent = new File(parent, "subobjects");
248 CompilationTestUtils.assertFilesCount(parent, 1);
249 parent = new File(parent, "subobject");
250 CompilationTestUtils.assertFilesCount(parent, 1);
251 parent = new File(parent, "type");
252 assertTrue(new File(parent, "PathKey.java").exists());
253 assertTrue(new File(parent, "PathKeyBuilder.java").exists());
254 CompilationTestUtils.assertFilesCount(parent, 3);
256 parent = new File(parent, "path");
257 CompilationTestUtils.assertFilesCount(parent, 1);
258 parent = new File(parent, "key");
259 assertTrue(new File(parent, "PathKey.java").exists());
260 assertTrue(new File(parent, "PathKeyBuilder.java").exists());
261 CompilationTestUtils.assertFilesCount(parent, 2);
263 // Test if all sources were generated from 'module bar'
264 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_BAR);
265 assertTrue(new File(parent, "BarData.java").exists());
266 assertTrue(new File(parent, "BasicExplicitRouteSubobjects.java").exists());
267 assertTrue(new File(parent, "ExplicitRouteSubobjects.java").exists());
268 assertTrue(new File(parent, "RouteSubobjects.java").exists());
269 CompilationTestUtils.assertFilesCount(parent, 6);
270 svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_BAR);
271 CompilationTestUtils.assertFilesCount(svcParent, 1);
273 parent = new File(parent, "route");
274 CompilationTestUtils.assertFilesCount(parent, 1);
275 parent = new File(new File(sourcesOutputDir, CompilationTestUtils.NS_BAR), "basic");
276 CompilationTestUtils.assertFilesCount(parent, 1);
277 parent = new File(parent, "explicit");
278 CompilationTestUtils.assertFilesCount(parent, 1);
279 parent = new File(parent, "route");
280 CompilationTestUtils.assertFilesCount(parent, 1);
282 parent = new File(parent, "subobjects");
283 CompilationTestUtils.assertFilesCount(parent, 2);
284 assertTrue(new File(parent, "SubobjectType.java").exists());
286 parent = new File(parent, "subobject");
287 CompilationTestUtils.assertFilesCount(parent, 1);
289 parent = new File(parent, "type");
290 assertTrue(new File(parent, "IpPrefix.java").exists());
291 assertTrue(new File(parent, "IpPrefixBuilder.java").exists());
292 assertTrue(new File(parent, "Label.java").exists());
293 assertTrue(new File(parent, "LabelBuilder.java").exists());
294 CompilationTestUtils.assertFilesCount(parent, 4);
296 // Test if sources are compilable
297 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
299 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
303 public void testAugmentOfAugmentGeneration() throws Exception {
304 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("aug-of-aug");
305 final File compiledOutputDir = CompilationTestUtils.compilerOutput("aug-of-aug");
306 generateTestSources("/compilation/augment-of-augment", sourcesOutputDir);
308 // Test if all sources were generated from 'module foo'
309 File parent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO);
310 assertTrue(new File(parent, "FooData.java").exists());
311 assertTrue(new File(parent, "PathAttributes.java").exists());
312 assertTrue(new File(parent, "Update.java").exists());
313 assertTrue(new File(parent, "UpdateBuilder.java").exists());
314 CompilationTestUtils.assertFilesCount(parent, 6);
315 File svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_FOO);
316 CompilationTestUtils.assertFilesCount(svcParent, 1);
318 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO + CompilationTestUtils.FS + "path");
319 CompilationTestUtils.assertFilesCount(parent, 1);
320 parent = new File(parent, "attributes");
321 CompilationTestUtils.assertFilesCount(parent, 2);
322 final File origin = new File(parent, "Origin.java");
323 final File originBuilder = new File(parent, "OriginBuilder.java");
324 assertTrue(origin.exists());
325 assertTrue(originBuilder.exists());
327 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO + CompilationTestUtils.FS + "update");
328 CompilationTestUtils.assertFilesCount(parent, 2);
329 assertTrue(new File(parent, "PathAttributes.java").exists());
330 assertTrue(new File(parent, "PathAttributesBuilder.java").exists());
332 // Test if all sources were generated from 'module bar'
333 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_BAR);
334 assertTrue(new File(parent, "BarData.java").exists());
335 assertTrue(new File(parent, "Destination.java").exists());
336 assertTrue(new File(parent, "PathAttributes1.java").exists());
337 assertTrue(new File(parent, "PathAttributes1Builder.java").exists());
338 CompilationTestUtils.assertFilesCount(parent, 6);
339 svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_BAR);
340 CompilationTestUtils.assertFilesCount(svcParent, 1);
342 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_BAR + CompilationTestUtils.FS + "destination");
343 CompilationTestUtils.assertFilesCount(parent, 2);
344 final File destinationType = new File(parent, "DestinationType.java");
345 assertTrue(destinationType.exists());
347 parent = new File(parent, "destination");
348 CompilationTestUtils.assertFilesCount(parent, 1);
349 parent = new File(parent, "type");
350 CompilationTestUtils.assertFilesCount(parent, 2);
351 final File destinationIpv4 = new File(parent, "DestinationIp.java");
352 final File destinationIpv4Builder = new File(parent, "DestinationIpBuilder.java");
353 assertTrue(destinationIpv4.exists());
354 assertTrue(destinationIpv4Builder.exists());
356 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_BAR + CompilationTestUtils.FS + "update");
357 CompilationTestUtils.assertFilesCount(parent, 1);
358 parent = new File(parent, "path");
359 CompilationTestUtils.assertFilesCount(parent, 1);
360 parent = new File(parent, "attributes");
361 final File mpUnreachNlri = new File(parent, "MpUnreachNlri.java");
362 final File mpUnreachNlriBuilder = new File(parent, "MpUnreachNlriBuilder.java");
363 assertTrue(mpUnreachNlri.exists());
364 assertTrue(mpUnreachNlriBuilder.exists());
365 CompilationTestUtils.assertFilesCount(parent, 3);
367 parent = new File(parent, "mp");
368 CompilationTestUtils.assertFilesCount(parent, 1);
369 parent = new File(parent, "unreach");
370 CompilationTestUtils.assertFilesCount(parent, 1);
371 parent = new File(parent, "nlri");
372 assertTrue(new File(parent, "WithdrawnRoutes.java").exists());
373 assertTrue(new File(parent, "WithdrawnRoutesBuilder.java").exists());
374 CompilationTestUtils.assertFilesCount(parent, 2);
376 // Test if all sources were generated from 'module baz'
377 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_BAZ);
378 assertTrue(new File(parent, "BazData.java").exists());
379 assertTrue(new File(parent, "LinkstateDestination.java").exists());
380 CompilationTestUtils.assertFilesCount(parent, 3);
381 svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_BAZ);
382 CompilationTestUtils.assertFilesCount(svcParent, 1);
384 parent = new File(sourcesOutputDir, CompilationTestUtils.NS_BAZ + CompilationTestUtils.FS + "update");
385 CompilationTestUtils.assertFilesCount(parent, 1);
386 parent = new File(parent, "path");
387 CompilationTestUtils.assertFilesCount(parent, 1);
388 parent = new File(parent, "attributes");
389 CompilationTestUtils.assertFilesCount(parent, 1);
390 parent = new File(parent, "mp");
391 CompilationTestUtils.assertFilesCount(parent, 1);
392 parent = new File(parent, "unreach");
393 CompilationTestUtils.assertFilesCount(parent, 1);
394 parent = new File(parent, "nlri");
395 CompilationTestUtils.assertFilesCount(parent, 1);
396 parent = new File(parent, "withdrawn");
397 CompilationTestUtils.assertFilesCount(parent, 1);
398 parent = new File(parent, "routes");
399 CompilationTestUtils.assertFilesCount(parent, 1);
400 parent = new File(parent, "destination");
401 CompilationTestUtils.assertFilesCount(parent, 1);
402 parent = new File(parent, "type");
403 final File destinationLinkstate = new File(parent, "DestinationLinkstate.java");
404 final File destinationLinkstateBuilder = new File(parent, "DestinationLinkstateBuilder.java");
405 assertTrue(destinationLinkstate.exists());
406 assertTrue(destinationLinkstateBuilder.exists());
407 CompilationTestUtils.assertFilesCount(parent, 3);
408 parent = new File(parent, "destination");
409 CompilationTestUtils.assertFilesCount(parent, 1);
410 parent = new File(parent, "linkstate");
411 final File links = new File(parent, "Links.java");
412 final File linksBuilder = new File(parent, "LinksBuilder.java");
413 assertTrue(links.exists());
414 assertTrue(linksBuilder.exists());
415 CompilationTestUtils.assertFilesCount(parent, 3);
416 parent = new File(parent, "links");
417 final File source = new File(parent, "Source.java");
418 final File sourceBuilder = new File(parent, "SourceBuilder.java");
419 assertTrue(source.exists());
420 assertTrue(sourceBuilder.exists());
421 CompilationTestUtils.assertFilesCount(parent, 3);
422 parent = new File(parent, "source");
423 final File address = new File(parent, "Address.java");
424 final File addressBuilder = new File(parent, "AddressBuilder.java");
425 assertTrue(address.exists());
426 assertTrue(addressBuilder.exists());
427 CompilationTestUtils.assertFilesCount(parent, 2);
429 // Test if sources are compilable
430 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
432 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
436 public void testLeafReturnTypes() throws Exception {
437 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("leaf-return-types");
438 final File compiledOutputDir = CompilationTestUtils.compilerOutput("leaf-return-types");
439 generateTestSources("/compilation/leaf-return-types", sourcesOutputDir);
441 final File parent = new File(sourcesOutputDir, CompilationTestUtils.NS_TEST);
442 assertTrue(new File(parent, "TestData.java").exists());
443 assertTrue(new File(parent, "Nodes.java").exists());
444 assertTrue(new File(parent, "NodesBuilder.java").exists());
445 assertTrue(new File(parent, "Alg.java").exists());
446 CompilationTestUtils.assertFilesCount(parent, 4);
447 final File svcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_TEST);
448 CompilationTestUtils.assertFilesCount(svcParent, 1);
450 // Test if sources are compilable
451 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
453 final String pkg = CompilationTestUtils.BASE_PKG + ".urn.opendaylight.test.rev131008";
454 final ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
455 final Class<?> nodesClass = Class.forName(pkg + ".Nodes", true, loader);
456 final Class<?> builderClass = Class.forName(pkg + ".NodesBuilder", true, loader);
458 // Test methods return type
459 final byte[] b = new byte[] {};
460 CompilationTestUtils.assertContainsMethod(nodesClass, b.getClass(), "getIdBinary");
461 CompilationTestUtils.assertContainsMethod(nodesClass, pkg + ".Nodes$IdBits", "getIdBits", loader);
462 CompilationTestUtils.assertContainsMethod(nodesClass, Boolean.class, "getIdBoolean");
463 CompilationTestUtils.assertContainsMethod(nodesClass, Decimal64.class, "getIdDecimal64");
464 CompilationTestUtils.assertContainsMethod(nodesClass, Empty.class, "getIdEmpty");
465 CompilationTestUtils.assertContainsMethod(nodesClass, pkg + ".Nodes$IdEnumeration", "getIdEnumeration", loader);
466 testReturnTypeIdentityref(nodesClass, "getIdIdentityref", pkg + ".Alg");
467 testReturnTypeInstanceIdentitifer(loader, nodesClass, "getIdInstanceIdentifier");
468 CompilationTestUtils.assertContainsMethod(nodesClass, Byte.class, "getId8");
469 CompilationTestUtils.assertContainsMethod(nodesClass, Short.class, "getId16");
470 CompilationTestUtils.assertContainsMethod(nodesClass, Integer.class, "getId32");
471 CompilationTestUtils.assertContainsMethod(nodesClass, Long.class, "getId64");
472 CompilationTestUtils.assertContainsMethod(nodesClass, Long.class, "getIdLeafref");
473 CompilationTestUtils.assertContainsMethod(nodesClass, String.class, "getIdString");
474 CompilationTestUtils.assertContainsMethod(nodesClass, Uint8.class, "getIdU8");
475 CompilationTestUtils.assertContainsMethod(nodesClass, Uint16.class, "getIdU16");
476 CompilationTestUtils.assertContainsMethod(nodesClass, Uint32.class, "getIdU32");
477 CompilationTestUtils.assertContainsMethod(nodesClass, Uint64.class, "getIdU64");
478 CompilationTestUtils.assertContainsMethod(nodesClass, pkg + ".Nodes$IdUnion", "getIdUnion", loader);
480 final Object builderObj = builderClass.getDeclaredConstructor().newInstance();
482 Method method = CompilationTestUtils.assertContainsMethod(builderClass, builderClass, "setIdBinary",
484 final List<Range<Integer>> lengthConstraints = new ArrayList<>();
485 lengthConstraints.add(Range.closed(1, 10));
486 byte[] arg = new byte[] {};
487 String expectedMsg = String.format("Invalid length: %s, expected: %s.", HexFormat.of().formatHex(arg),
489 CompilationTestUtils.assertContainsRestrictionCheck(builderObj, method, expectedMsg, arg);
491 method = CompilationTestUtils.assertContainsMethod(builderClass, builderClass, "setIdDecimal64",
493 final List<Range<Decimal64>> rangeConstraints = new ArrayList<>();
494 rangeConstraints.add(Range.closed(Decimal64.valueOf("1.5"), Decimal64.valueOf("5.5")));
495 Object arg1 = Decimal64.valueOf("1.4");
496 expectedMsg = String.format("Invalid range: %s, expected: %s.", arg1, rangeConstraints);
497 CompilationTestUtils.assertContainsRestrictionCheck(builderObj, method, expectedMsg, arg1);
499 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
503 public void testGenerationContextReferenceExtension() throws IOException, URISyntaxException,
504 ClassNotFoundException {
505 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("context-reference");
506 final File compiledOutputDir = CompilationTestUtils.compilerOutput("context-reference");
507 generateTestSources("/compilation/context-reference", sourcesOutputDir);
509 // Test if all sources are generated
510 final File fooParent = new File(sourcesOutputDir, CompilationTestUtils.NS_FOO);
511 CompilationTestUtils.assertFilesCount(fooParent, 3);
512 final File fooSvcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_FOO);
513 CompilationTestUtils.assertFilesCount(fooSvcParent, 1);
514 assertTrue(new File(fooParent, "FooData.java").exists());
515 assertTrue(new File(fooParent, "Nodes.java").exists());
516 assertTrue(new File(fooParent, "NodesBuilder.java").exists());
518 final File barParent = new File(sourcesOutputDir, CompilationTestUtils.NS_BAR);
519 CompilationTestUtils.assertFilesCount(barParent, 2);
520 final File barSvcParent = new File(sourcesOutputDir, CompilationTestUtils.NS_SVC_BAR);
521 CompilationTestUtils.assertFilesCount(barSvcParent, 1);
522 assertTrue(new File(barParent, "BarData.java").exists());
523 assertTrue(new File(barParent, "IdentityClass.java").exists());
525 // Test if sources are compilable
526 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
528 final ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
529 final Class<?> nodesClass = Class.forName(CompilationTestUtils.BASE_PKG
530 + ".urn.opendaylight.foo.rev131008.Nodes", true, loader);
531 final Class<?> identityClass = Class
532 .forName(CompilationTestUtils.BASE_PKG + ".urn.opendaylight.bar.rev131008.IdentityClass", true, loader);
535 final Class<?> baseIdentity = Class.forName("org.opendaylight.yangtools.yang.binding.BaseIdentity", true,
537 assertEquals(ImmutableList.of(baseIdentity), Arrays.asList(identityClass.getInterfaces()));
542 getId = nodesClass.getMethod("getId");
543 } catch (final NoSuchMethodException e) {
544 throw new AssertionError("Method getId() not found", e);
547 assertEquals(ImmutableSet.of(RoutingContext.class), Arrays.stream(getId.getAnnotations())
548 .map(Annotation::annotationType).collect(Collectors.toSet()));
549 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
553 public void compilationTest() throws Exception {
554 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("yang");
555 final File compiledOutputDir = CompilationTestUtils.compilerOutput("yang");
556 generateTestSources("/yang", sourcesOutputDir);
558 // Test if sources are compilable
559 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
561 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
565 public void testBug586() throws Exception {
566 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("bug586");
567 final File compiledOutputDir = CompilationTestUtils.compilerOutput("bug586");
568 generateTestSources("/compilation/bug586", sourcesOutputDir);
570 // Test if sources are compilable
571 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
573 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
577 public void testBug4760() throws Exception {
578 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("bug4760");
579 final File compiledOutputDir = CompilationTestUtils.compilerOutput("bug4760");
580 generateTestSources("/compilation/bug4760", sourcesOutputDir);
582 // Test if sources are compilable
583 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
585 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
589 * Test handling nested uses-augmentations.
592 public void testBug1172() throws Exception {
593 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("bug1172");
594 final File compiledOutputDir = CompilationTestUtils.compilerOutput("bug1172");
595 generateTestSources("/compilation/bug1172", sourcesOutputDir);
597 // Test if sources are compilable
598 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
600 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
604 public void testBug5461() throws Exception {
605 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("bug5461");
606 final File compiledOutputDir = CompilationTestUtils.compilerOutput("bug5461");
607 generateTestSources("/compilation/bug5461", sourcesOutputDir);
609 // Test if sources are compilable
610 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
612 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
616 public void testBug5882() throws Exception {
617 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("bug5882");
618 final File compiledOutputDir = CompilationTestUtils.compilerOutput("bug5882");
619 generateTestSources("/compilation/bug5882", sourcesOutputDir);
621 // Test if sources are compilable
622 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
624 final File parent = new File(sourcesOutputDir, CompilationTestUtils.NS_BUG5882);
625 assertTrue(new File(parent, "FooData.java").exists());
626 assertTrue(new File(parent, "TypedefCurrent.java").exists());
627 assertTrue(new File(parent, "TypedefDeprecated.java").exists());
629 try (URLClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() })) {
630 final String pkg = CompilationTestUtils.BASE_PKG + ".urn.yang.foo.rev160102";
631 final Class<?> cls = loader.loadClass(pkg + ".FooData");
632 final Class<?> clsContainer = loader.loadClass(pkg + ".ContainerMain");
633 final Class<?> clsTypedefDepr = loader.loadClass(pkg + ".TypedefDeprecated");
634 final Class<?> clsTypedefCur = loader.loadClass(pkg + ".TypedefCurrent");
635 final Class<?> clsGroupingDepr = loader.loadClass(pkg + ".GroupingDeprecated");
636 final Class<?> clsGroupingCur = loader.loadClass(pkg + ".GroupingCurrent");
637 final Class<?> clsTypeDef1 = loader.loadClass(pkg + ".Typedef1");
638 final Class<?> clsTypeDef2 = loader.loadClass(pkg + ".Typedef2");
639 final Class<?> clsTypeDef3 = loader.loadClass(pkg + ".Typedef3");
640 assertEquals(1, clsTypedefDepr.getAnnotations().length);
641 assertThat(clsTypedefDepr.getAnnotations()[0].toString(), startsWith("@java.lang.Deprecated"));
642 assertEquals(0, clsTypedefCur.getAnnotations().length);
643 assertEquals(1, clsGroupingDepr.getAnnotations().length);
644 assertThat(clsGroupingDepr.getAnnotations()[0].toString(), startsWith("@java.lang.Deprecated"));
645 assertEquals(0, clsGroupingCur.getAnnotations().length);
646 assertEquals(0, clsTypeDef1.getAnnotations().length);
647 assertEquals(1, clsTypeDef2.getAnnotations().length);
648 assertThat(clsTypeDef2.getAnnotations()[0].toString(), startsWith("@java.lang.Deprecated"));
649 assertEquals(0, clsTypeDef3.getAnnotations().length);
651 /*methods inside container*/
652 assertTrue(clsContainer.getMethod("getContainerMainLeafDepr").isAnnotationPresent(Deprecated.class));
653 assertTrue(clsContainer.getMethod("getContainerMainListDepr").isAnnotationPresent(Deprecated.class));
654 assertTrue(clsContainer.getMethod("getContainerMainChoiceDepr").isAnnotationPresent(Deprecated.class));
655 assertFalse(clsContainer.getMethod("getContainerMainLeafCurrent").isAnnotationPresent(Deprecated.class));
656 assertFalse(clsContainer.getMethod("getContainerMainListCurrent").isAnnotationPresent(Deprecated.class));
657 assertFalse(clsContainer.getMethod("getContainerMainChoiceCur").isAnnotationPresent(Deprecated.class));
659 /*methods inside module*/
660 assertTrue(cls.getMethod("getContainerMainLeafDepr").isAnnotationPresent(Deprecated.class));
661 assertTrue(cls.getMethod("getContainerMainListDepr").isAnnotationPresent(Deprecated.class));
662 assertTrue(cls.getMethod("getContainerMainChoiceDepr").isAnnotationPresent(Deprecated.class));
663 assertFalse(cls.getMethod("getContainerMainLeafCurrent").isAnnotationPresent(Deprecated.class));
664 assertFalse(cls.getMethod("getContainerMainListCurrent").isAnnotationPresent(Deprecated.class));
665 assertFalse(cls.getMethod("getContainerMainChoiceCur").isAnnotationPresent(Deprecated.class));
666 assertTrue(cls.getMethod("getLeafDeprecated").isAnnotationPresent(Deprecated.class));
669 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
673 * Test if class generated for node from grouping implements ChildOf.
676 public void testBug1377() throws Exception {
677 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("bug1377");
678 final File compiledOutputDir = CompilationTestUtils.compilerOutput("bug1377");
680 generateTestSources("/compilation/bug1377", sourcesOutputDir);
682 // Test if sources are compilable
683 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
685 final ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
686 final Class<?> outputActionClass = Class.forName(CompilationTestUtils.BASE_PKG
687 + ".urn.test.foo.rev140717.action.action.output.action._case.OutputAction", true, loader);
688 final Class<?> actionClass = Class.forName(CompilationTestUtils.BASE_PKG + ".urn.test.foo.rev140717.Action",
691 // Test generated 'container output-action'
692 assertTrue(outputActionClass.isInterface());
693 CompilationTestUtils.assertImplementsParameterizedIfc(outputActionClass, ChildOf.class.toString(),
694 actionClass.getCanonicalName());
696 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
700 public void testMdsal327() throws Exception {
701 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal327");
702 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal327");
703 generateTestSources("/compilation/mdsal327", sourcesOutputDir);
704 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
705 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
709 public void testMdsal365() throws Exception {
710 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal365");
711 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal365");
712 generateTestSources("/compilation/mdsal365", sourcesOutputDir);
713 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
714 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
718 public void testMdsal395() throws Exception {
719 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal395");
720 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal395");
721 generateTestSources("/compilation/mdsal395", sourcesOutputDir);
722 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
723 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
727 public void classNamesColisionTest() throws Exception {
728 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("class-name-collision");
729 final File compiledOutputDir = CompilationTestUtils.compilerOutput("class-name-collision");
730 generateTestSources("/compilation/class-name-collision", sourcesOutputDir);
731 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
732 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
736 public void innerEnumerationNameCollisionTest() throws Exception {
737 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal321");
738 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal321");
739 generateTestSources("/compilation/mdsal321", sourcesOutputDir);
740 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
741 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
745 public void twoNestedUnionsTest() throws Exception {
746 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal320");
747 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal320");
748 generateTestSources("/compilation/mdsal320", sourcesOutputDir);
749 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
750 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
754 public void testMdsal425() throws Exception {
755 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal425");
756 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal425");
757 generateTestSources("/compilation/mdsal425", sourcesOutputDir);
758 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
759 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
763 public void testMdsal426() throws Exception {
764 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal426");
765 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal426");
766 generateTestSources("/compilation/mdsal426", sourcesOutputDir);
767 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
768 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
772 public void testMdsal529() throws Exception {
773 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal529");
774 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal529");
775 generateTestSources("/compilation/mdsal529", sourcesOutputDir);
776 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
777 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
781 public void testMdsal589() throws Exception {
782 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal589");
783 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal589");
784 generateTestSources("/compilation/mdsal589", sourcesOutputDir);
785 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
786 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
790 public void testMdsal533() throws Exception {
791 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal533");
792 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal533");
793 generateTestSources("/compilation/mdsal533", sourcesOutputDir);
794 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
795 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
799 public void testMdsal664() throws Exception {
800 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal664");
801 final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal664");
802 generateTestSources("/compilation/mdsal664", sourcesOutputDir);
803 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
804 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
808 public void testUnionStringPatterns() throws Exception {
809 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("union-string-pattern");
810 final File compiledOutputDir = CompilationTestUtils.compilerOutput("union-string-pattern");
811 generateTestSources("/compilation/union-string-pattern", sourcesOutputDir);
812 CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
814 final ClassLoader loader = new URLClassLoader(new URL[]{compiledOutputDir.toURI().toURL()});
815 final Class<?> fooClass = Class.forName(CompilationTestUtils.BASE_PKG + ".foo.norev.Foo", true, loader);
817 final Field patterns = fooClass.getDeclaredField(TypeConstants.PATTERN_CONSTANT_NAME);
818 assertEquals(List.class, patterns.getType());
820 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
824 public void yangDataCompilation() throws Exception {
825 final File sourcesOutputDir = CompilationTestUtils.generatorOutput("yang-data-gen");
826 final File compiledOutputDir = CompilationTestUtils.compilerOutput("yang-data-gen");
828 generateTestSources("/compilation/yang-data-gen", sourcesOutputDir);
830 final ClassLoader loader = new URLClassLoader(new URL[]{compiledOutputDir.toURI().toURL()});
831 final List<String> artifactNames = List.of(
832 // module with top level container
833 "YangDataDemoData", "RootContainer", "RootContainerBuilder",
835 // yang-data artifacts
836 "YangDataWithContainer", "YangDataWithContainerBuilder",
837 "YangDataWithList", "YangDataWithListBuilder",
838 "YangDataWithLeaf", "YangDataWithLeafBuilder",
839 "YangDataWithLeafList", "YangDataWithLeafListBuilder",
840 "YangDataWithAnydata", "YangDataWithAnydataBuilder",
841 "YangDataWithAnyxml", "YangDataWithAnyxmlBuilder",
843 // yang-data content artifacts
844 "yang.data.with.container.ContainerFromYangData",
845 "yang.data.with.container.ContainerFromYangDataBuilder",
846 "yang.data.with.list.ListFromYangData", "yang.data.with.list.ListFromYangDataBuilder",
847 "yang.data.with.anydata.AnydataFromYangData", "yang.data.with.anyxml.AnyxmlFromYangData",
849 // yang-data artifacts using groups
850 "YangDataWithContainerFromGroup", "YangDataWithContainerFromGroupBuilder",
851 "YangDataWithListFromGroup", "YangDataWithListFromGroupBuilder",
852 "YangDataWithLeafFromGroup", "YangDataWithLeafFromGroupBuilder",
853 "YangDataWithLeafListFromGroup", "YangDataWithLeafListFromGroupBuilder",
854 "YangDataWithAnydataFromGroup", "YangDataWithAnydataFromGroupBuilder",
855 "YangDataWithAnyxmlFromGroup", "YangDataWithAnyxmlFromGroupBuilder",
858 "GrpForContainer", "GrpForList", "GrpForLeaf", "GrpForLeafList", "GrpForAnydata", "GrpForAnyxml",
860 // group content artifacts
861 "grp._for.container.ContainerFromGroup", "grp._for.container.ContainerFromGroupBuilder",
862 "grp._for.list.ListFromGroup", "grp._for.list.ListFromGroupBuilder",
863 "grp._for.anydata.AnydataFromGroup", "grp._for.anyxml.AnyxmlFromGroup",
865 // artifacts for non-ascii template naming: yang data artifact, inner container + builder
866 "$ľaľaho$20$papľuhu", "$ľaľaho$20$papľuhuBuilder",
867 "$ľaľaho$20$papľuhu$.LatinNaming", "$ľaľaho$20$papľuhu$.LatinNamingBuilder",
868 "привет", "приветBuilder", "привет$.CyrillicNaming", "привет$.CyrillicNamingBuilder"
871 for (String name : artifactNames) {
872 final String className = CompilationTestUtils.BASE_PKG + ".urn.test.yang.data.demo.rev220222." + name;
873 // ensure class source is generated
874 final String srcPath = className.replace('.', File.separatorChar) + ".java";
875 assertTrue(srcPath + " exists", new File(sourcesOutputDir, srcPath).exists());
878 CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
881 private static void testReturnTypeIdentityref(final Class<?> clazz, final String methodName,
882 final String returnTypeStr) throws NoSuchMethodException {
883 Class<?> returnType = clazz.getMethod(methodName).getReturnType();
884 assertTrue(returnType.isInterface());
885 assertEquals(returnTypeStr, returnType.getName());
888 private static void testReturnTypeInstanceIdentitifer(final ClassLoader loader, final Class<?> clazz,
889 final String methodName) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
890 final Method method = clazz.getMethod(methodName);
891 final Class<?> rawReturnType = Class.forName("org.opendaylight.yangtools.yang.binding.InstanceIdentifier", true,
893 assertEquals(rawReturnType, method.getReturnType());
894 final Type returnType = method.getGenericReturnType();
895 assertTrue(returnType instanceof ParameterizedType);
896 final ParameterizedType pt = (ParameterizedType) returnType;
897 final Type[] parameters = pt.getActualTypeArguments();
898 assertEquals(1, parameters.length);
899 final Type parameter = parameters[0];
900 assertTrue(parameter instanceof WildcardType);
901 final WildcardType wildcardType = (WildcardType) parameter;
902 assertEquals("?", wildcardType.toString());