ahmaddarawshi / powermock

Automatically exported from code.google.com/p/powermock
0 stars 0 forks source link

Invoke on Varargs Constructor Taking Wrong Argument as the Varags #118

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
When you have a constructor with multiple arguments AND varargs, then 
NewInvocationControlImpl assumes the first argument is the varargs. It should 
pick 
the last argument since varags argument can only be the last in the list of 
arguments. The code only works if the constructor has only one argument which 
is 
varargs.

Here is the snippet that causes this 
(org.powermock.api.easymock.internal.invocationcontrol.NewInvocationControlImpl.
java
 line 41 - 49)
<snip>
public Object invoke(Class<?> type, Object[] args, Class<?>[] sig) throws 
Exception 
{
    Constructor<?> constructor = WhiteboxImpl.getConstructor(type, sig);
    if (constructor.isVarArgs()) {
    /*
     * Get the first argument because this contains the actual varargs
     * arguments.
     */
    args = (Object[]) args[0];
    }
</snip>

Fix should be to replace args = (Object) args[0]; with

    args = (Object[]) args[args.length - 1]; // varargs is the last argument

What steps will reproduce the problem?
1. Assume a class Bom like this:
public class Bom {
    private String firstArg;
    private String[] args;

    public Bom(String firstArg, String... args) {
        firstArg = firstArg;
        args = args;
    }
}

2. And a Test class like this:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Bom.class)
public class BomTest {
    @Test
    public void test() throws Exception {
        PowerMock.createMockAndExpectNew(Bom.class, "abc", "xyz", "123");
        PowerMock.replayAll();

        Bom b = new Bom("abc", "xyz", "123");

        PowerMock.verifyAll();
    }
}

3. Then running this test will result in the following stacktrace:
java.lang.ClassCastException: java.lang.String cannot be cast to 
[Ljava.lang.Object;
    at 
org.powermock.api.easymock.internal.invocationcontrol.NewInvocationControlImpl.i
nvok
e(NewInvocationControlImpl.java:48)
    at org.powermock.core.MockGateway.newInstanceCall(MockGateway.java:107)
    at rf.actors.BomTest.test(BomTest.java:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
    at 
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$2.
runT
estMethod(PowerMockJUnit44RunnerDelegateImpl.java:222)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
    at 
org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadi
e.ja
va:87)
    at 
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$2.
runB
eforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:212)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
    at 
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.in
voke
TestMethod(PowerMockJUnit44RunnerDelegateImpl.java:205)
    at 
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.ru
nMet
hods(PowerMockJUnit44RunnerDelegateImpl.java:159)
    at 
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.
run(
PowerMockJUnit44RunnerDelegateImpl.java:133)
    at 
org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    at 
org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.ru
n(Po
werMockJUnit44RunnerDelegateImpl.java:131)
    at 
org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run
(JUn
it4TestSuiteChunkerImpl.java:112)
    at 
org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.
run(
AbstractCommonPowerMockRunner.java:44)
    at 
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReferen
ce.j
ava:45)
    at 
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner
.jav
a:460)
    at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner
.jav
a:673)
    at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java
:386
)
    at 
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.jav
a:19
6)

What is the expected output? What do you see instead?

What version of the product are you using? On what operating system?
1.2.5 on Java 1.6.0_13 on Windows.

Please provide any additional information below.

Original issue reported on code.google.com by cemca...@gmail.com on 12 Jun 2009 at 11:02

GoogleCodeExporter commented 9 years ago
Thanks for reporting this

Original comment by johan.ha...@gmail.com on 15 Jun 2009 at 8:58

GoogleCodeExporter commented 9 years ago
Work around for now is to change the vararg contructor argument to an array a 
la:

public Bom(String firstArg, String[] args) {
    firstArg = firstArg;
    args = args;
}

Original comment by cemca...@gmail.com on 15 Jun 2009 at 5:56

GoogleCodeExporter commented 9 years ago
This has now been fixed in trunk.

Original comment by johan.ha...@gmail.com on 15 Jun 2009 at 9:32

GoogleCodeExporter commented 9 years ago
The Bom and BomTest code have new problem on 1.4.10 on Java 1.7 on Windows:

java.lang.AssertionError: 
  Unexpected constructor call begin.Bom("xyz", "123"):
    begin.Bom("abc", "xyz", "123"): expected: 1, actual: 0
    at org.powermock.api.easymock.internal.invocationcontrol.NewInvocationControlAssertionError.throwAssertionErrorForNewSubstitutionFailure(NewInvocationControlAssertionError.java:20)
    at org.powermock.api.easymock.internal.invocationcontrol.NewInvocationControlImpl.invoke(NewInvocationControlImpl.java:66)
    at org.powermock.core.MockGateway.newInstanceCall(MockGateway.java:189)
    at begin.BomTest.test(BomTest.java:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:307)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:112)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:73)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Original comment by spring8...@gmail.com on 10 Dec 2011 at 3:34

GoogleCodeExporter commented 9 years ago
Is it really a Java 7 issue only?

Original comment by johan.ha...@gmail.com on 12 Dec 2011 at 7:09

GoogleCodeExporter commented 9 years ago
I'm getting it on with Java 6 as well.
Using release 1.4.9

Original comment by ronki...@gmail.com on 18 Dec 2011 at 11:42