1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.luni.tests.java.lang.reflect;
19
20import java.lang.reflect.InvocationTargetException;
21import java.lang.reflect.Method;
22import java.lang.reflect.Modifier;
23
24public class MethodTest extends junit.framework.TestCase {
25
26	static class TestMethod {
27		public TestMethod() {
28		}
29
30		public void voidMethod() throws IllegalArgumentException {
31		}
32
33		public void parmTest(int x, short y, String s, boolean bool, Object o,
34				long l, byte b, char c, double d, float f) {
35		}
36
37		public int intMethod() {
38			return 1;
39		}
40
41		public static final void printTest(int x, short y, String s,
42				boolean bool, Object o, long l, byte b, char c, double d,
43				float f) {
44		}
45
46		public double doubleMethod() {
47			return 1.0;
48		}
49
50		public short shortMethod() {
51			return (short) 1;
52		}
53
54		public byte byteMethod() {
55			return (byte) 1;
56		}
57
58		public float floatMethod() {
59			return 1.0f;
60		}
61
62		public long longMethod() {
63			return 1l;
64		}
65
66		public char charMethod() {
67			return 'T';
68		}
69
70		public Object objectMethod() {
71			return new Object();
72		}
73
74		private static void prstatic() {
75		}
76
77		public static void pustatic() {
78		}
79
80		public static synchronized void pustatsynch() {
81		}
82
83		public static int invokeStaticTest() {
84			return 1;
85		}
86
87		public int invokeInstanceTest() {
88			return 1;
89		}
90
91		private int privateInvokeTest() {
92			return 1;
93		}
94
95		public int invokeExceptionTest() throws NullPointerException {
96			throw new NullPointerException();
97		}
98
99		public static synchronized native void pustatsynchnat();
100
101		public void invokeCastTest1(byte param) {
102		}
103
104		public void invokeCastTest1(short param) {
105		}
106
107		public void invokeCastTest1(int param) {
108		}
109
110		public void invokeCastTest1(long param) {
111		}
112
113		public void invokeCastTest1(float param) {
114		}
115
116		public void invokeCastTest1(double param) {
117		}
118
119		public void invokeCastTest1(char param) {
120		}
121
122		public void invokeCastTest1(boolean param) {
123		}
124	}
125
126	abstract class AbstractTestMethod {
127		public abstract void puabs();
128	}
129
130	class TestMethodSub extends TestMethod {
131		public int invokeInstanceTest() {
132			return 0;
133		}
134	}
135
136	/**
137	 * @tests java.lang.reflect.Method#equals(java.lang.Object)
138	 */
139	public void test_equalsLjava_lang_Object() throws Exception {
140		// Test for method boolean
141		// java.lang.reflect.Method.equals(java.lang.Object)
142
143		Method m1 = null, m2 = null;
144		m1 = TestMethod.class.getMethod("invokeInstanceTest", new Class[0]);
145		m2 = TestMethodSub.class.getMethod("invokeInstanceTest",
146				new Class[0]);
147
148		assertTrue("Overriden method returned equal", !m1.equals(m2));
149		assertTrue("Same method returned not-equal", m1.equals(m1));
150                m1 = TestMethod.class.getMethod("invokeStaticTest", new Class[0]);
151                m2 = TestMethodSub.class
152                                .getMethod("invokeStaticTest", new Class[0]);
153
154                assertTrue("Inherited method returned not-equal", m1.equals(m2));
155	}
156
157	/**
158	 * @tests java.lang.reflect.Method#getDeclaringClass()
159	 */
160	public void test_getDeclaringClass() {
161		// Test for method java.lang.Class
162		// java.lang.reflect.Method.getDeclaringClass()
163
164		Method[] mths;
165
166                mths = TestMethod.class.getDeclaredMethods();
167                assertTrue("Returned incorrect declaring class: "
168                                + mths[0].getDeclaringClass().toString(), mths[0]
169                                .getDeclaringClass().equals(TestMethod.class));
170	}
171
172	/**
173	 * @tests java.lang.reflect.Method#getExceptionTypes()
174	 */
175	public void test_getExceptionTypes() throws Exception {
176		// Test for method java.lang.Class []
177		// java.lang.reflect.Method.getExceptionTypes()
178
179                Method mth = TestMethod.class.getMethod("voidMethod", new Class[0]);
180                Class[] ex = mth.getExceptionTypes();
181                assertEquals("Returned incorrect number of exceptions",
182                                1, ex.length);
183                assertTrue("Returned incorrect exception type", ex[0]
184                                .equals(IllegalArgumentException.class));
185                mth = TestMethod.class.getMethod("intMethod", new Class[0]);
186                ex = mth.getExceptionTypes();
187                assertEquals("Returned incorrect number of exceptions",
188                                0, ex.length);
189	}
190
191	/**
192	 * @tests java.lang.reflect.Method#getModifiers()
193	 */
194	public void test_getModifiers() throws Exception {
195		// Test for method int java.lang.reflect.Method.getModifiers()
196
197		Class cl = TestMethod.class;
198		int mods = 0;
199		Method mth = null;
200		int mask = 0;
201                mth = cl.getMethod("pustatic", new Class[0]);
202                mods = mth.getModifiers();
203
204                mask = Modifier.PUBLIC | Modifier.STATIC;
205		assertTrue("Incorrect modifiers returned", (mods | mask) == mask);
206                mth = cl.getDeclaredMethod("prstatic", new Class[0]);
207                mods = mth.getModifiers();
208
209                mask = Modifier.PRIVATE | Modifier.STATIC;
210		assertTrue("Incorrect modifiers returned", (mods | mask) == mask);
211		mth = cl.getDeclaredMethod("pustatsynch", new Class[0]);
212		mods = mth.getModifiers();
213
214                mask = (Modifier.PUBLIC | Modifier.STATIC) | Modifier.SYNCHRONIZED;
215		assertTrue("Incorrect modifiers returned", (mods | mask) == mask);
216		mth = cl.getDeclaredMethod("pustatsynchnat", new Class[0]);
217		mods = mth.getModifiers();
218
219                mask = ((Modifier.PUBLIC | Modifier.STATIC) | Modifier.SYNCHRONIZED)
220				| Modifier.NATIVE;
221		assertTrue("Incorrect modifiers returned", (mods | mask) == mask);
222		cl = AbstractTestMethod.class;
223                mth = cl.getDeclaredMethod("puabs", new Class[0]);
224                mods = mth.getModifiers();
225
226                mask = Modifier.PUBLIC | Modifier.ABSTRACT;
227		assertTrue("Incorrect modifiers returned", (mods | mask) == mask);
228	}
229
230	/**
231	 * @tests java.lang.reflect.Method#getName()
232	 */
233	public void test_getName() throws Exception {
234		// Test for method java.lang.String java.lang.reflect.Method.getName()
235		Method mth = null;
236		mth = TestMethod.class.getMethod("voidMethod", new Class[0]);
237
238                assertEquals("Returned incorrect method name",
239				"voidMethod", mth.getName());
240	}
241
242	/**
243	 * @tests java.lang.reflect.Method#getParameterTypes()
244	 */
245	public void test_getParameterTypes() throws Exception {
246		// Test for method java.lang.Class []
247		// java.lang.reflect.Method.getParameterTypes()
248		Class cl = TestMethod.class;
249		Method mth = null;
250		Class[] parms = null;
251		Method[] methods = null;
252		Class[] plist = { int.class, short.class, String.class, boolean.class,
253				Object.class, long.class, byte.class, char.class, double.class,
254				float.class };
255		mth = cl.getMethod("voidMethod", new Class[0]);
256		parms = mth.getParameterTypes();
257
258                assertEquals("Returned incorrect parameterTypes", 0, parms.length);
259		mth = cl.getMethod("parmTest", plist);
260		parms = mth.getParameterTypes();
261
262                assertTrue("Invalid number of parameters returned",
263				plist.length == parms.length);
264		for (int i = 0; i < plist.length; i++)
265			assertTrue("Incorrect parameter returned", plist[i]
266					.equals(parms[i]));
267
268		// Test same method. but this time pull it from the list of methods
269		// rather than asking for it explicitly
270		methods = cl.getDeclaredMethods();
271
272		int i;
273		for (i = 0; i < methods.length; i++)
274			if (methods[i].getName().equals("parmTest")) {
275				mth = methods[i];
276				i = methods.length + 1;
277			}
278		if (i < methods.length) {
279			parms = mth.getParameterTypes();
280			assertTrue("Incorrect number of parameters returned",
281					parms.length == plist.length);
282			for (i = 0; i < plist.length; i++)
283				assertTrue("Incorrect parameter returned", plist[i]
284						.equals(parms[i]));
285		}
286	}
287
288	/**
289	 * @tests java.lang.reflect.Method#getReturnType()
290	 */
291	public void test_getReturnType() throws Exception {
292		// Test for method java.lang.Class
293		// java.lang.reflect.Method.getReturnType()
294		Class cl = TestMethod.class;
295		Method mth = null;
296		mth = cl.getMethod("charMethod", new Class[0]);
297
298                assertTrue("Gave incorrect returne type, wanted char", mth
299				.getReturnType().equals(char.class));
300		mth = cl.getMethod("longMethod", new Class[0]);
301
302                assertTrue("Gave incorrect returne type, wanted long", mth
303				.getReturnType().equals(long.class));
304		mth = cl.getMethod("shortMethod", new Class[0]);
305
306                assertTrue("Gave incorrect returne type, wanted short", mth
307				.getReturnType().equals(short.class));
308		mth = cl.getMethod("intMethod", new Class[0]);
309
310                assertTrue("Gave incorrect returne type, wanted int: "
311				+ mth.getReturnType(), mth.getReturnType().equals(int.class));
312		mth = cl.getMethod("doubleMethod", new Class[0]);
313
314                assertTrue("Gave incorrect returne type, wanted double", mth
315				.getReturnType().equals(double.class));
316		mth = cl.getMethod("byteMethod", new Class[0]);
317
318                assertTrue("Gave incorrect returne type, wanted byte", mth
319				.getReturnType().equals(byte.class));
320		mth = cl.getMethod("byteMethod", new Class[0]);
321
322                assertTrue("Gave incorrect returne type, wanted byte", mth
323				.getReturnType().equals(byte.class));
324		mth = cl.getMethod("objectMethod", new Class[0]);
325
326                assertTrue("Gave incorrect returne type, wanted Object", mth
327				.getReturnType().equals(Object.class));
328
329		mth = cl.getMethod("voidMethod", new Class[0]);
330
331                assertTrue("Gave incorrect returne type, wanted void", mth
332				.getReturnType().equals(void.class));
333	}
334
335	/**
336	 * @tests java.lang.reflect.Method#invoke(java.lang.Object,
337	 *        java.lang.Object[])
338	 */
339	public void test_invokeLjava_lang_Object$Ljava_lang_Object() throws Exception {
340		// Test for method java.lang.Object
341		// java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object
342		// [])
343
344		Class cl = TestMethod.class;
345		Method mth = null;
346		Object ret = null;
347		Class[] dcl = new Class[0];
348
349		// Get and invoke a static method
350		mth = cl.getDeclaredMethod("invokeStaticTest", dcl);
351                ret = mth.invoke(null, new Object[0]);
352
353                assertEquals("Invoke returned incorrect value", 1, ((Integer) ret)
354				.intValue());
355
356		// Get and invoke an instance method
357		mth = cl.getDeclaredMethod("invokeInstanceTest", dcl);
358                ret = mth.invoke(new TestMethod(), new Object[0]);
359
360                assertEquals("Invoke returned incorrect value", 1, ((Integer) ret)
361				.intValue());
362
363		// Get and attempt to invoke a private method
364		mth = cl.getDeclaredMethod("privateInvokeTest", dcl);
365
366		try {
367			ret = mth.invoke(new TestMethod(), new Object[0]);
368		} catch (IllegalAccessException e) {
369			// Correct behaviour
370		}
371
372		// Generate an IllegalArgumentException
373		mth = cl.getDeclaredMethod("invokeInstanceTest", dcl);
374
375                try {
376			Object[] args = { Object.class };
377			ret = mth.invoke(new TestMethod(), args);
378		} catch (IllegalArgumentException e) {
379			// Correct behaviour
380		}
381
382		// Generate a NullPointerException
383		mth = cl.getDeclaredMethod("invokeInstanceTest", dcl);
384
385                try {
386			ret = mth.invoke(null, new Object[0]);
387		} catch (NullPointerException e) {
388			// Correct behaviour
389		}
390
391		// Generate an InvocationTargetException
392		mth = cl.getDeclaredMethod("invokeExceptionTest", dcl);
393		try {
394			ret = mth.invoke(new TestMethod(), new Object[0]);
395		} catch (InvocationTargetException e) {
396			// Correct behaviour
397		}
398
399		mth = String.class.getMethod("valueOf", new Class[] { Integer.TYPE });
400        try {
401            mth.invoke(String.class, new Object[] { null });
402            fail("should throw IllegalArgumentException");
403        } catch (IllegalArgumentException e) {
404            // Expected
405        }
406
407		TestMethod testMethod = new TestMethod();
408		Method methods[] = cl.getMethods();
409		for (int i = 0; i < methods.length; i++) {
410			if (methods[i].getName().startsWith("invokeCastTest1")) {
411				Class param = methods[i].getParameterTypes()[0];
412
413				try {
414					methods[i].invoke(testMethod, new Object[] { new Byte(
415							(byte) 1) });
416					assertTrue("invalid invoke with Byte: " + methods[i],
417							param == Byte.TYPE || param == Short.TYPE
418									|| param == Integer.TYPE
419									|| param == Long.TYPE
420									|| param == Float.TYPE
421									|| param == Double.TYPE);
422				} catch (Exception e) {
423					assertTrue("Byte invalid exception: " + e,
424							e instanceof IllegalArgumentException);
425					assertTrue("Byte invalid failure: " + methods[i],
426							param == Boolean.TYPE || param == Character.TYPE);
427				}
428
429				try {
430					methods[i].invoke(testMethod, new Object[] { new Short(
431							(short) 1) });
432					assertTrue("invalid invoke with Short: " + methods[i],
433							param == Short.TYPE || param == Integer.TYPE
434									|| param == Long.TYPE
435									|| param == Float.TYPE
436									|| param == Double.TYPE);
437				} catch (Exception e) {
438					assertTrue("Short invalid exception: " + e,
439							e instanceof IllegalArgumentException);
440					assertTrue("Short invalid failure: " + methods[i],
441							param == Byte.TYPE || param == Boolean.TYPE
442									|| param == Character.TYPE);
443				}
444
445				try {
446					methods[i].invoke(testMethod,
447							new Object[] { new Integer(1) });
448					assertTrue("invalid invoke with Integer: " + methods[i],
449							param == Integer.TYPE || param == Long.TYPE
450									|| param == Float.TYPE
451									|| param == Double.TYPE);
452				} catch (Exception e) {
453					assertTrue("Integer invalid exception: " + e,
454							e instanceof IllegalArgumentException);
455					assertTrue("Integer invalid failure: " + methods[i],
456							param == Byte.TYPE || param == Short.TYPE
457									|| param == Boolean.TYPE
458									|| param == Character.TYPE);
459				}
460
461				try {
462					methods[i].invoke(testMethod, new Object[] { new Long(1) });
463					assertTrue("invalid invoke with Long: " + methods[i],
464							param == Long.TYPE || param == Float.TYPE
465									|| param == Double.TYPE);
466				} catch (Exception e) {
467					assertTrue("Long invalid exception: " + e,
468							e instanceof IllegalArgumentException);
469					assertTrue("Long invalid failure: " + methods[i],
470							param == Byte.TYPE || param == Short.TYPE
471									|| param == Integer.TYPE
472									|| param == Boolean.TYPE
473									|| param == Character.TYPE);
474				}
475
476				try {
477					methods[i].invoke(testMethod, new Object[] { new Character(
478							'a') });
479					assertTrue("invalid invoke with Character: " + methods[i],
480							param == Character.TYPE || param == Integer.TYPE
481									|| param == Long.TYPE
482									|| param == Float.TYPE
483									|| param == Double.TYPE);
484				} catch (Exception e) {
485					assertTrue("Character invalid exception: " + e,
486							e instanceof IllegalArgumentException);
487					assertTrue("Character invalid failure: " + methods[i],
488							param == Byte.TYPE || param == Short.TYPE
489									|| param == Boolean.TYPE);
490				}
491
492				try {
493					methods[i]
494							.invoke(testMethod, new Object[] { new Float(1) });
495					assertTrue("invalid invoke with Float: " + methods[i],
496							param == Float.TYPE || param == Double.TYPE);
497				} catch (Exception e) {
498					assertTrue("Float invalid exception: " + e,
499							e instanceof IllegalArgumentException);
500					assertTrue("Float invalid failure: " + methods[i],
501							param == Byte.TYPE || param == Short.TYPE
502									|| param == Integer.TYPE
503									|| param == Long.TYPE
504									|| param == Boolean.TYPE
505									|| param == Character.TYPE);
506				}
507
508				try {
509					methods[i].invoke(testMethod,
510							new Object[] { new Double(1) });
511					assertTrue("invalid invoke with Double: " + methods[i],
512							param == Double.TYPE);
513				} catch (Exception e) {
514					assertTrue("Double invalid exception: " + e,
515							e instanceof IllegalArgumentException);
516					assertTrue("Double invalid failure: " + methods[i],
517							param == Byte.TYPE || param == Short.TYPE
518									|| param == Integer.TYPE
519									|| param == Long.TYPE
520									|| param == Boolean.TYPE
521									|| param == Character.TYPE
522									|| param == Float.TYPE);
523				}
524
525				try {
526					methods[i].invoke(testMethod, new Object[] { new Boolean(
527							true) });
528					assertTrue("invalid invoke with Boolean: " + methods[i],
529							param == Boolean.TYPE);
530				} catch (Exception e) {
531					assertTrue("Boolean invalid exception: " + e,
532							e instanceof IllegalArgumentException);
533					assertTrue("Boolean invalid failure: " + methods[i],
534							param == Byte.TYPE || param == Short.TYPE
535									|| param == Integer.TYPE
536									|| param == Long.TYPE
537									|| param == Character.TYPE
538									|| param == Float.TYPE
539									|| param == Double.TYPE);
540				}
541			}
542		}
543	}
544
545	public void test_invoke_InvocationTargetException() throws Exception {
546        Method method = MockObject.class.getDeclaredMethod("mockMethod", Class.class);
547        MockObject mockObject = new MockObject();
548
549        try {
550            method.invoke(mockObject, InvocationTargetException.class);
551            fail("should throw InvocationTargetException");
552        } catch (InvocationTargetException e) {
553            // Expected
554        }
555
556        try {
557            method.invoke(mockObject, IllegalAccessException.class);
558            fail("should throw InvocationTargetException");
559        } catch (InvocationTargetException e) {
560            // Expected
561        }
562
563        try {
564            method.invoke(mockObject, IllegalArgumentException.class);
565            fail("should throw InvocationTargetException");
566        } catch (InvocationTargetException e) {
567            // Expected
568        }
569
570        try {
571            method.invoke(mockObject, InvocationTargetException.class);
572            fail("should throw InvocationTargetException");
573        } catch (InvocationTargetException e) {
574            // Expected
575        }
576
577        try {
578            method.invoke(mockObject, Throwable.class);
579            fail("should throw InvocationTargetException");
580        } catch (InvocationTargetException e) {
581            // Expected
582        }
583    }
584
585    static class MockObject {
586
587        public void mockMethod (Class<?> clazz) throws Exception {
588            if (clazz == InstantiationException.class) {
589                throw new InstantiationException();
590            } else if (clazz == IllegalAccessException.class) {
591                throw new IllegalAccessException();
592            } else if (clazz == IllegalArgumentException.class) {
593                throw new IllegalArgumentException();
594            } else if (clazz == InvocationTargetException.class) {
595                throw new InvocationTargetException(new Throwable());
596            } else {
597                throw new Exception();
598            }
599        }
600    }
601
602	/**
603	 * @tests java.lang.reflect.Method#toString()
604	 */
605	public void test_toString() throws Exception {
606        Method mth = null;
607        Class[] parms = { int.class, short.class, String.class, boolean.class,
608                Object.class, long.class, byte.class, char.class, double.class,
609                float.class };
610        mth = TestMethod.class.getDeclaredMethod("printTest", parms);
611
612        assertTrue(
613                "Returned incorrect string for method: " + mth.toString(),
614                mth
615                        .toString()
616                        .equals(
617                                "public static final void org.apache.harmony.luni.tests.java.lang.reflect.MethodTest$TestMethod.printTest(int,short,java.lang.String,boolean,java.lang.Object,long,byte,char,double,float)"));
618    }
619}
620