blob: 51704cf61dab8a2c6f525ef30486cbf8612a852c [file] [log] [blame]
/*
* $Id$
*
* Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided that the
* following conditions are met:
* 1. Redistributions of source code must retain copyright statements and
* notices. Redistributions must also contain a copy of this document.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name "groovy" must not be used to endorse or promote products
* derived from this Software without prior written permission of The Codehaus.
* For written permission, please contact info@codehaus.org.
* 4. Products derived from this Software may not be called "groovy" nor may
* "groovy" appear in their names without prior written permission of The
* Codehaus. "groovy" is a registered trademark of The Codehaus.
* 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
*
* THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*/
package org.codehaus.groovy.runtime;
import groovy.lang.GString;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.IntRange;
import groovy.util.GroovyTestCase;
import junit.framework.AssertionFailedError;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Tests method invocation
*
* @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
* @version $Revision$
*/
public class InvokeMethodTest extends GroovyTestCase {
protected Invoker invoker = InvokerHelper.getInstance();
// Method invocation tests
//-------------------------------------------------------------------------
public void testInvokeMethodNoParams() throws Throwable {
Object value = invoke(this, "mockCallWithNoParams", null);
assertEquals("return value", "NoParams", value);
value = invoke(this, "mockCallWithNoParams", new Object[0]);
assertEquals("return value", "NoParams", value);
}
public void testInvokeMethodOneParam() throws Throwable {
Object value = invoke(this, "mockCallWithOneParam", "abc");
assertEquals("return value", "OneParam", value);
}
public void testInvokeMethodOneParamWhichIsNull() throws Throwable {
Object value = invoke(this, "mockCallWithOneNullParam", new Object[]{null});
assertEquals("return value", "OneParamWithNull", value);
value = invoke(this, "mockCallWithOneNullParam", null);
assertEquals("return value", "OneParamWithNull", value);
}
public void testInvokeOverloadedMethodWithOneParamWhichIsNull() throws Throwable {
Object value = invoke(this, "mockOverloadedMethod", new Object[]{null});
assertEquals("return value", "Object", value);
}
public void testInvokeMethodOneCollectionParameter() throws Throwable {
Object[] foo = {"a", "b", "c"};
Object value = invoke(this, "mockCallWithOneCollectionParam", new Object[]{foo});
assertEquals("return value", new Integer(3), value);
List list = new ArrayList();
list.add("a");
list.add("b");
value = invoke(this, "mockCallWithOneCollectionParam", list);
assertEquals("return value", new Integer(2), value);
}
public void testInvokePrintlnMethod() throws Throwable {
Object value = invoke(System.out, "println", "testing System.out.println...");
assertEquals("return value", null, value);
}
public void testMethodChooserNull() throws Throwable {
assertMethodChooser("Object", new Object[]{null});
}
public void testMethodChooserNoParams() throws Throwable {
assertMethodChooser("void", null);
}
public void testMethodChooserObject() throws Throwable {
assertMethodChooser("Object", new Object());
assertMethodChooser("Object", new Date());
}
public void testMethodChooserString_FAILS() throws Throwable {
if (notYetImplemented()) return;
assertMethodChooser("String", "foo");
assertMethodChooser("String", new StringBuffer());
assertMethodChooser("String", new Character('a'));
}
public void testMethodChooserNumber() throws Throwable {
assertMethodChooser("Number", new Integer(2));
assertMethodChooser("Number", new Double(2));
}
public void testMethodChooserTwoParams() throws Throwable {
List list = new ArrayList();
list.add("foo");
list.add("bar");
assertMethodChooser("Object,Object", list.toArray());
Object[] blah = {"a", "b"};
assertMethodChooser("Object,Object", blah);
}
public void testInstanceofWorksForArray() {
Class type = Object[].class;
Object value = new Object[1];
assertTrue("instanceof works for array", type.isInstance(value));
}
public void testMethodChooserTwoParamsWithSecondAnObjectArray() throws Throwable {
Object[] blah = {"a", new Object[]{"b"}
};
assertMethodChooser("Object,Object[]", blah);
}
public void testCollectionMethods() throws Throwable {
Object list = InvokerHelper.createList(new Object[]{"a", "b"});
Object value = invoke(list, "size", null);
assertEquals("size of collection", new Integer(2), value);
value = invoke(list, "contains", "a");
assertEquals("contains method", Boolean.TRUE, value);
}
public void testNewMethods() throws Throwable {
Object value = invoke("hello", "size", null);
assertEquals("size of string", new Integer(5), value);
}
public void testStaticMethod() throws Throwable {
Object value = invoke(DummyBean.class, "dummyStaticMethod", "abc");
assertEquals("size of string", "ABC", value);
}
public void testBaseClassMethod() throws Throwable {
Object object = new DummyBean();
Object value = invoke(object, "toString", null);
assertEquals("toString", object.toString(), value);
}
//SPG modified to reflect DefaultGroovyMethod name change and expected result from
//Integer/Integer division.
public void testDivideNumbers() throws Throwable {
assertMethodCall(new Double(10), "div", new Double(2), new Double(5));
assertMethodCall(new Double(10), "div", new Integer(2), new Double(5));
assertMethodCall(new Integer(10), "div", new Double(2), new Double(5));
assertMethodCall(new Integer(10), "div", new Integer(2), new java.math.BigDecimal("5"));
}
public void testBaseFailMethod() throws Throwable {
try {
invoke(this, "fail", "hello");
} catch (AssertionFailedError e) {
// worked
}
}
public void testToArrayOnList() throws Throwable {
List object = new ArrayList();
object.add("Hello");
Object[] value = (Object[]) invoke(object, "toArray", null);
assertArrayEquals(object.toArray(), value);
assertEquals(1, value.length);
assertEquals("Hello", value[0]);
value = (Object[]) invoke(object, "toArray", new Object[0]);
assertArrayEquals(object.toArray(), value);
}
public void testInvalidOverloading() throws Throwable {
try {
invoke(this, "badOverload", new Object[]{"a", "b"});
fail("Should fail as an unambiguous method is invoked");
}
catch (GroovyRuntimeException e) {
System.out.println("Caught: " + e);
}
}
public void testPlusWithNull() throws Throwable {
String param = "called with: ";
Object value = invoke(param, "plus", new Object[]{null});
assertEquals("called with null", param + null, value);
}
public void testCallIntMethodWithInteger() throws Throwable {
Object value = invoke(this, "overloadedRemove", new Object[]{new Integer(5)});
assertEquals("called with integer", "int5", value);
}
public void testCallListRemove() throws Throwable {
List list = new ArrayList();
list.add("foo");
list.add("bar");
invoke(list, "remove", new Object[]{new Integer(0)});
assertEquals("Should have just 1 item left: " + list, 1, list.size());
}
public void testCoerceGStringToString() throws Throwable {
GString param = new GString(new Object[]{"James"}) {
public String[] getStrings() {
return new String[]{"Hello "};
}
};
Object value = invoke(this, "methodTakesString", new Object[]{param});
assertEquals("converted GString to string", param.toString(), value);
}
public void testCoerceGStringToStringOnGetBytes() throws Throwable {
GString param = new GString(new Object[]{"US-ASCII"}) {
public String[] getStrings() {
return new String[]{""};
}
};
Object value = invoke("test", "getBytes", new Object[]{param});
assertEquals("converted GString to string", "test".getBytes("US-ASCII").getClass(), value.getClass());
}
public void testBadBDToDoubleCoerce() throws Throwable {
try {
invoke(Math.class, "floor", new BigDecimal("1.7E309"));
} catch (IllegalArgumentException e) {
assertTrue("Math.floor(1.7E309) should fail because it is out of range for a Double. "
+ e, e.getMessage().indexOf("out of range") > 0);
return;
}
fail("Math.floor(1.7E309) should fail because it is out of range for a Double.");
}
public void testClassMethod() throws Throwable {
Class c = String.class;
Object value = invoke(c, "getName", null);
assertEquals("Class.getName()", c.getName(), value);
c = getClass();
value = invoke(c, "getName", null);
assertEquals("Class.getName()", c.getName(), value);
}
public void testProtectedMethod() throws Throwable {
String param = "hello";
Object value = invoke(this, "aProtectedMethod", param);
assertEquals("protected method call", aProtectedMethod(param), value);
}
public void testPrivateMethod() throws Throwable {
String param = "hello";
Object value = invoke(this, "aPrivateMethod", param);
assertEquals("private method call", aPrivateMethod(param), value);
}
public void testStringSubstringMethod() throws Throwable {
String object = "hello";
Object value = invoke(object, "substring", new Integer(2));
assertEquals("substring(2)", object.substring(2), value);
value = invoke(object, "substring", new Object[]{new Integer(1), new Integer(3)});
assertEquals("substring(1,3)", object.substring(1, 3), value);
}
public void testListGetWithRange() throws Throwable {
List list = Arrays.asList(new Object[]{"a", "b", "c"});
Object range = new IntRange(0, 2);
Object value = invoke(list, "getAt", range);
assertTrue("Returned List: " + value, value instanceof List);
List retList = (List) value;
assertEquals("List size", 3, retList.size());
}
public void testSetLenientOnDateFormat() throws Throwable {
SimpleDateFormat a = new SimpleDateFormat("MM/dd/yyyy");
Object value = invoke(a, "setLenient", new Object[]{Boolean.FALSE});
assertEquals("void method", null, value);
}
public void testInvokeUnknownMethod() throws Throwable {
try {
Object value = invoke(this, "unknownMethod", "abc");
fail("Should have thrown an exception");
}
catch (GroovyRuntimeException e) {
// worked
}
}
public void testInvokeMethodWithWrongNumberOfParameters() throws Throwable {
try {
Object[] args = {"a", "b"};
invoke(this, "unknownMethod", args);
fail("Should have thrown an exception");
}
catch (GroovyRuntimeException e) {
// worked
}
}
public void testInvokeMethodOnNullObject() throws Throwable {
try {
invoke(null, "mockCallWithNoParams", null);
fail("Should have thrown an exception");
}
catch (NullPointerException e) {
// worked
}
}
// Mock methods used for testing
//-------------------------------------------------------------------------
public Object mockCallWithNoParams() {
return "NoParams";
}
public Object mockCallWithOneParam(Object value) {
assertEquals("Method not passed in the correct value", "abc", value);
return "OneParam";
}
public Object mockCallWithOneNullParam(Object value) {
assertEquals("Method not passed in the correct value", null, value);
return "OneParamWithNull";
}
public Integer mockCallWithOneCollectionParam(Object collection) {
Collection coll = DefaultTypeTransformation.asCollection(collection);
return new Integer(coll.size());
}
public Object mockOverloadedMethod() {
return "void";
}
public Object mockOverloadedMethod(Object object) {
return "Object";
}
public Object mockOverloadedMethod(Number object) {
return "Number";
}
public Object mockOverloadedMethod(String object) {
return "String";
}
public Object mockOverloadedMethod(Object object, Object bar) {
return "Object,Object";
}
public Object mockOverloadedMethod(Object object, Object[] array) {
return "Object,Object[]";
}
public Object badOverload(String a, Object b) {
return "String, Object";
}
public Object badOverload(Object a, String b) {
return "Object, String";
}
public Object methodTakesString(String x) {
return x;
}
public Object overloadedRemove(int idx) {
return "int" + idx;
}
public Object overloadedRemove(Object value) {
return "Object" + value;
}
// Implementation methods
//-------------------------------------------------------------------------
protected Object aProtectedMethod(String param) {
return param + " there!";
}
private Object aPrivateMethod(String param) {
return param + " James!";
}
protected void assertMethodCall(Object object, String method, Object param, Object expected) {
Object value = InvokerHelper.invokeMethod(object, method, new Object[]{param});
assertEquals("result of method: " + method, expected, value);
}
/**
* Asserts that invoking the method chooser finds the right overloaded
* method implementation
*
* @param expected is the expected value of the method
* @param arguments the argument(s) to the method invocation
*/
protected void assertMethodChooser(Object expected, Object arguments) throws Throwable {
Object value = invoke(this, "mockOverloadedMethod", arguments);
assertEquals("Invoking overloaded method for arguments: " + InvokerHelper.toString(arguments), expected, value);
}
protected Object invoke(Object object, String method, Object args) throws Throwable {
try {
return invoker.invokeMethod(object, method, args);
}
catch (InvokerInvocationException e) {
throw e.getCause();
}
}
}