• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package libcore.java.lang.reflect;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNotSame;
23 import static org.junit.Assert.assertSame;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 
27 import dalvik.system.PathClassLoader;
28 
29 import libcore.io.Streams;
30 
31 import java.io.File;
32 import java.io.FileOutputStream;
33 import java.io.InputStream;
34 import java.lang.annotation.ElementType;
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 import java.lang.annotation.Target;
38 import java.lang.reflect.Constructor;
39 import java.lang.reflect.Executable;
40 import java.lang.reflect.MalformedParametersException;
41 import java.lang.reflect.Method;
42 import java.lang.reflect.Modifier;
43 import java.lang.reflect.Parameter;
44 import java.text.NumberFormat;
45 import java.util.Arrays;
46 import java.util.concurrent.Callable;
47 import java.util.function.Function;
48 
49 import org.junit.Before;
50 import org.junit.Ignore;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.junit.runners.JUnit4;
54 
55 
56 /**
57  * Tests for {@link Parameter}. For annotation-related tests see
58  * {@link libcore.java.lang.reflect.annotations.AnnotatedElementParameterTest} and
59  * {@link libcore.java.lang.reflect.annotations.ExecutableParameterTest}.
60  *
61  * <p>Tests suffixed with _withMetadata() require parameter metadata compiled in to work properly.
62  * These are handled by loading pre-compiled .dex files.
63  * See also {@link DependsOnParameterMetadata}.
64  */
65 @RunWith(JUnit4.class)
66 public class ParameterTest {
67 
68     /**
69      * A ClassLoader that can be used to load the
70      * libcore.java.lang.reflect.parameter.ParameterMetadataTestClasses class and its nested
71      * classes. The loaded classes have valid metadata that can be created by a valid Java compiler
72      * / Android dexer.
73      */
74     private ClassLoader classesWithMetadataClassLoader;
75 
76     /**
77      * A ClassLoader that can be used to load the
78      * libcore.java.lang.reflect.parameter.MetadataVariations class.
79      * The loaded class has invalid metadata that could not be created by a valid Java compiler /
80      * Android dexer.
81      */
82     private ClassLoader metadataVariationsClassLoader;
83 
84     @Before
setUp()85     public void setUp() throws Exception {
86         File tempDir = File.createTempFile("tempDir", "");
87         assertTrue(tempDir.delete());
88         assertTrue(tempDir.mkdirs());
89 
90         classesWithMetadataClassLoader =
91                 createClassLoaderForResource(tempDir, "parameter-metadata-test.jar");
92         String metadataVariationsResourcePath =
93                 "libcore/java/lang/reflect/parameter/metadata_variations.dex";
94         metadataVariationsClassLoader =
95                 createClassLoaderForResource(tempDir, metadataVariationsResourcePath);
96     }
97 
98     /**
99      * A source annotation used to mark code below with behavior that is highly dependent on
100      * parameter metadata. It is intended to bring readers here for the following:
101      *
102      * <p>Unless the compiler supports (and is configured to enable) storage of metadata
103      * for parameters, the runtime does not have access to the parameter name from the source and
104      * some modifier information like "implicit" (AKA "mandated"), "synthetic" and "final".
105      *
106      * <p>This test class is expected to be compiled <em>without</em> requesting that the metadata
107      * be compiled in. dex files that contains classes with metadata are loaded in setUp() and
108      * used from the tests suffixed with "_withMetadata".
109      */
110     @Retention(RetentionPolicy.SOURCE)
111     @Target(ElementType.METHOD)
112     private @interface DependsOnParameterMetadata {}
113 
114     private static class SingleParameter {
115         @SuppressWarnings("unused")
SingleParameter(String p0)116         SingleParameter(String p0) {}
117 
118         @SuppressWarnings("unused")
oneParameter(String p0)119         void oneParameter(String p0) {}
120     }
121 
122     @Test
testSingleParameterConstructor()123     public void testSingleParameterConstructor() throws Exception {
124         Constructor<?> constructor = SingleParameter.class.getDeclaredConstructor(String.class);
125         checkSingleStringParameter(constructor);
126     }
127 
128     @Test
testSingleParameterMethod()129     public void testSingleParameterMethod() throws Exception {
130         Method method = SingleParameter.class.getDeclaredMethod("oneParameter", String.class);
131         checkSingleStringParameter(method);
132     }
133 
checkSingleStringParameter(Executable executable)134     private static void checkSingleStringParameter(Executable executable) {
135         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
136         helper.checkStandardParametersBehavior()
137                 .checkParametersToString("[java.lang.String arg0]")
138                 .checkParametersMetadataNotAvailable()
139                 .checkParametersNoVarArgs();
140 
141         helper.getParameterTestHelper(0)
142                 .checkGetType(String.class)
143                 .checkGetParameterizedType("class java.lang.String");
144     }
145 
146     @Test
testSingleParameterConstructor_withMetadata()147     public void testSingleParameterConstructor_withMetadata() throws Exception {
148         Class<?> clazz = loadTestInnerClassWithMetadata("SingleParameter");
149         Constructor<?> constructor  = clazz.getDeclaredConstructor(String.class);
150         checkSingleStringParameter_withMetadata(constructor);
151     }
152 
153     @Test
testSingleParameterMethod_withMetadata()154     public void testSingleParameterMethod_withMetadata() throws Exception {
155         Class<?> clazz = loadTestInnerClassWithMetadata("SingleParameter");
156         Method method = clazz.getDeclaredMethod("oneParameter", String.class);
157         checkSingleStringParameter_withMetadata(method);
158     }
159 
checkSingleStringParameter_withMetadata(Executable executable)160     private static void checkSingleStringParameter_withMetadata(Executable executable) {
161         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
162         helper.checkStandardParametersBehavior()
163                 .checkParametersToString("[java.lang.String p0]")
164                 .checkParametersNoVarArgs();
165 
166         helper.getParameterTestHelper(0)
167                 .checkGetType(String.class)
168                 .checkName(true /* expectedNameIsPresent */, "p0")
169                 .checkModifiers(0)
170                 .checkImplicitAndSynthetic(false, false)
171                 .checkGetParameterizedType("class java.lang.String");
172     }
173 
174     private static class GenericParameter {
175         @SuppressWarnings("unused")
GenericParameter(Function<String, Integer> p0)176         GenericParameter(Function<String, Integer> p0) {}
177 
178         @SuppressWarnings("unused")
genericParameter(Function<String, Integer> p0)179         void genericParameter(Function<String, Integer> p0) {}
180     }
181 
182     @Test
testGenericParameterConstructor()183     public void testGenericParameterConstructor() throws Exception {
184         Constructor<?> constructor = GenericParameter.class.getDeclaredConstructor(Function.class);
185         checkGenericParameter(constructor);
186     }
187 
188     @Test
testGenericParameterMethod()189     public void testGenericParameterMethod() throws Exception {
190         Method method = GenericParameter.class.getDeclaredMethod(
191                 "genericParameter", Function.class);
192         checkGenericParameter(method);
193     }
194 
checkGenericParameter(Executable executable)195     private static void checkGenericParameter(Executable executable) {
196         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
197         helper.checkStandardParametersBehavior()
198                 .checkParametersToString(
199                         "[java.util.function.Function<java.lang.String, java.lang.Integer> arg0]")
200                 .checkParametersMetadataNotAvailable()
201                 .checkParametersNoVarArgs();
202 
203         helper.getParameterTestHelper(0)
204                 .checkGetType(Function.class)
205                 .checkGetParameterizedType(
206                         "java.util.function.Function<java.lang.String, java.lang.Integer>");
207     }
208 
209     @Test
testGenericParameterConstructor_withMetadata()210     public void testGenericParameterConstructor_withMetadata() throws Exception {
211         Class<?> clazz = loadTestInnerClassWithMetadata("GenericParameter");
212         Constructor<?> constructor = clazz.getDeclaredConstructor(Function.class);
213         checkGenericParameter_withMetadata(constructor);
214     }
215 
216     @Test
testGenericParameterMethod_withMetadata()217     public void testGenericParameterMethod_withMetadata() throws Exception {
218         Class<?> clazz = loadTestInnerClassWithMetadata("GenericParameter");
219         Method method = clazz.getDeclaredMethod("genericParameter", Function.class);
220         checkGenericParameter_withMetadata(method);
221     }
222 
checkGenericParameter_withMetadata(Executable executable)223     private static void checkGenericParameter_withMetadata(Executable executable) {
224         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
225         helper.checkStandardParametersBehavior()
226                 .checkParametersToString(
227                         "[java.util.function.Function<java.lang.String, java.lang.Integer> p0]")
228                 .checkParametersNoVarArgs();
229 
230         helper.getParameterTestHelper(0)
231                 .checkGetType(Function.class)
232                 .checkName(true /* expectedNameIsPresent */, "p0")
233                 .checkModifiers(0)
234                 .checkImplicitAndSynthetic(false, false)
235                 .checkGetParameterizedType(
236                         "java.util.function.Function<java.lang.String, java.lang.Integer>");
237     }
238 
239     private static class TwoParameters {
240         @SuppressWarnings("unused")
TwoParameters(String p0, Integer p1)241         TwoParameters(String p0, Integer p1) {}
242         @SuppressWarnings("unused")
twoParameters(String p0, Integer p1)243         void twoParameters(String p0, Integer p1) {}
244     }
245 
246     @Test
testTwoParameterConstructor()247     public void testTwoParameterConstructor() throws Exception {
248         Constructor<?> constructor =
249                 TwoParameters.class.getDeclaredConstructor(String.class, Integer.class);
250         checkTwoParameters(constructor);
251     }
252 
253     @Test
testTwoParameterMethod()254     public void testTwoParameterMethod() throws Exception {
255         Method method = TwoParameters.class.getDeclaredMethod(
256                 "twoParameters", String.class, Integer.class);
257         checkTwoParameters(method);
258     }
259 
checkTwoParameters(Executable executable)260     private static void checkTwoParameters(Executable executable) {
261         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
262         helper.checkStandardParametersBehavior()
263                 .checkParametersToString("[java.lang.String arg0, java.lang.Integer arg1]")
264                 .checkParametersMetadataNotAvailable()
265                 .checkParametersNoVarArgs();
266 
267         helper.getParameterTestHelper(0)
268                 .checkGetType(String.class)
269                 .checkGetParameterizedType("class java.lang.String");
270 
271         helper.getParameterTestHelper(1)
272                 .checkGetType(Integer.class)
273                 .checkGetParameterizedType("class java.lang.Integer");
274     }
275 
276     @Test
testTwoParameterConstructor_withMetadata()277     public void testTwoParameterConstructor_withMetadata() throws Exception {
278         Class<?> clazz = loadTestInnerClassWithMetadata("TwoParameters");
279         Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
280         checkTwoParameters_withMetadata(constructor);
281     }
282 
283     @Test
testTwoParameterMethod_withMetadata()284     public void testTwoParameterMethod_withMetadata() throws Exception {
285         Class<?> clazz = loadTestInnerClassWithMetadata("TwoParameters");
286         Method method = clazz.getDeclaredMethod("twoParameters", String.class, Integer.class);
287         checkTwoParameters_withMetadata(method);
288     }
289 
checkTwoParameters_withMetadata(Executable executable)290     private static void checkTwoParameters_withMetadata(Executable executable) {
291         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
292         helper.checkStandardParametersBehavior()
293                 .checkParametersToString("[java.lang.String p0, java.lang.Integer p1]")
294                 .checkParametersNoVarArgs();
295 
296         helper.getParameterTestHelper(0)
297                 .checkGetType(String.class)
298                 .checkName(true /* expectedNameIsPresent */, "p0")
299                 .checkModifiers(0)
300                 .checkImplicitAndSynthetic(false, false)
301                 .checkGetParameterizedType("class java.lang.String");
302 
303         helper.getParameterTestHelper(1)
304                 .checkGetType(Integer.class)
305                 .checkName(true /* expectedNameIsPresent */, "p1")
306                 .checkModifiers(0)
307                 .checkImplicitAndSynthetic(false, false)
308                 .checkGetParameterizedType("class java.lang.Integer");
309     }
310 
311     private static class FinalParameter {
312         @SuppressWarnings("unused")
FinalParameter(final String p0)313         FinalParameter(final String p0) {}
314         @SuppressWarnings("unused")
finalParameter(final String p0)315         void finalParameter(final String p0) {}
316     }
317 
318     @Test
testFinalParameterConstructor()319     public void testFinalParameterConstructor() throws Exception {
320         Constructor<?> constructor = FinalParameter.class.getDeclaredConstructor(String.class);
321         checkFinalParameter(constructor);
322     }
323 
324     @Test
testFinalParameterMethod()325     public void testFinalParameterMethod() throws Exception {
326         Method method = FinalParameter.class.getDeclaredMethod("finalParameter", String.class);
327         checkFinalParameter(method);
328     }
329 
checkFinalParameter(Executable executable)330     private static void checkFinalParameter(Executable executable) {
331         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
332         helper.checkStandardParametersBehavior()
333                 .checkParametersToString("[java.lang.String arg0]")
334                 .checkParametersMetadataNotAvailable()
335                 .checkParametersNoVarArgs();
336 
337         helper.getParameterTestHelper(0)
338                 .checkGetType(String.class)
339                 .checkGetParameterizedType("class java.lang.String");
340     }
341 
342     @Test
testFinalParameterConstructor_withMetdata()343     public void testFinalParameterConstructor_withMetdata() throws Exception {
344         Class<?> clazz = loadTestInnerClassWithMetadata("FinalParameter");
345         Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
346         checkFinalParameter_withMetadata(constructor);
347     }
348 
349     @Test
testFinalParameterMethod_withMetdata()350     public void testFinalParameterMethod_withMetdata() throws Exception {
351         Class<?> clazz = loadTestInnerClassWithMetadata("FinalParameter");
352         Method method = clazz.getDeclaredMethod("finalParameter", String.class);
353         checkFinalParameter_withMetadata(method);
354     }
355 
checkFinalParameter_withMetadata(Executable executable)356     private static void checkFinalParameter_withMetadata(Executable executable) {
357         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
358         helper.checkStandardParametersBehavior()
359                 .checkParametersToString("[final java.lang.String p0]")
360                 .checkParametersNoVarArgs();
361 
362         helper.getParameterTestHelper(0)
363                 .checkGetType(String.class)
364                 .checkName(true /* expectedNameIsPresent */, "p0")
365                 .checkModifiers(Modifier.FINAL)
366                 .checkImplicitAndSynthetic(false, false)
367                 .checkGetParameterizedType("class java.lang.String");
368     }
369 
370     /**
371      * An inner class, used for checking compiler-inserted parameters: The first parameter is an
372      * instance of the surrounding class.
373      */
374     private class InnerClass {
375         @SuppressWarnings("unused")
InnerClass()376         public InnerClass() {}
377         @SuppressWarnings("unused")
InnerClass(String p1)378         public InnerClass(String p1) {}
379         @SuppressWarnings("unused")
InnerClass(Function<String, Integer> p1)380         public InnerClass(Function<String, Integer> p1) {}
381     }
382 
383     @Test
testInnerClassSingleParameter()384     public void testInnerClassSingleParameter() throws Exception {
385         Class<?> outerClass = ParameterTest.class;
386         Class<?> innerClass = InnerClass.class;
387         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
388 
389         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
390         helper.checkStandardParametersBehavior()
391                 .checkParametersToString("[final " + outerClass.getName() + " arg0]")
392                 .checkParametersNoVarArgs();
393 
394         helper.getParameterTestHelper(0)
395                 .checkGetType(outerClass)
396                 .checkName(false, "arg0")
397                 .checkModifiers(4112) // 4112 == Modifier.SYNTHETIC & Modifier.FINAL
398                 .checkImplicitAndSynthetic(false, true)
399                 .checkGetParameterizedType("class " + outerClass.getName() + "");
400     }
401 
402     @Test
testInnerClassSingleParameter_withMetadata()403     public void testInnerClassSingleParameter_withMetadata() throws Exception {
404         Class<?> outerClass = loadTestOuterClassWithMetadata();
405         Class<?> innerClass = loadTestInnerClassWithMetadata("InnerClass");
406         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
407 
408         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
409         helper.checkStandardParametersBehavior()
410                 .checkParametersToString("[final " + outerClass.getName() + " this$0]")
411                 .checkParametersNoVarArgs();
412 
413         helper.getParameterTestHelper(0)
414                 .checkGetType(outerClass)
415                 .checkName(true /* expectedNameIsPresent */, "this$0")
416                 .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
417                 .checkImplicitAndSynthetic(true, false)
418                 .checkGetParameterizedType("class " + outerClass.getName());
419     }
420 
421     @Test
testInnerClassTwoParameters()422     public void testInnerClassTwoParameters() throws Exception {
423         Class<?> outerClass = ParameterTest.class;
424         Class<?> innerClass = InnerClass.class;
425         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, String.class);
426 
427         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
428         helper.checkStandardParametersBehavior()
429                 .checkParametersToString(
430                         "[final " + outerClass.getName() + " arg0, java.lang.String arg1]")
431                 .checkParametersNoVarArgs();
432 
433         helper.getParameterTestHelper(0)
434                 .checkName(false, "arg0")
435                 .checkModifiers(4112) // 4112 == Modifier.SYNTHETIC & Modifier.FINAL
436                 .checkImplicitAndSynthetic(false, true)
437                 .checkGetType(outerClass)
438                 .checkGetParameterizedType("class " + outerClass.getName());
439 
440         helper.getParameterTestHelper(1)
441                 .checkName(false, "arg1")
442                 .checkModifiers(0)
443                 .checkImplicitAndSynthetic(false, false)
444                 .checkGetType(String.class)
445                 .checkGetParameterizedType("class java.lang.String");
446     }
447 
448     @Test
testInnerClassTwoParameters_withMetadata()449     public void testInnerClassTwoParameters_withMetadata() throws Exception {
450         Class<?> outerClass = loadTestOuterClassWithMetadata();
451         Class<?> innerClass = loadTestInnerClassWithMetadata("InnerClass");
452         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, String.class);
453 
454         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
455         helper.checkStandardParametersBehavior()
456                 .checkParametersToString(
457                         "[final " + outerClass.getName() + " this$0, java.lang.String p1]")
458                 .checkParametersNoVarArgs();
459 
460         helper.getParameterTestHelper(0)
461                 .checkName(true /* expectedNameIsPresent */, "this$0")
462                 .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
463                 .checkImplicitAndSynthetic(true, false)
464                 .checkGetType(outerClass)
465                 .checkGetParameterizedType("class " + outerClass.getName() + "");
466 
467         helper.getParameterTestHelper(1)
468                 .checkName(true /* expectedNameIsPresent */, "p1")
469                 .checkModifiers(0)
470                 .checkImplicitAndSynthetic(false, false)
471                 .checkGetType(String.class)
472                 .checkGetParameterizedType("class java.lang.String");
473     }
474 
475     @Test
testInnerClassGenericParameter()476     public void testInnerClassGenericParameter() throws Exception {
477         Class<?> outerClass = ParameterTest.class;
478         Class<?> innerClass = InnerClass.class;
479         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, Function.class);
480 
481         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
482         helper.checkStandardParametersBehavior()
483                 .checkParametersToString(
484                         "[final " + outerClass.getName() + " arg0, " +
485                         "java.util.function.Function<java.lang.String, java.lang.Integer> arg1]")
486                 .checkParametersNoVarArgs();
487 
488         helper.getParameterTestHelper(0)
489                 .checkName(false, "arg0")
490                 .checkModifiers(4112) // 4112 == Modifier.SYNTHETIC & Modifier.FINAL
491                 .checkImplicitAndSynthetic(false, true)
492                 .checkGetType(outerClass)
493                 .checkGetParameterizedType("class " + outerClass.getName() + "");
494 
495         helper.getParameterTestHelper(1)
496                 .checkName(false, "arg1")
497                 .checkModifiers(0)
498                 .checkImplicitAndSynthetic(false, false)
499                 .checkGetType(Function.class)
500                 .checkGetParameterizedType("java.util.function.Function<java.lang.String, java.lang.Integer>");
501 
502         // The non-genericised string above is probably the result of a spec bug due to a mismatch
503         // between the generic signature for the constructor (which suggests a single parameter)
504         // and the actual parameters (which suggests two). In the absence of parameter metadata
505         // to identify the synthetic parameter the code reverts to using non-Signature (type erased)
506         // information.
507     }
508 
509     @Test
testInnerClassGenericParameter_withMetadata()510     public void testInnerClassGenericParameter_withMetadata() throws Exception {
511         Class<?> outerClass = loadTestOuterClassWithMetadata();
512         Class<?> innerClass = loadTestInnerClassWithMetadata("InnerClass");
513         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, Function.class);
514 
515         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
516         helper.checkStandardParametersBehavior()
517                 .checkParametersToString("[final " + outerClass.getName() + " this$0, "
518                         + "java.util.function.Function<java.lang.String, java.lang.Integer> p1]")
519                 .checkParametersNoVarArgs();
520 
521         helper.getParameterTestHelper(0)
522                 .checkName(true /* expectedNameIsPresent */, "this$0")
523                 .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
524                 .checkImplicitAndSynthetic(true, false)
525                 .checkGetType(outerClass)
526                 .checkGetParameterizedType("class " + outerClass.getName() + "");
527 
528         helper.getParameterTestHelper(1)
529                 .checkName(true /* expectedNameIsPresent */, "p1")
530                 .checkModifiers(0)
531                 .checkImplicitAndSynthetic(false, false)
532                 .checkGetType(Function.class)
533                 .checkGetParameterizedType(
534                         "java.util.function.Function<java.lang.String, java.lang.Integer>");
535     }
536 
537     @SuppressWarnings("unused")
538     enum TestEnum { ONE, TWO }
539 
540     /**
541      * Enums are a documented example of a type of class with synthetic constructor parameters and
542      * generated methods. This test may be brittle as it may rely on the compiler's implementation
543      * of enums.
544      */
545     @Test
testEnumConstructor()546     public void testEnumConstructor() throws Exception {
547         Constructor<?> constructor = TestEnum.class.getDeclaredConstructor(String.class, int.class);
548 
549         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
550         helper.checkStandardParametersBehavior()
551                 .checkParametersToString("[ java.lang.String arg0,  int arg1]")
552                 .checkParametersNoVarArgs();
553 
554         helper.getParameterTestHelper(0)
555                 .checkGetType(String.class)
556                 .checkGetParameterizedType("class java.lang.String");
557 
558         helper.getParameterTestHelper(1)
559                 .checkGetType(int.class)
560                 .checkGetParameterizedType("int");
561     }
562 
563     @Test
testEnumConstructor_withMetadata()564     public void testEnumConstructor_withMetadata() throws Exception {
565         Class<?> clazz = loadTestInnerClassWithMetadata("TestEnum");
566         Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
567 
568         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
569         helper.checkStandardParametersBehavior()
570                 // The extra spaces below are the result of a trivial upstream bug in
571                 // Parameter.toString() due to Modifier.toString(int) outputting nothing for
572                 // "SYNTHETIC".
573                 .checkParametersToString("[ java.lang.String $enum$name,  int $enum$ordinal]")
574                 .checkParametersNoVarArgs();
575 
576         helper.getParameterTestHelper(0)
577                 .checkName(true /* expectedNameIsPresent */, "$enum$name")
578                 .checkModifiers(4096) // 4096 == Modifier.SYNTHETIC
579                 .checkImplicitAndSynthetic(false, true)
580                 .checkGetType(String.class)
581                 .checkGetParameterizedType("class java.lang.String");
582 
583         helper.getParameterTestHelper(1)
584                 .checkName(true /* expectedNameIsPresent */, "$enum$ordinal")
585                 .checkModifiers(4096) // 4096 == Modifier.SYNTHETIC
586                 .checkImplicitAndSynthetic(false, true)
587                 .checkGetType(int.class)
588                 .checkGetParameterizedType("int");
589     }
590 
591     @Test
testEnumValueOf()592     public void testEnumValueOf() throws Exception {
593         Method method = TestEnum.class.getDeclaredMethod("valueOf", String.class);
594 
595         ExecutableTestHelper helper = new ExecutableTestHelper(method);
596         helper.checkStandardParametersBehavior()
597                 .checkParametersToString("[ java.lang.String arg0]")
598                 .checkParametersNoVarArgs();
599 
600         helper.getParameterTestHelper(0)
601                 .checkName(false, "arg0")
602                 .checkModifiers(32768) // 32768 == Modifier.MANDATED
603                 .checkImplicitAndSynthetic(true, false)
604                 .checkGetType(String.class)
605                 .checkGetParameterizedType("class java.lang.String");
606     }
607 
608     @Test
testEnumValueOf_withMetadata()609     public void testEnumValueOf_withMetadata() throws Exception {
610         Class<?> clazz = loadTestInnerClassWithMetadata("TestEnum");
611         Method method = clazz.getDeclaredMethod("valueOf", String.class);
612 
613         ExecutableTestHelper helper = new ExecutableTestHelper(method);
614         helper.checkStandardParametersBehavior()
615                 // The extra space below are the result of a trivial upstream bug in
616                 // Parameter.toString() due to Modifier.toString(int) outputting nothing for
617                 // "MANDATED".
618                 .checkParametersToString("[ java.lang.String name]")
619                 .checkParametersNoVarArgs();
620 
621         helper.getParameterTestHelper(0)
622                 .checkName(true /* expectedNameIsPresent */, "name")
623                 .checkModifiers(32768) // 32768 == Modifier.MANDATED
624                 .checkImplicitAndSynthetic(true, false)
625                 .checkGetType(String.class)
626                 .checkGetParameterizedType("class java.lang.String");
627     }
628 
629     private static class SingleVarArgs {
630         @SuppressWarnings("unused")
SingleVarArgs(String... p0)631         SingleVarArgs(String... p0) {}
632 
633         @SuppressWarnings("unused")
varArgs(String... p0)634         void varArgs(String... p0) {}
635     }
636 
637     @Test
testSingleVarArgsConstructor()638     public void testSingleVarArgsConstructor() throws Exception {
639         Constructor<?> constructor = SingleVarArgs.class.getDeclaredConstructor(String[].class);
640         checkSingleVarArgsParameter(constructor);
641     }
642 
643     @Test
testSingleVarArgsMethod()644     public void testSingleVarArgsMethod() throws Exception {
645         Method method = SingleVarArgs.class.getDeclaredMethod("varArgs", String[].class);
646         checkSingleVarArgsParameter(method);
647     }
648 
checkSingleVarArgsParameter(Executable executable)649     private static void checkSingleVarArgsParameter(Executable executable) {
650         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
651         helper.checkStandardParametersBehavior()
652                 .checkParametersToString("[java.lang.String... arg0]")
653                 .checkParametersMetadataNotAvailable();
654 
655         helper.getParameterTestHelper(0)
656                 .checkGetType(String[].class)
657                 .checkIsVarArg(true)
658                 .checkGetParameterizedType("class [Ljava.lang.String;");
659     }
660 
661     @Test
testSingleVarArgsConstructor_withMetadata()662     public void testSingleVarArgsConstructor_withMetadata() throws Exception {
663         Class<?> clazz = loadTestInnerClassWithMetadata("SingleVarArgs");
664         Constructor<?> constructor = clazz.getDeclaredConstructor(String[].class);
665         checkSingleVarArgsParameter_withMetadata(constructor);
666     }
667 
668     @Test
testSingleVarArgsMethod_withMetadata()669     public void testSingleVarArgsMethod_withMetadata() throws Exception {
670         Class<?> clazz = loadTestInnerClassWithMetadata("SingleVarArgs");
671         Method method = clazz.getDeclaredMethod("varArgs", String[].class);
672         checkSingleVarArgsParameter_withMetadata(method);
673     }
674 
checkSingleVarArgsParameter_withMetadata(Executable executable)675     private static void checkSingleVarArgsParameter_withMetadata(Executable executable) {
676         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
677         helper.checkStandardParametersBehavior()
678                 .checkParametersToString("[java.lang.String... p0]");
679 
680         helper.getParameterTestHelper(0)
681                 .checkName(true /* expectedNameIsPresent */, "p0")
682                 .checkModifiers(0)
683                 .checkImplicitAndSynthetic(false, false)
684                 .checkGetType(String[].class)
685                 .checkIsVarArg(true)
686                 .checkGetParameterizedType("class [Ljava.lang.String;");
687     }
688 
689     private static class MixedVarArgs {
690         @SuppressWarnings("unused")
MixedVarArgs(Integer[] p0, String... p1)691         MixedVarArgs(Integer[] p0, String... p1) {}
692         @SuppressWarnings("unused")
both(Integer[] p0, String... p1)693         void both(Integer[] p0, String... p1) {}
694     }
695 
696     @Test
testMixedVarArgsConstructor()697     public void testMixedVarArgsConstructor() throws Exception {
698         Constructor<?> constructor =
699                 MixedVarArgs.class.getDeclaredConstructor(Integer[].class, String[].class);
700         checkMixedVarArgsParameter(constructor);
701     }
702 
703     @Test
testMixedVarArgsMethod()704     public void testMixedVarArgsMethod() throws Exception {
705         Method method = MixedVarArgs.class.getDeclaredMethod("both", Integer[].class, String[].class);
706         checkMixedVarArgsParameter(method);
707     }
708 
checkMixedVarArgsParameter(Executable executable)709     private static void checkMixedVarArgsParameter(Executable executable) {
710         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
711         helper.checkStandardParametersBehavior()
712                 .checkParametersToString("[java.lang.Integer[] arg0, java.lang.String... arg1]")
713                 .checkParametersMetadataNotAvailable();
714 
715         helper.getParameterTestHelper(0)
716                 .checkGetType(Integer[].class)
717                 .checkIsVarArg(false)
718                 .checkGetParameterizedType("class [Ljava.lang.Integer;");
719 
720         helper.getParameterTestHelper(1)
721                 .checkGetType(String[].class)
722                 .checkIsVarArg(true)
723                 .checkGetParameterizedType("class [Ljava.lang.String;");
724     }
725 
726     private static class NonVarArgs {
727         @SuppressWarnings("unused")
NonVarArgs(Integer[] p0)728         NonVarArgs(Integer[] p0) {}
729         @SuppressWarnings("unused")
notVarArgs(Integer[] p0)730         void notVarArgs(Integer[] p0) {}
731     }
732 
733     @Test
testNonVarsArgsConstructor()734     public void testNonVarsArgsConstructor() throws Exception {
735         Constructor<?> constructor = NonVarArgs.class.getDeclaredConstructor(Integer[].class);
736         checkNonVarsArgsParameter(constructor);
737     }
738 
739     @Test
testNonVarsArgsMethod()740     public void testNonVarsArgsMethod() throws Exception {
741         Method method = NonVarArgs.class.getDeclaredMethod("notVarArgs", Integer[].class);
742         checkNonVarsArgsParameter(method);
743     }
744 
checkNonVarsArgsParameter(Executable executable)745     private static void checkNonVarsArgsParameter(Executable executable) {
746         ExecutableTestHelper helper = new ExecutableTestHelper(executable);
747         helper.checkStandardParametersBehavior()
748                 .checkParametersToString("[java.lang.Integer[] arg0]")
749                 .checkParametersMetadataNotAvailable();
750 
751         helper.getParameterTestHelper(0)
752                 .checkGetType(Integer[].class)
753                 .checkIsVarArg(false)
754                 .checkGetParameterizedType("class [Ljava.lang.Integer;");
755     }
756 
757     @Test
testAnonymousClassConstructor()758     public void testAnonymousClassConstructor() throws Exception {
759         Class<?> outerClass = ParameterTest.class;
760         Class<?> innerClass = getAnonymousClassWith1ParameterConstructor();
761         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
762 
763         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
764         helper.checkStandardParametersBehavior()
765                 .checkParametersToString("[final " + outerClass.getName() + " arg0]")
766                 .checkParametersNoVarArgs();
767 
768         helper.getParameterTestHelper(0)
769                 .checkName(false, "arg0")
770                 .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
771                 .checkImplicitAndSynthetic(true, false)
772                 .checkGetType(outerClass)
773                 .checkGetParameterizedType("class " + outerClass.getName() + "");
774     }
775 
getAnonymousClassWith1ParameterConstructor()776     private Class<?> getAnonymousClassWith1ParameterConstructor() {
777         // Deliberately not implemented with a lambda. Do not refactor.
778         Callable<String> anonymousClassObject = new Callable<String>() {
779             @Override
780             public String call() throws Exception {
781                 return ParameterTest.this.outerClassMethod();
782             }
783         };
784         return anonymousClassObject.getClass();
785     }
786 
787     @Test
testAnonymousClassConstructor_withMetadata()788     public void testAnonymousClassConstructor_withMetadata() throws Exception {
789         Class<?> outerClass = loadTestOuterClassWithMetadata();
790         Object outer = outerClass.newInstance();
791         Class<?> innerClass = (Class<?>) outerClass.getDeclaredMethod(
792                 "getAnonymousClassWith1ParameterConstructor").invoke(outer);
793         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
794 
795         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
796         helper.checkStandardParametersBehavior()
797                 .checkParametersToString("[final " + outerClass.getName() + " this$0]")
798                 .checkParametersNoVarArgs();
799 
800         helper.getParameterTestHelper(0)
801                 .checkName(true /* expectedNameIsPresent */, "this$0")
802                 .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
803                 .checkImplicitAndSynthetic(true, false)
804                 .checkGetType(outerClass)
805                 .checkGetParameterizedType("class " + outerClass.getName() + "");
806     }
807 
808     @Test
testMethodClassConstructor()809     public void testMethodClassConstructor() throws Exception {
810         Class<?> outerClass = ParameterTest.class;
811         Class<?> innerClass = getMethodClassWith1ImplicitParameterConstructor();
812         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
813 
814         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
815         helper.checkStandardParametersBehavior()
816                 .checkParametersToString("[final " + outerClass.getName() + " arg0]")
817                 .checkParametersNoVarArgs();
818 
819         helper.getParameterTestHelper(0)
820                 .checkName(false, "arg0")
821                 .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
822                 .checkImplicitAndSynthetic(true, false)
823                 .checkGetType(outerClass)
824                 .checkGetParameterizedType("class " + outerClass.getName() + "");
825     }
826 
getMethodClassWith1ImplicitParameterConstructor()827     private Class<?> getMethodClassWith1ImplicitParameterConstructor() {
828         class MethodClass {
829             MethodClass() {
830                 ParameterTest.this.outerClassMethod();
831             }
832         }
833         return MethodClass.class;
834     }
835 
836     @Test
testMethodClassConstructor_withMetadata()837     public void testMethodClassConstructor_withMetadata() throws Exception {
838         Class<?> outerClass = loadTestOuterClassWithMetadata();
839         Object outer = outerClass.newInstance();
840         Class<?> innerClass = (Class<?>) outerClass.getDeclaredMethod(
841                 "getMethodClassWith1ImplicitParameterConstructor").invoke(outer);
842         Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
843 
844         ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
845         helper.checkStandardParametersBehavior()
846                 .checkParametersToString("[final " + outerClass.getName() + " this$0]")
847                 .checkParametersNoVarArgs();
848 
849         helper.getParameterTestHelper(0)
850                 .checkName(true /* expectedNameIsPresent */, "this$0")
851                 .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
852                 .checkImplicitAndSynthetic(true, false)
853                 .checkGetType(outerClass)
854                 .checkGetParameterizedType("class " + outerClass.getName() + "");
855     }
856 
857     private static class NonIdenticalParameters {
858         @SuppressWarnings("unused")
method0(String p0)859         void method0(String p0) {}
860         @SuppressWarnings("unused")
method1(String p0)861         void method1(String p0) {}
862     }
863 
864     @Test
testEquals_checksExecutable()865     public void testEquals_checksExecutable() throws Exception {
866         Method method0 = NonIdenticalParameters.class.getDeclaredMethod("method0", String.class);
867         Method method1 = NonIdenticalParameters.class.getDeclaredMethod("method1", String.class);
868         Parameter method0P0 = method0.getParameters()[0];
869         Parameter method1P0 = method1.getParameters()[0];
870         assertFalse(method0P0.equals(method1P0));
871         assertFalse(method1P0.equals(method0P0));
872         assertTrue(method0P0.equals(method0P0));
873     }
874 
875     @Test
testManyParameters_withMetadata()876     public void testManyParameters_withMetadata() throws Exception {
877         int expectedParameterCount = 300;
878         Class<?>[] parameterTypes = new Class[expectedParameterCount];
879         Arrays.fill(parameterTypes, int.class);
880         Method method = getMetadataVariationsMethod("manyParameters", parameterTypes);
881         Parameter[] parameters = method.getParameters();
882         assertEquals(expectedParameterCount, parameters.length);
883 
884         NumberFormat format = NumberFormat.getIntegerInstance();
885         format.setMinimumIntegerDigits(3);
886         for (int i = 0; i < parameters.length; i++) {
887             assertEquals(true, parameters[i].isNamePresent());
888             assertEquals(Modifier.FINAL, parameters[i].getModifiers());
889             assertEquals("a" + format.format(i), parameters[i].getName());
890         }
891     }
892 
893     @Test
testEmptyMethodParametersAnnotation_withMetadata()894     public void testEmptyMethodParametersAnnotation_withMetadata() throws Exception {
895         Method method = getMetadataVariationsMethod("emptyMethodParametersAnnotation");
896         assertEquals(0, method.getParameters().length);
897     }
898 
899     @Test
testTooManyAccessFlags_withMetadata()900     public void testTooManyAccessFlags_withMetadata() throws Exception {
901         Method method = getMetadataVariationsMethod("tooManyAccessFlags", String.class);
902         checkGetParametersThrowsMalformedParametersException(method);
903     }
904 
905     @Test
testTooFewAccessFlags_withMetadata()906     public void testTooFewAccessFlags_withMetadata() throws Exception {
907         Method method = getMetadataVariationsMethod(
908                 "tooFewAccessFlags", String.class, String.class);
909         checkGetParametersThrowsMalformedParametersException(method);
910     }
911 
912     @Test
testTooManyNames_withMetadata()913     public void testTooManyNames_withMetadata() throws Exception {
914         Method method = getMetadataVariationsMethod("tooManyNames", String.class);
915         checkGetParametersThrowsMalformedParametersException(method);
916     }
917 
918     @Test
testTooFewNames_withMetadata()919     public void testTooFewNames_withMetadata() throws Exception {
920         Method method = getMetadataVariationsMethod("tooFewNames", String.class, String.class);
921         checkGetParametersThrowsMalformedParametersException(method);
922     }
923 
924     @Test
testTooManyBoth_withMetadata()925     public void testTooManyBoth_withMetadata() throws Exception {
926         Method method = getMetadataVariationsMethod("tooManyBoth", String.class);
927         checkGetParametersThrowsMalformedParametersException(method);
928     }
929 
930     @Test
testTooFewBoth_withMetadata()931     public void testTooFewBoth_withMetadata() throws Exception {
932         Method method = getMetadataVariationsMethod("tooFewBoth", String.class, String.class);
933         checkGetParametersThrowsMalformedParametersException(method);
934     }
935 
936     @Test
testNullName_withMetadata()937     public void testNullName_withMetadata() throws Exception {
938         Method method = getMetadataVariationsMethod("nullName", String.class);
939         Parameter parameter0 = method.getParameters()[0];
940         assertEquals("arg0", parameter0.getName());
941         assertEquals(Modifier.FINAL, parameter0.getModifiers());
942     }
943 
944     @Test
testEmptyName_withMetadata()945     public void testEmptyName_withMetadata() throws Exception {
946         Method method = getMetadataVariationsMethod("emptyName", String.class);
947         checkGetParametersThrowsMalformedParametersException(method);
948     }
949 
950     @Test
testNameWithSemicolon_withMetadata()951     public void testNameWithSemicolon_withMetadata() throws Exception {
952         Method method = getMetadataVariationsMethod("nameWithSemicolon", String.class);
953         checkGetParametersThrowsMalformedParametersException(method);
954     }
955 
956     @Test
testNameWithSlash_withMetadata()957     public void testNameWithSlash_withMetadata() throws Exception {
958         Method method = getMetadataVariationsMethod("nameWithSlash", String.class);
959         checkGetParametersThrowsMalformedParametersException(method);
960     }
961 
962     @Test
testNameWithPeriod_withMetadata()963     public void testNameWithPeriod_withMetadata() throws Exception {
964         Method method = getMetadataVariationsMethod("nameWithPeriod", String.class);
965         checkGetParametersThrowsMalformedParametersException(method);
966     }
967 
968     @Test
testNameWithOpenSquareBracket_withMetadata()969     public void testNameWithOpenSquareBracket_withMetadata() throws Exception {
970         Method method = getMetadataVariationsMethod("nameWithOpenSquareBracket", String.class);
971         checkGetParametersThrowsMalformedParametersException(method);
972     }
973 
974     @Test
testBadAccessModifier_withMetadata()975     public void testBadAccessModifier_withMetadata() throws Exception {
976         Method method = getMetadataVariationsMethod("badAccessModifier", String.class);
977         checkGetParametersThrowsMalformedParametersException(method);
978     }
979 
980     @Test
testBadlyFormedAnnotation()981     public void testBadlyFormedAnnotation() throws Exception {
982         Method method = getMetadataVariationsMethod("badlyFormedAnnotation", String.class);
983         // Badly formed annotations are treated as if the annotation is entirely absent.
984         Parameter parameter0 = method.getParameters()[0];
985         assertFalse(parameter0.isNamePresent());
986     }
987 
988     /** A non-static method that exists to be called by inner classes, lambdas, etc. */
outerClassMethod()989     private String outerClassMethod() {
990         return "Howdy";
991     }
992 
993     private static class ExecutableTestHelper {
994         private final Executable executable;
995 
ExecutableTestHelper(Executable executable)996         ExecutableTestHelper(Executable executable) {
997             this.executable = executable;
998         }
999 
1000         @DependsOnParameterMetadata
checkParametersToString(String expectedString)1001         ExecutableTestHelper checkParametersToString(String expectedString) {
1002             assertEquals(expectedString, Arrays.toString(executable.getParameters()));
1003             return this;
1004         }
1005 
1006         /**
1007          * Combines checks that should be true of any result from
1008          * {@link Executable#getParameters()}
1009          */
checkStandardParametersBehavior()1010         ExecutableTestHelper checkStandardParametersBehavior() {
1011             return checkGetParametersClonesArray()
1012                     .checkParametersGetDeclaringExecutable()
1013                     .checkParametersEquals()
1014                     .checkParametersHashcode();
1015         }
1016 
checkParametersGetDeclaringExecutable()1017         ExecutableTestHelper checkParametersGetDeclaringExecutable() {
1018             for (Parameter p : executable.getParameters()) {
1019                 assertSame(executable, p.getDeclaringExecutable());
1020             }
1021             return this;
1022         }
1023 
checkGetParametersClonesArray()1024         ExecutableTestHelper checkGetParametersClonesArray() {
1025             Parameter[] parameters1 = executable.getParameters();
1026             Parameter[] parameters2 = executable.getParameters();
1027             assertNotSame(parameters1, parameters2);
1028 
1029             assertEquals(parameters1.length, parameters2.length);
1030             for (int i = 0; i < parameters1.length; i++) {
1031                 assertSame(parameters1[i], parameters2[i]);
1032             }
1033             return this;
1034         }
1035 
checkParametersEquals()1036         ExecutableTestHelper checkParametersEquals() {
1037             Parameter[] parameters = executable.getParameters();
1038             for (int i = 0; i < parameters.length; i++) {
1039                 assertEquals(parameters[i], parameters[i]);
1040                 if (i > 0) {
1041                     assertFalse(parameters[0].equals(parameters[i]));
1042                     assertFalse(parameters[i].equals(parameters[0]));
1043                 }
1044             }
1045             return this;
1046         }
1047 
checkParametersHashcode()1048         ExecutableTestHelper checkParametersHashcode() {
1049             for (Parameter parameter : executable.getParameters()) {
1050                 // Not much to assert. Just call the method and check it is consistent.
1051                 assertEquals(parameter.hashCode(), parameter.hashCode());
1052             }
1053             return this;
1054         }
1055 
1056         @DependsOnParameterMetadata
checkParametersMetadataNotAvailable()1057         ExecutableTestHelper checkParametersMetadataNotAvailable() {
1058             ParameterTestHelper[] parameterTestHelpers = getParameterTestHelpers();
1059             for (int i = 0; i < parameterTestHelpers.length; i++) {
1060                 ParameterTestHelper parameterTestHelper = parameterTestHelpers[i];
1061                 parameterTestHelper.checkName(false, "arg" + i)
1062                         .checkImplicitAndSynthetic(false, false)
1063                         .checkModifiers(0);
1064             }
1065             return this;
1066         }
1067 
1068         /**
1069          * Checks that non of the parameters return {@code true} for {@link Parameter#isVarArgs()}.
1070          */
checkParametersNoVarArgs()1071         ExecutableTestHelper checkParametersNoVarArgs() {
1072             for (ParameterTestHelper parameterTestHelper : getParameterTestHelpers()) {
1073                 parameterTestHelper.checkIsVarArg(false);
1074             }
1075             return this;
1076         }
1077 
getParameterTestHelper(int index)1078         ParameterTestHelper getParameterTestHelper(int index) {
1079             return new ParameterTestHelper(executable.getParameters()[index]);
1080         }
1081 
getParameterTestHelpers()1082         private ParameterTestHelper[] getParameterTestHelpers() {
1083             final int parameterCount = executable.getParameterCount();
1084             ParameterTestHelper[] parameterTestHelpers = new ParameterTestHelper[parameterCount];
1085             for (int i = 0; i < parameterCount; i++) {
1086                 parameterTestHelpers[i] = getParameterTestHelper(i);
1087             }
1088             return parameterTestHelpers;
1089         }
1090 
1091         private static class ParameterTestHelper {
1092             private final Parameter parameter;
1093 
ParameterTestHelper(Parameter parameter)1094             ParameterTestHelper(Parameter parameter) {
1095                 this.parameter = parameter;
1096             }
1097 
checkGetType(Class<?> expectedType)1098             ParameterTestHelper checkGetType(Class<?> expectedType) {
1099                 assertEquals(expectedType, parameter.getType());
1100                 return this;
1101             }
1102 
1103             @DependsOnParameterMetadata
checkName(boolean expectedIsNamePresent, String expectedName)1104             ParameterTestHelper checkName(boolean expectedIsNamePresent, String expectedName) {
1105                 assertEquals(expectedIsNamePresent, parameter.isNamePresent());
1106                 assertEquals(expectedName, parameter.getName());
1107                 return this;
1108             }
1109 
1110             @DependsOnParameterMetadata
checkModifiers(int expectedModifiers)1111             ParameterTestHelper checkModifiers(int expectedModifiers) {
1112                 assertEquals(expectedModifiers, parameter.getModifiers());
1113                 return this;
1114             }
1115 
checkGetParameterizedType(String expectedParameterizedTypeString)1116             ParameterTestHelper checkGetParameterizedType(String expectedParameterizedTypeString) {
1117                 assertEquals(
1118                         expectedParameterizedTypeString,
1119                         parameter.getParameterizedType().toString());
1120                 return this;
1121             }
1122 
1123             @DependsOnParameterMetadata
checkImplicitAndSynthetic( boolean expectedIsImplicit, boolean expectedIsSynthetic)1124             ParameterTestHelper checkImplicitAndSynthetic(
1125                     boolean expectedIsImplicit, boolean expectedIsSynthetic) {
1126                 assertEquals(expectedIsImplicit, parameter.isImplicit());
1127                 assertEquals(expectedIsSynthetic, parameter.isSynthetic());
1128                 return this;
1129             }
1130 
checkIsVarArg(boolean expectedIsVarArg)1131             ParameterTestHelper checkIsVarArg(boolean expectedIsVarArg) {
1132                 assertEquals(expectedIsVarArg, parameter.isVarArgs());
1133                 return this;
1134             }
1135         }
1136     }
1137 
createClassLoaderForResource(File destDir, String resourcePath)1138     private static ClassLoader createClassLoaderForResource(File destDir, String resourcePath)
1139             throws Exception {
1140         String fileName = new File(resourcePath).getName();
1141         File dexOrJarFile = new File(destDir, fileName);
1142         copyResource(resourcePath, dexOrJarFile);
1143         assertTrue(dexOrJarFile.setReadOnly());
1144         return new PathClassLoader(
1145                 dexOrJarFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
1146     }
1147 
1148     /**
1149      * Copy a resource in the libcore/java/lang/reflect/parameter/ resource path to the indicated
1150      * target file.
1151      */
copyResource(String resourcePath, File destination)1152     private static void copyResource(String resourcePath, File destination) throws Exception {
1153         assertFalse(destination.exists());
1154         ClassLoader classLoader = ParameterTest.class.getClassLoader();
1155         assertNotNull(classLoader);
1156 
1157         try (InputStream in = classLoader.getResourceAsStream(resourcePath);
1158              FileOutputStream out = new FileOutputStream(destination)) {
1159             if (in == null) {
1160                 throw new IllegalStateException("Resource not found: " + resourcePath);
1161             }
1162             Streams.copy(in, out);
1163         }
1164     }
1165 
1166     /**
1167      * Loads an inner class from the ParameterMetadataTestClasses class defined in a separate dex
1168      * file. See src/test/java/libcore/java/lang/reflect/parameter/ for the associated source code.
1169      */
loadTestInnerClassWithMetadata(String name)1170     private Class<?> loadTestInnerClassWithMetadata(String name) throws Exception {
1171         return classesWithMetadataClassLoader.loadClass(
1172                 "libcore.java.lang.reflect.parameter.ParameterMetadataTestClasses$" + name);
1173     }
1174 
1175     /**
1176      * Loads the ParameterMetadataTestClasses class defined in a separate dex file.
1177      * See src/test/java/libcore/java/lang/reflect/parameter/ for the associated source code.
1178      */
loadTestOuterClassWithMetadata()1179     private Class<?> loadTestOuterClassWithMetadata() throws Exception {
1180         return classesWithMetadataClassLoader.loadClass(
1181                 "libcore.java.lang.reflect.parameter.ParameterMetadataTestClasses");
1182     }
1183 
1184     /**
1185      * Loads a method from the MetadataVariations class defined in a separate dex file. See
1186      * src/test/java/libcore/java/lang/reflect/parameter/ for the associated source code.
1187      */
getMetadataVariationsMethod(String methodName, Class<?>... parameterTypes)1188     private Method getMetadataVariationsMethod(String methodName, Class<?>... parameterTypes)
1189             throws Exception {
1190         Class<?> metadataVariationsClass = metadataVariationsClassLoader.loadClass(
1191                 "libcore.java.lang.reflect.parameter.MetadataVariations");
1192         return metadataVariationsClass.getDeclaredMethod(methodName, parameterTypes);
1193     }
1194 
checkGetParametersThrowsMalformedParametersException(Method method)1195     private static void checkGetParametersThrowsMalformedParametersException(Method method) {
1196         try {
1197             method.getParameters();
1198             fail();
1199         } catch (MalformedParametersException expected) {}
1200     }
1201 }
1202