You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2006/07/20 18:50:24 UTC

svn commit: r423984 [2/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/ioc/ main/java/org/apache/tapestry/internal/ioc/services/ main/java/org/apache/tapestry/internal/util/ main/java/org/apache/tapestry/ioc/...

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java?rev=423984&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java Thu Jul 20 09:50:22 2006
@@ -0,0 +1,354 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.ioc.services;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.DataFormatException;
+
+import javassist.CtClass;
+
+import org.apache.hivemind.impl.BaseLocatable;
+import org.apache.hivemind.service.MethodFab;
+import org.apache.hivemind.util.PropertyUtils;
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.MethodSignature;
+import org.apache.tapestry.test.BaseTestCase;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ClassFabImplTest extends BaseTestCase
+{
+    private final CtClassSource _source;
+
+    public ClassFabImplTest()
+    {
+        ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
+
+        ClassFactoryClassPool pool = new ClassFactoryClassPool();
+
+        pool.appendClassLoader(threadLoader);
+
+        _source = new CtClassSource(pool);
+    }
+
+    private ClassFab newClassFab(String className, Class superClass)
+    {
+        CtClass ctClass = _source.newClass(className, superClass);
+
+        return new ClassFabImpl(_source, ctClass);
+    }
+
+    @Test
+    public void create_simple_bean() throws Exception
+    {
+        ClassFab cf = newClassFab("TargetBean", Object.class);
+
+        cf.addField("_stringValue", String.class);
+
+        MethodSignature setStringValue = new MethodSignature(void.class, "setStringValue",
+                new Class[]
+                { String.class }, null);
+
+        cf.addMethod(Modifier.PUBLIC, setStringValue, "_stringValue = $1;");
+
+        MethodSignature getStringValue = new MethodSignature(String.class, "getStringValue", null,
+                null);
+
+        cf.addMethod(Modifier.PUBLIC, getStringValue, "return _stringValue;");
+
+        Class targetClass = cf.createClass();
+
+        Object targetBean = targetClass.newInstance();
+
+        PropertyUtils.write(targetBean, "stringValue", "Fred");
+
+        // May keep a test-time dependency on HiveMind, just for PropertyUtils.
+
+        String actual = (String) PropertyUtils.read(targetBean, "stringValue");
+
+        assertEquals(actual, "Fred");
+    }
+
+    @Test
+    public void add_constructor() throws Exception
+    {
+        ClassFab cf = newClassFab("ConstructableBean", Object.class);
+
+        cf.addField("_stringValue", String.class);
+        cf.addConstructor(new Class[]
+        { String.class }, null, "{ _stringValue = $1; }");
+
+        MethodSignature getStringValue = new MethodSignature(String.class, "getStringValue", null,
+                null);
+
+        cf.addMethod(Modifier.PUBLIC, getStringValue, "return _stringValue;");
+
+        Class targetClass = cf.createClass();
+
+        try
+        {
+            targetClass.newInstance();
+            unreachable();
+        }
+        catch (InstantiationException ex)
+        {
+        }
+
+        Constructor c = targetClass.getConstructors()[0];
+
+        Object targetBean = c.newInstance(new Object[]
+        { "Buffy" });
+
+        String actual = (String) PropertyUtils.read(targetBean, "stringValue");
+
+        assertEquals("Buffy", actual);
+    }
+
+    @Test
+    public void add_constructor_from_base_class() throws Exception
+    {
+        ClassFab cf = newClassFab("MyIntHolder", AbstractIntWrapper.class);
+
+        cf.addField("_intValue", int.class);
+        cf.addConstructor(new Class[]
+        { int.class }, null, "{ _intValue = $1; }");
+
+        cf.addMethod(
+                Modifier.PUBLIC,
+                new MethodSignature(int.class, "getIntValue", null, null),
+                "return _intValue;");
+
+        Class targetClass = cf.createClass();
+        Constructor c = targetClass.getConstructors()[0];
+
+        AbstractIntWrapper targetBean = (AbstractIntWrapper) c.newInstance(new Object[]
+        { new Integer(137) });
+
+        assertEquals(targetBean.getIntValue(), 137);
+    }
+
+    @Test
+    public void invalid_super_class() throws Exception
+    {
+        ClassFab cf = newClassFab("InvalidSuperClass", List.class);
+
+        try
+        {
+            cf.createClass();
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertExceptionSubstring(ex, "Unable to create class InvalidSuperClass");
+        }
+    }
+
+    private void assertExceptionSubstring(Throwable t, String partialMessage)
+    {
+        assertTrue(t.getMessage().contains(partialMessage));
+    }
+
+    @Test
+    public void add_interface() throws Exception
+    {
+        ClassFab cf = newClassFab("SimpleService", Object.class);
+
+        cf.addInterface(SimpleService.class);
+
+        cf.addMethod(Modifier.PUBLIC, new MethodSignature(int.class, "add", new Class[]
+        { int.class, int.class }, null), "return $1 + $2;");
+
+        Class targetClass = cf.createClass();
+
+        SimpleService s = (SimpleService) targetClass.newInstance();
+
+        assertEquals(207, s.add(99, 108));
+    }
+
+    @Test
+    public void attempt_to_subclass_from_final_class() throws Exception
+    {
+        ClassFab cf = newClassFab("StringSubclass", String.class);
+
+        try
+        {
+            cf.createClass();
+        }
+        catch (RuntimeException ex)
+        {
+            assertExceptionRegexp(
+                    ex,
+                    "Unable to create class StringSubclass\\:.*Cannot inherit from final class");
+        }
+    }
+
+    private void assertExceptionRegexp(Throwable ex, String pattern)
+    {
+        assertTrue(ex.getMessage().matches(pattern));
+    }
+
+    @Test
+    public void create_class_within_non_default_package() throws Exception
+    {
+        ClassFab cf = newClassFab("org.apache.hivemind.InPackage", Object.class);
+
+        Class c = cf.createClass();
+
+        Object o = c.newInstance();
+
+        assertEquals("org.apache.hivemind.InPackage", o.getClass().getName());
+    }
+
+    @Test
+    public void invalid_method_body() throws Exception
+    {
+        ClassFab cf = newClassFab("BadMethodBody", Object.class);
+
+        cf.addInterface(Runnable.class);
+
+        try
+        {
+            cf.addMethod(
+                    Modifier.PUBLIC,
+                    new MethodSignature(void.class, "run", null, null),
+                    "fail;");
+        }
+        catch (RuntimeException ex)
+        {
+            assertExceptionSubstring(ex, "Unable to add method void run() to class BadMethodBody:");
+        }
+    }
+
+    @Test
+    public void add_duplicate_method_signature() throws Exception
+    {
+        ClassFab cf = newClassFab("DupeMethodAdd", Object.class);
+
+        cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "foo", null, null), "{}");
+
+        try
+        {
+            cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "foo", null, null), "{}");
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertEquals("Attempt to redefine method void foo() of class DupeMethodAdd.", ex
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void invalid_constructor_body() throws Exception
+    {
+        ClassFab cf = newClassFab("BadConstructor", Object.class);
+
+        try
+        {
+            cf.addConstructor(null, null, " woops!");
+        }
+        catch (RuntimeException ex)
+        {
+            assertExceptionSubstring(ex, "Unable to add constructor to class BadConstructor");
+        }
+
+    }
+
+    @Test
+    public void invalid_field() throws Exception
+    {
+        ClassFab cf = newClassFab("InvalidField", Object.class);
+
+        // You'd think some of these would fail, but the ultimate failure
+        // occurs when we create the class.
+
+        cf.addField(".", String.class);
+        cf.addField("buffy", int.class);
+        cf.addField("", int.class);
+
+        try
+        {
+            cf.createClass();
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertExceptionSubstring(ex, "Unable to create class InvalidField");
+        }
+
+        // Javassist lets us down here; I can't think of a way to get addField() to actually
+        // fail.
+    }
+
+    @Test
+    public void to_string() throws Exception
+    {
+        ClassFab cf = newClassFab("FredRunnable", BaseLocatable.class);
+
+        cf.addInterface(Runnable.class);
+        cf.addInterface(Serializable.class);
+
+        cf.addField("_map", Map.class);
+
+        cf.addConstructor(new Class[]
+        { Map.class, Runnable.class }, new Class[]
+        { IllegalArgumentException.class, DataFormatException.class }, "{ _map = $1; }");
+
+        MethodSignature sig = new MethodSignature(Map.class, "doTheNasty", new Class[]
+        { int.class, String.class }, new Class[]
+        { InstantiationException.class, IllegalAccessException.class });
+
+        cf.addMethod(
+                Modifier.PUBLIC + Modifier.FINAL + Modifier.SYNCHRONIZED,
+                sig,
+                "{ return _map; }");
+
+        String toString = cf.toString();
+
+        assertContains(
+                toString,
+                "public class FredRunnable extends org.apache.hivemind.impl.BaseLocatable\n"
+                        + "  implements java.lang.Runnable, java.io.Serializable");
+
+        assertContains(toString, "private java.util.Map _map;");
+
+        assertContains(
+                toString,
+                "public FredRunnable(java.util.Map $1, java.lang.Runnable $2)\n"
+                        + "  throws java.lang.IllegalArgumentException, java.util.zip.DataFormatException\n"
+                        + "{ _map = $1; }");
+
+        assertContains(
+                toString,
+                "public final synchronized java.util.Map doTheNasty(int $1, java.lang.String $2)\n"
+                        + "  throws java.lang.InstantiationException, java.lang.IllegalAccessException\n"
+                        + "{ return _map; }");
+
+    }
+
+    private void assertContains(String actual, String expectedSubstring)
+    {
+        assertTrue(actual.contains(expectedSubstring), "Missing substring: " + expectedSubstring);
+    }
+}

Copied: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/SimpleService.java (from r386879, jakarta/hivemind/trunk/framework/src/test/hivemind/test/services/SimpleService.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/SimpleService.java?p2=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/SimpleService.java&p1=jakarta/hivemind/trunk/framework/src/test/hivemind/test/services/SimpleService.java&r1=386879&r2=423984&rev=423984&view=diff
==============================================================================
--- jakarta/hivemind/trunk/framework/src/test/hivemind/test/services/SimpleService.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/SimpleService.java Thu Jul 20 09:50:22 2006
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package hivemind.test.services;
+package org.apache.tapestry.internal.ioc.services;
 
 /**
- * Basic service used for testing HiveMind.
- *
+ * Used by {@link org.apache.tapestry.internal.ioc.services.ClassFabImplTest}.
+ * 
  * @author Howard Lewis Ship
  */
 public interface SimpleService
 {
-	public int add(int a, int b);
+    public int add(int a, int b);
 }

Propchange: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/SimpleService.java
------------------------------------------------------------------------------
    cvs2svn:cvs-rev = 1.5

Propchange: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/SimpleService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/SimpleService.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java?rev=423984&r1=423983&r2=423984&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/InternalUtilsTest.java Thu Jul 20 09:50:22 2006
@@ -69,4 +69,19 @@
 
         assertEquals(InternalUtils.asString(m), "java.util.Arrays.sort(Object[])");
     }
+
+    @Test
+    public void array_size_when_null()
+    {
+        assertEquals(InternalUtils.size(null), 0);
+    }
+
+    @Test
+    public void array_size_when_non_null()
+    {
+        Object[] array =
+        { 1, 2, 3 };
+
+        assertEquals(InternalUtils.size(array), 3);
+    }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodIteratorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodIteratorTest.java?rev=423984&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodIteratorTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodIteratorTest.java Thu Jul 20 09:50:22 2006
@@ -0,0 +1,154 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.ioc.services;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+import org.apache.tapestry.test.BaseTestCase;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class MethodIteratorTest extends BaseTestCase
+{
+    static interface Play extends Runnable
+    {
+        public void jump();
+    }
+
+    static interface Runnable2
+    {
+        public void run();
+    }
+
+    static interface Runnable3 extends Runnable, Runnable2
+    {
+    }
+
+    static interface ToString
+    {
+        public String toString();
+    }
+
+    static interface Openable
+    {
+        public void open();
+    }
+
+    static interface OpenableWithError
+    {
+        public void open() throws IOException;
+    }
+
+    static interface CombinedOpeneable extends Openable, OpenableWithError
+    {
+    }
+
+    @Test
+    public void simple_interface()
+    {
+        MethodIterator mi = new MethodIterator(Runnable.class);
+
+        assertTrue(mi.hasNext());
+
+        MethodSignature actual = mi.next();
+
+        assertEquals(new MethodSignature(void.class, "run", null, null), actual);
+
+        assertFalse(mi.hasNext());
+
+        try
+        {
+            mi.next();
+        }
+        catch (NoSuchElementException ex)
+        {
+            //
+        }
+
+        assertEquals(false, mi.getToString());
+    }
+
+    @Test
+    public void inherited_methods_from_super_interface()
+    {
+        MethodIterator mi = new MethodIterator(Play.class);
+
+        assertTrue(mi.hasNext());
+
+        // Problematic because the order in which they are returned is
+        // JDK specific and not defined! Perhaps we should sort by alpha?
+
+        MethodSignature actual = mi.next();
+
+        assertEquals(new MethodSignature(void.class, "jump", null, null), actual);
+
+        assertTrue(mi.hasNext());
+
+        actual = mi.next();
+
+        assertEquals(new MethodSignature(void.class, "run", null, null), actual);
+
+        assertFalse(mi.hasNext());
+
+        assertEquals(false, mi.getToString());
+    }
+
+    @Test
+    public void duplicate_methods_filtered_out()
+    {
+        MethodIterator mi = new MethodIterator(Runnable3.class);
+
+        MethodSignature actual = mi.next();
+
+        assertEquals(new MethodSignature(void.class, "run", null, null), actual);
+
+        assertEquals(false, mi.getToString());
+    }
+
+    @Test
+    public void to_string_method_identified()
+    {
+        MethodIterator mi = new MethodIterator(ToString.class);
+
+        // Show that this is known immediately.
+
+        assertEquals(true, mi.getToString());
+
+        MethodSignature actual = mi.next();
+
+        assertEquals(new MethodSignature(String.class, "toString", null, null), actual);
+
+    }
+
+    @Test
+    public void inherited_methods_filtered_if_less_specific()
+    {
+        MethodIterator mi = new MethodIterator(CombinedOpeneable.class);
+
+        MethodSignature actual = mi.next();
+
+        assertEquals(new MethodSignature(void.class, "open", null, new Class[]
+        { IOException.class }), actual);
+
+        assertEquals(false, mi.hasNext());
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodSignatureTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodSignatureTest.java?rev=423984&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodSignatureTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/MethodSignatureTest.java Thu Jul 20 09:50:22 2006
@@ -0,0 +1,214 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.ioc.services;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+
+import org.apache.tapestry.test.BaseTestCase;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class MethodSignatureTest extends BaseTestCase
+{
+    private MethodSignature find(Class sourceClass, String methodName)
+    {
+        Method[] methods = sourceClass.getMethods();
+
+        for (int i = 0; i < methods.length; i++)
+        {
+            Method m = methods[i];
+
+            if (m.getName().equals(methodName))
+                return new MethodSignature(m);
+        }
+
+        unreachable();
+        return null;
+    }
+
+    @Test
+    public void excercize_equals_and_hashcode()
+    {
+        MethodSignature m1 = find(Object.class, "hashCode");
+        MethodSignature m2 = find(Boolean.class, "hashCode");
+
+        assertEquals(m1.hashCode(), m2.hashCode());
+        assertTrue(m1.equals(m2));
+
+        m1 = find(String.class, "charAt");
+        m2 = find(StringBuffer.class, "charAt");
+
+        assertEquals(m1.hashCode(), m2.hashCode());
+        assertTrue(m1.equals(m2));
+
+        m1 = find(ObjectInput.class, "close");
+        m2 = find(ObjectInputStream.class, "close");
+
+        assertEquals(m1.hashCode(), m2.hashCode());
+        assertTrue(m1.equals(m2));
+    }
+
+    @Test
+    public void equals_and_hashcode_with_null_parameters_and_exception_lists()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", null, null);
+        MethodSignature m2 = new MethodSignature(void.class, "foo", new Class[0], new Class[0]);
+
+        assertEquals(m1, m2);
+        assertEquals(m2, m1);
+
+        assertEquals(m1.hashCode(), m2.hashCode());
+    }
+
+    @Test
+    public void equals_with_name_mismatch()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", null, null);
+        MethodSignature m2 = new MethodSignature(void.class, "bar", null, null);
+
+        assertEquals(false, m1.equals(m2));
+    }
+
+    @Test
+    public void equals_with_parameters_mismatch()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", new Class[]
+        { String.class }, null);
+        MethodSignature m2 = new MethodSignature(void.class, "foo", new Class[]
+        { Boolean.class }, null);
+
+        assertEquals(false, m1.equals(m2));
+    }
+
+    @Test
+    public void equals_with_null()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", null, null);
+
+        assertEquals(m1.equals(null), false);
+    }
+
+    @Test
+    public void equals_with_not_method_signature()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", null, null);
+
+        assertEquals(m1.equals("Method Signature"), false);
+    }
+
+    @Test
+    public void to_string()
+    {
+        MethodSignature m = find(String.class, "getChars");
+
+        assertEquals(m.toString(), "void getChars(int, int, char[], int)");
+
+        m = find(Class.class, "newInstance");
+
+        assertEquals(
+                m.toString(),
+                "java.lang.Object newInstance() throws java.lang.InstantiationException, java.lang.IllegalAccessException");
+    }
+
+    @Test
+    public void unique_id()
+    {
+        MethodSignature m = find(String.class, "getChars");
+
+        assertEquals(m.getUniqueId(), "getChars(int,int,char[],int)");
+
+        m = find(Class.class, "newInstance");
+
+        assertEquals(m.getUniqueId(), "newInstance()");
+    }
+
+    @Test
+    public void overriding_signature_type_mismatch()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", null, null);
+        MethodSignature m2 = new MethodSignature(int.class, "foo", null, null);
+
+        assertEquals(m1.isOverridingSignatureOf(m2), false);
+    }
+
+    @Test
+    public void overriding_signature_name_mismatch()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", null, null);
+        MethodSignature m2 = new MethodSignature(void.class, "bar", null, null);
+
+        assertEquals(m1.isOverridingSignatureOf(m2), false);
+    }
+
+    @Test
+    public void overriding_signature_parameters_mismatch()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "foo", null, null);
+        MethodSignature m2 = new MethodSignature(void.class, "foo", new Class[]
+        { String.class }, null);
+
+        assertEquals(m1.isOverridingSignatureOf(m2), false);
+    }
+
+    @Test
+    public void overriding_signature()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "close", null, new Class[]
+        { Exception.class });
+        MethodSignature m2 = new MethodSignature(void.class, "close", null, new Class[]
+        { RuntimeException.class });
+
+        assertEquals(m1.isOverridingSignatureOf(m2), true);
+        assertEquals(m2.isOverridingSignatureOf(m1), false);
+    }
+
+    /**
+     * Tests a shorcut used when one signature has zero exceptions.
+     */
+    @Test
+    public void overriding_signature_with_no_exceptions()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "close", null, null);
+        MethodSignature m2 = new MethodSignature(void.class, "close", null, new Class[]
+        { RuntimeException.class });
+
+        assertEquals(m1.isOverridingSignatureOf(m2), false);
+        assertEquals(m2.isOverridingSignatureOf(m1), true);
+    }
+
+    /**
+     * Fill in code coverage for multiple matched signatures.
+     */
+    @Test
+    public void overriding_signature_with_multiple_matched_exceptions()
+    {
+        MethodSignature m1 = new MethodSignature(void.class, "close", null, new Class[]
+        { SQLException.class, NumberFormatException.class });
+        MethodSignature m2 = new MethodSignature(void.class, "close", null, new Class[]
+        { SQLException.class, IOException.class });
+
+        assertEquals(m1.isOverridingSignatureOf(m2), false);
+        assertEquals(m2.isOverridingSignatureOf(m1), false);
+    }
+}