[easymock] 38/41: Imported Upstream version 2.4+ds1

Markus Koschany apo-guest at moszumanska.debian.org
Tue Nov 25 16:49:13 GMT 2014


This is an automated email from the git hooks/post-receive script.

apo-guest pushed a commit to branch master
in repository easymock.

commit 560caa535956cea8e8f34c20d570524d93ececae
Author: Markus Koschany <apo at gambaru.de>
Date:   Tue Nov 25 17:48:02 2014 +0100

    Imported Upstream version 2.4+ds1
---
 Documentation.html                                 |  993 ++++++++++++
 Documentation_fr.html                              | 1042 +++++++++++++
 License.html                                       |   33 +
 easymock.css                                       |   55 +
 samples/org/easymock/samples/ClassUnderTest.java   |   93 ++
 samples/org/easymock/samples/Collaborator.java     |   17 +
 samples/org/easymock/samples/ExampleTest.java      |  116 ++
 samples/org/easymock/samples/ThrowableEquals.java  |   40 +
 src/org/easymock/AbstractMatcher.java              |  125 ++
 src/org/easymock/ArgumentsMatcher.java             |   42 +
 src/org/easymock/Capture.java                      |   67 +
 src/org/easymock/EasyMock.java                     | 1632 ++++++++++++++++++++
 src/org/easymock/IAnswer.java                      |   23 +
 src/org/easymock/IArgumentMatcher.java             |   36 +
 src/org/easymock/IExpectationSetters.java          |  115 ++
 src/org/easymock/IMocksControl.java                |   75 +
 src/org/easymock/LogicalOperator.java              |   48 +
 src/org/easymock/MockControl.java                  |  597 +++++++
 src/org/easymock/internal/AlwaysMatcher.java       |   21 +
 src/org/easymock/internal/ArrayMatcher.java        |   24 +
 .../easymock/internal/AssertionErrorWrapper.java   |   20 +
 src/org/easymock/internal/EqualsMatcher.java       |   13 +
 src/org/easymock/internal/ExpectedInvocation.java  |  122 ++
 .../internal/ExpectedInvocationAndResult.java      |   30 +
 .../internal/ExpectedInvocationAndResults.java     |   35 +
 .../easymock/internal/ILegacyMatcherMethods.java   |   16 +
 src/org/easymock/internal/ILegacyMethods.java      |   13 +
 src/org/easymock/internal/IMocksBehavior.java      |   27 +
 src/org/easymock/internal/IMocksControlState.java  |   38 +
 src/org/easymock/internal/IProxyFactory.java       |   11 +
 src/org/easymock/internal/Invocation.java          |  168 ++
 src/org/easymock/internal/JavaProxyFactory.java    |   16 +
 src/org/easymock/internal/LastControl.java         |  110 ++
 .../easymock/internal/LegacyMatcherProvider.java   |   56 +
 .../internal/MethodSerializationWrapper.java       |   66 +
 .../easymock/internal/MockInvocationHandler.java   |   41 +
 src/org/easymock/internal/MocksBehavior.java       |  162 ++
 src/org/easymock/internal/MocksControl.java        |  279 ++++
 src/org/easymock/internal/ObjectMethodsFilter.java |   98 ++
 src/org/easymock/internal/Range.java               |   73 +
 src/org/easymock/internal/RecordState.java         |  346 +++++
 src/org/easymock/internal/ReplayState.java         |  132 ++
 src/org/easymock/internal/Result.java              |   69 +
 src/org/easymock/internal/Results.java             |   78 +
 .../easymock/internal/RuntimeExceptionWrapper.java |   20 +
 src/org/easymock/internal/ThrowableWrapper.java    |   20 +
 src/org/easymock/internal/UnorderedBehavior.java   |   95 ++
 src/org/easymock/internal/matchers/And.java        |   42 +
 src/org/easymock/internal/matchers/Any.java        |   28 +
 .../easymock/internal/matchers/ArrayEquals.java    |   81 +
 src/org/easymock/internal/matchers/Captures.java   |   31 +
 src/org/easymock/internal/matchers/Compare.java    |   42 +
 .../easymock/internal/matchers/CompareEqual.java   |   24 +
 src/org/easymock/internal/matchers/CompareTo.java  |   38 +
 src/org/easymock/internal/matchers/Contains.java   |   29 +
 src/org/easymock/internal/matchers/EndsWith.java   |   28 +
 src/org/easymock/internal/matchers/Equals.java     |   61 +
 .../internal/matchers/EqualsWithDelta.java         |   35 +
 src/org/easymock/internal/matchers/Find.java       |   30 +
 .../easymock/internal/matchers/GreaterOrEqual.java |   24 +
 .../easymock/internal/matchers/GreaterThan.java    |   24 +
 src/org/easymock/internal/matchers/InstanceOf.java |   28 +
 .../easymock/internal/matchers/LessOrEqual.java    |   24 +
 src/org/easymock/internal/matchers/LessThan.java   |   24 +
 src/org/easymock/internal/matchers/Matches.java    |   29 +
 src/org/easymock/internal/matchers/Not.java        |   30 +
 src/org/easymock/internal/matchers/NotNull.java    |   28 +
 src/org/easymock/internal/matchers/Null.java       |   27 +
 src/org/easymock/internal/matchers/Or.java         |   42 +
 src/org/easymock/internal/matchers/Same.java       |   40 +
 src/org/easymock/internal/matchers/StartsWith.java |   29 +
 tests/org/easymock/tests/ArgumentsMatcherTest.java |  143 ++
 tests/org/easymock/tests/ArrayMatcherTest.java     |  108 ++
 tests/org/easymock/tests/CapturesMatcherTest.java  |   37 +
 tests/org/easymock/tests/DefaultMatcherTest.java   |   94 ++
 tests/org/easymock/tests/EqualsMatcherTest.java    |   33 +
 .../org/easymock/tests/ExpectedMethodCallTest.java |   37 +
 tests/org/easymock/tests/IMethods.java             |   88 ++
 tests/org/easymock/tests/IVarArgs.java             |   27 +
 tests/org/easymock/tests/InvocationTest.java       |   87 ++
 tests/org/easymock/tests/LegacyBehaviorTests.java  |   66 +
 .../org/easymock/tests/MatchableArgumentsTest.java |   45 +
 .../tests/MethodSerializationWrapperTest.java      |   24 +
 tests/org/easymock/tests/MockNameTest.java         |   24 +
 ...ceMockControlLongCompatibleReturnValueTest.java |   56 +
 tests/org/easymock/tests/NiceMockControlTest.java  |   49 +
 tests/org/easymock/tests/ObjectMethodsTest.java    |   81 +
 .../RecordStateInvalidDefaultReturnValueTest.java  |   91 ++
 .../RecordStateInvalidDefaultThrowableTest.java    |   81 +
 .../tests/RecordStateInvalidMatcherTest.java       |   75 +
 .../tests/RecordStateInvalidRangeTest.java         |   74 +
 .../tests/RecordStateInvalidReturnValueTest.java   |  147 ++
 .../tests/RecordStateInvalidStateChangeTest.java   |   66 +
 .../tests/RecordStateInvalidThrowableTest.java     |   81 +
 .../tests/RecordStateInvalidUsageTest.java         |  157 ++
 .../tests/RecordStateMethodCallMissingTest.java    |  302 ++++
 .../tests/ReplayStateInvalidCallsTest.java         |  139 ++
 .../tests/ReplayStateInvalidUsageTest.java         |  473 ++++++
 tests/org/easymock/tests/ResultTest.java           |   24 +
 tests/org/easymock/tests/StacktraceTest.java       |   83 +
 tests/org/easymock/tests/UsageCallCountTest.java   |  133 ++
 .../tests/UsageDefaultReturnValueTest.java         |  126 ++
 .../tests/UsageExpectAndDefaultReturnTest.java     |   76 +
 .../tests/UsageExpectAndDefaultThrowTest.java      |  156 ++
 .../easymock/tests/UsageExpectAndReturnTest.java   |  199 +++
 .../easymock/tests/UsageExpectAndThrowTest.java    |  387 +++++
 .../tests/UsageFloatingPointReturnValueTest.java   |   54 +
 .../tests/UsageLongCompatibleReturnValueTest.java  |   99 ++
 .../tests/UsageOverloadedDefaultValueTest.java     |  112 ++
 .../easymock/tests/UsageOverloadedMethodTest.java  |  165 ++
 tests/org/easymock/tests/UsageRangeTest.java       |  106 ++
 tests/org/easymock/tests/UsageStrictMockTest.java  |  239 +++
 tests/org/easymock/tests/UsageTest.java            |  217 +++
 tests/org/easymock/tests/UsageThrowableTest.java   |  143 ++
 tests/org/easymock/tests/UsageUnorderedTest.java   |   49 +
 tests/org/easymock/tests/UsageVarargTest.java      |  149 ++
 tests/org/easymock/tests/UsageVerifyTest.java      |  154 ++
 tests/org/easymock/tests/Util.java                 |   16 +
 tests/org/easymock/tests2/AnswerTest.java          |  148 ++
 .../easymock/tests2/CallbackAndArgumentsTest.java  |   86 ++
 tests/org/easymock/tests2/CallbackTest.java        |   87 ++
 tests/org/easymock/tests2/CaptureTest.java         |  158 ++
 tests/org/easymock/tests2/CompareToTest.java       |   79 +
 .../easymock/tests2/ConstraintsToStringTest.java   |  147 ++
 tests/org/easymock/tests2/NameTest.java            |   75 +
 tests/org/easymock/tests2/NiceMockTest.java        |   47 +
 tests/org/easymock/tests2/SerializationTest.java   |   49 +
 tests/org/easymock/tests2/StubTest.java            |   72 +
 tests/org/easymock/tests2/ThreadingTest.java       |   91 ++
 .../org/easymock/tests2/UsageConstraintsTest.java  |  641 ++++++++
 tests/org/easymock/tests2/UsageMatchersTest.java   |   22 +
 tests/org/easymock/tests2/UsageStrictMockTest.java |  200 +++
 tests/org/easymock/tests2/UsageTest.java           |  305 ++++
 133 files changed, 15745 insertions(+)

diff --git a/Documentation.html b/Documentation.html
new file mode 100644
index 0000000..640acfa
--- /dev/null
+++ b/Documentation.html
@@ -0,0 +1,993 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />	
+<title>EasyMock 2.4 Readme</title>
+<link rel="stylesheet" href="easymock.css" />
+</head>
+<body><div class="bodywidth">
+
+<h2>EasyMock 2.4 Readme</h2>
+ 
+<p>Documentation for release 2.4 (July 2 2008)<br />
+© 2001-2008 <a href="http://www.offis.de" title="OFFIS">OFFIS</a>, <a href="http://tammofreese.de" id="id" title="Tammo Freese">Tammo Freese</a>.
+</p>
+<p>
+EasyMock 2 is a library that provides an easy way to use Mock Objects for given
+interfaces. EasyMock 2 is available under the terms of the <a href="License.html">MIT license</a>.
+</p>
+<p>
+Mock Objects simulate parts of the behavior of domain code,
+and are able to check whether they are used as defined.
+Domain classes can be tested in isolation
+by simulating their collaborators with Mock Objects.
+</p>
+<p>
+Writing and maintaining Mock Objects often is a tedious
+task that may introduce errors. EasyMock 2 generates Mock Objects
+dynamically - no need to write them, and no generated code!
+</p>
+<h3>
+EasyMock 2 Benefits
+</h3>
+<ul>
+<li>Hand-writing classes for Mock Objects is not needed.
+</li>
+<li>Supports refactoring-safe Mock Objects: test code will not break at runtime when renaming methods or reordering method parameters
+</li>
+<li>Supports return values and exceptions.
+</li>
+<li>Supports checking the order of method calls, for one or more Mock Objects.
+</li>
+</ul>
+<h3>EasyMock 2 Drawbacks
+</h3>
+<ul>
+<li>EasyMock 2 does only work with Java 2 Version 5.0 and above.
+</li>
+</ul>
+<p>
+EasyMock by default supports the generation of Mock Objects
+for interfaces only. For those who would like to generate
+Mock Objects for classes, there is an extension
+available at the EasyMock home page.
+</p>
+<h2>
+Installation
+</h2>
+<ol>
+<li>Java 2 (at least 5.0) is required.
+</li>
+<li>Unzip the EasyMock zip file (<code>easymock2.4.zip</code>). It contains a directory
+<code>easymock2.4</code>. Add the EasyMock jar file (<code>easymock.jar</code>) from this directory to your
+classpath.
+</li>
+</ol>
+<p>
+To execute the EasyMock tests, add <code>tests.zip</code> and the JUnit 4.1 jar 
+to your class path and start
+<code>'java org.easymock.tests.AllTests'</code>.
+</p>
+<p>
+The source code of EasyMock is stored in the zip file <code>src.zip</code>.
+</p>
+<h2>
+Usage
+</h2>
+<p>
+Most parts of a software system do not work in isolation, but collaborate
+with other parts to get their job done. In a lot of cases, we do not care
+about using collaborators in unit testing, as we trust these collaborators.
+If we <em>do</em> care about it, Mock Objects help us to test the unit under test
+in isolation. Mock Objects replace collaborators of the unit under
+test.
+</p>
+<p>
+The following examples use the interface <code>Collaborator</code>:
+</p>
+<pre>
+package org.easymock.samples;
+
+public interface Collaborator {
+    void documentAdded(String title);
+    void documentChanged(String title);
+    void documentRemoved(String title);
+    byte voteForRemoval(String title);
+    byte[] voteForRemovals(String[] title);
+}
+</pre>
+<p>
+Implementors of this interface are collaborators 
+(in this case listeners) of a class named <code>ClassUnderTest</code>:
+</p>
+<pre>
+public class ClassUnderTest {
+    // ...    
+    public void addListener(Collaborator listener) {
+        // ... 
+    }
+    public void addDocument(String title, byte[] document) { 
+        // ... 
+    }
+    public boolean removeDocument(String title) {
+        // ... 
+    }
+    public boolean removeDocuments(String[] titles) {
+        // ... 
+    }
+}
+</pre>
+<p>
+The code for both the class and the interface may be found 
+in the package
+<code>org.easymock.samples</code> in <code>samples.zip</code>.
+</p>
+<p>
+The following examples assume that you are familiar with the JUnit testing framework.
+Although the tests shown here use JUnit in version 3.8.1, you may as well use JUnit 4 or TestNG.
+</p>
+<h3>
+The first Mock Object
+</h3>
+<p>
+We will now build a test case and toy around with it to understand the
+functionality of the EasyMock package. <code>samples.zip</code>
+contains a modified version of this test. Our first test should check
+whether the removal of a non-existing document does <strong>not </strong> lead to a notification
+of the collaborator. Here is the test without the definition of the
+Mock Object:
+</p>
+<pre>
+package org.easymock.samples;
+
+import junit.framework.TestCase;
+
+public class ExampleTest extends TestCase {
+
+    private ClassUnderTest classUnderTest;
+    private Collaborator mock;
+
+    protected void setUp() {
+        classUnderTest = new ClassUnderTest();
+        classUnderTest.addListener(mock);
+    }
+
+    public void testRemoveNonExistingDocument() {    
+        // This call should not lead to any notification
+        // of the Mock Object: 
+        classUnderTest.removeDocument("Does not exist");
+    }
+}
+</pre>
+<p>
+For many tests using EasyMock 2, 
+we only need a static import of methods of <code>org.easymock.EasyMock</code>.
+This is the only non-internal, non-deprecated class of EasyMock 2. 
+</p>
+<pre>
+import static org.easymock.EasyMock.*;
+import junit.framework.TestCase;
+
+public class ExampleTest extends TestCase {
+
+    private ClassUnderTest classUnderTest;
+    private Collaborator mock;
+    
+}    
+</pre>
+<p>
+To get a Mock Object, we need to
+</p>
+<ol>
+<li>create a Mock Object for the interface we would like to simulate,
+</li>
+<li>record the expected behavior, and
+</li>
+<li>switch the Mock Object to replay state.
+</li>
+</ol>
+<p>
+Here is a first example:
+</p>
+<pre>
+    protected void setUp() {
+        mock = createMock(Collaborator.class); // 1
+        classUnderTest = new ClassUnderTest();
+        classUnderTest.addListener(mock);
+    }
+
+    public void testRemoveNonExistingDocument() {
+        // 2 (we do not expect anything)
+        replay(mock); // 3
+        classUnderTest.removeDocument("Does not exist");
+    }
+</pre>
+<p>
+After activation in step 3, <code>mock</code>
+is a Mock Object for the <code>Collaborator</code>
+interface that expects no calls. This means that if we change
+our <code>ClassUnderTest</code> to call
+any of the interface's methods, the Mock Object will throw
+an <code>AssertionError</code>:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentRemoved("Does not exist"):
+    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+    at $Proxy0.documentRemoved(Unknown Source)
+    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)
+    at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)
+    at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)
+    ...
+</pre>
+
+<h3>
+   Adding Behavior
+</h3>
+<p>
+Let us write a second test. If a document
+is added on the class under test, we expect a call to <code>mock.documentAdded()</code>
+on the Mock Object with the title of the document as argument:
+</p>
+<pre>
+    public void testAddDocument() {
+        mock.documentAdded("New Document"); // 2
+        replay(mock); // 3
+        classUnderTest.addDocument("New Document", new byte[0]); 
+    }
+</pre>
+<p>
+So in the record state (before calling <code>replay</code>),
+the Mock Object does <em>not</em> behave like a Mock Object,
+but it records method calls. After calling <code>replay</code>,
+it behaves like a Mock Object, checking whether the expected
+method calls are really done.
+</p>
+<p>
+If <code>classUnderTest.addDocument("New Document", new byte[0])</code>
+calls the expected method with a wrong argument, the Mock Object will complain
+with an <code>AssertionError</code>:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentAdded("Wrong title"):
+    documentAdded("New Document"): expected: 1, actual: 0
+    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+    at $Proxy0.documentAdded(Unknown Source)
+    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)
+    at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)
+    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
+    ...
+</pre>
+<p>
+All missed expectations are shown, as well as all fulfilled
+expectations for the unexpected call (none in this case). If the method
+call is executed too often, the Mock Object complains, too:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentAdded("New Document"):
+    documentAdded("New Document"): expected: 1, actual: 1 (+1)
+    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+    at $Proxy0.documentAdded(Unknown Source)
+    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)
+    at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)
+    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
+    ...
+</pre>
+<h3>
+Verifying Behavior
+</h3>
+<p>
+There is one error that we have not handled so far: If we specify
+behavior, we would like to verify that it is actually used. The current
+test would pass if no method on the Mock Object is called. To verify that the
+specified behavior has been used, we have to call
+<code>verify(mock)</code>:
+</p>
+<pre>
+    public void testAddDocument() {
+        mock.documentAdded("New Document"); // 2 
+        replay(mock); // 3
+        classUnderTest.addDocument("New Document", new byte[0]);
+        verify(mock);
+    }
+</pre>
+<p>
+If the method is not called on the Mock Object, we now get the 
+following exception:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Expectation failure on verify:
+    documentAdded("New Document"): expected: 1, actual: 0
+    at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
+    at org.easymock.EasyMock.verify(EasyMock.java:536)
+    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:31)
+    ...
+</pre>
+<p>
+The message of the exception lists all missed expectations.
+</p>
+<h3>
+Expecting an Explicit Number of Calls
+</h3>
+<p>
+Up to now, our test has only considered a single method call. The next
+test should check whether the addition of an already existing
+document leads to a call to <code>mock.documentChanged()</code>
+with the appropriate argument. To be sure, we check this three
+times (hey, it is an example ;-)):
+</p>
+<pre>
+    public void testAddAndChangeDocument() {
+        mock.documentAdded("Document");
+        mock.documentChanged("Document");
+        mock.documentChanged("Document");
+        mock.documentChanged("Document");
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        verify(mock);
+    }
+</pre>
+<p>
+To avoid the repetition of <code>mock.documentChanged("Document")</code>,
+EasyMock provides a shortcut. We may specify the call count with the method
+<code>times(int times)</code> on the object returned by 
+<code>expectLastCall()</code>. The code then looks like:
+</p>
+<pre>
+    public void testAddAndChangeDocument() {
+        mock.documentAdded("Document");
+        mock.documentChanged("Document");
+        expectLastCall().times(3);
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        verify(mock);
+    }
+</pre>
+<p>
+If the method is called too often, we get an exception that
+tells us that the method has been called too many times.
+The failure occurs immediately at the first method call
+exceeding the limit:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentChanged("Document"):
+    documentChanged("Document"): expected: 3, actual: 3 (+1)
+	at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+	at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+	at $Proxy0.documentChanged(Unknown Source)
+	at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged(ClassUnderTest.java:67)
+	at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:26)
+	at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
+    ...
+</pre>
+<p>
+If there are too few calls, <code>verify(mock)</code> 
+throws an <code>AssertionError</code>:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Expectation failure on verify:
+    documentChanged("Document"): expected: 3, actual: 2
+	at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
+	at org.easymock.EasyMock.verify(EasyMock.java:536)
+	at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
+    ...
+</pre>
+<h3>
+Specifying Return Values
+</h3>
+<p>
+For specifying return values, 
+we wrap the expected call in <code>expect(T value)</code> and specify the return value
+with the method <code>andReturn(Object returnValue)</code> on the object returned by
+<code>expect(T value)</code>.
+</p>
+<p>
+As an example, we check the workflow for document
+removal. If <code>ClassUnderTest</code> gets a call for document
+removal, it asks all collaborators for their vote for removal
+with calls to <code>byte voteForRemoval(String title)</code> value.
+Positive return values are a vote for
+removal. If the sum of all values is positive, the document is removed
+and <code>documentRemoved(String title)</code> is called on
+all collaborators:
+</p>
+<pre>
+    public void testVoteForRemoval() {
+        mock.documentAdded("Document");   // expect document addition
+        // expect to be asked to vote for document removal, and vote for it
+        expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
+        mock.documentRemoved("Document"); // expect document removal
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        assertTrue(classUnderTest.removeDocument("Document"));
+        verify(mock);
+    }
+
+    public void testVoteAgainstRemoval() {
+        mock.documentAdded("Document");   // expect document addition
+        // expect to be asked to vote for document removal, and vote against it
+        expect(mock.voteForRemoval("Document")).andReturn((byte) -42);
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        assertFalse(classUnderTest.removeDocument("Document"));
+        verify(mock);
+    }
+</pre>
+<p>
+The type of the returned value is checked at compile time. As an example,
+the following code will not compile, as the type of the provided return value
+does not match the method's return value:
+</p>
+<pre>
+    expect(mock.voteForRemoval("Document")).andReturn("wrong type");
+</pre>
+<p>
+Instead of calling <code>expect(T value)</code>
+to retrieve the object for setting the return value, 
+we may also use the object returned by <code>expectLastCall()</code>.
+Instead of 
+</p>
+<pre>
+    expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
+</pre>
+<p>
+we may use
+</p>
+<pre>
+    mock.voteForRemoval("Document");
+    expectLastCall().andReturn((byte) 42);
+</pre>
+<p>
+This type of specification should only be used if the line gets too long, 
+as it does not support type checking at compile time. 
+</p>
+<h3>
+Working with Exceptions
+</h3>
+<p>
+For specifying exceptions (more exactly: Throwables) to be thrown, the object returned by
+<code>expectLastCall()</code> and <code>expect(T value)</code> provides the method
+<code>andThrow(Throwable throwable)</code>.
+The method has to be called in record state after the call to the Mock Object for 
+which it specifies the <code>Throwable</code> to be thrown.
+</p>
+<p>
+Unchecked exceptions (that is, <code>RuntimeException</code>, <code>Error</code>
+and all their subclasses) can be thrown from every method. Checked exceptions can only be
+thrown from the methods that do actually throw them.
+</p>
+<h3>
+Creating Return Values or Exceptions
+</h3>
+<p>
+Sometimes we would like our mock object to return a value or throw an exception
+that is created at the time of the actual call. Since EasyMock 2.2, the object returned by
+<code>expectLastCall()</code> and <code>expect(T value)</code> provides the method
+<code>andAnswer(IAnswer answer)</code> which allows to specify an implementation of the
+interface <code>IAnswer</code> that is used to create the return value or exception.
+</p>
+<p>
+Inside an <code>IAnswer</code> callback, the arguments passed to the mock call 
+are available via <code>EasyMock.getCurrentArguments()</code>.
+If you use these, refactorings like reordering parameters may break your tests. 
+You have been warned.
+</p>
+<h3>
+Changing Behavior for the Same Method Call
+</h3>
+<p>
+It is also possible to specify a changing behavior for a method.
+The methods <code>times</code>, <code>andReturn</code>, and <code>andThrow</code>
+may be chained. As an example, we define <code>voteForRemoval("Document")</code> to
+</p>
+<ul>
+<li>return 42 for the first three calls,
+</li>
+<li>throw a <code>RuntimeException</code> for the next four calls,
+</li>
+<li>return -42 once.
+</li>
+</ul>
+<pre>
+    expect(mock.voteForRemoval("Document"))
+        .andReturn((byte) 42).times(3)
+        .andThrow(new RuntimeException(), 4)
+        .andReturn((byte) -42);
+</pre>
+<h3>
+Relaxing Call Counts
+</h3>
+<p>
+To relax the expected call counts, there are additional methods
+that may be used instead of <code>times(int count)</code>:
+</p>
+<dl>
+<dt><code>times(int min, int max)</code></dt> 
+<dd>to expect between <code>min</code> and <code>max</code> calls,</dd>
+<dt><code>atLeastOnce()</code></dt>
+<dd>to expect at least one call, and</dd>
+<dt><code>anyTimes()</code></dt>
+<dd>to expected an unrestricted number of calls.</dd>
+</dl>
+<p>
+If no call count is specified, one call is expected. If we would like to state this
+explicitely, <code>once()</code> or <code>times(1)</code> may be used.
+</p>
+<h3>
+Strict Mocks
+</h3>
+<p>
+On a Mock Object returned by a <code>EasyMock.createMock()</code>,
+the order of method calls is not checked.
+If you would like a strict Mock Object that checks the order of method calls,
+use <code>EasyMock.create<i>Strict</i>Mock()</code> to create it.</p>
+<p>
+If an unexpected method is called on a strict Mock Object,
+the message of the exception will show the method calls
+expected at this point followed by the first conflicting one. 
+<code>verify(mock)</code> shows all missing method calls.
+</p>
+<h3>
+Switching Order Checking On and Off
+</h3>
+<p>
+Sometimes, it is necessary to have a Mock Object that checks the order of only some calls.
+In record phase, you may switch order checking on by calling <code>checkOrder(mock, true)</code>
+and switch it off by calling <code>checkOrder(mock, false)</code>.
+</p>
+<p>
+There are two differences between a strict Mock Object and a normal Mock Object:
+</p>
+<ol>
+	<li> A strict Mock Object has order checking enabled after creation. </li>
+	<li> A strict Mock Object has order checking enabled after reset (see <em>Reusing a Mock Object</em>). </li>
+</ol>
+<h3>
+Flexible Expectations with Argument Matchers
+</h3>
+<p>
+To match an actual method call on the Mock Object with an 
+expectation, <code>Object</code> arguments are by default compared with
+<code>equals()</code>. This may lead to problems. As an example,
+we consider the following expectation:
+</p>
+<pre>
+String[] documents = new String[] { "Document 1", "Document 2" };
+expect(mock.voteForRemovals(documents)).andReturn(42);
+</pre>
+<p>
+If the method is called with another array with the same contents,
+we get an exception, as <code>equals()</code> compares object
+identity for arrays: 
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call voteForRemovals([Ljava.lang.String;@9a029e):
+    voteForRemovals([Ljava.lang.String;@2db19d): expected: 1, actual: 0
+    documentRemoved("Document 1"): expected: 1, actual: 0
+    documentRemoved("Document 2"): expected: 1, actual: 0
+	at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+	at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+	at $Proxy0.voteForRemovals(Unknown Source)
+	at org.easymock.samples.ClassUnderTest.listenersAllowRemovals(ClassUnderTest.java:88)
+	at org.easymock.samples.ClassUnderTest.removeDocuments(ClassUnderTest.java:48)
+	at org.easymock.samples.ExampleTest.testVoteForRemovals(ExampleTest.java:83)
+    ...
+</pre>
+<p>
+To specify that only array equality is needed for this call, we may use the method
+<code>aryEq</code> that is statically imported from the <code>EasyMock</code> class:
+</p>
+<pre>
+String[] documents = new String[] { "Document 1", "Document 2" };
+expect(mock.voteForRemovals(aryEq(documents))).andReturn(42);
+</pre>
+<p>
+If you would like to use matchers in a call, you have to specify matchers for all
+arguments of the method call. 
+</p>
+<p>
+There are a couple of predefined argument matchers available.
+</p>
+<dl>
+
+<dt><code>eq(X value)</code></dt>
+<dd>Matches if the actual value is equals the expected value. Available for all primitive types and for objects.</dd>
+
+<dt><code>anyBoolean()</code>, <code>anyByte()</code>, <code>anyChar()</code>, <code>anyDouble()</code>, <code>anyFloat()</code>, <code>anyInt()</code>, <code>anyLong()</code>, <code>anyObject()</code>, <code>anyShort()</code></dt>
+<dd>Matches any value. Available for all primitive types and for objects.</dd>
+
+<dt><code>eq(X value, X delta)</code></dt>
+<dd>Matches if the actual value is equal to the given value allowing the given delta. Available for <code>float</code> and <code>double</code>.</dd>
+
+<dt><code>aryEq(X value)</code></dt>
+<dd>Matches if the actual value is equal to the given value according to <code>Arrays.equals()</code>. Available for primitive and object arrays.</dd>
+
+<dt><code>isNull()</code></dt>
+<dd>Matches if the actual value is null. Available for objects.</dd>
+
+<dt><code>notNull()</code></dt>
+<dd>Matches if the actual value is not null. Available for objects.</dd>
+
+<dt><code>same(X value)</code></dt>
+<dd>Matches if the actual value is the same as the given value. Available for objects.</dd>
+
+<dt><code>isA(Class clazz)</code></dt>
+<dd>Matches if the actual value is an instance of the given class, or if it is in instance of a class that extends or implements the given class. Null always return false. Available for objects.</dd>
+
+<dt><code>lt(X value)</code>, <code>leq(X value)</code>, <code>geq(X value)</code>, <code>gt(X value)</code></dt>
+<dd>Matches if the actual value is less/less or equal/greater or equal/greater than the given value. Available for all numeric primitive types and <code>Comparable</code>.</dd>
+
+<dt><code>startsWith(String prefix), contains(String substring), endsWith(String suffix)</code></dt>
+<dd>Matches if the actual value starts with/contains/ends with the given value. Available for <code>String</code>s.</dd>
+
+<dt><code>matches(String regex), find(String regex)</code></dt>
+<dd>Matches if the actual value/a substring of the actual value matches the given regular expression. Available for <code>String</code>s.</dd>
+
+<dt><code>and(X first, X second)</code></dt>
+<dd>Matches if the matchers used in <code>first</code> and <code>second</code> both match. Available for all primitive types and for objects.</dd>
+
+<dt><code>or(X first, X second)</code></dt>
+<dd>Matches if one of the matchers used in <code>first</code> and <code>second</code> match. Available for all primitive types and for objects.</dd>
+
+<dt><code>not(X value)</code></dt>
+<dd>Matches if the matcher used in <code>value</code> does not match.</dd>
+
+<dt><code>cmpEq(X value)</code></dt>
+<dd>Matches if the actual value is equals according to <code>Comparable.compareTo(X o)</code>. Available for all numeric primitive types and <code>Comparable</code>.</dd>
+
+<dt><code>cmp(X value, Comparator<X> comparator, LogicalOperator operator)</code></dt>
+<dd>Matches if <code>comparator.compare(actual, value) operator 0</code> where the operator is <,<=,>,>= or ==. Available for objects.</dd>
+
+<dt><code>capture(Capture<T> capture)</code></dt>
+<dd>Matches any value but captures it in the <code>Capture</code> parameter for later access. You can do <code>and(someMatcher(...), capture(c))</code> to 
+capture a parameter from a specific call to the method.</dd>
+
+</dl>
+
+<h3>
+Defining your own Argument Matchers
+</h3>
+<p>
+Sometimes it is desirable to define own argument matchers. Let's say that an
+argument matcher is needed that matches an exception if the given exception has the same type and an equal message.
+It should be used this way:
+</p>
+<pre>
+    IllegalStateException e = new IllegalStateException("Operation not allowed.")
+    expect(mock.logThrowable(eqException(e))).andReturn(true);
+</pre>
+<p>
+Two steps are necessary to achieve this: The new argument matcher has to be defined,
+and the static method <code>eqException</code> has to be declared.
+</p>
+<p>
+To define the new argument matcher, we implement the interface <code>org.easymock.IArgumentMatcher</code>.
+This interface contains two methods: <code>matches(Object actual)</code> checks whether the actual argument
+matches the given argument, and <code>appendTo(StringBuffer buffer)</code> appends a string representation
+of the argument matcher to the given string buffer. The implementation is straightforward:
+</p>
+<pre>
+import org.easymock.IArgumentMatcher;
+
+public class ThrowableEquals implements IArgumentMatcher {
+    private Throwable expected;
+
+    public ThrowableEquals(Throwable expected) {
+        this.expected = expected;
+    }
+
+    public boolean matches(Object actual) {
+        if (!(actual instanceof Throwable)) {
+            return false;
+        }
+        String actualMessage = ((Throwable) actual).getMessage();
+        return expected.getClass().equals(actual.getClass())
+                && expected.getMessage().equals(actualMessage);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("eqException(");
+        buffer.append(expected.getClass().getName());
+        buffer.append(" with message \"");
+        buffer.append(expected.getMessage());
+        buffer.append("\"")");
+
+    }
+}
+</pre>
+<p>
+The method <code>eqException</code> must create the argument matcher with the given Throwable,
+report it to EasyMock via the static method <code>reportMatcher(IArgumentMatcher matcher)</code>, 
+and return a value so that it may be used inside the call 
+(typically <code>0</code>, <code>null</code> or <code>false</code>). A first attempt may look like:
+</p>
+<pre>
+public static Throwable eqException(Throwable in) {
+    EasyMock.reportMatcher(new ThrowableEquals(in));
+    return null;
+}
+</pre>
+<p>
+However, this only works if the method <code>logThrowable</code> in the example usage accepts 
+<code>Throwable</code>s, and does not require something more specific like a <code>RuntimeException</code>.
+In the latter case, our code sample would not compile:
+</p>
+<pre>
+    IllegalStateException e = new IllegalStateException("Operation not allowed.")
+    expect(mock.logThrowable(eqException(e))).andReturn(true);
+</pre>
+<p>
+Java 5.0 to the rescue: Instead of defining <code>eqException</code> with a <code>Throwable</code> as
+parameter and return value, we use a generic type that extends <code>Throwable</code>: 
+</p>
+<pre>
+public static <T extends Throwable> T eqException(T in) {
+    reportMatcher(new ThrowableEquals(in));
+    return null;
+}
+</pre>
+<h3>
+Reusing a Mock Object
+</h3>
+<p>
+Mock Objects may be reset by <code>reset(mock)</code>.
+</p>
+<p>
+If needed, a mock can also be converted from one type to another by calling <code>resetToNice(mock)</code>, 
+<code>resetToDefault(mock)</code> ou <code>resetToStrict(mock)</code>.
+</p>
+<h3>
+Using Stub Behavior for Methods
+</h3>
+<p>
+Sometimes, we would like our Mock Object to respond to some method calls, but we do not want to
+check how often they are called, when they are called, or even if they are called at all.
+This stub behavoir may be defined by using the methods <code>andStubReturn(Object value)</code>, 
+<code>andStubThrow(Throwable throwable)</code>, <code>andStubAnswer(IAnswer<Tgt; answer)</code>
+and <code>asStub()</code>. The following code 
+configures the MockObject to answer 42 to <code>voteForRemoval("Document")</code> once
+and -1 for all other arguments:
+</p>
+<pre>
+    expect(mock.voteForRemoval("Document")).andReturn(42);
+    expect(mock.voteForRemoval(not(eq("Document")))).andStubReturn(-1);
+</pre>
+<h3>
+Nice Mocks
+</h3>
+<p>
+On a Mock Object returned by <code>createMock()</code> the default behavior for all methods is to throw an 
+<code>AssertionError</code> for all unexpected method calls.
+If you would like a "nice" Mock Object that by default allows all method calls and returns
+appropriate empty values (<code>0</code>, <code>null</code> or <code>false</code>), use <code>create<i>Nice</i>Mock()</code> instead.
+</p>
+
+<a id="Object_Methods"/><h3>Object Methods</h3>
+<p>
+The behavior for the three object methods <code>equals()</code>,
+<code>hashCode()</code> and <code>toString()</code>
+cannot be changed for Mock Objects created with EasyMock,
+even if they are part of the interface for which the
+Mock Object is created.
+</p>
+<h3>Checking Method Call Order Between Mocks</h3>
+<p>
+Up to this point, we have seen a mock object as a single object that is configured by static methods
+on the class <code>EasyMock</code>. But many of these static methods just identify the hidden control of the Mock Object
+and delegate to it. A Mock Control is an object implementing the <code>IMocksControl</code> interface. 
+</p>
+<p>
+So instead of
+</p>
+<pre>
+    IMyInterface mock = createStrictMock(IMyInterface.class);
+    replay(mock);
+    verify(mock); 
+    reset(mock);
+</pre>
+<p>
+we may use the equivalent code:
+</p>
+<pre>
+    IMocksControl ctrl = createStrictControl();
+    IMyInterface mock = ctrl.createMock(IMyInterface.class);
+    ctrl.replay();
+    ctrl.verify(); 
+    ctrl.reset();
+</pre>
+<p>
+The IMocksControl allows to create more than one Mock Object, and so it is possible to check the order of method calls
+between mocks. As an example, we set up two mock objects for the interface <code>IMyInterface</code>, and we expect the calls
+<code>mock1.a()</code> and <code>mock2.a()</code> ordered, then an open number of calls to <code>mock1.c()</code> 
+and <code>mock2.c()</code>, and finally <code>mock2.b()</code> and <code>mock1.b()</code>, in this order:
+</p>
+<pre>
+    IMocksControl ctrl = createStrictControl();
+    IMyInterface mock1 = ctrl.createMock(IMyInterface.class);
+    IMyInterface mock2 = ctrl.createMock(IMyInterface.class);
+
+    mock1.a();
+    mock2.a();
+
+    ctrl.checkOrder(false);
+
+    mock1.c();
+    expectLastCall().anyTimes();     
+    mock2.c();
+    expectLastCall().anyTimes();     
+
+    ctrl.checkOrder(true);
+
+    mock2.b();
+    mock1.b();
+
+    ctrl.replay();
+</pre>
+<h3>Naming Mock Objects</h3>
+<p>
+Mock Objects can be named at creation using 
+<code>createMock(String name, Class<T> toMock)</code>,
+<code>createStrictMock(String name, Class<T> toMock)</code> or
+<code>createNiceMock(String name, Class<T> toMock)</code>.
+The names will be shown in exception failures.
+</p>
+<h3>Serializing Mocks</h3>
+<p>
+Mocks can be serialized at any time during their life. However, there are some obvious contraints:
+</p>
+<ul>
+<li>All used matchers should be serializable (all genuine EasyMock ones are)
+</li>
+<li>Recorded parameters should also be serializable
+</li>
+</ul>
+<h3>Multithreading</h3>
+<p>
+By default, mocks are not thread-safe. They also checks that they are indeed used in 
+only one thread. To synchronize it, call the <code>makeThreadSafe</code> method. Note
+that all mocks create with a given <code>IMocksControl</code> will be synchronized with one another.
+</p>
+<h3>Backward Compatibility</h3>
+<p>
+EasyMock 2 contains a compatibility layer so that tests using EasyMock 1.2 for Java 1.5
+should work without any modification. The only known differences are visible when 
+failures occur: there are small changes in the failure messages and stack traces,
+and failures are now reported using Java's <code>AssertionError</code> instead of
+JUnit's <code>AssertionFailedError</code>.
+</p>
+<p>EasyMock 2.1 introduced a callback feature that has been removed in EasyMock 2.2,
+as it was too complex. Since EasyMock 2.2, the <code>IAnswer</code> interface
+provides the functionality for callbacks. 
+</p>
+<h2>
+EasyMock Development
+</h2>
+<p>
+EasyMock 1.0 has been developed by Tammo Freese at OFFIS.
+The development of EasyMock is now hosted on SourceForge
+to allow other developers and companies to contribute.
+</p>
+<p>
+Thanks to the people who gave feedback or provided patches, including
+Nascif Abousalh-Neto, Dave Astels, Francois Beausoleil, George Dinwiddie, Shane Duan, 
+Wolfgang Frech, Steve Freeman, Oren Gross, John D. Heintz, Dale King, Brian Knorr,
+Dierk Koenig, Chris Kreussling, Robert Leftwich, Patrick Lightbody, Johannes Link, 
+Rex Madden, David McIntosh, Karsten Menne, Bill Michell,
+Stephan Mikaty, Ivan Moore, Ilja Preuss, Justin Sampson, Markus Schmidlin, Richard Scott,
+Joel Shellman, Jiří Mareš, Alexandre de Pellegrin
+Shaun Smith, Marco Struck, Ralf Stuckert, Victor Szathmary, Henri Tremblay, Bill Uetrecht,
+Frank Westphal, Chad Woolley, Bernd Worsch, and numerous others.
+</p>
+<p>
+Please check the <a href="http://www.easymock.org">EasyMock home page</a> for new versions,
+and send bug reports and suggestions to the
+<a href="mailto:easymock at yahoogroups.com?subject=EasyMock 2.4 feedback">EasyMock Yahoo!Group</a>.
+If you would like to subscribe to the EasyMock Yahoo!Group, send a message to
+<a href="mailto:easymock-subscribe at yahoogroups.com">easymock-subscribe at yahoogroups.com</a>.
+</p>
+<h3>
+EasyMock Version 2.4 (July 2 2008) Release Notes
+</h3>
+<p>
+Changes since 2.3:
+</p>
+<ul>
+<li>Be able to capture an argument passed to a mock (1963449)
+</li>
+<li>Add resetToNice/Default/Strict methods (1963442)
+</li>
+<li>Make generic comparator more flexible
+</li>
+<li>Mocks are now serializable (1895630)
+</li>
+<li>Can now resume after an ignored failure (1896509)
+</li>
+<li>Can make a mock thread-safe (1895644,1953275)
+</li>
+<li>Check that an unsafe mock isn't used in a multithreaded environment 
+</li>
+</ul>
+<p>
+Changes since 2.2:
+</p>
+<ul>
+<li>French documentation
+</li>
+<li>Matchers for Comparable parameters 
+</li>
+<li>Decimal comparison fix
+</li>
+<li>Mock Objects can now be named 
+</li>
+<li>Include Bill Michell's ThreadLocal fix
+</li>
+<li>Converted EasyMock's unit tests to JUnit 4
+</li>
+</ul>
+<p>
+Changes since 2.1:
+</p>
+<ul>
+<li>answers for expected calls can now be created at call time via
+<code>andAnswer(IAnswer answer)</code> and <code>andStubAnswer(IAnswer answer)</code>
+</li>
+<li><code>callback(Runnable runnable)</code> has been removed, for callbacks, please 
+switch to  
+<code>andAnswer(IAnswer answer)</code> and <code>andStubAnswer(IAnswer answer)</code>
+</li>
+<li><code>replay()</code>, <code>verify()</code> and <code>reset()</code> now accept
+multiple mock objects as arguments
+</li>
+</ul>
+<p>
+Changes since 2.0:
+</p>
+<ul>
+<li>arguments passed to the mock object are now available in callbacks via
+<code>EasyMock.getCurrentArguments()</code>
+</li>
+<li>fixed bug reported in http://groups.yahoo.com/group/easymock/message/558
+</li>
+<li>earlier failing if unused matchers were specified
+</li>
+</ul>
+<p>
+Changes since 1.2:
+</p>
+<ul>
+<li>support for flexible, refactoring-safe argument matchers
+</li>
+<li>no mock control is needed for single Mock Objects
+</li>
+<li>stub behavior replaces default behavior
+</li>
+<li>support for call order checking for more than one mock, and to switch order checking on and off
+</li>
+<li>support for callbacks
+</li>
+<li>EasyMock now throws <code>java.lang.AssertionError</code> instead of <code>junit.framework.AssertionFailedError</code>
+so that it is now independent from the testing framework, you may use it with JUnit 3.8.x, JUnit 4 and TestNG
+</li>
+<li>deprecated old API
+</li>
+</ul>
+</div>
+</body>
+</html>
diff --git a/Documentation_fr.html b/Documentation_fr.html
new file mode 100644
index 0000000..1de704f
--- /dev/null
+++ b/Documentation_fr.html
@@ -0,0 +1,1042 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />	
+<title>EasyMock 2.4 Readme</title>
+<link rel="stylesheet" href="easymock.css" />
+</head>
+<body><div class="bodywidth">
+
+<h2>EasyMock 2.4 Readme</h2>
+ 
+<p>Documentation de la version 2.4 (July 2 2008)<br />
+© 2001-2008 <a href="http://www.offis.de" title="OFFIS">OFFIS</a>, <a href="http://tammofreese.de" id="id" title="Tammo Freese">Tammo Freese</a>.
+</p>
+<p>Traduit originellement de l'anglais par <a href="http://alexdp.free.fr">Alexandre de Pellegrin</a>.
+Maintenue par Henri Tremblay.
+</p>
+<p>
+EasyMock 2 est une librairie fournissant un moyen simple d'utiliser des Mock Objects pour
+une interface donnée. EasyMock 2 est disponible sous <a href="License.html">licence MIT</a>.
+</p>
+<p>
+Les Mock Objects simulent le comportement du code
+métier et sont capables de vérifier s'il est utilisé
+comme prévu.
+Les classes métier peuvent être testées
+de façon isolée en simulant leurs objets
+liés par des Mock Objects.
+</p>
+<p>
+Ecrire et maintenir des Mock Objects est souvent une
+tâche pénible et source d'erreurs. EasyMock 2
+génère les
+Mock Objects dynamiquement - pas besoin de les écrire, pas
+de code généré!
+</p>
+<h3>
+Avantages d'EasyMock 2
+</h3>
+<ul>
+<li>Pas d'écriture manuelle des Mock Objects.
+</li>
+<li>Supporte le refactoring sur les Mock Objects : le code de test ne sera pas cassé au runtime lors du renommage de
+    méthodes ou de la réorganisations de paramètres
+</li>
+<li>Supporte les valeurs de retour et les exceptions.
+</li>
+<li>Supporte la vérification de l'ordre d'appel des méthodes, sur un ou plusieurs Mock Objects.
+</li>
+</ul>
+<h3>Inconvénients d'EasyMock 2
+</h3>
+<ul>
+<li>EasyMock 2 fonctionne uniquement avec Java 2 Version 5.0 ou version supérieure.
+</li>
+</ul>
+<p>
+Par défaut, EasyMock supporte la génération de
+Mock Objects uniquement pour les interfaces. Pour ceux souhaitant
+générer des Mock Objects pour des 
+classes, il existe une extension disponible sur la page d'accueil d'EasyMock.
+</p>
+<h2>
+Installation
+</h2>
+<ol>
+<li>Java 2 (minimum 5.0) est requis.
+</li>
+<li>Décompressez le fichier zip d'EasyMock (<code>easymock2.4.zip</code>). Il contient le répertoire
+<code>easymock2.4</code>. Ajoutez le jar d'EasyMock (<code>easymock.jar</code>) de ce répertoire dans votre 
+classpath.
+</li>
+</ol>
+<p>
+Pour exécuter les tests d'EasyMock, ajoutez <code>tests.zip</code> et le jar de JUnit 4.1
+à votre classpath and lancez 
+<code>'java org.easymock.tests.AllTests'</code>.
+</p>
+<p>
+Le code source d'EasyMock est situé dans <code>src.zip</code>.
+</p>
+<h2>
+Utilisation
+</h2>
+<p>
+La plupart des éléments d'un logiciel ne fonctionnent
+pas de manière isolée mais en collaboration avec
+d'autres éléments (objets liés) pour effectuer leur
+tâche.
+Dans beaucoup de cas, nous ne nous soucions pas d'utiliser des objets
+liés pour nos tests unitaires du moment
+que nous avons confiance en eux. Si
+ce n'est pas le cas, les Mock Objects peuvent nous aider à
+tester unitairement de façon isolée. Les Mock Objects
+remplacent les objets liés de l'élément testé.
+</p>
+<p>
+Les exemples suivants utilisent l'interface <code>Collaborator</code>:
+</p>
+<pre>
+package org.easymock.samples;
+
+public interface Collaborator {
+    void documentAdded(String title);
+    void documentChanged(String title);
+    void documentRemoved(String title);
+    byte voteForRemoval(String title);
+    byte[] voteForRemovals(String[] title);
+}
+</pre>
+<p>
+Les implémentations de cette interface sont des
+objets liés (des listeners dans ce cas) à la classe nommée <code>ClassUnderTest</code>:
+</p>
+<pre>
+public class ClassUnderTest {
+    // ...    
+    public void addListener(Collaborator listener) {
+        // ... 
+    }
+    public void addDocument(String title, byte[] document) { 
+        // ... 
+    }
+    public boolean removeDocument(String title) {
+        // ... 
+    }
+    public boolean removeDocuments(String[] titles) {
+        // ... 
+    }
+}
+</pre>
+<p>
+Le code de la classe et de l'interface est disponible dans
+le package
+<code>org.easymock.samples</code> dans <code>samples.zip</code>.
+</p>
+<p>
+Les exemples qui suivent supposent que vous êtes familier avec le framework de test JUnit.
+Bien que les tests montrés ici utilisent JUnit version 3.8.1, vous pouvez également utiliser JUnit 4 ou TestNG.
+</p>
+<h3>
+Votre premier Mock Object
+</h3>
+<p>
+Nous allons maintenant construire un cas de test et jouer avec pour
+comprendre les fonctionnalités du package EasyMock. Le
+fichier <code>samples.zip</code> contient une version modifiée de ce test. 
+Notre premier test devra vérifier que la suppression d'un document non existant <strong>ne doit pas</strong>
+provoquer la notification de l'objet lié. Voici le test dans la définition du Mock Object:
+</p>
+<pre>
+package org.easymock.samples;
+
+import junit.framework.TestCase;
+
+public class ExampleTest extends TestCase {
+
+    private ClassUnderTest classUnderTest;
+    private Collaborator mock;
+
+    protected void setUp() {
+        classUnderTest = new ClassUnderTest();
+        classUnderTest.addListener(mock);
+    }
+
+    public void testRemoveNonExistingDocument() {    
+        // This call should not lead to any notification
+        // of the Mock Object: 
+        classUnderTest.removeDocument("Does not exist");
+    }
+}
+</pre>
+<p>
+Pour beaucoup de tests utilisant EasyMock 2, nous avons
+uniquement besoin de l'import statique des méthodes de la classe
+<code>org.easymock.EasyMock</code>.
+Cette classe est la seule non interne et non dépréciée d'EasyMock 2.
+</p>
+<pre>
+import static org.easymock.EasyMock.*;
+import junit.framework.TestCase;
+
+public class ExampleTest extends TestCase {
+
+    private ClassUnderTest classUnderTest;
+    private Collaborator mock;
+    
+}    
+</pre>
+<p>
+Pour obtenir un Mock Object, il faut:
+</p>
+<ol>
+<li>créer un Mock Object pour l'interface à simuler,
+</li>
+<li>enregistrer le comportement attendu, puis
+</li>
+<li>basculer le Mock Object à l'état 'replay'.
+</li>
+</ol>
+<p>
+Voici le premier exemple:
+</p>
+<pre>
+    protected void setUp() {
+        mock = createMock(Collaborator.class); // 1
+        classUnderTest = new ClassUnderTest();
+        classUnderTest.addListener(mock);
+    }
+
+    public void testRemoveNonExistingDocument() {
+        // 2 (we do not expect anything)
+        replay(mock); // 3
+        classUnderTest.removeDocument("Does not exist");
+    }
+</pre>
+<p>
+Après activation à l'étape 3, <code>mock</code> 
+est un Mock Object de l'interface <code>Collaborator</code>
+qui n'attend aucun appel. Cela signifie que si nous changeons notre <code>ClassUnderTest</code> 
+pour appeler n'importe quelle méthode de l'interface, le Mock Object lévera 
+une <code>AssertionError</code>:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentRemoved("Does not exist"):
+    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+    at $Proxy0.documentRemoved(Unknown Source)
+    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)
+    at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)
+    at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)
+    ...
+</pre>
+
+<h3>
+   Ajouter un comportement
+</h3>
+<p>
+Écrivons un second test. Si un document est ajouté à
+la classe testée, nous nous attendons à un appel à
+<code>mock.documentAdded()</code>
+sur le Mock Object avec le titre du document en argument:
+</p>
+<pre>
+    public void testAddDocument() {
+        mock.documentAdded("New Document"); // 2
+        replay(mock); // 3
+        classUnderTest.addDocument("New Document", new byte[0]); 
+    }
+</pre>
+<p>
+Aussi, dans l'étape d'enregistrement (avant d'appeler <code>replay</code>),
+le Mock Object ne se comporte pas comme<em></em> un Mock Object mais enregistre 
+les appels de méthode. Après l'appel à <code>replay</code>,
+il se comporte comme un Mock Object, vérifiant que les appels 
+de méthode attendus ont bien lieu.
+</p>
+<p>
+Si <code>classUnderTest.addDocument("New Document", new byte[0])</code>
+appelle la méthode attendue avec un mauvais argument, le
+Mock Object lèvera une <code>AssertionError</code>:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentAdded("Wrong title"):
+    documentAdded("New Document"): expected: 1, actual: 0
+    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+    at $Proxy0.documentAdded(Unknown Source)
+    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)
+    at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)
+    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
+    ...
+</pre>
+<p>
+Tous les appels attendus n'ayant pas eu lieu sont montrés, ainsi
+que tous les appels faits alors qu'ils étaient non attendus
+(aucun dans notre cas). Si l'appel à la méthode est
+effectué trop de fois, le Mock Object le signale
+également:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentAdded("New Document"):
+    documentAdded("New Document"): expected: 1, actual: 1 (+1)
+    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+    at $Proxy0.documentAdded(Unknown Source)
+    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)
+    at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)
+    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
+    ...
+</pre>
+<h3>
+Vérifier le comportement
+</h3>
+<p>
+Il y a un type d'erreur dont nous ne nous sommes pas
+préoccupés jusqu'à présent: si nous décrivons un
+comportement, nous voulons vérifier qu'il est bien respecté. 
+Le test qui suit passe si une méthode du Mock Object est appelée. 
+Pour vérifier cela, nous devons appeler <code>verify(mock)</code>:
+</p>
+<pre>
+    public void testAddDocument() {
+        mock.documentAdded("New Document"); // 2 
+        replay(mock); // 3
+        classUnderTest.addDocument("New Document", new byte[0]);
+        verify(mock);
+    }
+</pre>
+<p>
+Si la méthode du Mock Object n'est pas appelée, 
+l'exception suivante sera levée :
+</p>
+<pre>
+java.lang.AssertionError: 
+  Expectation failure on verify:
+    documentAdded("New Document"): expected: 1, actual: 0
+    at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
+    at org.easymock.EasyMock.verify(EasyMock.java:536)
+    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:31)
+    ...
+</pre>
+<p>
+Le message de l'exception liste tous les appels attendus qui n'ont pas eu lieu.
+</p>
+<h3>
+Attendre un nombre explicite d'appels
+</h3>
+<p>
+Jusqu'à maintenant, nos tests ont été faits uniquement
+sur un seul appel de méthode. Le test suivant
+vérifiera que l'ajout d'un document déjà existant
+déclenche l'appel à <code>mock.documentChanged()</code>
+avec l'argument approprié. Pour en être certain, nous
+vérifions cela trois fois (après tout, c'est un exemple
+;-)):
+</p>
+<pre>
+    public void testAddAndChangeDocument() {
+        mock.documentAdded("Document");
+        mock.documentChanged("Document");
+        mock.documentChanged("Document");
+        mock.documentChanged("Document");
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        verify(mock);
+    }
+</pre>
+<p>
+Afin d'éviter la répétition de  <code>mock.documentChanged("Document")</code>,
+EasyMock fournit un raccourci. Nous pouvons spécifier le nombre d'appel avec la méthode
+<code>times(int times)</code> sur l'objet retourné par <code>expectLastCall()</code>.
+Le code ressemble alors à cela:
+</p>
+<pre>
+    public void testAddAndChangeDocument() {
+        mock.documentAdded("Document");
+        mock.documentChanged("Document");
+        expectLastCall().times(3);
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        verify(mock);
+    }
+</pre>
+<p>
+Si la méthode est appelée un trop grand nombre de fois,
+une exception sera levée nous indiquant que la méthode a
+été appelée trop de fois.
+L'erreur est levée immédiatement après le premier
+appel dépassant la limite:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call documentChanged("Document"):
+    documentChanged("Document"): expected: 3, actual: 3 (+1)
+	at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+	at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+	at $Proxy0.documentChanged(Unknown Source)
+	at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged(ClassUnderTest.java:67)
+	at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:26)
+	at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
+    ...
+</pre>
+<p>
+S'il y a trop peu d'appels, <code>verify(mock)</code>
+lève une <code>AssertionError</code>:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Expectation failure on verify:
+    documentChanged("Document"): expected: 3, actual: 2
+	at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
+	at org.easymock.EasyMock.verify(EasyMock.java:536)
+	at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
+    ...
+</pre>
+<h3>
+Spécifier des valeurs de retour
+</h3>
+<p>
+Pour spécifier des valeurs de retour, nous encapsulons l'appel attendu dans
+<code>expect(T value)</code> et spécifions la valeur de retour avec la 
+méthode <code>andReturn(Object returnValue)</code> sur l'objet retourné par
+<code>expect(T value)</code>.
+</p>
+<p>
+Prenons par exemple la vérification du workflow lors de la suppresion d'un document. 
+Si <code>ClassUnderTest</code> fait un appel pour supprimer un document, 
+il doit demander aux objets liés de voter pour cette suppression 
+par appel à <code>byte voteForRemoval(String title)</code>.
+Une réponse positive approuve la suppression. Si la somme de
+toutes les réponses est positive, alors le document est
+supprimé et l'appel à <code>documentRemoved(String title)</code> 
+est effectué sur les objets liés:
+</p>
+<pre>
+    public void testVoteForRemoval() {
+        mock.documentAdded("Document");   // expect document addition
+        // expect to be asked to vote for document removal, and vote for it
+        expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
+        mock.documentRemoved("Document"); // expect document removal
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        assertTrue(classUnderTest.removeDocument("Document"));
+        verify(mock);
+    }
+
+    public void testVoteAgainstRemoval() {
+        mock.documentAdded("Document");   // expect document addition
+        // expect to be asked to vote for document removal, and vote against it
+        expect(mock.voteForRemoval("Document")).andReturn((byte) -42);
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        assertFalse(classUnderTest.removeDocument("Document"));
+        verify(mock);
+    }
+</pre>
+<p>
+Le type de la valeur de retour est vérifié à la
+compilation. Par exemple, le code suivant ne compilera pas du fait que
+le type fourni ne correspond au type retourné par la
+méthode:
+</p>
+<pre>
+    expect(mock.voteForRemoval("Document")).andReturn("wrong type");
+</pre>
+<p>
+Au lieu d'appeler <code>expect(T value)</code> pour
+récuperer l'objet auquel affecter une valeur de retour, 
+nous pouvons aussi utiliser l'objet retourné par <code>expectLastCall()</code>.
+Ainsi, au lieu de 
+</p>
+<pre>
+    expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
+</pre>
+<p>
+nous pouvons écrire
+</p>
+<pre>
+    mock.voteForRemoval("Document");
+    expectLastCall().andReturn((byte) 42);
+</pre>
+<p>
+Ce type d'écriture doit uniquement être utilisé
+si la ligne est trop longue car il n'inclut pas la vérification
+du type à la compilation.
+</p>
+<h3>
+Travailler avec les exceptions
+</h3>
+<p>
+Afin de spécifier les exceptions (plus précisemment:
+les Throwables) devant être levées, l'objet
+retourné par <code>expectLastCall()</code> et <code>expect(T value)</code> 
+fournit la méthode <code>andThrow(Throwable throwable)</code>.
+Cette méthode doit être appelée durant l'étape
+d'enregistrement après l'appel au Mock Object pour lequel le <code>Throwable</code>
+doit être levé.
+</p>
+<p>
+Les exception non "checkées" (comme <code>RuntimeException</code>,
+<code>Error</code> ainsi que toutes leurs sous classes) peuvent
+être levées de n'importe quelle méthode. Les
+exceptions "checkées" ne doivent être levées que 
+pour methodes où cela est prévu.
+</p>
+<h3>
+Créer des valeurs de retour ou des exceptions
+</h3>
+<p>
+Parfois, nous voulons que notre Mock Object retourne une valeur ou
+lève une exception créée au moment de l'appel.
+Depuis la version 2.2 d'EasyMock, l'objet retourné 
+par <code>expectLastCall()</code> et <code>expect(T value)</code> fournit la méthode
+<code>andAnswer(IAnswer answer)</code> permettant de spécifier une implémentation 
+de l'interface <code>IAnswer</code> utilisée pour créer 
+une valeur de retour ou une exception.
+</p>
+<p>
+Au sein d'<code>IAnswer</code>, les arguments passés lors de l'appel au mock sont 
+disponibles via <code>EasyMock.getCurrentArguments()</code>.
+Si vous utilisez cela, les refactorings du type réorganisation
+de l'ordre des arguments brisseront vos tests. Vous êtes prévenu.
+</p>
+<h3>
+Changer de comportement sur le même appel de méthode
+</h3>
+<p>
+Il est également possible de spécifier un changement de comportement pour une méthode.
+Les méthodes <code>times</code>, <code>andReturn</code> et <code>andThrow</code>
+peuvent être chaînées. Comme exemple, 
+nous définissons <code>voteForRemoval("Document")</code> pour
+</p>
+<ul>
+<li>retourner 42 pour les trois premiers appels,
+</li>
+<li>lever une <code>RuntimeException</code> sur le quatrième appel,
+</li>
+<li>renvoyer -42 une fois.
+</li>
+</ul>
+<pre>
+    expect(mock.voteForRemoval("Document"))
+        .andReturn((byte) 42).times(3)
+        .andThrow(new RuntimeException(), 4)
+        .andReturn((byte) -42);
+</pre>
+<h3>
+Être plus permissif sur le nombre d'appels
+</h3>
+<p>
+Afin d'être plus permissif sur le nombre d'appels attendus,
+des méthodes additionnelles peuvent être
+utilisées à la place de <code>times(int count)</code>:
+</p>
+<dl>
+<dt><code>times(int min, int max)</code></dt> 
+<dd>pour attendre entre <code>min</code> and <code>max</code> appels,</dd>
+<dt><code>atLeastOnce()</code></dt>
+<dd>pour attendre au moins un appel, et</dd>
+<dt><code>anyTimes()</code></dt>
+<dd>pour attendre une quantité non définie d'appels.</dd>
+</dl>
+<p>
+Si aucun nombre d'appels n'est explicitement défini,
+alors seul un appel est attendu. Pour le définir explicitement,
+vous pouvez utiliser <code>once()</code> ou <code>times(1)</code>.
+</p>
+<h3>
+Mocks stricts
+</h3>
+<p>
+Sur un Mock Object retourné par <code>EasyMock.createMock()</code>,
+l'ordre d'appel des méthodes n'est pas vérifié.
+Si vous souhaitez avoir un Mock Object 'strict' vérifiant cet ordre,
+utilisez <code>EasyMock.create<i>Strict</i>Mock()</code>.</p>
+<p>
+Lorsqu'un appel inattendu à une méthode est fait sur
+un Mock Object 'strict', le message de l'exception contient les appels 
+de méthode attendus à ce moment, suivi du premier appel en
+conflit. <code>verify(mock)</code> montre tous les appels de méthode manqués.
+</p>
+<h3>
+Activer/Désactiver la vérification de l'ordre d'appel des méthodes
+</h3>
+<p>
+Il est parfois nécessaire qu'un Mock Object vérifie
+l'ordre d'appel sur certains appels uniquement. Pendant la phase
+d'enregistrement, vous pouvez activer la vérification de l'ordre
+d'appel en utilisant <code>checkOrder(mock, true)</code> et la 
+désactiver en utilisant <code>checkOrder(mock, false)</code>.
+</p>
+<p>
+Il y a deux différences entre un Mock Object 'strict' et un Mock Object 'normal':
+</p>
+<ol>
+	<li> Un mock 'strict' à la vérification de l'order d'appel activé à la cré. </li>
+	<li> Un mock 'strict' à la vérification de l'order d'appel activé ès reset (voir <em>Réutilisation d'un Mock Object</em>). </li>
+</ol>
+<h3>
+Définir des comparateurs d'arguments pour plus de souplesse
+</h3>
+<p>
+Pour vérifier la correspondance à un appel de méthode prévu sur un Mock Object, 
+les arguments<code> de type Object</code> sont comparés, par défaut, avec
+<code>equals()</code>. Cela peut introduire des problèmes. Considérons l'exemple suivant:
+</p>
+<pre>
+String[] documents = new String[] { "Document 1", "Document 2" };
+expect(mock.voteForRemovals(documents)).andReturn(42);
+</pre>
+<p>
+Si la méthode est appelée avec un autre tableau ayant le même contenu,
+cela provoque une exception du fait que <code>equals()</code> compare l'identité 
+des objets pour les tableaux:
+</p>
+<pre>
+java.lang.AssertionError: 
+  Unexpected method call voteForRemovals([Ljava.lang.String;@9a029e):
+    voteForRemovals([Ljava.lang.String;@2db19d): expected: 1, actual: 0
+    documentRemoved("Document 1"): expected: 1, actual: 0
+    documentRemoved("Document 2"): expected: 1, actual: 0
+	at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
+	at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
+	at $Proxy0.voteForRemovals(Unknown Source)
+	at org.easymock.samples.ClassUnderTest.listenersAllowRemovals(ClassUnderTest.java:88)
+	at org.easymock.samples.ClassUnderTest.removeDocuments(ClassUnderTest.java:48)
+	at org.easymock.samples.ExampleTest.testVoteForRemovals(ExampleTest.java:83)
+    ...
+</pre>
+<p>
+Pour spécifier que seule l'égalité de tableau
+est nécessaire pour cet appel, utilisez la méthode 
+<code>aryEq</code>, importée statiquement de la classe <code>EasyMock</code>:
+</p>
+<pre>
+String[] documents = new String[] { "Document 1", "Document 2" };
+expect(mock.voteForRemovals(aryEq(documents))).andReturn(42);
+</pre>
+<p>
+Si vous souhaitez utiliser les comparateurs lors d'un appel, vous devez
+en utiliser pour chaque argument de la méthode appelée.
+</p>
+<p>
+Voici quelques comparateurs prédéfinis disponible:
+</p>
+<dl>
+
+<dt><code>eq(X value)</code></dt>
+<dd>Vérifie que la valeur reçue égale la valeur attendue. Disponible pour tous les types primitifs et objets.</dd>
+
+<dt><code>anyBoolean()</code>, <code>anyByte()</code>, <code>anyChar()</code>, <code>anyDouble()</code>, <code>anyFloat()</code>, <code>anyInt()</code>, <code>anyLong()</code>, <code>anyObject()</code>, <code>anyShort()</code></dt>
+<dd>Laisse passer n'importe quelle valeur. Disponible pour tous les types primitifs et objets.</dd>
+
+<dt><code>eq(X value, X delta)</code></dt>
+<dd>Vérifie que la valeur recçue égale la valeur attendue, plus ou moins un delta. Disponible pour les <code>float</code> et <code>double</code>.</dd>
+
+<dt><code>aryEq(X value)</code></dt>
+<dd>Vérifie que la valeur recçue égale la valeur attendue en s'appuyant sur <code>Arrays.equals()</code>. Disponible pour les tableaux d'objets et de types primitifs.</dd>
+
+<dt><code>isNull()</code></dt>
+<dd>Vérifie que la valeur reçue est nulle. Disponible pour les objets.</dd>
+
+<dt><code>notNull()</code></dt>
+<dd>Vérifie que la valeur reçue n'est pas nulle. Disponible pour les objets.</dd>
+
+<dt><code>same(X value)</code></dt>
+<dd>Vérifie que la valeur reçue est la même que la value attendue. Disponible pour les objets.</dd>
+
+<dt><code>isA(Class clazz)</code></dt>
+<dd>Vérifie que la valeur reçue est une instance de clazz ou d'une classe hérite ou implémente clazz. Disponible pour les objets.</dd>
+
+<dt><code>lt(X value)</code>, <code>leq(X value)</code>, <code>geq(X value)</code>, <code>gt(X value)</code></dt>
+<dd>Vérifie que la valeur reçue est inférieure/inférieure ou égale/supérieure
+ou égale/supérieure à la valeur attendue. Disponible pour tous les types primitifs numériques et les implémentations de <code>Comparable</code>.</dd>
+
+<dt><code>startsWith(String prefix), contains(String substring), endsWith(String suffix)</code></dt>
+<dd>Vérifie que la valeur reçue commence par/contient/se termine par la valeur attendue. Disponible pour les <code>String</code>s.</dd>
+
+<dt><code>matches(String regex), find(String regex)</code></dt>
+<dd>Vérifie que la valeur reçue/une sous-chaîne de la valeur reçue correspond à l'expression ré. Disponible pour les <code>String</code>s.</dd>
+
+<dt><code>and(X first, X second)</code></dt>
+<dd>Est valide si les résultats des deux comparateurs utilisés en <code>first</code> et <code>second</code> sont vérifiés. Disponible pour tous les types primitifs et objets.</dd>
+
+<dt><code>or(X first, X second)</code></dt>
+<dd>Est valide si l'un des résultats des deux comparateurs utilisés en <code>first</code> et <code>second</code> est vérifié. Disponible pour tous les types primitifs et objets.</dd>
+
+<dt><code>not(X value)</code></dt>
+<dd>Est valide si le résultat du comparateur utilisé dans <code>value</code> est négatif.</dd>
+
+<dt><code>cmpEq(X value)</code></dt>
+<dd>Vérifie que la valeur reçue égale la valeur attendue du point de vue de <code>Comparable.compareTo(X o)</code>. Disponible pour tous les types primitifs numériques et les implémentations de <code>Comparable</code>.</dd>
+
+<dt><code>cmp(X value, Comparator<X> comparator, LogicalOperator operator)</code></dt>
+<dd>Vérifie que <code>comparator.compare(reçue, value) operator 0</code> où <code>operator</code> est <,<=,>,>= ou ==.</dd>
+
+<dt><code>capture(Capture<T> capture)</code></dt>
+<dd>Laisse passer n'importe quelle valeur mais la capture dans le paramètre <code>Capture</code> pour un usage ultérieurs. Vous pouvez utiliser <code>and(someMatcher(...), capture(c))</code> pour 
+capturer un paramètre d'un appel de méthode en particulier.</dd>
+
+</dl>
+
+<h3>
+Définir son propre comparateur d'arguments
+</h3>
+<p>
+Il peut être intéressant de définir son propre
+comparateur d'argument. Prenons un comparateur dont le rôle
+serait de vérifier une exception par rapport à son
+type et message. Il pourrait être utilisé de la façon suivante:
+</p>
+<pre>
+    IllegalStateException e = new IllegalStateException("Operation not allowed.")
+    expect(mock.logThrowable(eqException(e))).andReturn(true);
+</pre>
+<p>
+Deux étapes sont nécessaires pour réaliser cela: le nouveau comparateur
+doit être défini et la méthode statique <code>eqException</code> 
+doit être déclarée.
+</p>
+<p>
+Pour définir le nouveau comparateur d'argument, nous implémentons l'interface <code>org.easymock.IArgumentMatcher</code>.
+Cette interface contient deux méthodes: <code>matches(Object actual)</code>, vérifiant 
+que l'argument reçu est bien celui attendu, et <code>appendTo(StringBuffer buffer)</code>,
+ajoutant au StringBuffer une chaine de caractères représentative du comparateur d'argument.
+L'implémentation est la suivante :
+</p>
+<pre>
+import org.easymock.IArgumentMatcher;
+
+public class ThrowableEquals implements IArgumentMatcher {
+    private Throwable expected;
+
+    public ThrowableEquals(Throwable expected) {
+        this.expected = expected;
+    }
+
+    public boolean matches(Object actual) {
+        if (!(actual instanceof Throwable)) {
+            return false;
+        }
+        String actualMessage = ((Throwable) actual).getMessage();
+        return expected.getClass().equals(actual.getClass())
+                && expected.getMessage().equals(actualMessage);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("eqException(");
+        buffer.append(expected.getClass().getName());
+        buffer.append(" with message \"");
+        buffer.append(expected.getMessage());
+        buffer.append("\"")");
+
+    }
+}
+</pre>
+<p>
+La méthode <code>eqException</code> doit instancier le
+comparateur d'argument avec l'objet Throwable donné, le fournir
+à EasyMock via la méthode statique <code>reportMatcher(IArgumentMatcher matcher)</code>
+et retourner une valeur afin d'être utilisée au sein de l'appel à la méthode mockée 
+(typiquement <code>0</code>, <code>null</code> ou <code>false</code>). Une première tentative ressemblerait à ceci:
+</p>
+<pre>
+public static Throwable eqException(Throwable in) {
+    EasyMock.reportMatcher(new ThrowableEquals(in));
+    return null;
+}
+</pre>
+<p>
+Cependant, cela ne fonctionnerait que si la méthode <code>logThrowable</code>
+de l'exemple acceptait <code>Throwable</code>s et quelque chose de plus spécifique du style de <code>RuntimeException</code>. 
+Dans ce dernier cas, le code de notre exemple ne compilerait pas:
+</p>
+<pre>
+    IllegalStateException e = new IllegalStateException("Operation not allowed.")
+    expect(mock.logThrowable(eqException(e))).andReturn(true);
+</pre>
+<p>
+Java 5.0 à la rescousse: Au lieu de définir <code>eqException</code>
+avec un <code>Throwable</code> en paramètre, nous utilisons un type générique 
+qui hérite de <code>Throwable</code>:
+</p>
+<pre>
+public static <T extends Throwable> T eqException(T in) {
+    reportMatcher(new ThrowableEquals(in));
+    return null;
+}
+</pre>
+<h3>
+Réutilisation d'un Mock Object
+</h3>
+<p>
+Les Mock Objects peuvent être réinitialisés avec <code>reset(mock)</code>.
+</p>
+<p>
+Au besoin, un Mock Object peut aussi être converti d'un type à l'autre en appelant <code>resetToNice(mock)</code>, 
+<code>resetToDefault(mock)</code> ou <code>resetToStrict(mock)</code>.
+</p>
+<h3>
+Utilisation d'un comportement de "stub" pour les méthodes
+</h3>
+<p>
+Dans certains cas, nous voudrions que nos Mock Object répondent
+à certains appels, mais sans tenir compte du nombre de fois, de l'ordre
+ni même s'ils ont été eu lieu.
+Ce comportement de "stub" peut être défini en utilisant
+les méthodes <code>andStubReturn(Object value)</code>, 
+<code>andStubThrow(Throwable throwable)</code>, <code>andStubAnswer(IAnswer<t> answer)</code>
+et <code>asStub()</code>. Le code suivant configure le Mock Object pour répondre 42 
+à <code>voteForRemoval("Document")</code> une fois et -1 pour tous les autres arguments:
+</p>
+<pre>
+    expect(mock.voteForRemoval("Document")).andReturn(42);
+    expect(mock.voteForRemoval(not(eq("Document")))).andStubReturn(-1);
+</pre>
+<h3>
+Création de mocks dits "gentils"
+</h3>
+<p>
+Pour un Mock Object retourné par <code>createMock()</code>, le comportement par défaut pour toutes 
+les méthodes est de léver une <code>AssertionError</code> pour tous les appels non prévus.
+Si vous souhaitez avoir un Mock Object "gentil" autorisant, par défaut, l'appel à 
+toutes les méthodes et retournant la valeur vide appropriée (<code>0</code>, <code>null</code>
+ou <code>false</code>), utilisez <code>create<i>Nice</i>Mock()</code> au lieu de <code>createMock()</code>.
+</p>
+
+<a id="Object_Methods"/><h3>Méthodes de la classe Object</h3>
+<p>
+Les comportements des trois méthodes <code>equals()</code>,
+<code>hashCode()</code> et <code>toString()</code>
+ne peuvent être changés sur des Mock Objects créés avec EasyMock,
+même si elles font partie de l'interface duquel le Mock Object est créé.
+</p>
+<h3>Vérifier l'ordre d'appel des méthodes entre plusieurs Mocks</h3>
+<p>
+Jusqu'à présent, nous avons vu un Mock Object comme étant
+seul et configuré par les méthodes statiques de la classe <code>EasyMock</code>. 
+Mais beaucoup de ces méthodes statiques font référence à l'objet "control"
+caché de chaque Mock Object et lui délègue l'appel. Un
+Mock Control est un objet implementant l'interface <code>IMocksControl</code>.
+</p>
+<p>
+Du coup, au lieu de
+</p>
+<pre>
+    IMyInterface mock = createStrictMock(IMyInterface.class);
+    replay(mock);
+    verify(mock); 
+    reset(mock);
+</pre>
+<p>
+nous pourrions utiliser le code équivalent:
+</p>
+<pre>
+    IMocksControl ctrl = createStrictControl();
+    IMyInterface mock = ctrl.createMock(IMyInterface.class);
+    ctrl.replay();
+    ctrl.verify(); 
+    ctrl.reset();
+</pre>
+<p>
+L'interface <code>IMocksControl</code> permet de créer plus d'un seul Mock Object. 
+Ainsi, il est possible de vérifier l'ordre d'appel des méthodes entre les mocks. 
+Par exemple, configurons deux mock objects pour l'interface <code>IMyInterface</code> pour lesquels 
+nous attendons respectivement les appels à <code>mock1.a()</code> et <code>mock2.a()</code>, 
+un nombre indéfini d'appels à <code>mock1.c()</code> et <code>mock2.c()</code>, 
+et enfin <code>mock2.b()</code> et <code>mock1.b()</code>, dans cet ordre:
+</p>
+<pre>
+    IMocksControl ctrl = createStrictControl();
+    IMyInterface mock1 = ctrl.createMock(IMyInterface.class);
+    IMyInterface mock2 = ctrl.createMock(IMyInterface.class);
+
+    mock1.a();
+    mock2.a();
+
+    ctrl.checkOrder(false);
+
+    mock1.c();
+    expectLastCall().anyTimes();     
+    mock2.c();
+    expectLastCall().anyTimes();     
+
+    ctrl.checkOrder(true);
+
+    mock2.b();
+    mock1.b();
+
+    ctrl.replay();
+</pre>
+<h3>Nommer un Mock Object</h3>
+<p>
+Les Mock Objects peuvent ê nommés à leur création en utilisant 
+<code>createMock(String name, Class<T> toMock)</code>,
+<code>createStrictMock(String name, Class<T> toMock)</code> ou
+<code>createNiceMock(String name, Class<T> toMock)</code>.
+Les noms seront affichés dans le message des <code>AssertionError</code>.
+</p>
+<h3>Sérializer un Mock Object</h3>
+<p>
+Un Mock Object peut être sérializé à n'importe quelle étape de son 
+existence. Il y a toutefois des contraintes évidentes:
+</p>
+<ul>
+<li>Les comparateurs d'arguments utilisés doivent être sérializable (ceux fournis avec EasyMock le sont)
+</li>
+<li>Les paramètres enregistrés doivent être sérializable
+</li>
+</ul>
+<h3>Traitement multifil</h3>
+<p>
+Par défaut, les Mock Objects ne sont pas à fil sécurisé. De plus, ils vérifient 
+qu'ils sont bien utilisés dans un seul fil. Pour les synchroniser, appellez la méthode 
+<code>makeThreadSafe</code>. Notez que les Mock Objects créés à partir du même 
+<code>IMocksControl</code> seront synchronisés l'un avec l'autre.
+</p>
+<h3>
+Compatibilité avec les anciennes versions
+</h3>
+<p>
+EasyMock 2 contient une couche de compatibilité. Ainsi, les
+tests utilisant EasyMock 1.2 en Java 1.5 fonctionneront sans aucune modification. 
+Les seules différences connues sont visibles lorsque qu'un test est en erreur: il y a de
+légers changements dans les messages d'erreur, les stack traces et les erreurs 
+sont maintenant remontées en utilisant <code>AssertionError</code> de Java 
+au lieu de <code>AssertionFailedError</code> de JUnit.
+</p>
+<p>EasyMock 2.1 introduisait une fonctionnalité de callback
+qui a été retirée dans EasyMock 2.2, car trop complexe. 
+Depuis EasyMock 2.2, l'interface <code>IAnswer</code>
+fournit la fonctionnalité de callback. 
+</p>
+<h2>
+Développement d'EasyMock
+</h2>
+<p>
+EasyMock 1.0 a été développé par Tammo Freese chef OFFIS.
+Le développement d'EasyMock est hébergé par SourceForge
+pour permettre à d'autres développeurs et sociétés d'y contribuer.
+</p>
+<p>
+Rémerciements à ceux qui nous ont fourni retour d'expérience et rustines, incluant
+Nascif Abousalh-Neto, Dave Astels, Francois Beausoleil, George Dinwiddie, Shane Duan, 
+Wolfgang Frech, Steve Freeman, Oren Gross, John D. Heintz, Dale King, Brian Knorr,
+Dierk Koenig, Chris Kreussling, Robert Leftwich, Patrick Lightbody, Johannes Link, 
+Rex Madden, David McIntosh, Karsten Menne, Bill Michell,
+Stephan Mikaty, Ivan Moore, Ilja Preuss, Justin Sampson, Markus Schmidlin, Richard Scott,
+Joel Shellman, Jiří Mareš, Alexandre de Pellegrin
+Shaun Smith, Marco Struck, Ralf Stuckert, Victor Szathmary, Henri Tremblay, Bill Uetrecht,
+Frank Westphal, Chad Woolley, Bernd Worsch, et de nombreux autres.
+</p>
+<p>
+Merci de consulter la <a href="http://www.easymock.org">page d'accueil EasyMock</a> 
+pour être informé des nouvelles versions et transmettez vos bogues et suggestions à
+<a href="mailto:easymock at yahoogroups.com?subject=EasyMock 2.4 feedback">EasyMock Yahoo!Group</a> (en anglais SVP).
+Si vous souhaitez souscrire au EasyMock Yahoo!Group, envoyez un message à
+<a href="mailto:easymock-subscribe at yahoogroups.com">easymock-subscribe at yahoogroups.com</a>.
+</p>
+<h3>
+EasyMock Version 2.4 (July 2 2008), Notes de Mise à Jour
+</h3>
+<p>
+Changements depuis la version 2.3:
+</p>
+<ul>
+<li>Pouvoir capturer un argument passé à un Mock Object (1963449)
+</li>
+<li>Ajout des méthodes resetToNice/Default/Strict methods (1963442)
+</li>
+<li>Rendre les Comparators génériques plus flexibles
+</li>
+<li>Les Mock Objects sont maintenant sérializable (1895630)
+</li>
+<li>Il est maintenant possible de continuer normalement après une assertion ignorée (1896509)
+</li>
+<li>Possibilité de rendre un Mock Object à fil sécurisé (1895644,1953275)
+</li>
+<li>Vérification qu'un Mock Object non sécurisé n'est pas utilisé dans un environnement multifil 
+</li>
+</ul>
+<p>
+Changements depuis la version 2.2:
+</p>
+<ul>
+<li>Documentation en français
+</li>
+<li>Comparateurs pour arguments de type Comparable
+</li>
+<li>Correction de la comparaison de nombres décimaux
+</li>
+<li>Les Mock Objects peuvent maintenant être nommés
+</li>
+<li>Includ le fix de Bill Michell pour sur les ThreadLocals
+</li>
+<li>Migration des test unitaires d'EasyMock vers JUnit 4
+</li>
+</ul>
+<p>
+Changements depuis la version 2.1:
+</p>
+<ul>
+<li>la réponse aux appels peut ètre créée au moment de l'appel via
+<code>andAnswer(IAnswer answer)</code> et <code>andStubAnswer(IAnswer answer)</code>
+</li>
+<li><code>callback(Runnable runnable)</code> a été retiré, pour un callback, veuillez 
+convertir à
+<code>andAnswer(IAnswer answer)</code> et <code>andStubAnswer(IAnswer answer)</code>
+</li>
+<li><code>replay()</code>, <code>verify()</code> et <code>reset()</code> acceptent maintenant
+plusieurs mock objects comme arguments
+</li>
+</ul>
+<p>
+Changements depuis la version 2.0:
+</p>
+<ul>
+<li>les arguments passés à un mock object sont à disponibles dans un callback via 
+<code>EasyMock.getCurrentArguments()</code>
+</li>
+<li>Correction du bogue reporté par http://groups.yahoo.com/group/easymock/message/558
+</li>
+<li>remontée plus rapide d'une erreur si des comparateurs ne sont pas utilisés
+</li>
+</ul>
+<p>
+Changements depuis la version 1.2:
+</p>
+<ul>
+<li>support de comparateurs d'arguments souple et ré au refactoring-safe
+</li>
+<li>aucun mock control n'est nécessaire pour un Mock Object solitaire
+</li>
+<li>le comportement de "stub" remplace le comportement "défaut"
+</li>
+<li>support de la vérification d'ordre d'appels entre plusieurs mocks 
+avec possibilité d'activer/désactiver cette vérification
+</li>
+<li>support de callbacks
+</li>
+<li>EasyMock lève désormais des <code>java.lang.AssertionError</code> au lieu 
+de <code>junit.framework.AssertionFailedError</code> ce qui permet d'être indépendant 
+du framework de test. Vous pouvez l'utiliser avec JUnit 3.8.x, JUnit 4 et TestNG
+</li>
+<li>ancienne API dépréciée
+</li>
+</ul>
+</div>
+</body>
+</html>
diff --git a/License.html b/License.html
new file mode 100644
index 0000000..5725458
--- /dev/null
+++ b/License.html
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+
+<head>
+	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />	
+	<title>EasyMock License</title>
+	<link rel="stylesheet" href="easymock.css" />
+</head>
+
+<body><div class="bodywidth">
+
+<h2>
+EasyMock 2 License (MIT License)
+</h2>
+
+<em>Copyright (c) 2001-2008 <a href="http://www.offis.de">OFFIS</a>, <a href="http://tammofreese.de">Tammo Freese</a>.</em>
+
+<p>
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+</p>
+<p>
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+</p>
+<p>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+</p>
+
+</div>
+</body>
+</html>
+
+
diff --git a/easymock.css b/easymock.css
new file mode 100644
index 0000000..30d37e7
--- /dev/null
+++ b/easymock.css
@@ -0,0 +1,55 @@
+body {
+        font-family:Arial,Helvetica,sans-serif; 
+        font-size:11pt;
+        color:#000000;
+        background-color:#ffffff;
+        text-align:left;
+}
+
+.bodywidth { 
+        width:750px;
+}
+
+h1, h2, h3, .contentbar {
+        padding:3px;
+}
+
+
+h1, h2, h3 {
+        font-weight:bold;
+}
+
+h1 { 
+        font-size:24pt;
+        text-align:center;
+}
+
+h2, h3, .contentbar {
+        color:#000000;
+        background-color:#ccccff;
+        border:none;
+}
+
+h2 {
+        font-size:14pt; 
+}
+
+h3 {
+        font-size:10pt;
+}
+
+img {
+        border:0;
+}
+
+ul {
+        list-style-type:square;
+}
+
+pre {
+        color:#000000;
+        background-color:#cccccc;
+        font-family:monospace;
+        font-size:8pt;
+        padding:3px;
+}
diff --git a/samples/org/easymock/samples/ClassUnderTest.java b/samples/org/easymock/samples/ClassUnderTest.java
new file mode 100644
index 0000000..4fd46e3
--- /dev/null
+++ b/samples/org/easymock/samples/ClassUnderTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.samples;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class ClassUnderTest {
+
+    private Set<Collaborator> listeners = new HashSet<Collaborator>();
+
+    private Map<String, byte[]> documents = new HashMap<String, byte[]>();
+
+    public void addListener(Collaborator listener) {
+        listeners.add(listener);
+    }
+
+    public void addDocument(String title, byte[] document) {
+        boolean documentChange = documents.containsKey(title);
+        documents.put(title, document);
+        if (documentChange) {
+            notifyListenersDocumentChanged(title);
+        } else {
+            notifyListenersDocumentAdded(title);
+        }
+    }
+
+    public boolean removeDocument(String title) {
+        if (!documents.containsKey(title)) {
+            return true;
+        }
+
+        if (!listenersAllowRemoval(title)) {
+            return false;
+        }
+
+        documents.remove(title);
+        notifyListenersDocumentRemoved(title);
+
+        return true;
+    }
+
+    public boolean removeDocuments(String[] titles) {
+        if (!listenersAllowRemovals(titles)) {
+            return false;
+        }
+
+        for (String title : titles) {
+            documents.remove(title);
+            notifyListenersDocumentRemoved(title);
+        }
+        return true;
+    }
+
+    private void notifyListenersDocumentAdded(String title) {
+        for (Collaborator listener : listeners) {
+            listener.documentAdded(title);
+        }
+    }
+
+    private void notifyListenersDocumentChanged(String title) {
+        for (Collaborator listener : listeners) {
+            listener.documentChanged(title);
+        }
+    }
+
+    private void notifyListenersDocumentRemoved(String title) {
+        for (Collaborator listener : listeners) {
+            listener.documentRemoved(title);
+        }
+    }
+
+    private boolean listenersAllowRemoval(String title) {
+        int result = 0;
+        for (Collaborator listener : listeners) {
+            result += listener.voteForRemoval(title);
+        }
+        return result > 0;
+    }
+
+    private boolean listenersAllowRemovals(String[] titles) {
+        int result = 0;
+        for (Collaborator listener : listeners) {
+            result += listener.voteForRemovals(titles);
+        }
+        return result > 0;
+    }
+
+}
diff --git a/samples/org/easymock/samples/Collaborator.java b/samples/org/easymock/samples/Collaborator.java
new file mode 100644
index 0000000..9526393
--- /dev/null
+++ b/samples/org/easymock/samples/Collaborator.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.samples;
+
+public interface Collaborator {
+    void documentAdded(String title);
+
+    void documentChanged(String title);
+
+    void documentRemoved(String title);
+
+    byte voteForRemoval(String title);
+
+    byte voteForRemovals(String[] title);
+}
diff --git a/samples/org/easymock/samples/ExampleTest.java b/samples/org/easymock/samples/ExampleTest.java
new file mode 100644
index 0000000..9ff3c38
--- /dev/null
+++ b/samples/org/easymock/samples/ExampleTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.samples;
+
+import static org.easymock.EasyMock.aryEq;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ExampleTest {
+
+    private ClassUnderTest classUnderTest;
+
+    private Collaborator mock;
+
+    @Before
+    public void setup() {
+        mock = createMock(Collaborator.class);
+        classUnderTest = new ClassUnderTest();
+        classUnderTest.addListener(mock);
+    }
+
+    @Test
+    public void removeNonExistingDocument() {
+        replay(mock);
+        classUnderTest.removeDocument("Does not exist");
+    }
+
+    @Test
+    public void addDocument() {
+        mock.documentAdded("New Document");
+        replay(mock);
+        classUnderTest.addDocument("New Document", new byte[0]);
+        verify(mock);
+    }
+
+    @Test
+    public void addAndChangeDocument() {
+        mock.documentAdded("Document");
+        mock.documentChanged("Document");
+        expectLastCall().times(3);
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        classUnderTest.addDocument("Document", new byte[0]);
+        verify(mock);
+    }
+
+    @Test
+    public void voteForRemoval() {
+        // expect document addition
+        mock.documentAdded("Document");
+        // expect to be asked to vote, and vote for it
+        expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
+        // expect document removal
+        mock.documentRemoved("Document");
+
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        assertTrue(classUnderTest.removeDocument("Document"));
+        verify(mock);
+    }
+
+    @Test
+    public void voteAgainstRemoval() {
+        // expect document addition
+        mock.documentAdded("Document");
+        // expect to be asked to vote, and vote against it
+        expect(mock.voteForRemoval("Document")).andReturn((byte) -42); // 
+        // document removal is *not* expected
+
+        replay(mock);
+        classUnderTest.addDocument("Document", new byte[0]);
+        assertFalse(classUnderTest.removeDocument("Document"));
+        verify(mock);
+    }
+
+    @Test
+    public void voteForRemovals() {
+        mock.documentAdded("Document 1");
+        mock.documentAdded("Document 2");
+        String[] documents = new String[] { "Document 1", "Document 2" };
+        expect(mock.voteForRemovals(aryEq(documents))).andReturn((byte) 42);
+        mock.documentRemoved("Document 1");
+        mock.documentRemoved("Document 2");
+        replay(mock);
+        classUnderTest.addDocument("Document 1", new byte[0]);
+        classUnderTest.addDocument("Document 2", new byte[0]);
+        assertTrue(classUnderTest.removeDocuments(new String[] { "Document 1",
+                "Document 2" }));
+        verify(mock);
+    }
+
+    @Test
+    public void voteAgainstRemovals() {
+        mock.documentAdded("Document 1");
+        mock.documentAdded("Document 2");
+        String[] documents = new String[] { "Document 1", "Document 2" };
+        expect(mock.voteForRemovals(aryEq(documents))).andReturn((byte) -42);
+        replay(mock);
+        classUnderTest.addDocument("Document 1", new byte[0]);
+        classUnderTest.addDocument("Document 2", new byte[0]);
+        assertFalse(classUnderTest.removeDocuments(new String[] { "Document 1",
+                "Document 2" }));
+        verify(mock);
+    }
+}
diff --git a/samples/org/easymock/samples/ThrowableEquals.java b/samples/org/easymock/samples/ThrowableEquals.java
new file mode 100644
index 0000000..ed22071
--- /dev/null
+++ b/samples/org/easymock/samples/ThrowableEquals.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.samples;
+
+import static org.easymock.EasyMock.reportMatcher;
+
+import org.easymock.IArgumentMatcher;
+
+public class ThrowableEquals implements IArgumentMatcher {
+    private Throwable expected;
+
+    public ThrowableEquals(Throwable expected) {
+        this.expected = expected;
+    }
+
+    public boolean matches(Object actual) {
+        if (!(actual instanceof Throwable)) {
+            return false;
+        }
+        String actualMessage = ((Throwable) actual).getMessage();
+        return expected.getClass().equals(actual.getClass())
+                && expected.getMessage().equals(actualMessage);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("<");
+        buffer.append(expected.getClass().getName());
+        buffer.append(" with message \"");
+        buffer.append(expected.getMessage());
+        buffer.append("\">");
+
+    }
+
+    public static <T extends Throwable> T eqException(T in) {
+        reportMatcher(new ThrowableEquals(in));
+        return in;
+    }            
+}
diff --git a/src/org/easymock/AbstractMatcher.java b/src/org/easymock/AbstractMatcher.java
new file mode 100644
index 0000000..4f47744
--- /dev/null
+++ b/src/org/easymock/AbstractMatcher.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+import java.io.Serializable;
+
+/**
+ * A convenience implementation of {@link ArgumentsMatcher}. A subclass that
+ * does not redefine any method will behave like
+ * {@link MockControl#EQUALS_MATCHER}.
+ * 
+ * @deprecated Since EasyMock 2.0, <code>ArgumentsMatcher</code>s are only supported
+ * for the legacy <code>MockControl</code>. For mock objects generated by the methods
+ * on <code>EasyMock</code>, there are per-argument matchers available. For more
+ * information, see the EasyMock documentation.
+ */
+public abstract class AbstractMatcher implements ArgumentsMatcher, Serializable {
+
+    private static final long serialVersionUID = -5463061331694985383L;
+
+    /**
+     * Checks whether an expected argument matches an actual argument; the method
+     * is used by
+     * {@link AbstractMatcher#matches(Object[], Object[])}. The arguments
+     * provided to this method are always not <code>null</code>.
+     * 
+     * @param expected
+     *            the expected argument.
+     * @param actual
+     *            the actual argument.
+     * @return true if the arguments match, false otherwise.
+     */
+    protected boolean argumentMatches(Object expected, Object actual) {
+        return expected.equals(actual);
+    }
+
+    /**
+     * Converts an argument to a String, used by
+     * {@link AbstractMatcher#toString(Object[])}.
+     * 
+     * @param argument
+     *            the argument to convert to a String.
+     * @return a <code>String</code> representation of the argument.
+     */
+    protected String argumentToString(Object argument) {
+        if (argument instanceof String) {
+            return "\"" + argument + "\"";
+        }
+        return "" + argument;
+    }
+
+    /**
+     * Checks whether an expected argument array matches an actual argument array.
+     * This convenience implementation uses
+     * <code>argumentMatches(Object, Object)</code> to check whether arguments
+     * pairs match. If all the arguments match, true is returned, otherwise
+     * false. In two cases, <code>argumentMatches(Object, Object)</code> is
+     * not called: If both argument arrays are null, they match; if one and only
+     * one is null, they do not match.
+     * 
+     * @param expected
+     *            the expected arguments.
+     * @param actual
+     *            the actual arguments.
+     * @return true if the arguments match, false otherwise.
+     */
+    public boolean matches(Object[] expected, Object[] actual) {
+        if (expected == actual) {
+            return true;
+        }
+        if (expected == null || actual == null) {
+            return false;
+        }
+        if (expected.length != actual.length) {
+            return false;
+        }
+        for (int i = 0; i < expected.length; i++) {
+            Object expectedObject = expected[i];
+            Object actualObject = actual[i];
+
+            if (expectedObject == null && actualObject == null) {
+                continue;
+            }
+
+            if (expectedObject == null && actualObject != null) {
+                return false;
+            }
+
+            if (expectedObject != null && actualObject == null) {
+                return false;
+            }
+
+            if (!argumentMatches(expectedObject, actualObject)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns a string representation of the matcher. This convenience
+     * implementation calls {@link AbstractMatcher#argumentToString(Object)}
+     * for every argument in the given array and returns the string representations
+     * of the arguments separated by commas.
+     * 
+     * @param arguments
+     *            the arguments to be used in the string representation.
+     * @return a string representation of the matcher.
+     */
+    public String toString(Object[] arguments) {
+        if (arguments == null)
+            arguments = new Object[0];
+
+        StringBuffer result = new StringBuffer();
+
+        for (int i = 0; i < arguments.length; i++) {
+            if (i > 0)
+                result.append(", ");
+            result.append(argumentToString(arguments[i]));
+        }
+        return result.toString();
+    }
+}
diff --git a/src/org/easymock/ArgumentsMatcher.java b/src/org/easymock/ArgumentsMatcher.java
new file mode 100644
index 0000000..428c8b2
--- /dev/null
+++ b/src/org/easymock/ArgumentsMatcher.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+/**
+ * A comparison function that is used to match arguments.
+ * 
+ * @see MockControl#setDefaultMatcher
+ * @see MockControl#setMatcher
+ * @see MockControl#EQUALS_MATCHER
+ * @see MockControl#ARRAY_MATCHER
+ * @see MockControl#ALWAYS_MATCHER
+ * 
+ * @deprecated Since EasyMock 2.0, <code>ArgumentsMatcher</code>s are only supported
+ * for the legacy <code>MockControl</code>. For mock objects generated by the methods
+ * on <code>EasyMock</code>, there are per-argument matchers available. For more
+ * information, see the EasyMock documentation.
+ */
+public interface ArgumentsMatcher {
+
+    /**
+     * Matches two arrays of arguments.
+     * 
+     * @param expected
+     *            the expected arguments.
+     * @param actual
+     *            the actual arguments.
+     * @return true if the arguments match, false otherwise.
+     */
+    boolean matches(Object[] expected, Object[] actual);
+
+    /**
+     * Returns a string representation of the arguments.
+     * 
+     * @param arguments
+     *            the arguments to be used in the string representation.
+     * @return a string representation of the arguments.
+     */
+    String toString(Object[] arguments);
+}
diff --git a/src/org/easymock/Capture.java b/src/org/easymock/Capture.java
new file mode 100644
index 0000000..6bfd6c2
--- /dev/null
+++ b/src/org/easymock/Capture.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2003-2008 OFFIS, Henri Tremblay. 
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+import java.io.Serializable;
+
+/**
+ * Will contain what was captured by the <code>capture()</code> matcher. Knows if
+ * something was captured or not (allows to capture a null value).
+ *
+ * @param <T> Type of the captured element
+ */
+public class Capture<T> implements Serializable {
+
+    private static final long serialVersionUID = -4214363692271370781L;
+
+    private boolean captured = false;
+
+    private T value;
+
+    /**
+     * Will reset capture to a "nothing captured yet" state
+     */
+    public void reset() {
+        value = null;
+        captured = false;
+    }
+    
+    /**
+     * @return true if something was captured 
+     */
+    public boolean hasCaptured() {
+        return captured;
+    }
+
+    /**
+     * Return the captured value
+     * 
+     * @throws AssertionError if nothing was captured yet
+     * @return What was captured
+     */
+    public T getValue() {
+        if (!captured) {
+            throw new AssertionError("Nothing captured yet");
+        }
+        return value;
+    }
+
+    /**
+     * Used internally by the EasyMock framework to set the captured value
+     * @param value Value captured
+     */
+    public void setValue(T value) {
+        this.value = value;
+        this.captured = true;
+    }
+
+    @Override
+    public String toString() {
+        if (!captured) {
+            return "Nothing captured yet";
+        }
+        return value == null ? null : value.toString();
+    }
+}
diff --git a/src/org/easymock/EasyMock.java b/src/org/easymock/EasyMock.java
new file mode 100644
index 0000000..24c4d49
--- /dev/null
+++ b/src/org/easymock/EasyMock.java
@@ -0,0 +1,1632 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+import java.lang.reflect.Proxy;
+import java.util.Comparator;
+
+import org.easymock.internal.LastControl;
+import org.easymock.internal.MocksControl;
+import org.easymock.internal.ObjectMethodsFilter;
+import org.easymock.internal.matchers.*;
+
+public class EasyMock {
+
+    /**
+     * Creates a mock object that implements the given interface, order checking
+     * is enabled by default.
+     * 
+     * @param <T>
+     *            the interface that the mock object should implement.
+     * @param toMock
+     *            the class of the interface that the mock object should
+     *            implement.
+     * @return the mock object.
+     */
+    public static <T> T createStrictMock(Class<T> toMock) {
+        return createStrictControl().createMock(toMock);
+    }
+
+    /**
+     * Creates a mock object that implements the given interface, order checking
+     * is enabled by default.
+     * @param name the name of the mock object.     
+     * @param toMock
+     *            the class of the interface that the mock object should
+     *            implement.
+     * @param <T>
+     *            the interface that the mock object should implement.
+     * @return the mock object.
+     * @throws IllegalArgumentException if the name is not a valid Java identifier.
+     */
+    public static <T> T createStrictMock(String name, Class<T> toMock) {
+        return createStrictControl().createMock(name, toMock);
+    }
+
+    /**
+     * Creates a mock object that implements the given interface, order checking
+     * is disabled by default.
+     * 
+     * @param <T>
+     *            the interface that the mock object should implement.
+     * @param toMock
+     *            the class of the interface that the mock object should
+     *            implement.
+     * @return the mock object.
+     */
+    public static <T> T createMock(Class<T> toMock) {
+        return createControl().createMock(toMock);
+    }
+
+    /**
+     * Creates a mock object that implements the given interface, order checking
+     * is disabled by default.
+     * @param name the name of the mock object.
+     * @param toMock
+     *            the class of the interface that the mock object should
+     *            implement.
+     * 
+     * @param <T>
+     *            the interface that the mock object should implement.
+     * @return the mock object.
+     * @throws IllegalArgumentException if the name is not a valid Java identifier.
+     */
+    public static <T> T createMock(String name, Class<T> toMock) {
+        return createControl().createMock(name, toMock);
+    }
+    
+    /**
+     * Creates a mock object that implements the given interface, order checking
+     * is disabled by default, and the mock object will return <code>0</code>,
+     * <code>null</code> or <code>false</code> for unexpected invocations.
+     * 
+     * @param <T>
+     *            the interface that the mock object should implement.
+     * @param toMock
+     *            the class of the interface that the mock object should
+     *            implement.
+     * @return the mock object.
+     */
+    public static <T> T createNiceMock(Class<T> toMock) {
+        return createNiceControl().createMock(toMock);
+    }
+
+    /**
+     * Creates a mock object that implements the given interface, order checking
+     * is disabled by default, and the mock object will return <code>0</code>,
+     * <code>null</code> or <code>false</code> for unexpected invocations.
+     * @param name the name of the mock object.
+     * @param toMock
+     *            the class of the interface that the mock object should
+     *            implement.
+     * 
+     * @param <T>
+     *            the interface that the mock object should implement.
+     * @return the mock object.
+     * @throws IllegalArgumentException if the name is not a valid Java identifier.
+     */
+    public static <T> T createNiceMock(String name, Class<T> toMock) {
+        return createNiceControl().createMock(name, toMock);
+    }
+    
+    /**
+     * Creates a control, order checking is enabled by default.
+     * 
+     * @return the control.
+     */
+    public static IMocksControl createStrictControl() {
+        return new MocksControl(MocksControl.MockType.STRICT);
+    }
+
+    /**
+     * Creates a control, order checking is disabled by default.
+     * 
+     * @return the control.
+     */
+    public static IMocksControl createControl() {
+        return new MocksControl(MocksControl.MockType.DEFAULT);
+    }
+
+    /**
+     * Creates a control, order checking is disabled by default, and the mock
+     * objects created by this control will return <code>0</code>,
+     * <code>null</code> or <code>false</code> for unexpected invocations.
+     * 
+     * @return the control.
+     */
+    public static IMocksControl createNiceControl() {
+        return new MocksControl(MocksControl.MockType.NICE);
+    }
+
+    /**
+     * Returns the expectation setter for the last expected invocation in the
+     * current thread.
+     * 
+     * @param value
+     *            the parameter is used to transport the type to the
+     *            ExpectationSetter. It allows writing the expected call as
+     *            argument, i.e.
+     *            <code>expect(mock.getName()).andReturn("John Doe")<code>.
+     * 
+     * @return the expectation setter.
+     */
+    public static <T> IExpectationSetters<T> expect(T value) {
+        return EasyMock.getControlForLastCall();
+    }
+
+    /**
+     * Returns the expectation setter for the last expected invocation in the
+     * current thread. This method is used for expected invocations on void
+     * methods.
+     * 
+     * @return the expectation setter.
+     */
+    public static <T> IExpectationSetters<T> expectLastCall() {
+        return getControlForLastCall();
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> IExpectationSetters<T> getControlForLastCall() {
+        MocksControl lastControl = LastControl.lastControl();
+        if (lastControl == null) {
+            throw new IllegalStateException("no last call on a mock available");
+        }
+        return (IExpectationSetters<T>) lastControl;
+    }
+
+    /**
+     * Expects any boolean argument. For details, see the EasyMock
+     * documentation.
+     * 
+     * @return <code>false</code>.
+     */
+    public static boolean anyBoolean() {
+        reportMatcher(Any.ANY);
+        return false;
+    }
+
+    /**
+     * Expects any byte argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>0</code>.
+     */
+    public static byte anyByte() {
+        reportMatcher(Any.ANY);
+        return 0;
+    }
+
+    /**
+     * Expects any char argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>0</code>.
+     */
+    public static char anyChar() {
+        reportMatcher(Any.ANY);
+        return 0;
+    }
+
+    /**
+     * Expects any int argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>0</code>.
+     */
+    public static int anyInt() {
+        reportMatcher(Any.ANY);
+        return 0;
+    }
+
+    /**
+     * Expects any long argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>0</code>.
+     */
+    public static long anyLong() {
+        reportMatcher(Any.ANY);
+        return 0;
+    }
+
+    /**
+     * Expects any float argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>0</code>.
+     */
+    public static float anyFloat() {
+        reportMatcher(Any.ANY);
+        return 0;
+    }
+
+    /**
+     * Expects any double argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>0</code>.
+     */
+    public static double anyDouble() {
+        reportMatcher(Any.ANY);
+        return 0;
+    }
+
+    /**
+     * Expects any short argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>0</code>.
+     */
+    public static short anyShort() {
+        reportMatcher(Any.ANY);
+        return 0;
+    }
+
+    /**
+     * Expects any Object argument. For details, see the EasyMock documentation.
+     * 
+     * @return <code>null</code>.
+     */
+    public static <T> T anyObject() {
+        reportMatcher(Any.ANY);
+        return null;
+    }
+
+    /**
+     * Expects a comparable argument greater than or equal the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>null</code>.
+     */
+    public static <T extends Comparable<T>> T geq(Comparable<T> value) {
+        reportMatcher(new GreaterOrEqual<T>(value));
+        return null;
+    }
+    
+    /**
+     * Expects a byte argument greater than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static byte geq(byte value) {
+        reportMatcher(new GreaterOrEqual<Byte>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a double argument greater than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static double geq(double value) {
+        reportMatcher(new GreaterOrEqual<Double>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a float argument greater than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static float geq(float value) {
+        reportMatcher(new GreaterOrEqual<Float>(value));
+        return 0;
+    }
+
+    /**
+     * Expects an int argument greater than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static int geq(int value) {
+        reportMatcher(new GreaterOrEqual<Integer>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a long argument greater than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static long geq(long value) {
+        reportMatcher(new GreaterOrEqual<Long>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a short argument greater than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static short geq(short value) {
+        reportMatcher(new GreaterOrEqual<Short>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a comparable argument less than or equal the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>null</code>.
+     */
+    public static <T extends Comparable<T>> T leq(Comparable<T> value) {
+        reportMatcher(new LessOrEqual<T>(value));
+        return null;
+    }
+     
+    /**
+     * Expects a byte argument less than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static byte leq(byte value) {
+        reportMatcher(new LessOrEqual<Byte>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a double argument less than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static double leq(double value) {
+        reportMatcher(new LessOrEqual<Double>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a float argument less than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static float leq(float value) {
+        reportMatcher(new LessOrEqual<Float>(value));
+        return 0;
+    }
+
+    /**
+     * Expects an int argument less than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static int leq(int value) {
+        reportMatcher(new LessOrEqual<Integer>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a long argument less than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static long leq(long value) {
+        reportMatcher(new LessOrEqual<Long>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a short argument less than or equal to the given value. For
+     * details, see the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static short leq(short value) {
+        reportMatcher(new LessOrEqual<Short>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a comparable argument greater than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>null</code>.
+     */
+    public static <T extends Comparable<T>> T gt(Comparable<T> value) {
+        reportMatcher(new GreaterThan<T>(value));
+        return null;
+    }
+    
+    /**
+     * Expects a byte argument greater than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static byte gt(byte value) {
+        reportMatcher(new GreaterThan<Byte>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a double argument greater than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static double gt(double value) {
+        reportMatcher(new GreaterThan<Double>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a float argument greater than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static float gt(float value) {
+        reportMatcher(new GreaterThan<Float>(value));
+        return 0;
+    }
+
+    /**
+     * Expects an int argument greater than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static int gt(int value) {
+        reportMatcher(new GreaterThan<Integer>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a long argument greater than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static long gt(long value) {
+        reportMatcher(new GreaterThan<Long>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a short argument greater than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static short gt(short value) {
+        reportMatcher(new GreaterThan<Short>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a comparable argument less than the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>null</code>.
+     */
+    public static <T extends Comparable<T>> T lt(Comparable<T> value) {
+        reportMatcher(new LessThan<T>(value));
+        return null;
+    }
+    
+    /**
+     * Expects a byte argument less than the given value. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static byte lt(byte value) {
+        reportMatcher(new LessThan<Byte>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a double argument less than the given value. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static double lt(double value) {
+        reportMatcher(new LessThan<Double>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a float argument less than the given value. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static float lt(float value) {
+        reportMatcher(new LessThan<Float>(value));
+        return 0;
+    }
+
+    /**
+     * Expects an int argument less than the given value. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static int lt(int value) {
+        reportMatcher(new LessThan<Integer>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a long argument less than the given value. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static long lt(long value) {
+        reportMatcher(new LessThan<Long>(value));
+        return 0;
+    }
+
+    /**
+     * Expects a short argument less than the given value. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static short lt(short value) {
+        reportMatcher(new LessThan<Short>(value));
+        return 0;
+    }
+
+    /**
+     * Expects an object implementing the given class. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param <T>
+     *            the accepted type.
+     * @param clazz
+     *            the class of the accepted type.
+     * @return <code>null</code>.
+     */
+    public static <T> T isA(Class<T> clazz) {
+        reportMatcher(new InstanceOf(clazz));
+        return null;
+    }
+
+    /**
+     * Expects a string that contains the given substring. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param substring
+     *            the substring.
+     * @return <code>null</code>.
+     */
+    public static String contains(String substring) {
+        reportMatcher(new Contains(substring));
+        return null;
+    }
+
+    /**
+     * Expects a boolean that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>false</code>.
+     */
+    public static boolean and(boolean first, boolean second) {
+        LastControl.reportAnd(2);
+        return false;
+    }
+
+    /**
+     * Expects a byte that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static byte and(byte first, byte second) {
+        LastControl.reportAnd(2);
+        return 0;
+    }
+
+    /**
+     * Expects a char that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static char and(char first, char second) {
+        LastControl.reportAnd(2);
+        return 0;
+    }
+
+    /**
+     * Expects a double that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static double and(double first, double second) {
+        LastControl.reportAnd(2);
+        return 0;
+    }
+
+    /**
+     * Expects a float that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static float and(float first, float second) {
+        LastControl.reportAnd(2);
+        return 0;
+    }
+
+    /**
+     * Expects an int that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static int and(int first, int second) {
+        LastControl.reportAnd(2);
+        return 0;
+    }
+
+    /**
+     * Expects a long that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static long and(long first, long second) {
+        LastControl.reportAnd(2);
+        return 0;
+    }
+
+    /**
+     * Expects a short that matches both given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static short and(short first, short second) {
+        LastControl.reportAnd(2);
+        return 0;
+    }
+
+    /**
+     * Expects an Object that matches both given expectations.
+     * 
+     * @param <T>
+     *            the type of the object, it is passed through to prevent casts.
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>null</code>.
+     */
+    public static <T> T and(T first, T second) {
+        LastControl.reportAnd(2);
+        return null;
+    }
+
+    /**
+     * Expects a boolean that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>false</code>.
+     */
+    public static boolean or(boolean first, boolean second) {
+        LastControl.reportOr(2);
+        return false;
+    }
+
+    /**
+     * Expects a byte that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static byte or(byte first, byte second) {
+        LastControl.reportOr(2);
+        return 0;
+    }
+
+    /**
+     * Expects a char that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static char or(char first, char second) {
+        LastControl.reportOr(2);
+        return 0;
+    }
+
+    /**
+     * Expects a double that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static double or(double first, double second) {
+        LastControl.reportOr(2);
+        return 0;
+    }
+
+    /**
+     * Expects a float that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static float or(float first, float second) {
+        LastControl.reportOr(2);
+        return 0;
+    }
+
+    /**
+     * Expects an int that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static int or(int first, int second) {
+        LastControl.reportOr(2);
+        return first;
+    }
+
+    /**
+     * Expects a long that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static long or(long first, long second) {
+        LastControl.reportOr(2);
+        return 0;
+    }
+
+    /**
+     * Expects a short that matches one of the given expectations.
+     * 
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>0</code>.
+     */
+    public static short or(short first, short second) {
+        LastControl.reportOr(2);
+        return 0;
+    }
+
+    /**
+     * Expects an Object that matches one of the given expectations.
+     * 
+     * @param <T>
+     *            the type of the object, it is passed through to prevent casts.
+     * @param first
+     *            placeholder for the first expectation.
+     * @param second
+     *            placeholder for the second expectation.
+     * @return <code>null</code>.
+     */
+    public static <T> T or(T first, T second) {
+        LastControl.reportOr(2);
+        return null;
+    }
+
+    /**
+     * Expects a boolean that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>false</code>.
+     */
+    public static boolean not(boolean first) {
+        LastControl.reportNot();
+        return false;
+    }
+
+    /**
+     * Expects a byte that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>0</code>.
+     */
+    public static byte not(byte first) {
+        LastControl.reportNot();
+        return 0;
+    }
+
+    /**
+     * Expects a char that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>0</code>.
+     */
+    public static char not(char first) {
+        LastControl.reportNot();
+        return 0;
+    }
+
+    /**
+     * Expects a double that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>0</code>.
+     */
+    public static double not(double first) {
+        LastControl.reportNot();
+        return 0;
+    }
+
+    /**
+     * Expects a float that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>0</code>.
+     */
+    public static float not(float first) {
+        LastControl.reportNot();
+        return first;
+    }
+
+    /**
+     * Expects an int that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>0</code>.
+     */
+    public static int not(int first) {
+        LastControl.reportNot();
+        return 0;
+    }
+
+    /**
+     * Expects a long that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>0</code>.
+     */
+    public static long not(long first) {
+        LastControl.reportNot();
+        return 0;
+    }
+
+    /**
+     * Expects a short that does not match the given expectation.
+     * 
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>0</code>.
+     */
+    public static short not(short first) {
+        LastControl.reportNot();
+        return 0;
+    }
+
+    /**
+     * Expects an Object that does not match the given expectation.
+     * 
+     * @param <T>
+     *            the type of the object, it is passed through to prevent casts.
+     * @param first
+     *            placeholder for the expectation.
+     * @return <code>null</code>.
+     */
+    public static <T> T not(T first) {
+        LastControl.reportNot();
+        return null;
+    }
+
+    /**
+     * Expects a boolean that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static boolean eq(boolean value) {
+        reportMatcher(new Equals(value));
+        return false;
+    }
+
+    /**
+     * Expects a byte that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static byte eq(byte value) {
+        reportMatcher(new Equals(value));
+        return 0;
+    }
+
+    /**
+     * Expects a char that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static char eq(char value) {
+        reportMatcher(new Equals(value));
+        return 0;
+    }
+
+    /**
+     * Expects a double that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static double eq(double value) {
+        reportMatcher(new Equals(value));
+        return 0;
+    }
+
+    /**
+     * Expects a float that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static float eq(float value) {
+        reportMatcher(new Equals(value));
+        return 0;
+    }
+
+    /**
+     * Expects an int that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static int eq(int value) {
+        reportMatcher(new Equals(value));
+        return 0;
+    }
+
+    /**
+     * Expects a long that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static long eq(long value) {
+        reportMatcher(new Equals(value));
+        return 0;
+    }
+
+    /**
+     * Expects a short that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    public static short eq(short value) {
+        reportMatcher(new Equals(value));
+        return 0;
+    }
+
+    /**
+     * Expects an Object that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>null</code>.
+     */
+    public static <T> T eq(T value) {
+        reportMatcher(new Equals(value));
+        return null;
+    }
+
+    /**
+     * Expects a boolean array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static boolean[] aryEq(boolean[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects a byte array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static byte[] aryEq(byte[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects a char array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static char[] aryEq(char[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects a double array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static double[] aryEq(double[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects a float array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static float[] aryEq(float[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects an int array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static int[] aryEq(int[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects a long array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static long[] aryEq(long[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects a short array that is equal to the given array, i.e. it has to
+     * have the same length, and each element has to be equal.
+     * 
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static short[] aryEq(short[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects an Object array that is equal to the given array, i.e. it has to
+     * have the same type, length, and each element has to be equal.
+     * 
+     * @param <T>
+     *            the type of the array, it is passed through to prevent casts.
+     * @param value
+     *            the given arry.
+     * @return <code>null</code>.
+     */
+    public static <T> T[] aryEq(T[] value) {
+        reportMatcher(new ArrayEquals(value));
+        return null;
+    }
+
+    /**
+     * Expects null.
+     * 
+     * @return <code>null</code>.
+     */
+    public static <T> T isNull() {
+        reportMatcher(Null.NULL);
+        return null;
+    }
+
+    /**
+     * Expects not null.
+     * 
+     * @return <code>null</code>.
+     */
+    public static <T> T notNull() {
+        reportMatcher(NotNull.NOT_NULL);
+        return null;
+    }
+
+    /**
+     * Expects a string that contains a substring that matches the given regular
+     * expression. For details, see the EasyMock documentation.
+     * 
+     * @param regex
+     *            the regular expression.
+     * @return <code>null</code>.
+     */
+    public static String find(String regex) {
+        reportMatcher(new Find(regex));
+        return null;
+    }
+
+    /**
+     * Expects a string that matches the given regular expression. For details,
+     * see the EasyMock documentation.
+     * 
+     * @param regex
+     *            the regular expression.
+     * @return <code>null</code>.
+     */
+    public static String matches(String regex) {
+        reportMatcher(new Matches(regex));
+        return null;
+    }
+
+    /**
+     * Expects a string that starts with the given prefix. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param prefix
+     *            the prefix.
+     * @return <code>null</code>.
+     */
+    public static String startsWith(String prefix) {
+        reportMatcher(new StartsWith(prefix));
+        return null;
+    }
+
+    /**
+     * Expects a string that ends with the given suffix. For details, see the
+     * EasyMock documentation.
+     * 
+     * @param suffix
+     *            the suffix.
+     * @return <code>null</code>.
+     */
+    public static String endsWith(String suffix) {
+        reportMatcher(new EndsWith(suffix));
+        return null;
+    }
+
+    /**
+     * Expects a double that has an absolute difference to the given value that
+     * is less than the given delta. For details, see the EasyMock
+     * documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @param delta
+     *            the given delta.
+     * @return <code>0</code>.
+     */
+    public static double eq(double value, double delta) {
+        reportMatcher(new EqualsWithDelta(value, delta));
+        return 0;
+    }
+
+    /**
+     * Expects a float that has an absolute difference to the given value that
+     * is less than the given delta. For details, see the EasyMock
+     * documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @param delta
+     *            the given delta.
+     * @return <code>0</code>.
+     */
+    public static float eq(float value, float delta) {
+        reportMatcher(new EqualsWithDelta(value, delta));
+        return 0;
+    }
+
+    /**
+     * Expects an Object that is the same as the given value. For details, see
+     * the EasyMock documentation.
+     * 
+     * @param <T>
+     *            the type of the object, it is passed through to prevent casts.
+     * @param value
+     *            the given value.
+     * @return <code>null</code>.
+     */
+    public static <T> T same(T value) {
+        reportMatcher(new Same(value));
+        return null;
+    }
+    
+    /**
+     * Expects a comparable argument equals to the given value according to their
+     * compareTo method. For details, see the EasMock documentation.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>null</code>.
+     */
+    public static <T extends Comparable<T>> T cmpEq(Comparable<T> value) {
+        reportMatcher(new CompareEqual<T>(value));
+        return null;
+    }
+    
+    /**
+     * Expects an argument that will be compared using the provided comparator.
+     * The following comparison will take place:
+     * <p>
+     * <code>comparator.compare(actual, expected) operator 0</code>
+     * </p>
+     * For details, see the EasyMock documentation.
+     * 
+     * @param value the given value.
+     * @param comparator Comparator used to compare the actual with expected value.
+     * @param operator The comparison operator.
+     * @return <code>null</code>
+     */
+    public static <T> T cmp(T value, Comparator<? super T> comparator, LogicalOperator operator) {
+        reportMatcher(new Compare<T>(value, comparator, operator));
+        return null;
+    }
+
+
+    /**
+     * Expects a byte that is equal to the given value.
+     * 
+     * @param value
+     *            the given value.
+     * @return <code>0</code>.
+     */
+    
+    
+    /**
+     * Expect any object but captures it for later use.
+     *  
+     * @param <T> Type of the captured object
+     * @param captured Where the parameter is captured
+     * @return <code>null</code>
+     */
+    public static <T> T capture(Capture<T> captured) {
+        reportMatcher(new Captures<T>(captured));
+        return null;
+    }
+    
+    /**
+     * Expect any int but captures it for later use.
+     *  
+     * @param captured Where the parameter is captured
+     * @return <code>0</code>
+     */
+    public static int capture(Capture<Integer> captured) {
+        reportMatcher(new Captures<Integer>(captured));
+        return 0;
+    }
+    
+    /**
+     * Expect any long but captures it for later use.
+     *  
+     * @param captured Where the parameter is captured
+     * @return <code>0</code>
+     */
+    public static long capture(Capture<Long> captured) {
+        reportMatcher(new Captures<Long>(captured));
+        return 0;
+    }
+    
+    /**
+     * Expect any float but captures it for later use.
+     *  
+     * @param captured Where the parameter is captured
+     * @return <code>0</code>
+     */
+    public static float capture(Capture<Float> captured) {
+        reportMatcher(new Captures<Float>(captured));
+        return 0;
+    }
+    
+    /**
+     * Expect any double but captures it for later use.
+     *  
+     * @param captured Where the parameter is captured
+     * @return <code>0</code>
+     */
+    public static double capture(Capture<Double> captured) {
+        reportMatcher(new Captures<Double>(captured));
+        return 0;
+    }
+
+    /**
+     * Expect any byte but captures it for later use.
+     *  
+     * @param captured Where the parameter is captured
+     * @return <code>0</code>
+     */
+    public static byte capture(Capture<Byte> captured) {
+        reportMatcher(new Captures<Byte>(captured));
+        return 0;
+    }
+    
+    /**
+     * Expect any char but captures it for later use.
+     *  
+     * @param captured Where the parameter is captured
+     * @return <code>0</code>
+     */
+    public static char capture(Capture<Character> captured) {
+        reportMatcher(new Captures<Character>(captured));
+        return 0;
+    }
+    
+    /**
+     * Switches the given mock objects (more exactly: the controls of the mock
+     * objects) to replay mode. For details, see the EasyMock documentation.
+     * 
+     * @param mocks
+     *            the mock objects.
+     */
+    public static void replay(Object... mocks) {
+        for (Object mock : mocks) {
+            getControl(mock).replay();
+        }
+    }
+
+    /**
+     * Resets the given mock objects (more exactly: the controls of the mock
+     * objects). For details, see the EasyMock documentation.
+     * 
+     * @param mocks
+     *            the mock objects.
+     */
+    public static void reset(Object... mocks) {
+        for (Object mock : mocks) {
+            getControl(mock).reset();
+        }
+    }
+
+    /**
+     * Resets the given mock objects (more exactly: the controls of the mock
+     * objects) and turn them to a mock with nice behavior. For details, see 
+     * the EasyMock documentation.
+     * 
+     * @param mocks
+     *            the mock objects
+     */
+    public static void resetToNice(Object... mocks) {
+        for (Object mock : mocks) {
+            getControl(mock).resetToNice();
+        }
+    }
+    
+    /**
+     * Resets the given mock objects (more exactly: the controls of the mock
+     * objects) and turn them to a mock with default behavior. For details, see 
+     * the EasyMock documentation.
+     * 
+     * @param mocks
+     *            the mock objects
+     */
+    public static void resetToDefault(Object... mocks) {
+        for (Object mock : mocks) {
+            getControl(mock).resetToDefault();
+        }
+    }
+    
+    /**
+     * Resets the given mock objects (more exactly: the controls of the mock
+     * objects) and turn them to a mock with strict behavior. For details, see 
+     * the EasyMock documentation.
+     * 
+     * @param mocks
+     *            the mock objects
+     */
+    public static void resetToStrict(Object... mocks) {
+        for (Object mock : mocks) {
+            getControl(mock).resetToStrict();
+        }
+    }
+    
+    /**
+     * Verifies the given mock objects (more exactly: the controls of the mock
+     * objects).
+     * 
+     * @param mocks
+     *            the mock objects.
+     */
+    public static void verify(Object... mocks) {
+        for (Object mock : mocks) {
+            getControl(mock).verify();
+        }
+    }
+
+    /**
+     * Switches order checking of the given mock object (more exactly: the
+     * control of the mock object) the on and off. For details, see the EasyMock
+     * documentation.
+     * 
+     * @param mock
+     *            the mock object.
+     * @param state
+     *            <code>true</code> switches order checking on,
+     *            <code>false</code> switches it off.
+     */
+    public static void checkOrder(Object mock, boolean state) {
+        getControl(mock).checkOrder(state);
+    }
+
+    /**
+     * Reports an argument matcher. This method is needed to define own argument
+     * matchers. For details, see the EasyMock documentation.
+     * 
+     * @param matcher
+     */
+    public static void reportMatcher(IArgumentMatcher matcher) {
+        LastControl.reportMatcher(matcher);
+    }
+
+    private static MocksControl getControl(Object mock) {
+        return ((ObjectMethodsFilter) Proxy
+        .getInvocationHandler(mock)).getDelegate().getControl();
+    }
+
+    /**
+     * Returns the arguments of the current mock method call, if inside an
+     * <code>IAnswer</code> callback - be careful here, reordering parameters of  
+     * method changes the semantics of your tests.
+     * 
+     * @return the arguments of the current mock method call.
+     * @throws IllegalStateException
+     *             if called outside of <code>IAnswer</code> callbacks.
+     */
+    public static Object[] getCurrentArguments() {
+        Object[] result = LastControl.getCurrentArguments();
+        if (result == null) {
+            throw new IllegalStateException(
+                    "current arguments are only available when executing callback methods");
+        }
+        return result;
+    }
+    
+    /**
+     * Makes the mock thread safe. The mock will be usable in a multithreaded
+     * environment.
+     * 
+     * @param mock the mock to make thread safe
+     * @param threadSafe If the mock should be thread safe or not
+     */
+    public static void makeThreadSafe(Object mock, boolean threadSafe) {
+        getControl(mock).makeThreadSafe(threadSafe);
+    }
+}
diff --git a/src/org/easymock/IAnswer.java b/src/org/easymock/IAnswer.java
new file mode 100644
index 0000000..c5e7129
--- /dev/null
+++ b/src/org/easymock/IAnswer.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+/**
+ * Used to answer expected calls.
+ * @param <T> the type to return.
+ */
+public interface IAnswer<T> {
+    /**
+     * is called by EasyMock to answer an expected call. 
+     * The answer may be to return a value, or to throw an exception.
+     * The arguments of the call for which the answer is generated 
+     * are available via {@link EasyMock#getCurrentArguments()} - be careful
+     * here, using the arguments is not refactoring-safe.
+     * 
+     * @return the value to be returned
+     * @throws Throwable the throwable to be thrown
+     */
+    T answer() throws Throwable;
+}
diff --git a/src/org/easymock/IArgumentMatcher.java b/src/org/easymock/IArgumentMatcher.java
new file mode 100644
index 0000000..f734194
--- /dev/null
+++ b/src/org/easymock/IArgumentMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2001-2006 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+/**
+ * Decides whether an actual argument is accepted.
+ */
+public interface IArgumentMatcher {
+    
+    /**
+     * Returns whether this matcher accepts the given argument. 
+     * <p>
+     * Like Object.equals(), it should be aware that the argument passed might 
+     * be null and of any type. So you will usually start the method with an 
+     * instanceof and/or null check.
+     * <p>
+     * The method should <b>never</b> assert if the argument doesn't match. It
+     * should only return false. EasyMock will take care of asserting if the
+     * call is really unexpected.
+     * 
+     * @param argument the argument
+     * @return whether this matcher accepts the given argument.
+     */
+    boolean matches(Object argument);
+
+    /**
+     * Appends a string representation of this matcher to the given buffer. In case
+     * of failure, the printed message will show this string to allow to know which
+     * matcher was used for the failing call.
+     * 
+     * @param buffer the buffer to which the string representation is appended.
+     */
+    void appendTo(StringBuffer buffer);
+}
diff --git a/src/org/easymock/IExpectationSetters.java b/src/org/easymock/IExpectationSetters.java
new file mode 100644
index 0000000..e6d7e63
--- /dev/null
+++ b/src/org/easymock/IExpectationSetters.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+/**
+ * Allows setting expectations for an associated expected invocation.
+ * Implementations of this interface are returned by
+ * {@link EasyMock#expect(Object)}, and by {@link EasyMock#expectLastCall()}.
+ */
+public interface IExpectationSetters<T> {
+
+    /**
+     * Sets a return value that will be returned for the expected invocation.
+     * 
+     * @param value
+     *            the value to return.
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> andReturn(T value);
+
+    /**
+     * Sets a throwable that will be thrown for the expected invocation.
+     * 
+     * @param throwable
+     *            the throwable to throw.
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> andThrow(Throwable throwable);
+
+    /**
+     * Sets an object that will be used to calculate the answer for the expected
+     * invocation (either return a value, or throw an exception).
+     * 
+     * @param answer
+     *            the object used to answer the invocation.
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> andAnswer(IAnswer<? extends T> answer);
+
+    /**
+     * Sets a stub return value that will be returned for the expected
+     * invocation.
+     * 
+     * @param value
+     *            the value to return.
+     */
+    void andStubReturn(T value);
+
+    /**
+     * Sets a stub throwable that will be thrown for the expected invocation.
+     * 
+     * @param throwable
+     *            the throwable to throw.
+     */
+    void andStubThrow(Throwable throwable);
+
+    /**
+     * Sets a stub object that will be used to calculate the answer for the
+     * expected invocation (either return a value, or throw an exception).
+     * 
+     * @param answer
+     *            the object used to answer the invocation.
+     */
+    void andStubAnswer(IAnswer<? extends T> answer);
+
+    /**
+     * Sets stub behavior for the expected invocation (this is needed for void
+     * methods).
+     */
+    void asStub();
+
+    /**
+     * Expect the last invocation <code>count</code> times.
+     * 
+     * @param count
+     *            the number of invocations expected.
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> times(int count);
+
+    /**
+     * Expect the last invocation between <code>min</code> and
+     * <code>max</code> times.
+     * 
+     * @param min
+     *            the minimum number of invocations expected.
+     * @param max
+     *            the maximum number of invocations expected.
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> times(int min, int max);
+
+    /**
+     * Expect the last invocation once. This is default in EasyMock.
+     * 
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> once();
+
+    /**
+     * Expect the last invocation at least once.
+     * 
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> atLeastOnce();
+
+    /**
+     * Expect the last invocation any times.
+     * 
+     * @return this object to allow method call chaining.
+     */
+    IExpectationSetters<T> anyTimes();
+}
diff --git a/src/org/easymock/IMocksControl.java b/src/org/easymock/IMocksControl.java
new file mode 100644
index 0000000..17f9ff6
--- /dev/null
+++ b/src/org/easymock/IMocksControl.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+/**
+ * Controls all the mock objects created by it.
+ * For details, see the EasyMock documentation.
+ */
+public interface IMocksControl {
+    /**
+     * Creates a mock object that implements the given interface.
+     * @param <T> the interface that the mock object should implement.
+     * @param toMock the class of the interface that the mock object should implement.
+     * @return the mock object.
+     */
+    <T> T createMock(Class<T> toMock);
+
+    /**
+     * Creates a mock object that implements the given interface.
+     * @param name the name of the mock object .
+     * @param toMock the class of the interface that the mock object should implement.
+     * @param <T> the interface that the mock object should implement.
+     * @return the mock object.
+     * @throws IllegalArgumentException if the name is not a valid Java identifier.
+     */
+    <T> T createMock(String name, Class<T> toMock);
+
+    /**
+     * Removes all expectations for the mock objects of this control.
+     */
+    void reset();
+    
+    /**
+     * Removes all expectations for the mock objects of this control and turn
+     * them to nice mocks.
+     */
+    void resetToNice();
+    
+    /**
+     * Removes all expectations for the mock objects of this control and turn
+     * them to default mocks.
+     */
+    void resetToDefault();
+    
+    /**
+     * Removes all expectations for the mock objects of this control and turn
+     * them to strict mocks.
+     */
+    void resetToStrict();
+
+    /**
+     * Switches the control from record mode to replay mode.
+     */
+    void replay();
+
+    /**
+     * Verifies that all expectations were met. 
+     */
+    void verify();
+
+    /**
+     * Switches order checking on and off.
+     * @param state <code>true</code> switches order checking on, <code>false</code> switches it off.
+     */
+    void checkOrder(boolean state);
+    
+    /**
+     * Makes the mock thread safe.
+     * 
+     * @param threadSafe If the mock should be thread safe or not
+     */
+    void makeThreadSafe(boolean threadSafe);
+}
diff --git a/src/org/easymock/LogicalOperator.java b/src/org/easymock/LogicalOperator.java
new file mode 100644
index 0000000..859598e
--- /dev/null
+++ b/src/org/easymock/LogicalOperator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Henri Tremblay.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+/**
+ * See {@link EasyMock#cmp}
+ */
+public enum LogicalOperator {
+    LESS_THAN("<") {
+        public boolean matchResult(int result) {
+            return result < 0;
+        }
+    },
+    LESS_OR_EQUAL("<=") {
+        public boolean matchResult(int result) {
+            return result <= 0;
+        }
+    },
+    EQUAL("==") {
+        public boolean matchResult(int result) {
+            return result == 0;
+        }
+    },
+    GREATER_OR_EQUAL(">=") {
+        public boolean matchResult(int result) {
+            return result >= 0;
+        }
+    },
+    GREATER(">") {
+        public boolean matchResult(int result) {
+            return result > 0;
+        }
+    };
+    
+    private String symbol;
+    
+    private LogicalOperator(String symbol) {
+        this.symbol = symbol;
+    }
+    
+    public String getSymbol() {
+        return symbol;
+    }
+    
+    public abstract boolean matchResult(int result);
+}
diff --git a/src/org/easymock/MockControl.java b/src/org/easymock/MockControl.java
new file mode 100644
index 0000000..9f04fb9
--- /dev/null
+++ b/src/org/easymock/MockControl.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock;
+
+import static org.easymock.EasyMock.expect;
+
+import org.easymock.internal.*;
+
+/**
+ * A <code>MockControl</code> object controls the behavior of its associated
+ * mock object. For more information, see the EasyMock documentation.
+ * 
+ * @deprecated Since EasyMock 2.0, static methods on <code>EasyMock</code> are
+ * used to create and control mock objects.
+ */
+public class MockControl<T> {
+    private final T mock;
+
+    private final MocksControl ctrl;
+
+    protected MockControl(MocksControl ctrl, Class<T> toMock) {
+        this.ctrl = ctrl;
+        this.mock = ctrl.createMock(toMock);
+    }
+
+    /**
+     * Creates a mock control object for the specified interface. The
+     * <code>MockControl</code> and its associated mock object will not check
+     * the order of expected method calls. An unexpected method call on the mock
+     * object will lead to an <code>AssertionError</code>.
+     * 
+     * @param toMock
+     *            the class of the interface to mock.
+     * @return the mock control.
+     */
+    public static <T> MockControl<T> createControl(Class<T> toMock) {
+        return new MockControl<T>((MocksControl) EasyMock.createControl(),
+                toMock);
+    }
+
+    /**
+     * Creates a mock control object for the specified interface. The
+     * <code>MockControl</code> and its associated mock object will check the
+     * order of expected method calls. An unexpected method call on the mock
+     * object will lead to an <code>AssertionError</code>.
+     * 
+     * @param toMock
+     *            the class of the interface to mock.
+     * @return the mock control.
+     */
+    public static <T extends Object> MockControl<T> createStrictControl(Class<T> toMock) {
+        return new MockControl<T>(
+                (MocksControl) EasyMock.createStrictControl(), toMock);
+    }
+
+    /**
+     * Creates a mock control object for the specified interface. The
+     * <code>MockControl</code> and its associated mock object will not check
+     * the order of expected method calls. An unexpected method call on the mock
+     * object will return an empty value (0, null, false).
+     * 
+     * @param toMock
+     *            the class of the interface to mock.
+     * @return the mock control.
+     */
+    public static <T> MockControl<T> createNiceControl(Class<T> toMock) {
+        return new MockControl<T>((MocksControl) EasyMock.createNiceControl(),
+                toMock);
+    }
+
+    /**
+     * Returns the mock object.
+     * 
+     * @return the mock object of this control
+     */
+    public T getMock() {
+        return mock;
+    }
+
+    /**
+     * Resets the mock control and the mock object to the state directly after
+     * creation.
+     */
+    public final void reset() {
+        ctrl.reset();
+    }
+
+    /**
+     * Switches the mock object from record state to replay state. For more
+     * information, see the EasyMock documentation.
+     * 
+     * @throws IllegalStateException
+     *             if the mock object already is in replay state.
+     */
+    public void replay() {
+        ctrl.replay();
+    }
+
+    /**
+     * Verifies that all expectations have been met. For more information, see
+     * the EasyMock documentation.
+     * 
+     * @throws IllegalStateException
+     *             if the mock object is in record state.
+     * @throws AssertionError
+     *             if any expectation has not been met.
+     */
+    public void verify() {
+        ctrl.verify();
+    }
+
+    /**
+     * Records that the mock object will expect the last method call once, and
+     * will react by returning silently.
+     * 
+     * @exception IllegalStateException
+     *                if the mock object is in replay state, if no method was
+     *                called on the mock object before, or if the last method
+     *                called on the mock was no void method.
+     */
+    public void setVoidCallable() {
+        expectLastCall(
+                "method call on the mock needed before setting void callable")
+                .once();
+    }
+
+    /**
+     * Records that the mock object will expect the last method call once, and
+     * will react by throwing the provided Throwable.
+     * 
+     * @param throwable
+     *            the Throwable to throw.
+     * @exception IllegalStateException
+     *                if the mock object is in replay state or if no method was
+     *                called on the mock object before.
+     * @exception IllegalArgumentException
+     *                if the last method called on the mock cannot throw the
+     *                provided Throwable.
+     * @exception NullPointerException
+     *                if throwable is null.
+     */
+    public void setThrowable(Throwable throwable) {
+        expectLastCall(
+                "method call on the mock needed before setting Throwable")
+                .andThrow(throwable).once();
+    }
+
+    /**
+     * Records that the mock object will expect the last method call once, and
+     * will react by returning the provided return value.
+     * 
+     * @param value
+     *            the return value.
+     * @throws IllegalStateException
+     *             if the mock object is in replay state, if no method was
+     *             called on the mock object before. or if the last method
+     *             called on the mock does not return <code>boolean</code>.
+     */
+    public void setReturnValue(Object value) {
+        expectLastCall(
+                "method call on the mock needed before setting return value")
+                .andReturn(value).once();
+    }
+
+    /**
+     * Records that the mock object will expect the last method call a fixed
+     * number of times, and will react by returning silently.
+     * 
+     * @param times
+     *            the number of times that the call is expected.
+     * @exception IllegalStateException
+     *                if the mock object is in replay state, if no method was
+     *                called on the mock object before, or if the last method
+     *                called on the mock was no void method.
+     */
+    public void setVoidCallable(int times) {
+        expectLastCall(
+                "method call on the mock needed before setting void callable")
+                .times(times);
+    }
+
+    /**
+     * Records that the mock object will expect the last method call a fixed
+     * number of times, and will react by throwing the provided Throwable.
+     * 
+     * @param throwable
+     *            the Throwable to throw.
+     * @param times
+     *            the number of times that the call is expected.
+     * @exception IllegalStateException
+     *                if the mock object is in replay state or if no method was
+     *                called on the mock object before.
+     * @exception IllegalArgumentException
+     *                if the last method called on the mock cannot throw the
+     *                provided Throwable.
+     * @exception NullPointerException
+     *                if throwable is null.
+     */
+    public void setThrowable(Throwable throwable, int times) {
+        expectLastCall(
+                "method call on the mock needed before setting Throwable")
+                .andThrow(throwable).times(times);
+    }
+
+    /**
+     * Records that the mock object will expect the last method call a fixed
+     * number of times, and will react by returning the provided return value.
+     * 
+     * @param value
+     *            the return value.
+     * @param times
+     *            the number of times that the call is expected.
+     * @throws IllegalStateException
+     *             if the mock object is in replay state, if no method was
+     *             called on the mock object before. or if the last method
+     *             called on the mock does not return <code>boolean</code>.
+     */
+    public void setReturnValue(Object value, int times) {
+        expectLastCall(
+                "method call on the mock needed before setting return value")
+                .andReturn(value).times(times);
+    }
+
+    /**
+     * Records that the mock object will expect the last method call a fixed
+     * number of times, and will react by returning the provided return value.
+     * 
+     * @param value
+     *            the return value.
+     * @param range
+     *            the number of times that the call is expected.
+     * @throws IllegalStateException
+     *             if the mock object is in replay state, if no method was
+     *             called on the mock object before. or if the last method
+     *             called on the mock does not return <code>boolean</code>.
+     */
+    public void setReturnValue(Object value, Range range) {
+        IExpectationSetters<Object> setter = expectLastCall(
+                "method call on the mock needed before setting return value")
+                .andReturn(value);
+        callWithConvertedRange(setter, range);
+    }
+
+    /**
+     * Records that the mock object will by default allow the last method
+     * specified by a method call.
+     * 
+     * @exception IllegalStateException
+     *                if the mock object is in replay state, if no method was
+     *                called on the mock object before, or if the last method
+     *                called on the mock was no void method.
+     */
+    public void setDefaultVoidCallable() {
+        ((MocksControl) expectLastCall("method call on the mock needed before setting default void callable"))
+                .setLegacyDefaultVoidCallable();
+    }
+
+    /**
+     * Records that the mock object will by default allow the last method
+     * specified by a method call, and will react by throwing the provided
+     * Throwable.
+     * 
+     * @param throwable
+     *            throwable the throwable to be thrown
+     * @exception IllegalArgumentException
+     *                if the last method called on the mock cannot throw the
+     *                provided Throwable.
+     * @exception NullPointerException
+     *                if throwable is null.
+     * @exception IllegalStateException
+     *                if the mock object is in replay state, or if no method was
+     *                called on the mock object before.
+     */
+    public void setDefaultThrowable(Throwable throwable) {
+        ctrl.setLegacyDefaultThrowable(throwable);
+    }
+
+    /**
+     * Records that the mock object will by default allow the last method
+     * specified by a method call, and will react by returning the provided
+     * return value.
+     * 
+     * @param value
+     *            the return value.
+     * @throws IllegalStateException
+     *             if the mock object is in replay state, if no method was
+     *             called on the mock object before. or if the last method
+     *             called on the mock does not return <code>boolean</code>.
+     */
+    public void setDefaultReturnValue(Object value) {
+        ctrl.setLegacyDefaultReturnValue(value);
+    }
+
+    /**
+     * Sets the ArgumentsMatcher for the last method called on the mock object.
+     * The matcher must be set before any behavior for the method is defined.
+     * 
+     * @throws IllegalStateException
+     *             if called in replay state, or if no method was called on the
+     *             mock object before.
+     */
+    public void setMatcher(ArgumentsMatcher matcher) {
+        ctrl.setLegacyMatcher(matcher);
+    }
+
+    /**
+     * Records that the mock object will expect the last method call between
+     * <code>minCount</code> and <code>maxCount</code> times, and will react
+     * by returning silently.
+     * 
+     * @param minCount
+     *            the minimum number of times that the call is expected.
+     * @param maxCount
+     *            the maximum number of times that the call is expected.
+     * @exception IllegalStateException
+     *                if the mock object is in replay state, if no method was
+     *                called on the mock object before, or if the last method
+     *                called on the mock was no void method.
+     */
+    public void setVoidCallable(int minCount, int maxCount) {
+        expectLastCall(
+                "method call on the mock needed before setting void callable")
+                .times(minCount, maxCount);
+    }
+
+    public void setVoidCallable(Range range) {
+        IExpectationSetters<Object> setter = expectLastCall("method call on the mock needed before setting void callable");
+        callWithConvertedRange(setter, range);
+    }
+
+    /**
+     * Records that the mock object will expect the last method call between
+     * <code>minCount</code> and <code>maxCount</code> times, and will react
+     * by throwing the provided Throwable.
+     * 
+     * @param throwable
+     *            the Throwable to throw.
+     * @param minCount
+     *            the minimum number of times that the call is expected.
+     * @param maxCount
+     *            the maximum number of times that the call is expected.
+     * @exception IllegalStateException
+     *                if the mock object is in replay state or if no method was
+     *                called on the mock object before.
+     * @exception IllegalArgumentException
+     *                if the last method called on the mock cannot throw the
+     *                provided Throwable.
+     * @exception NullPointerException
+     *                if throwable is null.
+     */
+    public void setThrowable(Throwable throwable, int minCount, int maxCount) {
+        expectLastCall(
+                "method call on the mock needed before setting Throwable")
+                .andThrow(throwable).times(minCount, maxCount);
+    }
+
+    public void setThrowable(Throwable throwable, Range range) {
+        IExpectationSetters<Object> setter = expectLastCall(
+                "method call on the mock needed before setting Throwable")
+                .andThrow(throwable);
+        callWithConvertedRange(setter, range);
+    }
+
+    /**
+     * Records that the mock object will expect the last method call between
+     * <code>minCount</code> and <code>maxCount</code> times, and will react
+     * by returning the provided return value.
+     * 
+     * @param value
+     *            the return value.
+     * @param minCount
+     *            the minimum number of times that the call is expected.
+     * @param maxCount
+     *            the maximum number of times that the call is expected.
+     * @throws IllegalStateException
+     *             if the mock object is in replay state, if no method was
+     *             called on the mock object before. or if the last method
+     *             called on the mock does not return <code>boolean</code>.
+     */
+    public void setReturnValue(Object value, int minCount, int maxCount) {
+        expectLastCall(
+                "method call on the mock needed before setting return value")
+                .andReturn(value).times(minCount, maxCount);
+    }
+
+    /**
+     * Exactly one call.
+     */
+    public static final Range ONE = MocksControl.ONCE;
+
+    /**
+     * One or more calls.
+     */
+    public static final Range ONE_OR_MORE = MocksControl.AT_LEAST_ONCE;
+
+    /**
+     * Zero or more calls.
+     */
+    public static final Range ZERO_OR_MORE = MocksControl.ZERO_OR_MORE;
+
+    /**
+     * Matches if each expected argument is equal to the corresponding actual
+     * argument.
+     */
+    public static final ArgumentsMatcher EQUALS_MATCHER = new EqualsMatcher();
+
+    /**
+     * Matches always.
+     */
+    public static final ArgumentsMatcher ALWAYS_MATCHER = new AlwaysMatcher();
+
+    /**
+     * Matches if each expected argument is equal to the corresponding actual
+     * argument for non-array arguments; array arguments are compared with the
+     * appropriate <code>java.util.Arrays.equals()</code> -method.
+     */
+    public static final ArgumentsMatcher ARRAY_MATCHER = new ArrayMatcher();
+
+    /**
+     * Sets the default ArgumentsMatcher for all methods of the mock object. The
+     * matcher must be set before any behavior is defined on the mock object.
+     * 
+     * @throws IllegalStateException
+     *             if called in replay state, or if any behavior is already
+     *             defined on the mock object.
+     */
+    public void setDefaultMatcher(ArgumentsMatcher matcher) {
+        ctrl.setLegacyDefaultMatcher(matcher);
+    }
+
+    /**
+     * Same as {@link MockControl#setReturnValue(Object)}. For explanation, see
+     * "Convenience Methods for Return Values" in the EasyMock documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public <V1, V2 extends V1> void expectAndReturn(V1 ignored, V2 value) {
+        EasyMock.expectLastCall().andReturn(value).once();
+    }
+
+    public void expectAndReturn(int ignored, int value) {
+        this.expectAndReturn((Object) ignored, (Object) value);
+    }
+
+    /**
+     * Same as {@link MockControl#setReturnValue(Object, Range)}. For
+     * explanation, see "Convenience Methods for Return Values" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public <V1, V2 extends V1> void expectAndReturn(V1 ignored, V2 value,
+            Range range) {
+        IExpectationSetters<Object> expectAndReturn = EasyMock.expectLastCall()
+                .andReturn(value);
+        callWithConvertedRange(expectAndReturn, range);
+    }
+
+    public void expectAndReturn(int ignored, int value, Range range) {
+        this.expectAndReturn((Object) ignored, (Object) value, range);
+    }
+
+    /**
+     * Same as {@link MockControl#setReturnValue(Object, int)}. For
+     * explanation, see "Convenience Methods for Return Values" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public <V1, V2 extends V1> void expectAndReturn(V1 ignored, V2 value,
+            int count) {
+        EasyMock.expectLastCall().andReturn(value).times(count);
+    }
+
+    public void expectAndReturn(int ignored, int value, int count) {
+        this.expectAndReturn((Object) ignored, (Object) value, count);
+    }
+
+    /**
+     * Same as {@link MockControl#setReturnValue(Object, int, int)}. For
+     * explanation, see "Convenience Methods for Return Values" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public <V1, V2 extends V1> void expectAndReturn(V1 ignored, V2 value,
+            int min, int max) {
+        EasyMock.expectLastCall().andReturn(value).times(min, max);
+    }
+
+    public void expectAndReturn(int ignored, int value, int min, int max) {
+        this.expectAndReturn((Object) ignored, (Object) value, min, max);
+    }
+
+    /**
+     * Same as {@link MockControl#setThrowable(Throwable)}. For explanation,
+     * see "Convenience Methods for Throwables" in the EasyMock documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public void expectAndThrow(Object ignored, Throwable throwable) {
+        EasyMock.expect(ignored).andThrow(throwable).once();
+    }
+
+    /**
+     * Same as {@link MockControl#setThrowable(Throwable, Range)}. For
+     * explanation, see "Convenience Methods for Throwables" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public void expectAndThrow(Object ignored, Throwable throwable, Range range) {
+        IExpectationSetters<Object> setter = EasyMock.expect(ignored).andThrow(
+                throwable);
+        callWithConvertedRange(setter, range);
+    }
+
+    /**
+     * Same as {@link MockControl#setThrowable(Throwable, int)}. For
+     * explanation, see "Convenience Methods for Throwables" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public void expectAndThrow(Object ignored, Throwable throwable, int count) {
+        expect(ignored).andThrow(throwable).times(count);
+    }
+
+    /**
+     * Same as {@link MockControl#setThrowable(Throwable, int, int)}. For
+     * explanation, see "Convenience Methods for Throwables" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public void expectAndThrow(Object ignored, Throwable throwable, int min,
+            int max) {
+        expect(ignored).andThrow(throwable).times(min, max);
+    }
+
+    /**
+     * Same as {@link MockControl#setDefaultReturnValue(Object)}. For
+     * explanation, see "Convenience Methods for Return Values" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public <V1, V2 extends V1> void expectAndDefaultReturn(V1 ignored, V2 value) {
+        EasyMock.expectLastCall().andStubReturn(value);
+    }
+
+    /**
+     * Same as {@link MockControl#setDefaultThrowable(Throwable)}. For
+     * explanation, see "Convenience Methods for Throwables" in the EasyMock
+     * documentation.
+     * 
+     * @param ignored
+     *            an ignored value.
+     */
+    public void expectAndDefaultThrow(Object ignored, Throwable throwable) {
+        expectLastCall(
+                "method call on the mock needed before setting default Throwable")
+                .andStubThrow(throwable);
+    }
+
+    private IExpectationSetters<Object> expectLastCall(String failureMessage) {
+        try {
+            return EasyMock.expectLastCall();
+        } catch (IllegalStateException e) {
+            throw new IllegalStateException(failureMessage);
+        }
+    }
+
+    private void callWithConvertedRange(IExpectationSetters<Object> setter, Range range) {
+        if (range == ONE) {
+            setter.once();
+        } else if (range == ONE_OR_MORE) {
+            setter.atLeastOnce();
+        } else if (range == ZERO_OR_MORE) {
+            setter.anyTimes();
+        } else {
+            throw new IllegalArgumentException("Unexpected Range");
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/AlwaysMatcher.java b/src/org/easymock/internal/AlwaysMatcher.java
new file mode 100644
index 0000000..03f52f1
--- /dev/null
+++ b/src/org/easymock/internal/AlwaysMatcher.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import org.easymock.AbstractMatcher;
+
+ at SuppressWarnings("deprecation")
+public class AlwaysMatcher extends AbstractMatcher {
+
+    private static final long serialVersionUID = 592339838132342008L;
+
+    public boolean matches(Object[] expected, Object[] actual) {
+        return true;
+    }
+
+    protected String argumentToString(Object argument) {
+        return "<any>";
+    }
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/ArrayMatcher.java b/src/org/easymock/internal/ArrayMatcher.java
new file mode 100644
index 0000000..c88be58
--- /dev/null
+++ b/src/org/easymock/internal/ArrayMatcher.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import org.easymock.AbstractMatcher;
+import org.easymock.internal.matchers.ArrayEquals;
+
+ at SuppressWarnings("deprecation")
+public class ArrayMatcher extends AbstractMatcher {
+
+    private static final long serialVersionUID = -4594659581004800814L;
+
+    public String argumentToString(Object argument) {
+        StringBuffer result = new StringBuffer();
+        new ArrayEquals(argument).appendTo(result);
+        return result.toString();
+    }
+
+    public boolean argumentMatches(Object expected, Object actual) {
+        return new ArrayEquals(expected).matches(actual);
+    }
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/AssertionErrorWrapper.java b/src/org/easymock/internal/AssertionErrorWrapper.java
new file mode 100644
index 0000000..17801ec
--- /dev/null
+++ b/src/org/easymock/internal/AssertionErrorWrapper.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+public class AssertionErrorWrapper extends RuntimeException {
+
+    private static final long serialVersionUID = -2087349195182278608L;
+    
+    private final AssertionError error;
+
+    public AssertionErrorWrapper(AssertionError error) {
+        this.error = error;
+    }
+
+    public AssertionError getAssertionError() {
+        return error;
+    }
+}
diff --git a/src/org/easymock/internal/EqualsMatcher.java b/src/org/easymock/internal/EqualsMatcher.java
new file mode 100644
index 0000000..5063fa2
--- /dev/null
+++ b/src/org/easymock/internal/EqualsMatcher.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import org.easymock.AbstractMatcher;
+
+ at SuppressWarnings("deprecation")
+public class EqualsMatcher extends AbstractMatcher {
+
+    private static final long serialVersionUID = 4152805764785966978L;
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/ExpectedInvocation.java b/src/org/easymock/internal/ExpectedInvocation.java
new file mode 100644
index 0000000..cec515e
--- /dev/null
+++ b/src/org/easymock/internal/ExpectedInvocation.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.easymock.IArgumentMatcher;
+import org.easymock.internal.matchers.Equals;
+
+public class ExpectedInvocation implements Serializable {
+
+    private static final long serialVersionUID = -5554816464613350531L;
+
+    private final Invocation invocation;
+
+    @SuppressWarnings("deprecation")
+    private final org.easymock.ArgumentsMatcher matcher;
+
+    private final List<IArgumentMatcher> matchers;
+
+    public ExpectedInvocation(Invocation invocation,
+            List<IArgumentMatcher> matchers) {
+        this(invocation, matchers, null);
+    }
+
+    private ExpectedInvocation(Invocation invocation,
+            List<IArgumentMatcher> matchers, @SuppressWarnings("deprecation")
+            org.easymock.ArgumentsMatcher matcher) {
+        this.invocation = invocation;
+        this.matcher = matcher;
+        this.matchers = (matcher == null) ? createMissingMatchers(invocation,
+                matchers) : null;
+    }
+
+    private List<IArgumentMatcher> createMissingMatchers(Invocation invocation,
+            List<IArgumentMatcher> matchers) {
+        if (matchers != null) {
+            if (matchers.size() != invocation.getArguments().length) {
+                throw new IllegalStateException(""
+                        + invocation.getArguments().length
+                        + " matchers expected, " + matchers.size()
+                        + " recorded.");
+            }
+            ;
+            return matchers;
+        }
+        List<IArgumentMatcher> result = new ArrayList<IArgumentMatcher>();
+        for (Object argument : invocation.getArguments()) {
+            result.add(new Equals(argument));
+        }
+        return result;
+    }
+
+    public boolean equals(Object o) {
+        if (o == null || !this.getClass().equals(o.getClass()))
+            return false;
+
+        ExpectedInvocation other = (ExpectedInvocation) o;
+        return this.invocation.equals(other.invocation)
+                && ((this.matcher == null && other.matcher == null) || (this.matcher != null && this.matcher
+                        .equals(other.matcher)))
+                && ((this.matchers == null && other.matchers == null) || (this.matchers != null && this.matchers
+                        .equals(other.matchers)));
+    }
+
+    public int hashCode() {
+        return invocation.hashCode();
+    }
+
+    public boolean matches(Invocation actual) {
+        return matchers != null ? this.invocation.getMock().equals(
+                actual.getMock())
+                && this.invocation.getMethod().equals(actual.getMethod())
+                && matches(actual.getArguments()) : this.invocation.matches(
+                actual, matcher);
+    }
+
+    private boolean matches(Object[] arguments) {
+        if (arguments.length != matchers.size()) {
+            return false;
+        }
+        for (int i = 0; i < arguments.length; i++) {
+            if (!matchers.get(i).matches(arguments[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public String toString() {
+        return matchers != null ? myToString() : invocation.toString(matcher);
+    }
+
+    private String myToString() {
+        StringBuffer result = new StringBuffer();
+        result.append(invocation.getMockAndMethodName());
+        result.append("(");
+        for (Iterator<IArgumentMatcher> it = matchers.iterator(); it.hasNext();) {
+            it.next().appendTo(result);
+            if (it.hasNext()) {
+                result.append(", ");
+            }
+        }
+        result.append(")");
+        return result.toString();
+    }
+
+    public Method getMethod() {
+        return invocation.getMethod();
+    }
+
+    public ExpectedInvocation withMatcher(@SuppressWarnings("deprecation")
+    org.easymock.ArgumentsMatcher matcher) {
+        return new ExpectedInvocation(invocation, null, matcher);
+    }
+}
diff --git a/src/org/easymock/internal/ExpectedInvocationAndResult.java b/src/org/easymock/internal/ExpectedInvocationAndResult.java
new file mode 100644
index 0000000..b7c631e
--- /dev/null
+++ b/src/org/easymock/internal/ExpectedInvocationAndResult.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+
+public class ExpectedInvocationAndResult implements Serializable {
+
+    private static final long serialVersionUID = -1951159588262854559L;
+
+    ExpectedInvocation expectedInvocation;
+
+    Result result;
+
+    public ExpectedInvocationAndResult(ExpectedInvocation expectedInvocation,
+            Result result) {
+        this.expectedInvocation = expectedInvocation;
+        this.result = result;
+    }
+
+    public ExpectedInvocation getExpectedInvocation() {
+        return expectedInvocation;
+    }
+
+    public Result getResult() {
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/ExpectedInvocationAndResults.java b/src/org/easymock/internal/ExpectedInvocationAndResults.java
new file mode 100644
index 0000000..3d5b1c3
--- /dev/null
+++ b/src/org/easymock/internal/ExpectedInvocationAndResults.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+
+public class ExpectedInvocationAndResults implements Serializable {
+    
+    private static final long serialVersionUID = 8189985418895395472L;
+
+    ExpectedInvocation expectedInvocation;
+
+    Results results;
+
+    public ExpectedInvocationAndResults(ExpectedInvocation expectedInvocation,
+            Results results) {
+        this.expectedInvocation = expectedInvocation;
+        this.results = results;
+    }
+
+    public ExpectedInvocation getExpectedInvocation() {
+        return expectedInvocation;
+    }
+
+    public Results getResults() {
+        return results;
+    }
+
+    @Override
+    public String toString() {
+        return expectedInvocation.toString() + ": " + results.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/ILegacyMatcherMethods.java b/src/org/easymock/internal/ILegacyMatcherMethods.java
new file mode 100644
index 0000000..2f6426a
--- /dev/null
+++ b/src/org/easymock/internal/ILegacyMatcherMethods.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.lang.reflect.Method;
+
+public interface ILegacyMatcherMethods {
+
+    @SuppressWarnings("deprecation")
+    void setDefaultMatcher(org.easymock.ArgumentsMatcher matcher);
+
+    @SuppressWarnings("deprecation")
+    void setMatcher(Method method, org.easymock.ArgumentsMatcher matcher);
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/ILegacyMethods.java b/src/org/easymock/internal/ILegacyMethods.java
new file mode 100644
index 0000000..cf7bc9b
--- /dev/null
+++ b/src/org/easymock/internal/ILegacyMethods.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+public interface ILegacyMethods extends ILegacyMatcherMethods {
+    void setDefaultReturnValue(Object value);
+
+    void setDefaultThrowable(Throwable throwable);
+
+    void setDefaultVoidCallable();
+}
diff --git a/src/org/easymock/internal/IMocksBehavior.java b/src/org/easymock/internal/IMocksBehavior.java
new file mode 100644
index 0000000..1d40ae9
--- /dev/null
+++ b/src/org/easymock/internal/IMocksBehavior.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+public interface IMocksBehavior extends ILegacyMatcherMethods {
+
+    // record
+    void addExpected(ExpectedInvocation expected, Result result, Range count);
+
+    void addStub(ExpectedInvocation expected, Result result);
+
+    void checkOrder(boolean value);
+
+    // replay
+    Result addActual(Invocation invocation);
+    
+    void makeThreadSafe(boolean isThreadSafe);
+
+    boolean isThreadSafe();
+    
+    void checkCurrentThreadSameAsLastThread();
+    
+    // verify
+    void verify();
+}
diff --git a/src/org/easymock/internal/IMocksControlState.java b/src/org/easymock/internal/IMocksControlState.java
new file mode 100644
index 0000000..6e6540c
--- /dev/null
+++ b/src/org/easymock/internal/IMocksControlState.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import org.easymock.IAnswer;
+
+public interface IMocksControlState extends ILegacyMethods {
+
+    Object invoke(Invocation invocation) throws Throwable;
+
+    void assertRecordState();
+
+    void andReturn(Object value);
+
+    void andThrow(Throwable throwable);
+
+    void andAnswer(IAnswer<?> answer);
+
+    void andStubReturn(Object value);
+
+    void andStubThrow(Throwable throwable);
+
+    void andStubAnswer(IAnswer<?> answer);
+
+    void asStub();
+
+    void times(Range range);
+
+    void checkOrder(boolean value);
+
+    void makeThreadSafe(boolean threadSafe);
+    
+    void replay();
+
+    void verify();
+}
diff --git a/src/org/easymock/internal/IProxyFactory.java b/src/org/easymock/internal/IProxyFactory.java
new file mode 100644
index 0000000..5729523
--- /dev/null
+++ b/src/org/easymock/internal/IProxyFactory.java
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.lang.reflect.InvocationHandler;
+
+public interface IProxyFactory<T> {
+    T createProxy(Class<T> toMock, InvocationHandler handler);
+}
diff --git a/src/org/easymock/internal/Invocation.java b/src/org/easymock/internal/Invocation.java
new file mode 100644
index 0000000..ae4ddcc
--- /dev/null
+++ b/src/org/easymock/internal/Invocation.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import static java.lang.Character.*;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import org.easymock.internal.matchers.ArrayEquals;
+
+public class Invocation implements Serializable {
+
+    private static final long serialVersionUID = -2836226970244118495L;
+
+    private final Object mock;
+
+    private transient Method method;
+
+    private final Object[] arguments;
+
+    public Invocation(Object mock, Method method, Object[] args) {
+        this.mock = mock;
+        this.method = method;
+        this.arguments = expandVarArgs(method.isVarArgs(), args);
+    }
+
+    private static Object[] expandVarArgs(final boolean isVarArgs,
+            final Object[] args) {
+        if (!isVarArgs || isVarArgs && args[args.length - 1] != null
+                && !args[args.length - 1].getClass().isArray()) {
+            return args == null ? new Object[0] : args;
+        }
+        Object[] varArgs = ArrayEquals.createObjectArray(args[args.length - 1]);
+        final int nonVarArgsCount = args.length - 1;
+        final int varArgsCount = varArgs.length;
+        Object[] newArgs = new Object[nonVarArgsCount + varArgsCount];
+        System.arraycopy(args, 0, newArgs, 0, nonVarArgsCount);
+        System.arraycopy(varArgs, 0, newArgs, nonVarArgsCount, varArgsCount);
+        return newArgs;
+    }
+
+    public Object getMock() {
+        return mock;
+    }
+
+    public Method getMethod() {
+        return method;
+    }
+
+    public Object[] getArguments() {
+        return arguments;
+    }
+
+    public boolean equals(Object o) {
+        if (o == null || !o.getClass().equals(this.getClass()))
+            return false;
+
+        Invocation other = (Invocation) o;
+
+        return this.mock.equals(other.mock) && this.method.equals(other.method)
+                && this.equalArguments(other.arguments);
+    }
+
+    public int hashCode() {
+        throw new UnsupportedOperationException("hashCode() is not implemented");
+    }
+
+    private boolean equalArguments(Object[] arguments) {
+        if (this.arguments.length != arguments.length) {
+            return false;
+        }
+        for (int i = 0; i < this.arguments.length; i++) {
+            Object myArgument = this.arguments[i];
+            Object otherArgument = arguments[i];
+
+            if (isPrimitiveParameter(i)) {
+                if (!myArgument.equals(otherArgument)) {
+                    return false;
+                }
+            } else {
+                if (myArgument != otherArgument) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean isPrimitiveParameter(int parameterPosition) {
+        Class<?>[] parameterTypes = method.getParameterTypes();
+        if (method.isVarArgs()) {
+            parameterPosition = Math.min(parameterPosition,
+                    parameterTypes.length - 1);
+        }
+        return parameterTypes[parameterPosition].isPrimitive();
+    }
+
+    @SuppressWarnings("deprecation")
+    public boolean matches(Invocation actual, org.easymock.ArgumentsMatcher matcher) {
+        return this.mock.equals(actual.mock)
+                && this.method.equals(actual.method)
+                && matcher.matches(this.arguments, actual.arguments);
+    }
+
+    @SuppressWarnings("deprecation")
+    public String toString(org.easymock.ArgumentsMatcher matcher) {
+        return getMockAndMethodName() + "(" + matcher.toString(arguments) + ")";
+    }
+
+    public String getMockAndMethodName() {
+        String mockName = mock.toString();
+        String methodName = method.getName();
+        if (toStringIsDefined(mock) && isJavaIdentifier(mockName)) {
+            return mockName + "." + methodName;
+        } else {
+            return methodName;
+        }
+    }
+
+    private boolean toStringIsDefined(Object o) {
+        try {
+            o.getClass().getDeclaredMethod("toString", (Class[]) null)
+                    .getModifiers();
+            return true;
+        } catch (SecurityException ignored) {
+            // ///CLOVER:OFF
+            return false;
+            // ///CLOVER:ON
+        } catch (NoSuchMethodException shouldNeverHappen) {
+            // ///CLOVER:OFF
+            throw new RuntimeException("The toString() method could not be found!");
+            // ///CLOVER:ON
+        }
+    }
+
+    public static boolean isJavaIdentifier(String mockName) {
+        if (mockName.length() == 0 || mockName.indexOf(' ') > -1
+                || !Character.isJavaIdentifierStart(mockName.charAt(0))) {
+            return false;
+        }
+        for (char c : mockName.substring(1).toCharArray()) {
+            if (!isJavaIdentifierPart(c)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        try {
+            method = ((MethodSerializationWrapper) stream.readObject()).getMethod();
+        } catch (NoSuchMethodException e) {
+            // ///CLOVER:OFF
+            throw new IOException(e.toString());
+            // ///CLOVER:ON
+        }
+    }
+    
+    private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+        stream.defaultWriteObject();
+        stream.writeObject(new MethodSerializationWrapper(method));
+    }    
+}
diff --git a/src/org/easymock/internal/JavaProxyFactory.java b/src/org/easymock/internal/JavaProxyFactory.java
new file mode 100644
index 0000000..4ff1126
--- /dev/null
+++ b/src/org/easymock/internal/JavaProxyFactory.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+
+public class JavaProxyFactory<T> implements IProxyFactory<T> {
+    @SuppressWarnings("unchecked")
+    public T createProxy(Class<T> toMock, InvocationHandler handler) {
+        return (T) Proxy.newProxyInstance(toMock.getClassLoader(),
+                new Class[] { toMock }, handler);
+    }
+}
diff --git a/src/org/easymock/internal/LastControl.java b/src/org/easymock/internal/LastControl.java
new file mode 100644
index 0000000..c74d8f7
--- /dev/null
+++ b/src/org/easymock/internal/LastControl.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.util.*;
+
+import org.easymock.IArgumentMatcher;
+import org.easymock.internal.matchers.And;
+import org.easymock.internal.matchers.Not;
+import org.easymock.internal.matchers.Or;
+
+public class LastControl {
+    private static final ThreadLocal<MocksControl> threadToControl = new ThreadLocal<MocksControl>();
+
+    private static final ThreadLocal<Stack<Object[]>> threadToCurrentArguments = new ThreadLocal<Stack<Object[]>>();
+
+    private static final ThreadLocal<Stack<IArgumentMatcher>> threadToArgumentMatcherStack = new ThreadLocal<Stack<IArgumentMatcher>>();
+
+    public static synchronized void reportLastControl(MocksControl control) {
+        if (control != null) {
+            threadToControl.set(control);
+        } else {
+            threadToControl.remove();
+        }
+    }
+
+    public static synchronized MocksControl lastControl() {
+        return threadToControl.get();
+    }
+
+    public static synchronized void reportMatcher(IArgumentMatcher matcher) {
+        Stack<IArgumentMatcher> stack = threadToArgumentMatcherStack.get();
+        if (stack == null) {
+            stack = new Stack<IArgumentMatcher>();
+            threadToArgumentMatcherStack.set(stack);
+        }
+        stack.push(matcher);
+    }
+
+    public static synchronized List<IArgumentMatcher> pullMatchers() {
+        Stack<IArgumentMatcher> stack = threadToArgumentMatcherStack.get();
+        if (stack == null) {
+            return null;
+        }
+        threadToArgumentMatcherStack.remove();
+        return new ArrayList<IArgumentMatcher>(stack);
+    }
+
+    public static synchronized void reportAnd(int count) {
+        Stack<IArgumentMatcher> stack = threadToArgumentMatcherStack.get();
+        assertState(stack != null, "no matchers found.");
+        stack.push(new And(popLastArgumentMatchers(count)));
+    }
+
+    public static synchronized void reportNot() {
+        Stack<IArgumentMatcher> stack = threadToArgumentMatcherStack.get();
+        assertState(stack != null, "no matchers found.");
+        stack.push(new Not(popLastArgumentMatchers(1).get(0)));
+    }
+
+    private static List<IArgumentMatcher> popLastArgumentMatchers(int count) {
+        Stack<IArgumentMatcher> stack = threadToArgumentMatcherStack.get();
+        assertState(stack != null, "no matchers found.");
+        assertState(stack.size() >= count, "" + count + " matchers expected, "
+                + stack.size() + " recorded.");
+        List<IArgumentMatcher> result = new LinkedList<IArgumentMatcher>();
+        result.addAll(stack.subList(stack.size() - count, stack.size()));
+        for (int i = 0; i < count; i++) {
+            stack.pop();
+        }
+        return result;
+    }
+
+    private static void assertState(boolean toAssert, String message) {
+        if (!toAssert) {
+            threadToArgumentMatcherStack.remove();
+            throw new IllegalStateException(message);
+        }
+    }
+
+    public static void reportOr(int count) {
+        Stack<IArgumentMatcher> stack = threadToArgumentMatcherStack.get();
+        assertState(stack != null, "no matchers found.");
+        stack.push(new Or(popLastArgumentMatchers(count)));
+    }
+
+    public static Object[] getCurrentArguments() {
+        Stack<Object[]> stack = threadToCurrentArguments.get();
+        if (stack == null || stack.empty()) {
+            return null;
+        }
+        return stack.lastElement();
+    }
+
+    public static void pushCurrentArguments(Object[] args) {
+        Stack<Object[]> stack = threadToCurrentArguments.get();
+        if (stack == null) {
+            stack = new Stack<Object[]>();
+            threadToCurrentArguments.set(stack);
+        }
+        stack.push(args);
+    }
+
+    public static void popCurrentArguments() {
+        Stack<Object[]> stack = threadToCurrentArguments.get();
+        stack.pop();
+    }
+}
diff --git a/src/org/easymock/internal/LegacyMatcherProvider.java b/src/org/easymock/internal/LegacyMatcherProvider.java
new file mode 100644
index 0000000..662b2a2
--- /dev/null
+++ b/src/org/easymock/internal/LegacyMatcherProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.easymock.ArgumentsMatcher;
+import org.easymock.MockControl;
+
+ at SuppressWarnings("deprecation")
+public class LegacyMatcherProvider {
+
+    private ArgumentsMatcher defaultMatcher;
+
+    private boolean defaultMatcherSet;
+
+    private Map<Method, ArgumentsMatcher> matchers = new HashMap<Method, ArgumentsMatcher>();
+
+    public ArgumentsMatcher getMatcher(Method method) {
+        if (!matchers.containsKey(method)) {
+            if (!defaultMatcherSet) {
+                setDefaultMatcher(MockControl.EQUALS_MATCHER);
+            }
+            matchers.put(method, defaultMatcher);
+        }
+        return matchers.get(method);
+    }
+
+    
+    public void setDefaultMatcher(ArgumentsMatcher matcher) {
+        if (defaultMatcherSet) {
+            throw new RuntimeExceptionWrapper(
+                    new IllegalStateException(
+                            "default matcher can only be set once directly after creation of the MockControl"));
+        }
+        defaultMatcher = matcher;
+        defaultMatcherSet = true;
+    }
+
+    public void setMatcher(Method method, ArgumentsMatcher matcher) {
+        if (matchers.containsKey(method) && matchers.get(method) != matcher) {
+            throw new RuntimeExceptionWrapper(new IllegalStateException(
+                    "for method "
+                            + method.getName()
+                            + "("
+                            + (method.getParameterTypes().length == 0 ? ""
+                                    : "...")
+                            + "), a matcher has already been set"));
+        }
+        matchers.put(method, matcher);
+    }
+}
diff --git a/src/org/easymock/internal/MethodSerializationWrapper.java b/src/org/easymock/internal/MethodSerializationWrapper.java
new file mode 100644
index 0000000..2a2c153
--- /dev/null
+++ b/src/org/easymock/internal/MethodSerializationWrapper.java
@@ -0,0 +1,66 @@
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MethodSerializationWrapper implements Serializable {
+
+    private static final long serialVersionUID = 1775475200823842126L;
+
+    private static final Map<String, Class<?>> primitiveTypes = new HashMap<String, Class<?>>(
+            10);
+
+    static {
+        primitiveTypes.put(Boolean.TYPE.getName(), Boolean.TYPE);
+        primitiveTypes.put(Byte.TYPE.getName(), Byte.TYPE);
+        primitiveTypes.put(Short.TYPE.getName(), Short.TYPE);
+        primitiveTypes.put(Character.TYPE.getName(), Character.TYPE);
+        primitiveTypes.put(Integer.TYPE.getName(), Integer.TYPE);
+        primitiveTypes.put(Long.TYPE.getName(), Long.TYPE);
+        primitiveTypes.put(Float.TYPE.getName(), Float.TYPE);
+        primitiveTypes.put(Double.TYPE.getName(), Double.TYPE);
+    }
+
+    private String className;
+
+    private String methodName;
+
+    private String[] parameterTypeNames;
+
+    public MethodSerializationWrapper(Method m) {
+        className = m.getDeclaringClass().getName();
+        methodName = m.getName();
+
+        Class<?>[] parameterTypes = m.getParameterTypes();
+
+        parameterTypeNames = new String[parameterTypes.length];
+
+        for (int i = 0; i < parameterTypes.length; i++) {
+            parameterTypeNames[i] = parameterTypes[i].getName();
+        }
+    }
+
+    public Method getMethod() throws ClassNotFoundException,
+            NoSuchMethodException {
+        Class<?> clazz = Class.forName(className, true, Thread.currentThread()
+                .getContextClassLoader());
+
+        Class<?>[] parameterTypes = new Class[parameterTypeNames.length];
+
+        for (int i = 0; i < parameterTypeNames.length; i++) {
+            Class<?> primitiveType = primitiveTypes.get(parameterTypeNames[i]);
+            if (primitiveType != null) {
+                parameterTypes[i] = primitiveType;
+            } else {
+                parameterTypes[i] = Class.forName(parameterTypeNames[i], true,
+                        Thread.currentThread().getContextClassLoader());
+            }
+        }
+
+        Method m = clazz.getMethod(methodName, parameterTypes);
+
+        return m;
+    }
+}
diff --git a/src/org/easymock/internal/MockInvocationHandler.java b/src/org/easymock/internal/MockInvocationHandler.java
new file mode 100644
index 0000000..60ade89
--- /dev/null
+++ b/src/org/easymock/internal/MockInvocationHandler.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+public final class MockInvocationHandler implements InvocationHandler, Serializable {
+
+    private static final long serialVersionUID = -7799769066534714634L;
+    
+    private final MocksControl control;
+
+    public MockInvocationHandler(MocksControl control) {
+        this.control = control;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        try {
+            if (control.getState() instanceof RecordState) {
+                LastControl.reportLastControl(control);
+            }
+            return control.getState().invoke(
+                    new Invocation(proxy, method, args));
+        } catch (RuntimeExceptionWrapper e) {
+            throw e.getRuntimeException().fillInStackTrace();
+        } catch (AssertionErrorWrapper e) {
+            throw e.getAssertionError().fillInStackTrace();
+        } catch (ThrowableWrapper t) {
+            throw t.getThrowable().fillInStackTrace();
+        }
+    }
+
+    public MocksControl getControl() {
+        return control;
+    }
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/MocksBehavior.java b/src/org/easymock/internal/MocksBehavior.java
new file mode 100644
index 0000000..706d74e
--- /dev/null
+++ b/src/org/easymock/internal/MocksBehavior.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MocksBehavior implements IMocksBehavior, Serializable {
+
+    private static final long serialVersionUID = 3265727009370529027L;
+
+    private final List<UnorderedBehavior> behaviorLists = new ArrayList<UnorderedBehavior>();
+
+    private List<ExpectedInvocationAndResult> stubResults = new ArrayList<ExpectedInvocationAndResult>();
+
+    private final boolean nice;
+
+    private boolean checkOrder;
+
+    private boolean isThreadSafe;
+
+    private int position = 0;
+
+    private transient volatile Thread lastThread;
+
+    public MocksBehavior(boolean nice) {
+        this.nice = nice;
+    }
+
+    public final void addStub(ExpectedInvocation expected, Result result) {
+        stubResults.add(new ExpectedInvocationAndResult(expected, result));
+    }
+
+    public void addExpected(ExpectedInvocation expected, Result result,
+            Range count) {
+        if (legacyMatcherProvider != null) {
+            expected = expected.withMatcher(legacyMatcherProvider
+                    .getMatcher(expected.getMethod()));
+        }
+        addBehaviorListIfNecessary(expected);
+        lastBehaviorList().addExpected(expected, result, count);
+    }
+
+    private final Result getStubResult(Invocation actual) {
+        for (ExpectedInvocationAndResult each : stubResults) {
+            if (each.getExpectedInvocation().matches(actual)) {
+                return each.getResult();
+            }
+        }
+        return null;
+    }
+
+    private void addBehaviorListIfNecessary(ExpectedInvocation expected) {
+        if (behaviorLists.isEmpty()
+                || !lastBehaviorList().allowsExpectedInvocation(expected,
+                        checkOrder)) {
+            behaviorLists.add(new UnorderedBehavior(checkOrder));
+        }
+    }
+
+    private UnorderedBehavior lastBehaviorList() {
+        return behaviorLists.get(behaviorLists.size() - 1);
+    }
+
+    @SuppressWarnings("deprecation")
+    public final Result addActual(Invocation actual) {
+        int tempPosition = position;
+        String errorMessage = "";
+        while (position < behaviorLists.size()) {
+            Result result = behaviorLists.get(position).addActual(actual);
+            if (result != null) {
+                return result;
+            }
+            errorMessage += behaviorLists.get(position).toString(actual);
+            if (!behaviorLists.get(position).verify()) {
+                break;
+            }
+            position++;
+        }
+        Result stubOrNice = getStubResult(actual);
+        if (stubOrNice == null && nice) {
+            stubOrNice = Result.createReturnResult(RecordState
+                    .emptyReturnValueFor(actual.getMethod().getReturnType()));
+        }
+
+        // Do not move the cursor in case of stub, nice or error
+        position = tempPosition;
+
+        if (stubOrNice != null) {
+            return stubOrNice;
+        }
+        throw new AssertionErrorWrapper(
+                new AssertionError(
+                        "\n  Unexpected method call "
+                                + actual
+                                        .toString(org.easymock.MockControl.EQUALS_MATCHER)
+                                + ":" + errorMessage.toString()));
+    }
+
+    public void verify() {
+        boolean verified = true;
+        StringBuffer errorMessage = new StringBuffer();
+
+        for (UnorderedBehavior behaviorList : behaviorLists.subList(position,
+                behaviorLists.size())) {
+            errorMessage.append(behaviorList.toString());
+            if (!behaviorList.verify()) {
+                verified = false;
+            }
+        }
+        if (verified) {
+            return;
+        }
+
+        throw new AssertionErrorWrapper(new AssertionError(
+                "\n  Expectation failure on verify:" + errorMessage.toString()));
+    }
+
+    public void checkOrder(boolean value) {
+        this.checkOrder = value;
+    }
+
+    public void makeThreadSafe(boolean isThreadSafe) {
+        this.isThreadSafe = isThreadSafe;
+    }
+
+    public boolean isThreadSafe() {
+        return this.isThreadSafe;
+    }
+
+    public void checkCurrentThreadSameAsLastThread() {
+        if (lastThread == null) {
+            lastThread = Thread.currentThread();
+        } else if(lastThread != Thread.currentThread()) {
+            throw new AssertionErrorWrapper(new AssertionError(
+                    "\n  Un-thread-safe mock called from multiple threads"));
+        }
+    }
+
+    private LegacyMatcherProvider legacyMatcherProvider;
+
+    public LegacyMatcherProvider getLegacyMatcherProvider() {
+        if (legacyMatcherProvider == null) {
+            legacyMatcherProvider = new LegacyMatcherProvider();
+        }
+        return legacyMatcherProvider;
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setDefaultMatcher(org.easymock.ArgumentsMatcher matcher) {
+        getLegacyMatcherProvider().setDefaultMatcher(matcher);
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setMatcher(Method method, org.easymock.ArgumentsMatcher matcher) {
+        getLegacyMatcherProvider().setMatcher(method, matcher);
+    }
+}
diff --git a/src/org/easymock/internal/MocksControl.java b/src/org/easymock/internal/MocksControl.java
new file mode 100644
index 0000000..62d2d9e
--- /dev/null
+++ b/src/org/easymock/internal/MocksControl.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+
+import org.easymock.IAnswer;
+import org.easymock.IExpectationSetters;
+import org.easymock.IMocksControl;
+
+public class MocksControl implements IMocksControl, IExpectationSetters<Object>, Serializable {
+
+    private static final long serialVersionUID = 443604921336702014L;
+
+    private IMocksControlState state;
+
+    private IMocksBehavior behavior;
+
+    public enum MockType {
+        NICE, DEFAULT, STRICT
+    }
+
+    private MockType type;
+
+    public MocksControl(MockType type) {
+        this.type = type;
+        reset();
+    }
+
+    public IMocksControlState getState() {
+        return state;
+    }
+
+    public <T> T createMock(Class<T> toMock) {
+        try {
+            state.assertRecordState();
+            IProxyFactory<T> proxyFactory = createProxyFactory(toMock);
+            return proxyFactory.createProxy(toMock, new ObjectMethodsFilter(
+                    toMock, new MockInvocationHandler(this), null));
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public <T> T createMock(String name, Class<T> toMock) {
+        try {
+            state.assertRecordState();
+            IProxyFactory<T> proxyFactory = createProxyFactory(toMock);
+            return proxyFactory.createProxy(toMock, new ObjectMethodsFilter(
+                    toMock, new MockInvocationHandler(this), name));
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    protected <T> IProxyFactory<T> createProxyFactory(Class<T> toMock) {
+        return new JavaProxyFactory<T>();
+    }
+
+    public final void reset() {
+        behavior = new MocksBehavior(type == MockType.NICE);
+        behavior.checkOrder(type == MockType.STRICT);
+        behavior.makeThreadSafe(false);
+        state = new RecordState(behavior);
+        LastControl.reportLastControl(null);
+    }
+
+    public void resetToNice() {
+        type = MockType.NICE;
+        reset();
+    }
+    
+    public void resetToDefault() {
+        type = MockType.DEFAULT;
+        reset();        
+    }
+    
+    public void resetToStrict() {
+        type = MockType.STRICT;
+        reset();
+    }
+    
+    public void replay() {
+        try {
+            state.replay();
+            state = new ReplayState(behavior);
+            LastControl.reportLastControl(null);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public void verify() {
+        try {
+            state.verify();
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        } catch (AssertionErrorWrapper e) {
+            throw (AssertionError) e.getAssertionError().fillInStackTrace();
+        }
+    }
+
+    public void checkOrder(boolean value) {
+        try {
+            state.checkOrder(value);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+    
+    public void makeThreadSafe(boolean threadSafe) {
+        try {
+            state.makeThreadSafe(threadSafe);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    // methods from IBehaviorSetters
+
+    public IExpectationSetters<Object> andReturn(Object value) {
+        try {
+            state.andReturn(value);
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public IExpectationSetters<Object> andThrow(Throwable throwable) {
+        try {
+            state.andThrow(throwable);
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public IExpectationSetters<Object> andAnswer(IAnswer<? extends Object> answer) {
+        try {
+            state.andAnswer(answer);
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public void andStubReturn(Object value) {
+        try {
+            state.andStubReturn(value);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public void andStubThrow(Throwable throwable) {
+        try {
+            state.andStubThrow(throwable);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public void andStubAnswer(IAnswer<? extends Object> answer) {
+        try {
+            state.andStubAnswer(answer);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public void asStub() {
+        try {
+            state.asStub();
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public IExpectationSetters<Object> times(int times) {
+        try {
+            state.times(new Range(times));
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public IExpectationSetters<Object> times(int min, int max) {
+        try {
+            state.times(new Range(min, max));
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public IExpectationSetters<Object> once() {
+        try {
+            state.times(ONCE);
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public IExpectationSetters<Object> atLeastOnce() {
+        try {
+            state.times(AT_LEAST_ONCE);
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public IExpectationSetters<Object> anyTimes() {
+        try {
+            state.times(ZERO_OR_MORE);
+            return this;
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    /**
+     * Exactly one call.
+     */
+    public static final Range ONCE = new Range(1);
+
+    /**
+     * One or more calls.
+     */
+    public static final Range AT_LEAST_ONCE = new Range(1, Integer.MAX_VALUE);
+
+    /**
+     * Zero or more calls.
+     */
+    public static final Range ZERO_OR_MORE = new Range(0, Integer.MAX_VALUE);
+
+    @SuppressWarnings("deprecation")
+    public void setLegacyDefaultMatcher(org.easymock.ArgumentsMatcher matcher) {
+        try {
+            state.setDefaultMatcher(matcher);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setLegacyMatcher(org.easymock.ArgumentsMatcher matcher) {
+        try {
+            state.setMatcher(null, matcher);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public void setLegacyDefaultReturnValue(Object value) {
+        try {
+            state.setDefaultReturnValue(value);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+
+    public void setLegacyDefaultVoidCallable() {
+        state.setDefaultVoidCallable();
+    }
+
+    public void setLegacyDefaultThrowable(Throwable throwable) {
+        try {
+            state.setDefaultThrowable(throwable);
+        } catch (RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+    }
+}
diff --git a/src/org/easymock/internal/ObjectMethodsFilter.java b/src/org/easymock/internal/ObjectMethodsFilter.java
new file mode 100644
index 0000000..e85a168
--- /dev/null
+++ b/src/org/easymock/internal/ObjectMethodsFilter.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class ObjectMethodsFilter implements InvocationHandler, Serializable {
+
+    private static final long serialVersionUID = -2120581954279966998L;
+
+    private transient Method equalsMethod;
+
+    private transient Method hashCodeMethod;
+
+    private transient Method toStringMethod;
+
+    private final MockInvocationHandler delegate;
+
+    private final String name;
+
+    public ObjectMethodsFilter(Class<?> toMock, MockInvocationHandler delegate,
+            String name) {
+        if (name != null && !Invocation.isJavaIdentifier(name)) {
+            throw new IllegalArgumentException(String.format("'%s' is not a valid Java identifier.", name));
+            
+        }
+        try {
+            if (toMock.isInterface()) {
+                toMock = Object.class;
+            }
+            equalsMethod = toMock.getMethod("equals",
+                    new Class[] { Object.class });
+            hashCodeMethod = toMock.getMethod("hashCode", (Class[]) null);
+            toStringMethod = toMock.getMethod("toString", (Class[]) null);
+        } catch (NoSuchMethodException e) {
+            // ///CLOVER:OFF
+            throw new RuntimeException("An Object method could not be found!");
+            // ///CLOVER:ON
+        }
+        this.delegate = delegate;
+        this.name = name;
+    }
+
+    public final Object invoke(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        if (equalsMethod.equals(method)) {
+            return Boolean.valueOf(proxy == args[0]);
+        }
+        if (hashCodeMethod.equals(method)) {
+            return Integer.valueOf(System.identityHashCode(proxy));
+        }
+        if (toStringMethod.equals(method)) {
+            return mockToString(proxy);
+        }
+        return delegate.invoke(proxy, method, args);
+    }
+
+    private String mockToString(Object proxy) {
+        return (name != null) ? name : "EasyMock for " + mockType(proxy);
+    }
+
+    private String mockType(Object proxy) {
+        if (Proxy.isProxyClass(proxy.getClass()))
+            return proxy.getClass().getInterfaces()[0].toString();
+        else
+            return proxy.getClass().getSuperclass().toString();
+    }
+
+    public MockInvocationHandler getDelegate() {
+        return delegate;
+    }
+    
+    private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        try {
+            toStringMethod = ((MethodSerializationWrapper) stream.readObject()).getMethod();
+            equalsMethod = ((MethodSerializationWrapper) stream.readObject()).getMethod();
+            hashCodeMethod = ((MethodSerializationWrapper) stream.readObject()).getMethod();
+        } catch (NoSuchMethodException e) {
+            // ///CLOVER:OFF
+            throw new IOException(e.toString());
+            // ///CLOVER:ON
+        }
+    }
+    
+    private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+        stream.defaultWriteObject();
+        stream.writeObject(new MethodSerializationWrapper(toStringMethod));
+        stream.writeObject(new MethodSerializationWrapper(equalsMethod));
+        stream.writeObject(new MethodSerializationWrapper(hashCodeMethod));
+    }
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/Range.java b/src/org/easymock/internal/Range.java
new file mode 100644
index 0000000..61b5faa
--- /dev/null
+++ b/src/org/easymock/internal/Range.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+
+public class Range implements Serializable {
+
+    private static final long serialVersionUID = -6743402320315331536L;
+
+    private int minimum;
+
+    private int maximum;
+
+    public Range(int count) {
+        this(count, count);
+    }
+
+    public Range(int minimum, int maximum) {
+        if (!(minimum <= maximum)) {
+            throw new RuntimeExceptionWrapper(new IllegalArgumentException(
+                    "minimum must be <= maximum"));
+        }
+
+        if (!(minimum >= 0)) {
+            throw new RuntimeExceptionWrapper(new IllegalArgumentException(
+                    "minimum must be >= 0"));
+        }
+
+        if (!(maximum >= 1)) {
+            throw new RuntimeExceptionWrapper(new IllegalArgumentException(
+                    "maximum must be >= 1"));
+        }
+        this.minimum = minimum;
+        this.maximum = maximum;
+    }
+
+    public boolean hasFixedCount() {
+        return minimum == maximum;
+    }
+
+    public int getMaximum() {
+        return maximum;
+    }
+
+    public int getMinimum() {
+        return minimum;
+    }
+
+    public String toString() {
+        if (hasFixedCount()) {
+            return "" + minimum;
+        } else if (hasOpenCount()) {
+            return "at least " + minimum;
+        } else {
+            return "between " + minimum + " and " + maximum;
+        }
+    }
+
+    public String expectedAndActual(int count) {
+        return "expected: " + this.toString() + ", actual: " + count;
+    }
+
+    public boolean contains(int count) {
+        return minimum <= count && count <= maximum;
+    }
+
+    public boolean hasOpenCount() {
+        return maximum == Integer.MAX_VALUE;
+    }
+}
diff --git a/src/org/easymock/internal/RecordState.java b/src/org/easymock/internal/RecordState.java
new file mode 100644
index 0000000..7fb4892
--- /dev/null
+++ b/src/org/easymock/internal/RecordState.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.easymock.IAnswer;
+import org.easymock.IArgumentMatcher;
+
+public class RecordState implements IMocksControlState, Serializable {
+
+    private static final long serialVersionUID = -5418279681566430252L;
+
+    private ExpectedInvocation lastInvocation;
+
+    private boolean lastInvocationUsed = true;
+
+    private Result lastResult;
+
+    private IMocksBehavior behavior;
+
+    private static Map<Class<?>, Object> emptyReturnValues = new HashMap<Class<?>, Object>();
+
+    static {
+        emptyReturnValues.put(Void.TYPE, null);
+        emptyReturnValues.put(Boolean.TYPE, Boolean.FALSE);
+        emptyReturnValues.put(Byte.TYPE, new Byte((byte) 0));
+        emptyReturnValues.put(Short.TYPE, new Short((short) 0));
+        emptyReturnValues.put(Character.TYPE, new Character((char) 0));
+        emptyReturnValues.put(Integer.TYPE, new Integer(0));
+        emptyReturnValues.put(Long.TYPE, new Long(0));
+        emptyReturnValues.put(Float.TYPE, new Float(0));
+        emptyReturnValues.put(Double.TYPE, new Double(0));
+    }
+
+    private static Map<Class<?>, Class<?>> primitiveToWrapperType = new HashMap<Class<?>, Class<?>>();
+
+    static {
+        primitiveToWrapperType.put(Boolean.TYPE, Boolean.class);
+        primitiveToWrapperType.put(Byte.TYPE, Byte.class);
+        primitiveToWrapperType.put(Short.TYPE, Short.class);
+        primitiveToWrapperType.put(Character.TYPE, Character.class);
+        primitiveToWrapperType.put(Integer.TYPE, Integer.class);
+        primitiveToWrapperType.put(Long.TYPE, Long.class);
+        primitiveToWrapperType.put(Float.TYPE, Float.class);
+        primitiveToWrapperType.put(Double.TYPE, Double.class);
+    }
+
+    public RecordState(IMocksBehavior behavior) {
+        this.behavior = behavior;
+    }
+
+    public void assertRecordState() {
+    }
+
+    public java.lang.Object invoke(Invocation invocation) {
+        closeMethod();
+        List<IArgumentMatcher> lastMatchers = LastControl.pullMatchers();
+        lastInvocation = new ExpectedInvocation(invocation, lastMatchers);
+        lastInvocationUsed = false;
+        return emptyReturnValueFor(invocation.getMethod().getReturnType());
+    }
+
+    public void replay() {
+        closeMethod();
+        if (LastControl.pullMatchers() != null) {
+            throw new IllegalStateException("matcher calls were used outside expectations");
+        }
+    }
+
+    public void verify() {
+        throw new RuntimeExceptionWrapper(new IllegalStateException(
+                "calling verify is not allowed in record state"));
+    }
+
+    public void andReturn(Object value) {
+        requireMethodCall("return value");
+        value = convertNumberClassIfNeccessary(value);
+        requireAssignable(value);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        lastResult = Result.createReturnResult(value);
+    }
+
+    public void andThrow(Throwable throwable) {
+        requireMethodCall("Throwable");
+        requireValidThrowable(throwable);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        lastResult = Result.createThrowResult(throwable);
+    }
+    
+    public void andAnswer(IAnswer<?> answer) {
+        requireMethodCall("answer");
+        requireValidAnswer(answer);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        lastResult = Result.createAnswerResult(answer);
+    }
+
+    public void andStubReturn(Object value) {
+        requireMethodCall("stub return value");
+        value = convertNumberClassIfNeccessary(value);
+        requireAssignable(value);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        behavior.addStub(lastInvocation, Result.createReturnResult(value));
+        lastInvocationUsed = true;
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setDefaultReturnValue(Object value) {
+        requireMethodCall("default return value");
+        value = convertNumberClassIfNeccessary(value);
+        requireAssignable(value);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        behavior.addStub(
+                lastInvocation.withMatcher(org.easymock.MockControl.ALWAYS_MATCHER), Result
+                        .createReturnResult(value));
+        lastInvocationUsed = true;
+    }
+
+    public void asStub() {
+        requireMethodCall("stub behavior");
+        requireVoidMethod();
+        behavior.addStub(lastInvocation, Result.createReturnResult(null));
+        lastInvocationUsed = true;
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setDefaultVoidCallable() {
+        requireMethodCall("default void callable");
+        requireVoidMethod();
+        behavior.addStub(
+                lastInvocation.withMatcher(org.easymock.MockControl.ALWAYS_MATCHER), Result
+                        .createReturnResult(null));
+        lastInvocationUsed = true;
+    }
+
+    public void andStubThrow(Throwable throwable) {
+        requireMethodCall("stub Throwable");
+        requireValidThrowable(throwable);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        behavior.addStub(lastInvocation, Result.createThrowResult(throwable));
+        lastInvocationUsed = true;
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setDefaultThrowable(Throwable throwable) {
+        requireMethodCall("default Throwable");
+        requireValidThrowable(throwable);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        behavior.addStub(
+                lastInvocation.withMatcher(org.easymock.MockControl.ALWAYS_MATCHER), Result
+                        .createThrowResult(throwable));
+        lastInvocationUsed = true;
+    }
+
+    public void andStubAnswer(IAnswer<?> answer) {
+        requireMethodCall("stub answer");
+        requireValidAnswer(answer);
+        if (lastResult != null) {
+            times(MocksControl.ONCE);
+        }
+        behavior.addStub(lastInvocation, Result.createAnswerResult(answer));
+        lastInvocationUsed = true;
+    }
+
+    public void times(Range range) {
+        requireMethodCall("times");
+        requireLastResultOrVoidMethod();
+
+        behavior.addExpected(lastInvocation, lastResult != null ? lastResult
+                : Result.createReturnResult(null), range);
+        lastInvocationUsed = true;
+        lastResult = null;
+    }
+
+    private Object createNumberObject(Object value, Class<?> returnType) {
+        if (!(value instanceof Number)) {
+            return value;
+        }
+        Number number = (Number) value;        
+        if (returnType.equals(Byte.TYPE)) {
+            return number.byteValue();
+        } else if (returnType.equals(Short.TYPE)) {
+            return number.shortValue();
+        } else if (returnType.equals(Character.TYPE)) {
+            return (char) number.intValue();
+        } else if (returnType.equals(Integer.TYPE)) {
+            return number.intValue();
+        } else if (returnType.equals(Long.TYPE)) {
+            return number.longValue();
+        } else if (returnType.equals(Float.TYPE)) {
+            return number.floatValue();
+        } else if (returnType.equals(Double.TYPE)) {
+            return number.doubleValue();
+        } else {
+            return number;
+        }
+    }
+
+    private Object convertNumberClassIfNeccessary(Object o) {
+        Class<?> returnType = lastInvocation.getMethod().getReturnType();
+        return createNumberObject(o, returnType);
+    }
+
+    @SuppressWarnings("deprecation")
+    private void closeMethod() {
+        if (lastInvocationUsed && lastResult == null) {
+            return;
+        }
+        if (!isLastResultOrVoidMethod()) {
+            throw new RuntimeExceptionWrapper(new IllegalStateException(
+                    "missing behavior definition for the preceeding method call "
+                            + lastInvocation.toString()));
+        }
+        this.times(org.easymock.MockControl.ONE);
+    }
+
+    public static Object emptyReturnValueFor(Class<?> type) {
+        return type.isPrimitive() ? emptyReturnValues.get(type) : null;
+    }
+
+    private void requireMethodCall(String failMessage) {
+        if (lastInvocation == null) {
+            throw new RuntimeExceptionWrapper(new IllegalStateException(
+                    "method call on the mock needed before setting "
+                            + failMessage));
+        }
+    }
+
+    private void requireAssignable(Object returnValue) {
+        if (lastMethodIsVoidMethod()) {
+            throw new RuntimeExceptionWrapper(new IllegalStateException(
+                    "void method cannot return a value"));
+        }
+        if (returnValue == null) {
+            return;
+        }
+        Class<?> returnedType = lastInvocation.getMethod().getReturnType();
+        if (returnedType.isPrimitive()) {
+            returnedType = primitiveToWrapperType.get(returnedType);
+
+        }
+        if (!returnedType.isAssignableFrom(returnValue.getClass())) {
+            throw new RuntimeExceptionWrapper(new IllegalStateException(
+                    "incompatible return value type"));
+        }
+    }
+
+    private void requireValidThrowable(Throwable throwable) {
+        if (throwable == null)
+            throw new RuntimeExceptionWrapper(new NullPointerException(
+                    "null cannot be thrown"));
+        if (isValidThrowable(throwable))
+            return;
+
+        throw new RuntimeExceptionWrapper(new IllegalArgumentException(
+                "last method called on mock cannot throw "
+                        + throwable.getClass().getName()));
+    }
+
+    private void requireValidAnswer(IAnswer<?> answer) {
+        if (answer == null)
+            throw new RuntimeExceptionWrapper(new NullPointerException(
+                    "answer object must not be null"));
+    }
+
+    private void requireLastResultOrVoidMethod() {
+        if (isLastResultOrVoidMethod()) {
+            return;
+        }
+        throw new RuntimeExceptionWrapper(new IllegalStateException(
+                "last method called on mock is not a void method"));
+    }
+
+    private void requireVoidMethod() {
+        if (lastMethodIsVoidMethod()) {
+            return;
+        }
+        throw new RuntimeExceptionWrapper(new IllegalStateException(
+                "last method called on mock is not a void method"));
+    }
+
+    private boolean isLastResultOrVoidMethod() {
+        return lastResult != null || lastMethodIsVoidMethod();
+    }
+
+    private boolean lastMethodIsVoidMethod() {
+        Class<?> returnType = lastInvocation.getMethod().getReturnType();
+        return returnType.equals(Void.TYPE);
+    }
+
+    private boolean isValidThrowable(Throwable throwable) {
+        if (throwable instanceof RuntimeException) {
+            return true;
+        }
+        if (throwable instanceof Error) {
+            return true;
+        }
+        Class<?>[] exceptions = lastInvocation.getMethod().getExceptionTypes();
+        Class<?> throwableClass = throwable.getClass();
+        for (Class<?> exception : exceptions) {
+            if (exception.isAssignableFrom(throwableClass))
+                return true;
+        }
+        return false;
+    }
+
+    public void checkOrder(boolean value) {
+        closeMethod();
+        behavior.checkOrder(value);
+    }
+
+    public void makeThreadSafe(boolean threadSafe) {
+        behavior.makeThreadSafe(threadSafe);
+    }
+    
+    @SuppressWarnings("deprecation")
+    public void setDefaultMatcher(org.easymock.ArgumentsMatcher matcher) {
+        behavior.setDefaultMatcher(matcher);
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setMatcher(Method method, org.easymock.ArgumentsMatcher matcher) {
+        requireMethodCall("matcher");
+        behavior.setMatcher(lastInvocation.getMethod(), matcher);
+    }
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/ReplayState.java b/src/org/easymock/internal/ReplayState.java
new file mode 100644
index 0000000..d20477f
--- /dev/null
+++ b/src/org/easymock/internal/ReplayState.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import org.easymock.IAnswer;
+
+public class ReplayState implements IMocksControlState, Serializable {
+
+    private static final long serialVersionUID = 6314142602251047572L;
+
+    private IMocksBehavior behavior;
+
+    public ReplayState(IMocksBehavior behavior) {
+        this.behavior = behavior;
+    }
+
+    public Object invoke(Invocation invocation) throws Throwable {
+
+        if (behavior.isThreadSafe()) {
+            // If thread safe, synchronize the mock
+            synchronized (this) {
+                return invokeInner(invocation);
+            }
+        }
+
+        // Check that the same thread is called all the time...
+        behavior.checkCurrentThreadSameAsLastThread();
+        return invokeInner(invocation);
+    }
+
+    private Object invokeInner(Invocation invocation) throws Throwable {
+        Result result = behavior.addActual(invocation);
+        LastControl.pushCurrentArguments(invocation.getArguments());
+        try {
+            try {
+                return result.answer();
+            } catch (Throwable t) {
+                throw new ThrowableWrapper(t);
+            }
+        } finally {
+            LastControl.popCurrentArguments();
+        }
+    }
+
+    public void verify() {
+        behavior.verify();
+    }
+
+    public void replay() {
+        throwWrappedIllegalStateException();
+    }
+
+    public void callback(Runnable runnable) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void checkOrder(boolean value) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void makeThreadSafe(boolean threadSafe) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void andReturn(Object value) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void andThrow(Throwable throwable) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void andAnswer(IAnswer<?> answer) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void andStubReturn(Object value) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void andStubThrow(Throwable throwable) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void andStubAnswer(IAnswer<?> answer) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void asStub() {
+        throwWrappedIllegalStateException();
+    }
+
+    public void times(Range range) {
+        throwWrappedIllegalStateException();
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setMatcher(Method method, org.easymock.ArgumentsMatcher matcher) {
+        throwWrappedIllegalStateException();
+    }
+
+    @SuppressWarnings("deprecation")
+    public void setDefaultMatcher(org.easymock.ArgumentsMatcher matcher) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void setDefaultReturnValue(Object value) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void setDefaultThrowable(Throwable throwable) {
+        throwWrappedIllegalStateException();
+    }
+
+    public void setDefaultVoidCallable() {
+        throwWrappedIllegalStateException();
+    }
+
+    private void throwWrappedIllegalStateException() {
+        throw new RuntimeExceptionWrapper(new IllegalStateException(
+                "This method must not be called in replay state."));
+    }
+
+    public void assertRecordState() {
+        throwWrappedIllegalStateException();
+    }
+}
diff --git a/src/org/easymock/internal/Result.java b/src/org/easymock/internal/Result.java
new file mode 100644
index 0000000..394096d
--- /dev/null
+++ b/src/org/easymock/internal/Result.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+
+import org.easymock.IAnswer;
+
+public class Result implements IAnswer<Object>, Serializable {
+
+    private static final long serialVersionUID = 5476251941213917681L;
+    
+    private IAnswer<?> value;
+
+    private Result(IAnswer<?> value) {
+        this.value = value;
+    }
+
+    public static Result createThrowResult(final Throwable throwable) {
+        class ThrowingAnswer implements IAnswer<Object>, Serializable {
+
+            private static final long serialVersionUID = -332797751209289222L;
+
+            public Object answer() throws Throwable {
+                throw throwable;
+            }
+
+            @Override
+            public String toString() {
+                return "Answer throwing " + throwable;
+            }
+        }
+        return new Result(new ThrowingAnswer());
+    }
+
+    public static Result createReturnResult(final Object value) {
+        class ReturningAnswer implements IAnswer<Object>, Serializable {
+
+            private static final long serialVersionUID = 6973893913593916866L;
+            
+            public Object answer() throws Throwable {
+                return value;
+            }
+            
+            @Override
+            public String toString() {
+                return "Answer returning " + value;
+            }
+        }
+        return new Result(new ReturningAnswer());
+    }
+
+    public static Result createAnswerResult(IAnswer<?> answer) {
+        return new Result(answer);
+    }
+
+    public Object answer() throws Throwable {
+        return value.answer();
+    }
+
+    @Override
+    public String toString() {
+        return value.toString();
+    }
+    
+    
+}
diff --git a/src/org/easymock/internal/Results.java b/src/org/easymock/internal/Results.java
new file mode 100644
index 0000000..567c04e
--- /dev/null
+++ b/src/org/easymock/internal/Results.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Results implements Serializable {
+
+    private static final long serialVersionUID = -2722051869610289637L;
+
+    private int callCount;
+
+    private LinkedList<Range> ranges = new LinkedList<Range>();
+
+    private List<Result> results = new ArrayList<Result>();
+
+    public void add(Result result, Range range) {
+        if (!ranges.isEmpty()) {
+            Range lastRange = ranges.getLast();
+            if (!lastRange.hasFixedCount())
+                throw new RuntimeExceptionWrapper(
+                        new IllegalStateException(
+                                "last method called on mock already has a non-fixed count set."));
+        }
+        ranges.add(range);
+        results.add(result);
+    }
+
+    public Result next() {
+        int currentPosition = 0;
+        for (int i = 0; i < ranges.size(); i++) {
+            Range interval = ranges.get(i);
+            if (interval.hasOpenCount()) {
+                callCount += 1;
+                return results.get(i);
+            }
+            currentPosition += interval.getMaximum();
+            if (currentPosition > callCount) {
+                callCount += 1;
+                return results.get(i);
+            }
+        }
+        return null;
+    }
+
+    public boolean hasValidCallCount() {
+        return getMainInterval().contains(getCallCount());
+    }
+
+    @Override
+    public String toString() {
+        return getMainInterval().expectedAndActual(getCallCount());
+    }
+
+    private Range getMainInterval() {
+        int min = 0, max = 0;
+
+        for (Range interval : ranges) {
+            min += interval.getMinimum();
+            if (interval.hasOpenCount() || max == Integer.MAX_VALUE) {
+                max = Integer.MAX_VALUE;
+            } else {
+                max += interval.getMaximum();
+            }
+        }
+
+        return new Range(min, max);
+    }
+
+    public int getCallCount() {
+        return callCount;
+    }
+}
diff --git a/src/org/easymock/internal/RuntimeExceptionWrapper.java b/src/org/easymock/internal/RuntimeExceptionWrapper.java
new file mode 100644
index 0000000..99e883b
--- /dev/null
+++ b/src/org/easymock/internal/RuntimeExceptionWrapper.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+public class RuntimeExceptionWrapper extends RuntimeException {
+
+    private static final long serialVersionUID = -3483500330975410177L;
+    
+    private final RuntimeException runtimeException;
+
+    public RuntimeExceptionWrapper(final RuntimeException runtimeException) {
+        this.runtimeException = runtimeException;
+    }
+
+    public RuntimeException getRuntimeException() {
+        return runtimeException;
+    }
+}
diff --git a/src/org/easymock/internal/ThrowableWrapper.java b/src/org/easymock/internal/ThrowableWrapper.java
new file mode 100644
index 0000000..0f82617
--- /dev/null
+++ b/src/org/easymock/internal/ThrowableWrapper.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+public class ThrowableWrapper extends Throwable {
+
+    private static final long serialVersionUID = -4434322855124959723L;
+    
+    private final Throwable throwable;
+
+    public ThrowableWrapper(final Throwable throwable) {
+        this.throwable = throwable;
+    }
+
+    public Throwable getThrowable() {
+        return throwable;
+    }
+}
diff --git a/src/org/easymock/internal/UnorderedBehavior.java b/src/org/easymock/internal/UnorderedBehavior.java
new file mode 100644
index 0000000..2144c20
--- /dev/null
+++ b/src/org/easymock/internal/UnorderedBehavior.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class UnorderedBehavior implements Serializable {
+
+    private static final long serialVersionUID = 2185791334636597469L;
+
+    private final List<ExpectedInvocationAndResults> results = new ArrayList<ExpectedInvocationAndResults>();
+
+    private final boolean checkOrder;
+
+    public UnorderedBehavior(boolean checkOrder) {
+        this.checkOrder = checkOrder;
+    }
+
+    public void addExpected(ExpectedInvocation expected, Result result,
+            Range count) {
+        for (ExpectedInvocationAndResults entry : results) {
+            if (entry.getExpectedInvocation().equals(expected)) {
+                entry.getResults().add(result, count);
+                return;
+            }
+        }
+        Results list = new Results();
+        list.add(result, count);
+        results.add(new ExpectedInvocationAndResults(expected, list));
+    }
+
+    public Result addActual(Invocation actual) {
+        for (ExpectedInvocationAndResults entry : results) {
+            if (!entry.getExpectedInvocation().matches(actual)) {
+                continue;
+            }
+            Result result = entry.getResults().next();
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    public boolean verify() {
+        for (ExpectedInvocationAndResults entry : results) {
+            if (!entry.getResults().hasValidCallCount()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return toString(null);
+    }
+
+    public String toString(Invocation invocation) {
+        StringBuffer result = new StringBuffer();
+        for (ExpectedInvocationAndResults entry : results) {
+            boolean unordered = !checkOrder;
+            boolean validCallCount = entry.getResults().hasValidCallCount();
+            boolean match = invocation != null
+                    && entry.getExpectedInvocation().matches(invocation);
+
+            if (unordered && validCallCount && !match) {
+                continue;
+            }
+            result.append("\n    " + entry.toString());
+            if (match) {
+                result.append(" (+1)");
+            }
+        }
+        return result.toString();
+    }
+
+    public boolean allowsExpectedInvocation(ExpectedInvocation expected,
+            boolean checkOrder) {
+        if (this.checkOrder != checkOrder) {
+            return false;
+        } else if (results.isEmpty() || !this.checkOrder) {
+            return true;
+        } else {
+            ExpectedInvocation lastMethodCall = results.get(results.size() - 1)
+                    .getExpectedInvocation();
+            return lastMethodCall.equals(expected);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/org/easymock/internal/matchers/And.java b/src/org/easymock/internal/matchers/And.java
new file mode 100644
index 0000000..8871acf
--- /dev/null
+++ b/src/org/easymock/internal/matchers/And.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+import org.easymock.IArgumentMatcher;
+
+public class And implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = 3874580646798403818L;
+    
+    private final List<IArgumentMatcher> matchers;
+
+    public And(List<IArgumentMatcher> matchers) {
+        this.matchers = matchers;
+    }
+
+    public boolean matches(Object actual) {
+        for (IArgumentMatcher matcher : matchers) {
+            if (!matcher.matches(actual)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("and(");
+        for (Iterator<IArgumentMatcher> it = matchers.iterator(); it.hasNext();) {
+            it.next().appendTo(buffer);
+            if (it.hasNext()) {
+                buffer.append(", ");
+            }
+        }
+        buffer.append(")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Any.java b/src/org/easymock/internal/matchers/Any.java
new file mode 100644
index 0000000..1a21d29
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Any.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class Any implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -3743894206806704049L;
+    
+    public static final Any ANY = new Any();    
+    
+    private Any() {
+        
+    }
+    
+    public boolean matches(Object actual) {
+        return true;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("<any>");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/ArrayEquals.java b/src/org/easymock/internal/matchers/ArrayEquals.java
new file mode 100644
index 0000000..24bb88f
--- /dev/null
+++ b/src/org/easymock/internal/matchers/ArrayEquals.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+public class ArrayEquals extends Equals {
+
+    private static final long serialVersionUID = 1L;
+
+    public ArrayEquals(Object expected) {
+        super(expected);
+    }
+
+    public boolean matches(Object actual) {
+        Object expected = getExpected();
+        if (expected instanceof boolean[]
+                && (actual == null || actual instanceof boolean[])) {
+            return Arrays.equals((boolean[]) expected, (boolean[]) actual);
+        } else if (expected instanceof byte[]
+                && (actual == null || actual instanceof byte[])) {
+            return Arrays.equals((byte[]) expected, (byte[]) actual);
+        } else if (expected instanceof char[]
+                && (actual == null || actual instanceof char[])) {
+            return Arrays.equals((char[]) expected, (char[]) actual);
+        } else if (expected instanceof double[]
+                && (actual == null || actual instanceof double[])) {
+            return Arrays.equals((double[]) expected, (double[]) actual);
+        } else if (expected instanceof float[]
+                && (actual == null || actual instanceof float[])) {
+            return Arrays.equals((float[]) expected, (float[]) actual);
+        } else if (expected instanceof int[]
+                && (actual == null || actual instanceof int[])) {
+            return Arrays.equals((int[]) expected, (int[]) actual);
+        } else if (expected instanceof long[]
+                && (actual == null || actual instanceof long[])) {
+            return Arrays.equals((long[]) expected, (long[]) actual);
+        } else if (expected instanceof short[]
+                && (actual == null || actual instanceof short[])) {
+            return Arrays.equals((short[]) expected, (short[]) actual);
+        } else if (expected instanceof Object[]
+                && (actual == null || actual instanceof Object[])) {
+            return Arrays.equals((Object[]) expected, (Object[]) actual);
+        } else {
+            return super.matches(actual);
+        }
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        if (getExpected() != null && getExpected().getClass().isArray()) {
+            appendArray(createObjectArray(getExpected()), buffer);
+        } else {
+            super.appendTo(buffer);
+        }
+    }
+
+    private void appendArray(Object[] array, StringBuffer buffer) {
+        buffer.append("[");
+        for (int i = 0; i < array.length; i++) {
+            new Equals(array[i]).appendTo(buffer);
+            if (i != array.length - 1) {
+                buffer.append(", ");
+            }
+        }
+        buffer.append("]");
+    }
+
+    public static Object[] createObjectArray(Object array) {
+        if (array instanceof Object[]) {
+            return (Object[]) array;
+        }
+        Object[] result = new Object[Array.getLength(array)];
+        for (int i = 0; i < Array.getLength(array); i++) {
+            result[i] = Array.get(array, i);
+        }
+        return result;
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Captures.java b/src/org/easymock/internal/matchers/Captures.java
new file mode 100644
index 0000000..116a630
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Captures.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2003-2008 OFFIS, Henri Tremblay. 
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.Capture;
+import org.easymock.IArgumentMatcher;
+
+public class Captures<T> implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = 5370646694100653250L;
+    
+    private Capture<T> capture;
+
+    public Captures(Capture<T> captured) {
+        this.capture = captured;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("capture(").append(capture).append(")");
+    }
+
+    @SuppressWarnings("unchecked")
+    public boolean matches(Object actual) {
+        capture.setValue((T) actual);
+        return true;
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Compare.java b/src/org/easymock/internal/matchers/Compare.java
new file mode 100644
index 0000000..98045ff
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Compare.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Henri Tremblay.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.easymock.IArgumentMatcher;
+import org.easymock.LogicalOperator;
+
+public class Compare<T> implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -4859402739599754147L;
+
+    private T expected;
+
+    private Comparator<? super T> comparator;
+
+    private LogicalOperator operator;
+
+    public Compare(T expected, Comparator<? super T> comparator, LogicalOperator result) {
+        this.expected = expected;
+        this.comparator = comparator;
+        this.operator = result;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append(comparator + "(" + expected + ") " + operator.getSymbol()
+                + " 0");
+    }
+
+    @SuppressWarnings("unchecked")
+    public boolean matches(Object actual) {
+        if(actual == null) {
+            return false;
+        }
+        return operator.matchResult(comparator.compare((T) actual, expected));
+    }
+
+}
diff --git a/src/org/easymock/internal/matchers/CompareEqual.java b/src/org/easymock/internal/matchers/CompareEqual.java
new file mode 100644
index 0000000..1f26e83
--- /dev/null
+++ b/src/org/easymock/internal/matchers/CompareEqual.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+public class CompareEqual<T extends Comparable<T>> extends CompareTo<T> {
+
+    private static final long serialVersionUID = 7616033998227799268L;
+
+    public CompareEqual(Comparable<T> value) {
+        super(value);
+    }
+
+    @Override
+    protected String getName() {
+        return "cmpEq";
+    }
+
+    @Override
+    protected boolean matchResult(int result) {
+        return result == 0;
+    }
+}
diff --git a/src/org/easymock/internal/matchers/CompareTo.java b/src/org/easymock/internal/matchers/CompareTo.java
new file mode 100644
index 0000000..bdf3e43
--- /dev/null
+++ b/src/org/easymock/internal/matchers/CompareTo.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public abstract class CompareTo<T extends Comparable<T>> implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -8447010713532143168L;
+    
+    private final Comparable<T> expected;
+
+    public CompareTo(Comparable<T> value) {
+        this.expected = value;
+    }
+
+    @SuppressWarnings("unchecked")
+    public boolean matches(Object actual) {
+        
+        if(!(actual instanceof Comparable)) {
+            return false;
+        }
+        
+        return matchResult(((Comparable) actual).compareTo(expected));
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append(getName() + "(" + expected + ")");
+    }
+    
+    protected abstract String getName();
+    
+    protected abstract boolean matchResult(int result);
+}
diff --git a/src/org/easymock/internal/matchers/Contains.java b/src/org/easymock/internal/matchers/Contains.java
new file mode 100644
index 0000000..3d90860
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Contains.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class Contains implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -6785245714002503134L;
+
+    private final String substring;
+
+    public Contains(String substring) {
+        this.substring = substring;
+    }
+
+    public boolean matches(Object actual) {
+        return (actual instanceof String)
+                && ((String) actual).indexOf(substring) >= 0;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("contains(\"" + substring + "\")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/EndsWith.java b/src/org/easymock/internal/matchers/EndsWith.java
new file mode 100644
index 0000000..41a1dee
--- /dev/null
+++ b/src/org/easymock/internal/matchers/EndsWith.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class EndsWith implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = 5159338714596685067L;
+
+    private final String suffix;
+
+    public EndsWith(String suffix) {
+        this.suffix = suffix;
+    }
+
+    public boolean matches(Object actual) {
+        return (actual instanceof String) && ((String) actual).endsWith(suffix);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("endsWith(\"" + suffix + "\")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Equals.java b/src/org/easymock/internal/matchers/Equals.java
new file mode 100644
index 0000000..deed3f6
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Equals.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class Equals implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = 583055160049982067L;
+
+    private final Object expected;
+
+    public Equals(Object expected) {
+        this.expected = expected;
+    }
+
+    public boolean matches(Object actual) {
+        if (this.expected == null) {
+            return actual == null;
+        }
+        return expected.equals(actual);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        appendQuoting(buffer);
+        buffer.append(expected);
+        appendQuoting(buffer);
+    }
+
+    private void appendQuoting(StringBuffer buffer) {
+        if (expected instanceof String) {
+            buffer.append("\"");
+        } else if (expected instanceof Character) {
+            buffer.append("'");
+        }
+    }
+
+    protected final Object getExpected() {
+        return expected;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !this.getClass().equals(o.getClass()))
+            return false;
+        Equals other = (Equals) o;
+        return this.expected == null && other.expected == null
+                || this.expected != null
+                && this.expected.equals(other.expected);
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException("hashCode() is not supported");
+    }
+
+}
diff --git a/src/org/easymock/internal/matchers/EqualsWithDelta.java b/src/org/easymock/internal/matchers/EqualsWithDelta.java
new file mode 100644
index 0000000..c6fbdeb
--- /dev/null
+++ b/src/org/easymock/internal/matchers/EqualsWithDelta.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class EqualsWithDelta implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -3018631689416120154L;
+
+    private final Number expected;
+
+    private final Number delta;
+
+    public EqualsWithDelta(Number value, Number delta) {
+        this.expected = value;
+        this.delta = delta;
+    }
+
+    public boolean matches(Object actual) {
+        Number actualNumber = (Number) actual;
+        return expected.doubleValue() - delta.doubleValue() <= actualNumber
+                .doubleValue()
+                && actualNumber.doubleValue() <= expected.doubleValue()
+                        + delta.doubleValue();
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("eq(" + expected + ", " + delta + ")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Find.java b/src/org/easymock/internal/matchers/Find.java
new file mode 100644
index 0000000..2ed435a
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Find.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+import java.util.regex.Pattern;
+
+import org.easymock.IArgumentMatcher;
+
+public class Find implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -7104607303959381785L;
+
+    private final String regex;
+
+    public Find(String regex) {
+        this.regex = regex;
+    }
+
+    public boolean matches(Object actual) {
+        return (actual instanceof String)
+                && Pattern.compile(regex).matcher((String) actual).find();
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("find(\"" + regex.replaceAll("\\\\", "\\\\\\\\") + "\")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/GreaterOrEqual.java b/src/org/easymock/internal/matchers/GreaterOrEqual.java
new file mode 100644
index 0000000..333fb3a
--- /dev/null
+++ b/src/org/easymock/internal/matchers/GreaterOrEqual.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+public class GreaterOrEqual<T extends Comparable<T>> extends CompareTo<T> {
+
+    private static final long serialVersionUID = -504083241204488174L;
+
+    public GreaterOrEqual(Comparable<T> value) {
+        super(value);
+    }
+
+    @Override
+    protected String getName() {
+        return "geq";
+    }
+
+    @Override
+    protected boolean matchResult(int result) {
+        return result >= 0;
+    }
+}
diff --git a/src/org/easymock/internal/matchers/GreaterThan.java b/src/org/easymock/internal/matchers/GreaterThan.java
new file mode 100644
index 0000000..a33e9d9
--- /dev/null
+++ b/src/org/easymock/internal/matchers/GreaterThan.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+public class GreaterThan<T extends Comparable<T>> extends CompareTo<T> {
+
+    private static final long serialVersionUID = 2736983121197045828L;
+
+    public GreaterThan(Comparable<T> value) {
+        super(value);
+    }
+
+    @Override
+    protected String getName() {
+        return "gt";
+    }
+
+    @Override
+    protected boolean matchResult(int result) {
+        return result > 0;
+    }    
+}
diff --git a/src/org/easymock/internal/matchers/InstanceOf.java b/src/org/easymock/internal/matchers/InstanceOf.java
new file mode 100644
index 0000000..ca81cee
--- /dev/null
+++ b/src/org/easymock/internal/matchers/InstanceOf.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class InstanceOf implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -551735356674347591L;
+
+    private final Class<?> clazz;
+
+    public InstanceOf(Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    public boolean matches(Object actual) {
+        return (actual != null) && clazz.isAssignableFrom(actual.getClass());
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("isA(" + clazz.getName() + ")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/LessOrEqual.java b/src/org/easymock/internal/matchers/LessOrEqual.java
new file mode 100644
index 0000000..cbb92f2
--- /dev/null
+++ b/src/org/easymock/internal/matchers/LessOrEqual.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+public class LessOrEqual<T extends Comparable<T>> extends CompareTo<T> {
+
+    private static final long serialVersionUID = -2485406702001842607L;
+
+    public LessOrEqual(Comparable<T> value) {
+        super(value);
+    }
+
+    @Override
+    protected String getName() {
+        return "leq";
+    }
+
+    @Override
+    protected boolean matchResult(int result) {
+        return result <= 0;
+    }
+}
diff --git a/src/org/easymock/internal/matchers/LessThan.java b/src/org/easymock/internal/matchers/LessThan.java
new file mode 100644
index 0000000..2626814
--- /dev/null
+++ b/src/org/easymock/internal/matchers/LessThan.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+public class LessThan<T extends Comparable<T>> extends CompareTo<T> {
+
+    private static final long serialVersionUID = 6004888476822043880L;
+
+    public LessThan(Comparable<T> value) {
+        super(value);
+    }
+
+    @Override
+    protected String getName() {
+        return "lt";
+    }
+
+    @Override
+    protected boolean matchResult(int result) {
+        return result < 0;
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Matches.java b/src/org/easymock/internal/matchers/Matches.java
new file mode 100644
index 0000000..6c7b8b4
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Matches.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class Matches implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -6657694947057597484L;
+
+    private final String regex;
+
+    public Matches(String regex) {
+        this.regex = regex;
+    }
+
+    public boolean matches(Object actual) {
+        return (actual instanceof String) && ((String) actual).matches(regex);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("matches(\"" + regex.replaceAll("\\\\", "\\\\\\\\")
+                + "\")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Not.java b/src/org/easymock/internal/matchers/Not.java
new file mode 100644
index 0000000..4d8a2c7
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Not.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class Not implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -5160559075998939348L;
+
+    private final IArgumentMatcher first;
+
+    public Not(IArgumentMatcher first) {
+        this.first = first;
+    }
+
+    public boolean matches(Object actual) {
+        return !first.matches(actual);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("not(");
+        first.appendTo(buffer);
+        buffer.append(")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/NotNull.java b/src/org/easymock/internal/matchers/NotNull.java
new file mode 100644
index 0000000..0a0edb2
--- /dev/null
+++ b/src/org/easymock/internal/matchers/NotNull.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class NotNull implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -2689588759855326190L;
+
+    public static final NotNull NOT_NULL = new NotNull();
+    
+    private NotNull() {
+        
+    }
+    
+    public boolean matches(Object actual) {
+        return actual != null;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("notNull()");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Null.java b/src/org/easymock/internal/matchers/Null.java
new file mode 100644
index 0000000..c94cf5e
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Null.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class Null implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = 6077244839421122011L;
+
+    public static final Null NULL = new Null();
+
+    private Null() {
+    }
+
+    public boolean matches(Object actual) {
+        return actual == null;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("isNull()");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Or.java b/src/org/easymock/internal/matchers/Or.java
new file mode 100644
index 0000000..b71c0da
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Or.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+import org.easymock.IArgumentMatcher;
+
+public class Or implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -5701204283180444317L;
+
+    private final List<IArgumentMatcher> matchers;
+
+    public Or(List<IArgumentMatcher> matchers) {
+        this.matchers = matchers;
+    }
+
+    public boolean matches(Object actual) {
+        for (IArgumentMatcher matcher : matchers) {
+            if (matcher.matches(actual)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("or(");
+        for (Iterator<IArgumentMatcher> it = matchers.iterator(); it.hasNext();) {
+            it.next().appendTo(buffer);
+            if (it.hasNext()) {
+                buffer.append(", ");
+            }
+        }
+        buffer.append(")");
+    }
+}
diff --git a/src/org/easymock/internal/matchers/Same.java b/src/org/easymock/internal/matchers/Same.java
new file mode 100644
index 0000000..8ac6ecf
--- /dev/null
+++ b/src/org/easymock/internal/matchers/Same.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class Same implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = 1094930851962278376L;
+    
+    private final Object expected;
+
+    public Same(Object expected) {
+        this.expected = expected;
+    }
+
+    public boolean matches(Object actual) {
+        return expected == actual;
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("same(");
+        appendQuoting(buffer);
+        buffer.append(expected);
+        appendQuoting(buffer);
+        buffer.append(")");
+    }
+
+    private void appendQuoting(StringBuffer buffer) {
+        if (expected instanceof String) {
+            buffer.append("\"");
+        } else if (expected instanceof Character) {
+            buffer.append("'");
+        }
+    }
+}
diff --git a/src/org/easymock/internal/matchers/StartsWith.java b/src/org/easymock/internal/matchers/StartsWith.java
new file mode 100644
index 0000000..782bc3d
--- /dev/null
+++ b/src/org/easymock/internal/matchers/StartsWith.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.internal.matchers;
+
+import java.io.Serializable;
+
+import org.easymock.IArgumentMatcher;
+
+public class StartsWith implements IArgumentMatcher, Serializable {
+
+    private static final long serialVersionUID = -658998692584342514L;
+    
+    private final String prefix;
+
+    public StartsWith(String prefix) {
+        this.prefix = prefix;
+    }
+
+    public boolean matches(Object actual) {
+        return (actual instanceof String)
+                && ((String) actual).startsWith(prefix);
+    }
+
+    public void appendTo(StringBuffer buffer) {
+        buffer.append("startsWith(\"" + prefix + "\")");
+    }
+}
diff --git a/tests/org/easymock/tests/ArgumentsMatcherTest.java b/tests/org/easymock/tests/ArgumentsMatcherTest.java
new file mode 100644
index 0000000..13df807
--- /dev/null
+++ b/tests/org/easymock/tests/ArgumentsMatcherTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.AbstractMatcher;
+import org.easymock.ArgumentsMatcher;
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class ArgumentsMatcherTest {
+
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setUp() {
+        control = MockControl.createStrictControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void expectedArgumentsDelegatedToMatcher() {
+        mock.twoArgumentMethod(0, 5);
+        control.setMatcher(new AbstractMatcher() {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public boolean matches(Object[] expected, Object[] actual) {
+                assertEquals(0, ((Integer) expected[0]).intValue());
+                assertEquals(5, ((Integer) expected[1]).intValue());
+                assertEquals(1, ((Integer) actual[0]).intValue());
+                assertEquals(6, ((Integer) actual[1]).intValue());
+                return true;
+            }
+        });
+        mock.simpleMethod();
+        control.replay();
+        mock.twoArgumentMethod(1, 6);
+        mock.simpleMethod();
+        control.verify();
+    }
+
+    @Test
+    public void expectedArgumentsDelegatedToMatcher2() {
+        mock.threeArgumentMethod(7, "", "A test");
+        control.setMatcher(new AbstractMatcher() {
+            
+            private static final long serialVersionUID = 1L;
+            
+            @Override
+            public boolean matches(Object[] expected, Object[] actual) {
+                int expectedInt = ((Integer) expected[0]).intValue();
+                int actualInt = ((Integer) actual[0]).intValue();
+                return expectedInt < actualInt;
+            }
+        });
+        control.setReturnValue("1");
+        mock.threeArgumentMethod(6, "", "A test");
+        control.setReturnValue("2");
+        mock.threeArgumentMethod(12, "", "A test");
+        control.setReturnValue("3");
+
+        control.replay();
+        mock.threeArgumentMethod(9, "test", "test");
+        mock.threeArgumentMethod(8, "test", "test");
+        mock.threeArgumentMethod(13, "test", "test");
+        control.verify();
+    }
+
+    @Test
+    public void errorString() {
+        mock.twoArgumentMethod(0, 5);
+        control.setMatcher(new ArgumentsMatcher() {
+            public boolean matches(Object[] expected, Object[] actual) {
+                return false;
+            }
+
+            public String toString(Object[] arguments) {
+                return "<<" + arguments[0] + ">>";
+            }
+        });
+        control.replay();
+        boolean failed = false;
+        try {
+            mock.twoArgumentMethod(1, 5);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals("\n  Unexpected method call twoArgumentMethod(1, 5):"
+                    + "\n    twoArgumentMethod(<<0>>): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("exception expected");
+        }
+    }
+
+    @Test
+    public void settingTheSameMatcherIsOk() {
+        try {
+            mock.twoArgumentMethod(1, 2);
+            control.setMatcher(MockControl.ARRAY_MATCHER);
+            control.setMatcher(MockControl.ARRAY_MATCHER);
+            mock.twoArgumentMethod(1, 2);
+            control.setMatcher(MockControl.ARRAY_MATCHER);
+
+        } catch (IllegalStateException unexpected) {
+            fail("no exception should be thrown if the same matcher is set twice");
+        }
+    }
+
+    @Test
+    public void abstractMatcher() {
+        AbstractMatcher trueMatcher = new AbstractMatcher() {
+            
+            private static final long serialVersionUID = 1L;
+            
+            protected boolean parameterMatches(Object expected, Object actual) {
+                return true;
+            }
+        };
+        Object[] arrayWithNull = new Object[] { null };
+        Object[] arrayWithObject = new Object[] { new Object() };
+        assertFalse(trueMatcher.matches(arrayWithNull, arrayWithObject));
+        assertFalse(trueMatcher.matches(arrayWithObject, arrayWithNull));
+    }
+
+    @Test
+    public void abstractMatcherToStringHandlesNullArray() {
+        AbstractMatcher matcher = new AbstractMatcher() {            
+            private static final long serialVersionUID = 1L;
+        };
+        assertEquals("", matcher.toString(null));
+    }
+
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/ArrayMatcherTest.java b/tests/org/easymock/tests/ArrayMatcherTest.java
new file mode 100644
index 0000000..62b0084
--- /dev/null
+++ b/tests/org/easymock/tests/ArrayMatcherTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.ArgumentsMatcher;
+import org.easymock.MockControl;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class ArrayMatcherTest {
+
+    private static ArgumentsMatcher MATCHER = MockControl.ARRAY_MATCHER;
+
+    @Test
+    public void booleanArray() {
+        assertTrue(equals(new boolean[] { true }, new boolean[] { true }));
+        assertFalse(equals(new boolean[] { true }, new boolean[] { false }));
+    }
+
+    @Test
+    public void byteArray() {
+        assertTrue(equals(new byte[] { 6 }, new byte[] { 6 }));
+        assertFalse(equals(new byte[] { 6 }, new byte[] { 7 }));
+    }
+
+    @Test
+    public void charArray() {
+        assertTrue(equals(new char[] { 'x' }, new char[] { 'x' }));
+        assertFalse(equals(new char[] { 'x' }, new char[] { 'y' }));
+    }
+
+    @Test
+    public void doubleArray() {
+        assertTrue(equals(new double[] { 6.0 }, new double[] { 6.0 }));
+        assertFalse(equals(new double[] { 6.0 }, new double[] { 7.0 }));
+    }
+
+    @Test
+    public void floatArray() {
+        assertTrue(equals(new float[] { 6.0F }, new float[] { 6.0F }));
+        assertFalse(equals(new float[] { 6.0F }, new float[] { 7.0F }));
+    }
+
+    @Test
+    public void intArray() {
+        assertTrue(equals(new int[] { 6 }, new int[] { 6 }));
+        assertFalse(equals(new int[] { 6 }, new int[] { 7 }));
+    }
+
+    @Test
+    public void longArray() {
+        assertTrue(equals(new long[] { 6 }, new long[] { 6 }));
+        assertFalse(equals(new long[] { 6 }, new long[] { 7 }));
+    }
+
+    @Test
+    public void shortArray() {
+        assertTrue(equals(new short[] { 6 }, new short[] { 6 }));
+        assertFalse(equals(new short[] { 6 }, new short[] { 7 }));
+    }
+
+    @Test
+    public void objectArray() {
+        assertTrue(equals(new String[] { "1", "2" }, new String[] { "1", "2" }));
+        assertFalse(equals(new String[] { "1", "2" }, new String[] { "2", "2" }));
+    }
+
+    @Test
+    public void nonArray() {
+        assertTrue(equals("1", "1"));
+        assertFalse(equals("1", "2"));
+    }
+
+    @Test
+    public void testToString() {
+        assertEquals("[true, false]", stringFor(new boolean[] { true, false }));
+        assertEquals("[6, 7]", stringFor(new byte[] { 6, 7 }));
+        assertEquals("['x', 'y']", stringFor(new char[] { 'x', 'y' }));
+        assertEquals("[6.0, 7.0]", stringFor(new double[] { 6, 7 }));
+        assertEquals("[6.0, 7.0]", stringFor(new float[] { 6, 7 }));
+        assertEquals("[6, 7]", stringFor(new int[] { 6, 7 }));
+        assertEquals("[6, 7]", stringFor(new long[] { 6, 7 }));
+        assertEquals("[6, 7]", stringFor(new short[] { 6, 7 }));
+        assertEquals("[\"1\", \"2\"]", stringFor(new String[] { "1", "2" }));
+        assertEquals("[\"1\", \"2\"]", stringFor(new Object[] { "1", "2" }));
+    }
+
+    @Test
+    public void toStringMixed() {
+        assertEquals("3, [\"1\", 2.0], \"Test\"", MATCHER
+                .toString(new Object[] { new Integer(3),
+                        new Object[] { "1", new Float(2.0) }, "Test" }));
+    }
+
+    private String stringFor(Object argument) {
+        return MATCHER.toString(new Object[] { argument });
+    }
+
+    private boolean equals(Object o1, Object o2) {
+        Object[] expected = new Object[] { o1 };
+        Object[] actual = new Object[] { o2 };
+        return MATCHER.matches(expected, actual);
+    }
+}
diff --git a/tests/org/easymock/tests/CapturesMatcherTest.java b/tests/org/easymock/tests/CapturesMatcherTest.java
new file mode 100644
index 0000000..f5e8bf7
--- /dev/null
+++ b/tests/org/easymock/tests/CapturesMatcherTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003-2008 OFFIS, Henri Tremblay. 
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.Capture;
+import org.easymock.internal.matchers.Captures;
+import org.junit.Test;
+
+
+public class CapturesMatcherTest {
+
+    private Capture<String> capture = new Capture<String>();
+    private Captures<String> matcher = new Captures<String>(capture);
+    
+    @Test
+    public void test() {
+        StringBuffer buffer = new StringBuffer();
+        matcher.appendTo(buffer);
+        assertEquals("capture(Nothing captured yet)", buffer.toString());
+        
+        assertTrue(matcher.matches(null));
+        
+        buffer.delete(0, buffer.length());        
+        matcher.appendTo(buffer);
+        assertEquals("capture(null)", buffer.toString());
+        
+        assertTrue(matcher.matches("s"));
+        
+        buffer.delete(0, buffer.length());        
+        matcher.appendTo(buffer);
+        assertEquals("capture(s)", buffer.toString());
+    }
+}
diff --git a/tests/org/easymock/tests/DefaultMatcherTest.java b/tests/org/easymock/tests/DefaultMatcherTest.java
new file mode 100644
index 0000000..bdfdf47
--- /dev/null
+++ b/tests/org/easymock/tests/DefaultMatcherTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class DefaultMatcherTest {
+
+    public static interface ArrayInterface {
+        void methodA(int[] argument);
+
+        void methodB(int[] argument);
+    }
+
+    private MockControl<ArrayInterface> control;
+
+    private ArrayInterface mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(ArrayInterface.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void defaultMatcher() {
+        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+
+        mock.methodA(new int[] { 1, 1 });
+        mock.methodB(new int[] { 2, 2 });
+
+        control.replay();
+
+        mock.methodA(new int[] { 1, 1 });
+        mock.methodB(new int[] { 2, 2 });
+
+        control.verify();
+    }
+
+    @Test
+    public void failInReplayState() {
+        control.replay();
+        try {
+            control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    @Test
+    public void failIfDefaultMatcherSetTwice() {
+        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+        try {
+            control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "default matcher can only be set once directly after creation of the MockControl",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void defaultMatcherSetTooLate() {
+        int[] integers = new int[] { 1, 1 };
+        int[] integers2 = new int[] { 2, 2 };
+        mock.methodA(integers);
+        control.setVoidCallable();
+        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+        mock.methodA(integers2);
+        control.setVoidCallable();
+        control.replay();
+
+        boolean failed = true;
+        try {
+            mock.methodA(new int[] { 1, 1 });
+            failed = false;
+        } catch (AssertionError expected) {
+        }
+        if (!failed) {
+            fail();
+        }
+        mock.methodA(integers);
+        mock.methodA(new int[] { 2, 2 });
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/EqualsMatcherTest.java b/tests/org/easymock/tests/EqualsMatcherTest.java
new file mode 100644
index 0000000..3298a15
--- /dev/null
+++ b/tests/org/easymock/tests/EqualsMatcherTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.ArgumentsMatcher;
+import org.easymock.MockControl;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class EqualsMatcherTest {
+    final ArgumentsMatcher MATCHER = MockControl.EQUALS_MATCHER;
+
+    @Test
+    public void equalsMatcher() {
+        assertTrue(MATCHER.matches(null, null));
+        assertFalse(MATCHER.matches(null, new Object[0]));
+        assertFalse(MATCHER.matches(new Object[0], null));
+        assertFalse(MATCHER.matches(new Object[] { "" }, new Object[] { null }));
+        assertFalse(MATCHER.matches(new Object[] { null }, new Object[] { "" }));
+        assertTrue(MATCHER
+                .matches(new Object[] { null }, new Object[] { null }));
+        assertTrue(MATCHER.matches(new Object[] { "x" }, new Object[] { "x" }));
+    }
+
+    @Test
+    public void differentNumberOfArguments() {
+        assertFalse(MATCHER.matches(new Object[2], new Object[3]));
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/ExpectedMethodCallTest.java b/tests/org/easymock/tests/ExpectedMethodCallTest.java
new file mode 100644
index 0000000..7a331a1
--- /dev/null
+++ b/tests/org/easymock/tests/ExpectedMethodCallTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.easymock.internal.ExpectedInvocation;
+import org.easymock.internal.Invocation;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ExpectedMethodCallTest {
+
+    private ExpectedInvocation call;
+
+    @Before
+    public void setup() throws SecurityException, NoSuchMethodException {
+        Object[] arguments1 = new Object[] { "" };
+        Method m = Object.class.getMethod("equals",
+                new Class[] { Object.class });
+        call = new ExpectedInvocation(new Invocation(null, m, arguments1), null);
+    }
+
+    @Test
+    public void testHashCode() {
+        try {
+            call.hashCode();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+            assertEquals("hashCode() is not implemented", expected.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/IMethods.java b/tests/org/easymock/tests/IMethods.java
new file mode 100644
index 0000000..fbade56
--- /dev/null
+++ b/tests/org/easymock/tests/IMethods.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import java.io.IOException;
+
+public interface IMethods {
+
+    boolean booleanReturningMethod(int index);
+
+    byte byteReturningMethod(int index);
+
+    short shortReturningMethod(int index);
+
+    char charReturningMethod(int index);
+
+    int intReturningMethod(int index);
+
+    long longReturningMethod(int index);
+
+    float floatReturningMethod(int index);
+
+    double doubleReturningMethod(int index);
+
+    Object objectReturningMethod(int index);
+
+    String oneArg(boolean value);
+
+    String oneArg(byte value);
+
+    String oneArg(short value);
+
+    String oneArg(char value);
+
+    String oneArg(int value);
+
+    String oneArg(long value);
+
+    String oneArg(float value);
+
+    String oneArg(double value);
+
+    String oneArg(Object value);
+
+    String oneArg(String value);
+
+    public String throwsNothing(boolean value);
+
+    public String throwsIOException(int count) throws IOException;
+
+    public String throwsError(int count) throws Error;
+
+    void simpleMethod();
+
+    void simpleMethodWithArgument(String argument);
+
+    Object threeArgumentMethod(int valueOne, Object valueTwo, String valueThree);
+
+    void twoArgumentMethod(int one, int two);
+
+    void arrayMethod(String[] strings);
+
+    String oneArray(boolean[] array);
+
+    String oneArray(byte[] array);
+
+    String oneArray(char[] array);
+
+    String oneArray(double[] array);
+
+    String oneArray(float[] array);
+
+    String oneArray(int[] array);
+
+    String oneArray(long[] array);
+
+    String oneArray(short[] array);
+
+    String oneArray(Object[] array);
+
+    String oneArray(String[] array);
+
+    void varargsString(int i, String... string);
+
+    void varargsObject(int i, Object... object);
+}
diff --git a/tests/org/easymock/tests/IVarArgs.java b/tests/org/easymock/tests/IVarArgs.java
new file mode 100644
index 0000000..4f4896e
--- /dev/null
+++ b/tests/org/easymock/tests/IVarArgs.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+public interface IVarArgs {
+    public void withVarargsString(int value, String... s);
+
+    public void withVarargsObject(int value, Object... o);
+
+    public void withVarargsBoolean(int value, boolean... b);
+
+    public void withVarargsByte(int value, byte... b);
+
+    public void withVarargsChar(int value, char... c);
+
+    public void withVarargsDouble(int value, double... d);
+
+    public void withVarargsFloat(int value, float... f);
+
+    public void withVarargsInt(int value, int... i);
+
+    public void withVarargsLong(int value, long... l);
+
+    public void withVarargsShort(int value, short... s);
+}
diff --git a/tests/org/easymock/tests/InvocationTest.java b/tests/org/easymock/tests/InvocationTest.java
new file mode 100644
index 0000000..7545d48
--- /dev/null
+++ b/tests/org/easymock/tests/InvocationTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.easymock.internal.EqualsMatcher;
+import org.easymock.internal.Invocation;
+import org.junit.Before;
+import org.junit.Test;
+
+public class InvocationTest {
+
+    private Invocation call;
+
+    private Invocation equalCall;
+
+    private Invocation nonEqualCall;
+
+    @Before
+    public void setup() throws SecurityException, NoSuchMethodException {
+        Object[] arguments1 = new Object[] { "" };
+        Object[] arguments2 = new Object[] { "" };
+        Object[] arguments3 = new Object[] { "X" };
+        Method m = Object.class.getMethod("equals",
+                new Class[] { Object.class });
+        Object mock = new Object();
+        call = new Invocation(mock, m, arguments1);
+        equalCall = new Invocation(mock, m, arguments2);
+        nonEqualCall = new Invocation(mock, m, arguments3);
+    }
+
+    @Test
+    public void testEquals() {
+        assertFalse(call.equals(null));
+        assertFalse(call.equals(""));
+        assertTrue(call.equals(equalCall));
+        assertFalse(call.equals(nonEqualCall));
+    }
+
+    @Test
+    public void testHashCode() {
+        try {
+            call.hashCode();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+            assertEquals("hashCode() is not implemented", expected.getMessage());
+        }
+    }
+
+    @Test
+    public void testShouldDisplayMocksToStringIfValidJavaIdentifier()
+            throws SecurityException, NoSuchMethodException {
+        class ToString {
+            private final String name;
+
+            public ToString(String name) {
+                this.name = name;
+            }
+
+            @Override
+            public String toString() {
+                return name;
+            }
+
+            public void aMethod() {
+            }
+        }
+
+        Method method = ToString.class.getMethod("aMethod", new Class[0]);
+        Invocation invocation = new Invocation(new ToString("validJavaIdentifier"),
+                method, null);
+
+        assertEquals(invocation.toString(new EqualsMatcher()),
+                "validJavaIdentifier.aMethod()");
+
+        invocation = new Invocation(new ToString("no-valid-java-identifier"),
+                method, null);
+
+        assertEquals(invocation.toString(new EqualsMatcher()), "aMethod()");
+
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/LegacyBehaviorTests.java b/tests/org/easymock/tests/LegacyBehaviorTests.java
new file mode 100644
index 0000000..081e6f9
--- /dev/null
+++ b/tests/org/easymock/tests/LegacyBehaviorTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.easymock.MockControl;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class LegacyBehaviorTests {
+
+    @Test
+    public void throwAfterThrowable() throws IOException {
+
+        MockControl<IMethods> control = MockControl
+                .createControl(IMethods.class);
+        IMethods mock = control.getMock();
+
+        mock.throwsIOException(0);
+        control.setThrowable(new IOException());
+        control.setThrowable(new IOException(), MockControl.ONE_OR_MORE);
+
+        control.replay();
+
+        try {
+            mock.throwsIOException(0);
+            fail("IOException expected");
+        } catch (IOException expected) {
+        }
+
+        boolean exceptionOccured = true;
+        try {
+            control.verify();
+            exceptionOccured = false;
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    throwsIOException(0): expected: at least 2, actual: 1",
+                    expected.getMessage());
+        }
+
+        if (!exceptionOccured)
+            fail("exception expected");
+
+        try {
+            mock.throwsIOException(0);
+            fail("IOException expected");
+        } catch (IOException expected) {
+        }
+
+        control.verify();
+
+        try {
+            mock.throwsIOException(0);
+            fail("IOException expected");
+        } catch (IOException expected) {
+        }
+
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/MatchableArgumentsTest.java b/tests/org/easymock/tests/MatchableArgumentsTest.java
new file mode 100644
index 0000000..214b9d8
--- /dev/null
+++ b/tests/org/easymock/tests/MatchableArgumentsTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.easymock.internal.ExpectedInvocation;
+import org.easymock.internal.Invocation;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MatchableArgumentsTest {
+
+    private Object[] arguments;
+
+    private Object[] arguments2;
+
+    @Before
+    public void setup() {
+        arguments = new Object[] { "" };
+        arguments2 = new Object[] { "", "" };
+    }
+
+    @Test
+    public void testEquals() throws SecurityException, NoSuchMethodException {
+        Method toPreventNullPointerExceptionm = Object.class.getMethod(
+                "toString", new Class[] {});
+
+        Object mock = new Object();
+
+        ExpectedInvocation matchableArguments = new ExpectedInvocation(
+                new Invocation(mock, toPreventNullPointerExceptionm, arguments),
+                null);
+        ExpectedInvocation nonEqualMatchableArguments = new ExpectedInvocation(
+                new Invocation(mock, toPreventNullPointerExceptionm, arguments2),
+                null);
+
+        assertFalse(matchableArguments.equals(null));
+        assertFalse(matchableArguments.equals(nonEqualMatchableArguments));
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/MethodSerializationWrapperTest.java b/tests/org/easymock/tests/MethodSerializationWrapperTest.java
new file mode 100644
index 0000000..592a7f8
--- /dev/null
+++ b/tests/org/easymock/tests/MethodSerializationWrapperTest.java
@@ -0,0 +1,24 @@
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.easymock.internal.MethodSerializationWrapper;
+import org.junit.Test;
+
+public class MethodSerializationWrapperTest {
+
+    public static class A {
+        public void foo(String s, int i, String[] sArray, int[] iArray, String...varargs ) {            
+        }
+    }
+    
+    @Test
+    public void testGetMethod() throws Exception {
+        Method foo = A.class.getMethod("foo", String.class, Integer.TYPE, String[].class, int[].class, String[].class);
+        MethodSerializationWrapper wrapper = new MethodSerializationWrapper(foo);
+        assertEquals(foo, wrapper.getMethod());
+    }
+
+}
diff --git a/tests/org/easymock/tests/MockNameTest.java b/tests/org/easymock/tests/MockNameTest.java
new file mode 100644
index 0000000..0e2614d
--- /dev/null
+++ b/tests/org/easymock/tests/MockNameTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class MockNameTest {
+
+    private MockControl<IMethods> control;
+
+    @Test
+    public void defaultName() {
+        control = MockControl.createControl(IMethods.class);
+        String expected = "EasyMock for " + IMethods.class.toString();
+        String actual = control.getMock().toString();
+        assertEquals(expected, actual);
+    }
+}
diff --git a/tests/org/easymock/tests/NiceMockControlLongCompatibleReturnValueTest.java b/tests/org/easymock/tests/NiceMockControlLongCompatibleReturnValueTest.java
new file mode 100644
index 0000000..0a5311b
--- /dev/null
+++ b/tests/org/easymock/tests/NiceMockControlLongCompatibleReturnValueTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class NiceMockControlLongCompatibleReturnValueTest {
+
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createNiceControl(IMethods.class);
+        mock = control.getMock();
+        control.replay();
+    }
+
+    @Test
+    public void byteReturningValue() {
+        assertEquals((byte) 0, mock.byteReturningMethod(12));
+        control.verify();
+    }
+
+    @Test
+    public void shortReturningValue() {
+        assertEquals((short) 0, mock.shortReturningMethod(12));
+        control.verify();
+    }
+
+    @Test
+    public void charReturningValue() {
+        assertEquals((char) 0, mock.charReturningMethod(12));
+        control.verify();
+    }
+
+    @Test
+    public void intReturningValue() {
+        assertEquals(0, mock.intReturningMethod(12));
+        control.verify();
+    }
+
+    @Test
+    public void longReturningValue() {
+        assertEquals((long) 0, mock.longReturningMethod(12));
+        control.verify();
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/NiceMockControlTest.java b/tests/org/easymock/tests/NiceMockControlTest.java
new file mode 100644
index 0000000..073c1a2
--- /dev/null
+++ b/tests/org/easymock/tests/NiceMockControlTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class NiceMockControlTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createNiceControl(IMethods.class);
+        mock = control.getMock();
+        control.replay();
+    }
+
+    @Test
+    public void defaultReturnValueBoolean() {
+        assertEquals(false, mock.booleanReturningMethod(12));
+        control.verify();
+    }
+
+    @Test
+    public void defaultReturnValueFloat() {
+        assertEquals(0.0f, mock.floatReturningMethod(12), 0.0f);
+        control.verify();
+    }
+
+    @Test
+    public void defaultReturnValueDouble() {
+        assertEquals(0.0d, mock.doubleReturningMethod(12), 0.0d);
+        control.verify();
+    }
+
+    @Test
+    public void defaultReturnValueObject() {
+        assertEquals(null, mock.objectReturningMethod(12));
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/ObjectMethodsTest.java b/tests/org/easymock/tests/ObjectMethodsTest.java
new file mode 100644
index 0000000..83f9928
--- /dev/null
+++ b/tests/org/easymock/tests/ObjectMethodsTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.easymock.MockControl;
+import org.easymock.internal.ObjectMethodsFilter;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class ObjectMethodsTest {
+    private MockControl<EmptyInterface> control;
+
+    private EmptyInterface mock;
+
+    private interface EmptyInterface {
+    }
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(EmptyInterface.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void equalsBeforeActivation() {
+        assertEquals(mock, mock);
+        assertTrue(!mock.equals(null));
+    }
+
+    @Test
+    public void equalsAfterActivation() {
+        control.replay();
+        assertEquals(mock, mock);
+        assertTrue(!mock.equals(null));
+    }
+
+    @Test
+    public void testHashCode() {
+        int hashCodeBeforeActivation = mock.hashCode();
+        control.replay();
+        int hashCodeAfterActivation = mock.hashCode();
+        assertEquals(hashCodeBeforeActivation, hashCodeAfterActivation);
+    }
+
+    @Test
+    public void toStringBeforeActivation() {
+        assertEquals("EasyMock for " + EmptyInterface.class.toString(), mock
+                .toString());
+    }
+
+    @Test
+    public void toStringAfterActivation() {
+        control.replay();
+        assertEquals("EasyMock for " + EmptyInterface.class.toString(), mock
+                .toString());
+    }
+
+    private static class MockedClass {
+    }
+
+    private static class DummyProxy extends MockedClass {
+    }
+
+    // if the class is no Proxy, ObjectMethodFilter should use the
+    // superclasses' name. This is needed for the class extension.
+    @Test
+    public void toStringForClasses() throws Throwable {
+        ObjectMethodsFilter filter = new ObjectMethodsFilter(Object.class, null, null);
+        Method toString = Object.class.getMethod("toString", new Class[0]);
+        assertEquals("EasyMock for " + MockedClass.class.toString(), filter
+                .invoke(new DummyProxy(), toString, new Object[0]));
+    }
+
+}
diff --git a/tests/org/easymock/tests/RecordStateInvalidDefaultReturnValueTest.java b/tests/org/easymock/tests/RecordStateInvalidDefaultReturnValueTest.java
new file mode 100644
index 0000000..989ce95
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidDefaultReturnValueTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidDefaultReturnValueTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void setInvalidDefaultBooleanReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setDefaultReturnValue(false);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidDefaultLongReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setDefaultReturnValue((long) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidDefaultFloatReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setDefaultReturnValue((float) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidDefaultDoubleReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setDefaultReturnValue((double) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidObjectDefaultReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setDefaultReturnValue(new Object());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setDefaultReturnValueWithoutMethodCall() {
+        try {
+            control.setDefaultReturnValue(new Object());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals(
+                    "method call on the mock needed before setting default return value",
+                    e.getMessage());
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/RecordStateInvalidDefaultThrowableTest.java b/tests/org/easymock/tests/RecordStateInvalidDefaultThrowableTest.java
new file mode 100644
index 0000000..be25d30
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidDefaultThrowableTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidDefaultThrowableTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    private class CheckedException extends Exception {
+        private static final long serialVersionUID = 1L;
+    }
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void throwNull() {
+        mock.throwsNothing(false);
+        try {
+            control.setDefaultThrowable(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException expected) {
+            assertEquals("null cannot be thrown", expected.getMessage());
+        }
+
+    }
+
+    @Test
+    public void throwCheckedExceptionWhereNoCheckedExceptionIsThrown() {
+        mock.throwsNothing(false);
+        try {
+            control.setDefaultThrowable(new CheckedException());
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("last method called on mock cannot throw "
+                    + this.getClass().getName() + "$CheckedException", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void throwWrongCheckedException() throws IOException {
+        mock.throwsIOException(0);
+        try {
+            control.setDefaultThrowable(new CheckedException());
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("last method called on mock cannot throw "
+                    + this.getClass().getName() + "$CheckedException", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setDefaultThrowableWithoutMethodCall() throws IOException {
+        try {
+            control.setDefaultThrowable(new RuntimeException());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default Throwable",
+                    expected.getMessage());
+        }
+    }
+
+}
diff --git a/tests/org/easymock/tests/RecordStateInvalidMatcherTest.java b/tests/org/easymock/tests/RecordStateInvalidMatcherTest.java
new file mode 100644
index 0000000..68263cf
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidMatcherTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidMatcherTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void setMatcherBeforeCallingMethods() {
+        try {
+            control.setMatcher(MockControl.ARRAY_MATCHER);
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting matcher",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setMatcherTwice() {
+        mock.simpleMethod();
+        control.setMatcher(MockControl.ARRAY_MATCHER);
+        try {
+            control.setMatcher(MockControl.EQUALS_MATCHER);
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "for method simpleMethod(), a matcher has already been set",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setMatcherTwice2() {
+        mock.simpleMethodWithArgument("");
+        control.setMatcher(MockControl.ARRAY_MATCHER);
+        try {
+            control.setMatcher(MockControl.EQUALS_MATCHER);
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "for method simpleMethodWithArgument(...), a matcher has already been set",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setSameMatcherTwice() {
+        mock.simpleMethod();
+        control.setMatcher(MockControl.ARRAY_MATCHER);
+        try {
+            control.setMatcher(MockControl.ARRAY_MATCHER);
+        } catch (IllegalStateException unexpected) {
+            fail("setting the same matcher should work");
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/RecordStateInvalidRangeTest.java b/tests/org/easymock/tests/RecordStateInvalidRangeTest.java
new file mode 100644
index 0000000..3633c29
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidRangeTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidRangeTest {
+
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setUp() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void setOpenCallCountTwice() {
+        mock.simpleMethod();
+        control.setVoidCallable(MockControl.ONE_OR_MORE);
+        try {
+            control.setVoidCallable(MockControl.ONE_OR_MORE);
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "last method called on mock already has a non-fixed count set.",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setIllegalMinimumCount() {
+        mock.simpleMethod();
+        int NEGATIVE = -1;
+        try {
+            control.setVoidCallable(NEGATIVE, 2);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            assertEquals("minimum must be >= 0", expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setIllegalMaximumCount() {
+        mock.simpleMethod();
+        int NON_POSITIVE = 0;
+        try {
+            control.setVoidCallable(0, NON_POSITIVE);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            assertEquals("maximum must be >= 1", expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setMinimumBiggerThanMaximum() {
+        mock.simpleMethod();
+        try {
+            control.setVoidCallable(4, 3);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            assertEquals("minimum must be <= maximum", expected.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/RecordStateInvalidReturnValueTest.java b/tests/org/easymock/tests/RecordStateInvalidReturnValueTest.java
new file mode 100644
index 0000000..b758398
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidReturnValueTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidReturnValueTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void setInvalidBooleanReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue(false);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+
+    }
+
+    @Test
+    public void setInvalidLongReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((long) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidFloatReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((float) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidDoubleReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((double) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidObjectReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue(new Object());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidBooleanReturnValueCount() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue(false, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+
+    }
+
+    @Test
+    public void setInvalidLongReturnValueCount() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((long) 0, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidFloatReturnValueCount() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((float) 0, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidDoubleReturnValueCount() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((double) 0, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setInvalidObjectReturnValueCount() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue(new Object(), 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("incompatible return value type", e.getMessage());
+        }
+    }
+
+    @Test
+    public void setReturnValueForVoidMethod() {
+        mock.simpleMethod();
+        try {
+            control.setReturnValue(null);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("void method cannot return a value", e.getMessage());
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/RecordStateInvalidStateChangeTest.java b/tests/org/easymock/tests/RecordStateInvalidStateChangeTest.java
new file mode 100644
index 0000000..c3ad494
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidStateChangeTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.easymock.internal.RecordState;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidStateChangeTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void activateWithoutReturnValue() {
+        mock.oneArg(false);
+        try {
+            control.replay();
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals(
+                    "missing behavior definition for the preceeding method call oneArg(false)",
+                    e.getMessage());
+            assertTrue("stack trace must be cut", Util.getStackTrace(e)
+                    .indexOf(RecordState.class.getName()) == -1);
+        }
+    }
+
+    @Test
+    public void secondCallWithoutReturnValue() {
+        mock.oneArg(false);
+        try {
+            mock.oneArg(false);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals(
+                    "missing behavior definition for the preceeding method call oneArg(false)",
+                    e.getMessage());
+            assertTrue("stack trace must be cut", Util.getStackTrace(e)
+                    .indexOf(RecordState.class.getName()) == -1);
+        }
+    }
+
+    @Test
+    public void verifyWithoutActivation() {
+        try {
+            control.verify();
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            assertEquals("calling verify is not allowed in record state", e
+                    .getMessage());
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/RecordStateInvalidThrowableTest.java b/tests/org/easymock/tests/RecordStateInvalidThrowableTest.java
new file mode 100644
index 0000000..64d1419
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidThrowableTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidThrowableTest {
+
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    private class CheckedException extends Exception {
+        private static final long serialVersionUID = 1L;
+    }
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void throwNull() {
+        mock.throwsNothing(false);
+        try {
+            control.setThrowable(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException expected) {
+            assertEquals("null cannot be thrown", expected.getMessage());
+        }
+
+    }
+
+    @Test
+    public void throwCheckedExceptionWhereNoCheckedExceptionIsThrown() {
+        mock.throwsNothing(false);
+        try {
+            control.setThrowable(new CheckedException());
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("last method called on mock cannot throw "
+                    + CheckedException.class.getName(), expected.getMessage());
+        }
+    }
+
+    @Test
+    public void throwWrongCheckedException() throws IOException {
+        mock.throwsIOException(0);
+        try {
+            control.setThrowable(new CheckedException());
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException expected) {
+            assertEquals("last method called on mock cannot throw "
+                    + CheckedException.class.getName(), expected.getMessage());
+        }
+    }
+
+    @Test
+    public void throwAfterThrowable() throws IOException {
+        mock.throwsIOException(0);
+        control.setThrowable(new IOException(), MockControl.ONE_OR_MORE);
+        try {
+            control.setThrowable(new IOException());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "last method called on mock already has a non-fixed count set.",
+                    expected.getMessage());
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/RecordStateInvalidUsageTest.java b/tests/org/easymock/tests/RecordStateInvalidUsageTest.java
new file mode 100644
index 0000000..0438e94
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateInvalidUsageTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateInvalidUsageTest {
+
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void setReturnValueWithoutMethodCall() {
+        try {
+            control.setReturnValue(false);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setExpectedVoidCallCountWithoutMethodCall() {
+        try {
+            control.setVoidCallable(3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting void callable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void openVoidCallCountWithoutMethodCall() {
+        try {
+            control.setVoidCallable();
+            fail("IllegalStateException expected");
+        } catch (Exception expected) {
+            assertEquals(
+                    "method call on the mock needed before setting void callable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueBoolean() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue(false);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueShort() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((short) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueChar() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((char) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueInt() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue(0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueLong() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((long) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueFloat() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((float) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueDouble() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue((double) 0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void setWrongReturnValueObject() {
+        mock.oneArg(false);
+        try {
+            control.setReturnValue(new Object());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals("incompatible return value type", expected
+                    .getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/RecordStateMethodCallMissingTest.java b/tests/org/easymock/tests/RecordStateMethodCallMissingTest.java
new file mode 100644
index 0000000..0064776
--- /dev/null
+++ b/tests/org/easymock/tests/RecordStateMethodCallMissingTest.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class RecordStateMethodCallMissingTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void setBooleanReturnValueWithoutMethodCall() {
+        try {
+            control.setReturnValue(false);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setLongReturnValueWithoutMethodCall() {
+        try {
+            control.setReturnValue(0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setFloatReturnValueWithoutMethodCall() {
+        try {
+            control.setReturnValue((float) 0.0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setDoubleReturnValueWithoutMethodCall() {
+        try {
+            control.setReturnValue(0.0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setObjectReturnValueWithoutMethodCall() {
+        try {
+            control.setReturnValue(null);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setVoidCallableWithoutMethodCall() {
+        try {
+            control.setVoidCallable();
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting void callable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setThrowableWithoutMethodCall() {
+        try {
+            control.setThrowable(new RuntimeException());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting Throwable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setBooleanReturnValueCountWithoutMethodCall() {
+        try {
+            control.setReturnValue(false, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setLongReturnValueCountWithoutMethodCall() {
+        try {
+            control.setReturnValue(0, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setFloatReturnValueCountWithoutMethodCall() {
+        try {
+            control.setReturnValue((float) 0.0, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setDoubleReturnValueCountWithoutMethodCall() {
+        try {
+            control.setReturnValue(0.0, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setObjectReturnValueCountWithoutMethodCall() {
+        try {
+            control.setReturnValue(null, 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setVoidCallableCountWithoutMethodCall() {
+        try {
+            control.setVoidCallable(3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting void callable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setThrowableCountWithoutMethodCall() {
+        try {
+            control.setThrowable(new RuntimeException(), 3);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting Throwable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setBooleanDefaultReturnValueWithoutMethodCall() {
+        try {
+            control.setDefaultReturnValue(false);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setLongDefaultReturnValueWithoutMethodCall() {
+        try {
+            control.setDefaultReturnValue(0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setFloatDefaultReturnValueWithoutMethodCall() {
+        try {
+            control.setDefaultReturnValue((float) 0.0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setDoubleDefaultReturnValueWithoutMethodCall() {
+        try {
+            control.setDefaultReturnValue(0.0);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setObjectDefaultReturnValueWithoutMethodCall() {
+        try {
+            control.setDefaultReturnValue(null);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default return value",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setDefaultVoidCallableWithoutMethodCall() {
+        try {
+            control.setDefaultVoidCallable();
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default void callable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void setDefaultThrowableWithoutMethodCall() {
+        try {
+            control.setDefaultThrowable(new RuntimeException());
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+            assertEquals(
+                    "method call on the mock needed before setting default Throwable",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void timesWithoutReturnValue() {
+        mock.booleanReturningMethod(1);
+        try {
+            expectLastCall().times(3);
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals("last method called on mock is not a void method",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void asStubWithNonVoidMethod() {
+        mock.booleanReturningMethod(1);
+        try {
+            expectLastCall().asStub();
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals("last method called on mock is not a void method",
+                    expected.getMessage());
+        }
+    }
+
+}
diff --git a/tests/org/easymock/tests/ReplayStateInvalidCallsTest.java b/tests/org/easymock/tests/ReplayStateInvalidCallsTest.java
new file mode 100644
index 0000000..1f18475
--- /dev/null
+++ b/tests/org/easymock/tests/ReplayStateInvalidCallsTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import org.easymock.MockControl;
+import org.easymock.internal.MocksBehavior;
+import org.easymock.internal.ReplayState;
+import org.easymock.internal.RuntimeExceptionWrapper;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class ReplayStateInvalidCallsTest {
+
+    private ReplayState control;
+
+    private Exception exception;
+
+    @Before
+    public void setUp() {
+        exception = new Exception();
+        control = new ReplayState(new MocksBehavior(false));
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void expectAndThrowLongWithMinMax() {
+        control.andThrow(exception);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void expectAndReturnObjectWithMinMax() {
+        control.andReturn("");
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void setDefaultMatcher() {
+        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void asStub() {
+        control.asStub();
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void setMatcher() {
+        control.setMatcher(null, MockControl.ARRAY_MATCHER);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void setDefaultReturnValue() {
+        control.setDefaultReturnValue("");
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void setDefaultThrowable() {
+        control.setDefaultThrowable(exception);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void setDefaultVoidCallable() {
+        control.setDefaultVoidCallable();
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void replay() {
+        control.replay();
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void checkOrder() {
+        control.checkOrder(true);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void makeThreadSafe() {
+        control.makeThreadSafe(true);
+    }
+    
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void andStubReturn() {
+        control.andStubReturn("7");
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void andStubThrow() {
+        control.andStubThrow(new RuntimeException());
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void andStubAnswer() {
+        control.andStubAnswer(null);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void times() {
+        control.times(MockControl.ONE);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void callback() {
+        control.callback(new Runnable() {
+            public void run() {
+            };
+        });
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void andReturn() {
+        control.andReturn(null);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void andThrow() {
+        control.andThrow(new RuntimeException());
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void andAnswer() {
+        control.andAnswer(null);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void defaultThrowable() {
+        control.setDefaultThrowable(new RuntimeException());
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void defaultReturnValue() {
+        control.setDefaultReturnValue(null);
+    }
+
+    @Test(expected = RuntimeExceptionWrapper.class)
+    public void defaultVoidCallable() {
+        control.setDefaultVoidCallable();
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/ReplayStateInvalidUsageTest.java b/tests/org/easymock/tests/ReplayStateInvalidUsageTest.java
new file mode 100644
index 0000000..50d20fa
--- /dev/null
+++ b/tests/org/easymock/tests/ReplayStateInvalidUsageTest.java
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import org.easymock.EasyMock;
+import org.easymock.IExpectationSetters;
+import org.easymock.IMocksControl;
+import org.easymock.MockControl;
+import org.easymock.internal.ReplayState;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class ReplayStateInvalidUsageTest {
+
+    private MockControl<IMethods> control;
+
+    private Exception exception;
+
+    private ReplayState replayState;
+
+    private IMocksControl mocksControl;
+    
+    private IExpectationSetters<String> expectationSetters;
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setUp() {
+        exception = new Exception();
+        control = MockControl.createControl(IMethods.class);
+        control.replay();
+        mocksControl = EasyMock.createControl();
+        mocksControl.replay();
+        expectationSetters = (IExpectationSetters<String>) mocksControl; 
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowObjectWithMinMax() {
+        control.expectAndThrow("", exception, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowDoubleWithMinMax() {
+        control.expectAndThrow(0.0d, exception, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowFloatWithMinMax() {
+        control.expectAndThrow(0.0f, exception, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowLongWithMinMax() {
+        control.expectAndThrow(0, exception, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowBooleanWithMinMax() {
+        control.expectAndThrow(false, exception, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowObjectWithCount() {
+        control.expectAndThrow("", exception, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowDoubleWithCount() {
+        control.expectAndThrow(0.0d, exception, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowFloatWithCount() {
+        control.expectAndThrow(0.0f, exception, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowLongWithCount() {
+        control.expectAndThrow(0, exception, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowBooleanWithCount() {
+        control.expectAndThrow(false, exception, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowObjectWithRange() {
+        control.expectAndThrow("", exception, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowDoubleWithRange() {
+        control.expectAndThrow(0.0d, exception, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowFloatWithRange() {
+        control.expectAndThrow(0.0f, exception, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowLongWithRange() {
+        control.expectAndThrow(0, exception, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowBooleanWithRange() {
+        control.expectAndThrow(false, exception, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowObject() {
+        control.expectAndThrow("", exception);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowDouble() {
+        control.expectAndThrow(0.0d, exception);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowFloat() {
+        control.expectAndThrow(0.0f, exception);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowLong() {
+        control.expectAndThrow(0, exception);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndThrowBoolean() {
+        control.expectAndThrow(false, exception);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnObjectWithMinMax() {
+        control.expectAndReturn("", "", 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnDoubleWithMinMax() {
+        control.expectAndReturn(0.0d, 0.0d, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnFloatWithMinMax() {
+        control.expectAndReturn(0.0f, 0.0f, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnLongWithMinMax() {
+        control.expectAndReturn(0, 0, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnBooleanWithMinMax() {
+        control.expectAndReturn(false, false, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnObjectWithCount() {
+        control.expectAndReturn("", "", 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnDoubleWithCount() {
+        control.expectAndReturn(0.0d, 0.0d, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnFloatWithCount() {
+        control.expectAndReturn(0.0f, 0.0f, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnLongWithCount() {
+        control.expectAndReturn(0, 0, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnBooleanWithCount() {
+        control.expectAndReturn(false, false, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnObjectWithRange() {
+        control.expectAndReturn("", "", MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnDoubleWithRange() {
+        control.expectAndReturn(0.0d, 0.0d, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnFloatWithRange() {
+        control.expectAndReturn(0.0f, 0.0f, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnLongWithRange() {
+        control.expectAndReturn(0, 0, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnBooleanWithRange() {
+        control.expectAndReturn(false, false, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnObject() {
+        control.expectAndReturn("", "");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnDouble() {
+        control.expectAndReturn(0.0d, 0.0d);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnFloat() {
+        control.expectAndReturn(0.0f, 0.0f);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnLong() {
+        control.expectAndReturn(0, 0);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void expectAndReturnBoolean() {
+        control.expectAndReturn(false, false);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultMatcher() {
+        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueObjectWithMinMax() {
+        control.setReturnValue("", 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueDoubleWithMinMax() {
+        control.setReturnValue(0.0d, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueFloatWithMinMax() {
+        control.setReturnValue(0.0f, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueLongWithMinMax() {
+        control.setReturnValue(0, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueBooleanWithMinMax() {
+        control.setReturnValue(false, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setThrowableWithMinMax() {
+        control.setThrowable(exception, 1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setVoidCallableWithMinMax() {
+        control.setVoidCallable(1, 2);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setMatcher() {
+        control.setMatcher(MockControl.ARRAY_MATCHER);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultReturnValueObject() {
+        control.setDefaultReturnValue("");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultReturnValueDouble() {
+        control.setDefaultReturnValue(0.0d);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultReturnValueFloat() {
+        control.setDefaultReturnValue(0.0f);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultReturnValueLong() {
+        control.setDefaultReturnValue(0);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultReturnValueBoolean() {
+        control.setDefaultReturnValue(false);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultThrowable() {
+        control.setDefaultThrowable(exception);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setDefaultVoidCallable() {
+        control.setDefaultVoidCallable();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueObjectWithRange() {
+        control.setReturnValue("", MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueLongWithRange() {
+        control.setReturnValue(0, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueFloatWithRange() {
+        control.setReturnValue(0.0f, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueDoubleWithRange() {
+        control.setReturnValue(0.0d, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueBooleanWithRange() {
+        control.setReturnValue(false, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setThrowableWithRange() {
+        control.setThrowable(exception, MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setVoidCallableWithRange() {
+        control.setVoidCallable(MockControl.ONE);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueObjectWithCount() {
+        control.setReturnValue("", 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueLongWithCount() {
+        control.setReturnValue(0, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueFloatWithCount() {
+        control.setReturnValue(0.0f, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueDoubleWithCount() {
+        control.setReturnValue(0.0d, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueBooleanWithCount() {
+        control.setReturnValue(false, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setThrowableWithCount() {
+        control.setThrowable(exception, 1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setVoidCallableWithCount() {
+        control.setVoidCallable(1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueObject() {
+        control.setReturnValue("");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueDouble() {
+        control.setReturnValue(0.0d);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueFloat() {
+        control.setReturnValue(0.0f);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueLong() {
+        control.setReturnValue(0);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setReturnValueBoolean() {
+        control.setReturnValue(false);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setThrowable() {
+        control.setThrowable(exception);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void setVoidCallable() {
+        control.setVoidCallable();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void replay() {
+        control.replay();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void createMock() {
+        mocksControl.createMock(IMethods.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void createMockWithName() {
+        mocksControl.createMock("", IMethods.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkOrder() {
+        mocksControl.checkOrder(true);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void makeThreadSafe() {
+        mocksControl.makeThreadSafe(true);
+    }
+    
+    @Test(expected = IllegalStateException.class)
+    public void andStubReturn() {
+        expectationSetters.andStubReturn("7");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void andStubThrow() {
+        expectationSetters.andStubThrow(new RuntimeException());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void asStub() {
+        expectationSetters.asStub();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void times() {
+        expectationSetters.times(3);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void anyTimes() {
+        expectationSetters.anyTimes();
+    }   
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/ResultTest.java b/tests/org/easymock/tests/ResultTest.java
new file mode 100644
index 0000000..f1ff041
--- /dev/null
+++ b/tests/org/easymock/tests/ResultTest.java
@@ -0,0 +1,24 @@
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.internal.Result;
+import org.junit.Test;
+
+
+public class ResultTest {
+
+    @Test
+    public void createThrowResultToString() {
+        Exception e = new Exception("Error message");
+        Result r = Result.createThrowResult(e);
+        assertEquals("Answer throwing " + e, r.toString());
+    }
+    
+    @Test
+    public void createReturnResultToString() {
+        String value = "My value";
+        Result r = Result.createReturnResult(value);
+        assertEquals("Answer returning " + value, r.toString());
+    }
+}
diff --git a/tests/org/easymock/tests/StacktraceTest.java b/tests/org/easymock/tests/StacktraceTest.java
new file mode 100644
index 0000000..867e210
--- /dev/null
+++ b/tests/org/easymock/tests/StacktraceTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class StacktraceTest {
+
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createStrictControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    private static class ToStringThrowsException {
+        @Override
+        public String toString() {
+            throw new NullPointerException();
+        }
+    }
+
+    @Test
+    public void assertRecordStateNoFillInStacktraceWhenExceptionNotFromEasyMock() {
+        mock.oneArg(new ToStringThrowsException());
+        try {
+            mock.oneArg(new ToStringThrowsException());
+        } catch (NullPointerException expected) {
+            assertTrue("stack trace must not be cut",
+                    Util.getStackTrace(expected).indexOf(
+                            ToStringThrowsException.class.getName()) > 0);
+        }
+    }
+
+    @Test
+    public void assertReplayNoFillInStacktraceWhenExceptionNotFromEasyMock() {
+        mock.oneArg(new ToStringThrowsException());
+        try {
+            control.replay();
+        } catch (NullPointerException expected) {
+            assertTrue("stack trace must not be cut",
+                    Util.getStackTrace(expected).indexOf(
+                            ToStringThrowsException.class.getName()) > 0);
+        }
+    }
+
+    @Test
+    public void assertReplayStateNoFillInStacktraceWhenExceptionNotFromEasyMock() {
+        control.replay();
+        try {
+            mock.oneArg(new ToStringThrowsException());
+        } catch (NullPointerException expected) {
+            assertTrue("stack trace must not be cut",
+                    Util.getStackTrace(expected).indexOf(
+                            ToStringThrowsException.class.getName()) > 0);
+        }
+    }
+
+    @Test
+    public void assertVerifyNoFillInStacktraceWhenExceptionNotFromEasyMock() {
+        mock.oneArg(new ToStringThrowsException());
+        control.setReturnValue("");
+        control.replay();
+        try {
+            control.verify();
+            fail();
+        } catch (NullPointerException expected) {
+            assertTrue("stack trace must not be cut",
+                    Util.getStackTrace(expected).indexOf(
+                            ToStringThrowsException.class.getName()) > 0);
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/UsageCallCountTest.java b/tests/org/easymock/tests/UsageCallCountTest.java
new file mode 100644
index 0000000..61fbbe6
--- /dev/null
+++ b/tests/org/easymock/tests/UsageCallCountTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageCallCountTest {
+
+    private MockControl<VoidMethodInterface> control;
+
+    private VoidMethodInterface mock;
+
+    private interface VoidMethodInterface {
+        void method();
+    }
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(VoidMethodInterface.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void mockWithNoExpectedCallsPassesWithNoCalls() {
+        control.replay();
+        control.verify();
+    }
+
+    @Test
+    public void mockWithNoExpectedCallsFailsAtFirstCall() {
+        control.replay();
+        assertMethodCallFails();
+    }
+
+    @Test
+    public void mockWithOneExpectedCallFailsAtVerify() {
+        callMethodOnce();
+        control.replay();
+        assertVerifyFails();
+    }
+
+    @Test
+    public void mockWithOneExpectedCallPassesWithOneCall() {
+        callMethodOnce();
+        control.replay();
+        callMethodOnce();
+        control.verify();
+    }
+
+    @Test
+    public void mockWithOneExpectedCallFailsAtSecondCall() {
+        callMethodOnce();
+        control.replay();
+        callMethodOnce();
+        assertMethodCallFails();
+    }
+
+    @Test
+    public void tooFewCalls() {
+        callMethodThreeTimes();
+        control.replay();
+        callMethodTwice();
+        assertVerifyFails();
+    }
+
+    @Test
+    public void correctNumberOfCalls() {
+        callMethodThreeTimes();
+        control.replay();
+        callMethodThreeTimes();
+        control.verify();
+    }
+
+    @Test
+    public void tooManyCalls() {
+        callMethodThreeTimes();
+        control.replay();
+        callMethodThreeTimes();
+        assertMethodCallFails();
+    }
+
+    private void callMethodOnce() {
+        mock.method();
+    }
+
+    private void callMethodTwice() {
+        mock.method();
+        mock.method();
+    }
+
+    private void callMethodThreeTimes() {
+        mock.method();
+        mock.method();
+        mock.method();
+    }
+
+    private void assertVerifyFails() {
+        try {
+            control.verify();
+            fail("Expected AssertionError");
+        } catch (AssertionError expected) {
+        }
+    }
+
+    private void assertMethodCallFails() {
+        try {
+            mock.method();
+            fail("Expected AssertionError");
+        } catch (AssertionError expected) {
+        }
+    }
+
+    @Test
+    public void noUpperLimitWithoutCallCountSet() {
+        mock.method();
+        control.setVoidCallable(MockControl.ONE_OR_MORE);
+        control.replay();
+        assertVerifyFails();
+        mock.method();
+        control.verify();
+        mock.method();
+        control.verify();
+        mock.method();
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/UsageDefaultReturnValueTest.java b/tests/org/easymock/tests/UsageDefaultReturnValueTest.java
new file mode 100644
index 0000000..e8818a9
--- /dev/null
+++ b/tests/org/easymock/tests/UsageDefaultReturnValueTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageDefaultReturnValueTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void defaultReturnValue() {
+        mock.threeArgumentMethod(7, "", "test");
+        control.setReturnValue("test", 1);
+
+        mock.threeArgumentMethod(8, null, "test2");
+        control.setReturnValue("test2", 1);
+
+        Object defaultValue = new Object();
+        control.setDefaultReturnValue(defaultValue);
+
+        control.replay();
+        assertEquals("test", mock.threeArgumentMethod(7, "", "test"));
+        assertEquals("test2", mock.threeArgumentMethod(8, null, "test2"));
+        assertSame(defaultValue, mock.threeArgumentMethod(7, new Object(),
+                "test"));
+        assertSame(defaultValue, mock.threeArgumentMethod(7, "", "test"));
+        assertSame(defaultValue, mock.threeArgumentMethod(8, null, "test"));
+        assertSame(defaultValue, mock.threeArgumentMethod(9, null, "test"));
+
+        control.verify();
+    }
+
+    @Test
+    public void defaultVoidCallable() {
+
+        mock.twoArgumentMethod(1, 2);
+        control.setDefaultVoidCallable();
+
+        mock.twoArgumentMethod(1, 1);
+        RuntimeException expected = new RuntimeException();
+        control.setThrowable(expected);
+
+        control.replay();
+        mock.twoArgumentMethod(2, 1);
+        mock.twoArgumentMethod(1, 2);
+        mock.twoArgumentMethod(3, 7);
+
+        try {
+            mock.twoArgumentMethod(1, 1);
+            fail("RuntimeException expected");
+        } catch (RuntimeException actual) {
+            assertSame(expected, actual);
+        }
+
+    }
+
+    @Test
+    public void defaultThrowable() {
+        mock.twoArgumentMethod(1, 2);
+        control.setVoidCallable();
+        mock.twoArgumentMethod(1, 1);
+        control.setVoidCallable();
+
+        RuntimeException expected = new RuntimeException();
+        control.setDefaultThrowable(expected);
+
+        control.replay();
+
+        mock.twoArgumentMethod(1, 2);
+        mock.twoArgumentMethod(1, 1);
+        try {
+            mock.twoArgumentMethod(2, 1);
+            fail("RuntimeException expected");
+        } catch (RuntimeException actual) {
+            assertSame(expected, actual);
+        }
+    }
+
+    @Test
+    public void defaultReturnValueBoolean() {
+        mock.booleanReturningMethod(12);
+        control.setReturnValue(true);
+        control.setDefaultReturnValue(false);
+
+        control.replay();
+
+        assertFalse(mock.booleanReturningMethod(11));
+        assertTrue(mock.booleanReturningMethod(12));
+        assertFalse(mock.booleanReturningMethod(13));
+
+        control.verify();
+    }
+
+    @Test
+    public void returnValueAndDefaultReturnValue() throws Exception {
+
+        mock.oneArg("");
+
+        expectLastCall().andReturn("1");
+        control.setDefaultReturnValue("2");
+
+        control.replay();
+
+        assertEquals("1", mock.oneArg(""));
+        assertEquals("2", mock.oneArg(""));
+        assertEquals("2", mock.oneArg("X"));
+
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/UsageExpectAndDefaultReturnTest.java b/tests/org/easymock/tests/UsageExpectAndDefaultReturnTest.java
new file mode 100644
index 0000000..7caf015
--- /dev/null
+++ b/tests/org/easymock/tests/UsageExpectAndDefaultReturnTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Same as UsageExpectAndReturnTest except that each mocked method is called
+ * twice to make sure the defaulting works fine.
+ * 
+ * @author Henri Tremblay
+ */
+ at SuppressWarnings("deprecation")
+public class UsageExpectAndDefaultReturnTest {
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void booleanType() {
+        control.expectAndDefaultReturn(mock.booleanReturningMethod(4), true);
+        control.replay();
+        assertEquals(true, mock.booleanReturningMethod(4));
+        assertEquals(true, mock.booleanReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void longType() {
+        control.expectAndDefaultReturn(mock.longReturningMethod(4), 12l);
+        control.replay();
+        assertEquals(12l, mock.longReturningMethod(4));
+        assertEquals(12l, mock.longReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void floatType() {
+        control.expectAndDefaultReturn(mock.floatReturningMethod(4), 12f);
+        control.replay();
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        control.verify();
+    }
+
+    @Test
+    public void doubleType() {
+        control.expectAndDefaultReturn(mock.doubleReturningMethod(4), 12.0);
+        control.replay();
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        control.verify();
+    }
+
+    @Test
+    public void objectType() {
+        control.expectAndDefaultReturn(mock.objectReturningMethod(4), "12");
+        control.replay();
+        assertEquals("12", mock.objectReturningMethod(4));
+        assertEquals("12", mock.objectReturningMethod(4));
+        control.verify();
+    }
+
+}
diff --git a/tests/org/easymock/tests/UsageExpectAndDefaultThrowTest.java b/tests/org/easymock/tests/UsageExpectAndDefaultThrowTest.java
new file mode 100644
index 0000000..5a86915
--- /dev/null
+++ b/tests/org/easymock/tests/UsageExpectAndDefaultThrowTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Same as UsageExpectAndThrowTest except that each mocked method is called
+ * twice to make sure the defaulting works fine.
+ * 
+ * @author Henri Tremblay
+ */
+ at SuppressWarnings("deprecation")
+public class UsageExpectAndDefaultThrowTest {
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    private static RuntimeException EXCEPTION = new RuntimeException();
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void booleanType() {
+        control
+                .expectAndDefaultThrow(mock.booleanReturningMethod(4),
+                        EXCEPTION);
+        control.replay();
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void longType() {
+        control.expectAndDefaultThrow(mock.longReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void floatType() {
+        control.expectAndDefaultThrow(mock.floatReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void doubleType() {
+        control.expectAndDefaultThrow(mock.doubleReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void object() {
+        control.expectAndDefaultThrow(mock.objectReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void throwableAndDefaultThrowable() throws Exception {
+
+        mock.oneArg("1");
+
+        expectLastCall().andThrow(new IllegalArgumentException());
+        control.setDefaultThrowable(new IllegalStateException());
+
+        control.replay();
+
+        try {
+            mock.oneArg("1");
+        } catch (IllegalArgumentException ignored) {
+        }
+        try {
+            mock.oneArg("1");
+        } catch (IllegalStateException ignored) {
+        }
+        try {
+            mock.oneArg("2");
+        } catch (IllegalStateException ignored) {
+        }
+        control.verify();
+    }
+
+}
diff --git a/tests/org/easymock/tests/UsageExpectAndReturnTest.java b/tests/org/easymock/tests/UsageExpectAndReturnTest.java
new file mode 100644
index 0000000..b48c41c
--- /dev/null
+++ b/tests/org/easymock/tests/UsageExpectAndReturnTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageExpectAndReturnTest {
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void booleanType() {
+        control.expectAndReturn(mock.booleanReturningMethod(4), true);
+        control.replay();
+        assertEquals(true, mock.booleanReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void longType() {
+        control.expectAndReturn(mock.longReturningMethod(4), 12l);
+        control.replay();
+        assertEquals((long) 12, mock.longReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void floatType() {
+        control.expectAndReturn(mock.floatReturningMethod(4), 12f);
+        control.replay();
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        control.verify();
+    }
+
+    @Test
+    public void doubleType() {
+        control.expectAndReturn(mock.doubleReturningMethod(4), 12.0);
+        control.replay();
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        control.verify();
+    }
+
+    @Test
+    public void object() {
+        control.expectAndReturn(mock.objectReturningMethod(4), "12");
+        control.replay();
+        assertEquals("12", mock.objectReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void booleanAndRange() {
+        control.expectAndReturn(mock.booleanReturningMethod(4), true,
+                MockControl.ONE);
+        control.replay();
+        assertEquals(true, mock.booleanReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void longAndRange() {
+        control.expectAndReturn(mock.longReturningMethod(4), 12l,
+                MockControl.ONE);
+        control.replay();
+        assertEquals((long) 12, mock.longReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void floatAndRange() {
+        control.expectAndReturn(mock.floatReturningMethod(4), 12f,
+                MockControl.ONE);
+        control.replay();
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        control.verify();
+    }
+
+    @Test
+    public void doubleAndRange() {
+        control.expectAndReturn(mock.doubleReturningMethod(4), 12.0,
+                MockControl.ONE);
+        control.replay();
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        control.verify();
+    }
+
+    @Test
+    public void objectAndRange() {
+        control.expectAndReturn(mock.objectReturningMethod(4), "12",
+                MockControl.ONE);
+        control.replay();
+        assertEquals("12", mock.objectReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void booleanAndCount() {
+        control.expectAndReturn(mock.booleanReturningMethod(4), true, 2);
+        control.replay();
+        assertEquals(true, mock.booleanReturningMethod(4));
+        assertEquals(true, mock.booleanReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void longAndCount() {
+        control.expectAndReturn(mock.longReturningMethod(4), 12l, 2);
+        control.replay();
+        assertEquals((long) 12, mock.longReturningMethod(4));
+        assertEquals((long) 12, mock.longReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void floatAndCount() {
+        control.expectAndReturn(mock.floatReturningMethod(4), 12f, 2);
+        control.replay();
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        control.verify();
+    }
+
+    @Test
+    public void doubleAndCount() {
+        control.expectAndReturn(mock.doubleReturningMethod(4), 12.0, 2);
+        control.replay();
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        control.verify();
+    }
+
+    @Test
+    public void objectAndCount() {
+        control.expectAndReturn(mock.objectReturningMethod(4), "12", 2);
+        control.replay();
+        assertEquals("12", mock.objectReturningMethod(4));
+        assertEquals("12", mock.objectReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void booleanAndMinMax() {
+        control.expectAndReturn(mock.booleanReturningMethod(4), true, 2, 3);
+        control.replay();
+        assertEquals(true, mock.booleanReturningMethod(4));
+        assertEquals(true, mock.booleanReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void longAndMinMax() {
+        control.expectAndReturn(mock.longReturningMethod(4), 12l, 2, 3);
+        control.replay();
+        assertEquals((long) 12, mock.longReturningMethod(4));
+        assertEquals((long) 12, mock.longReturningMethod(4));
+        control.verify();
+    }
+
+    @Test
+    public void floatAndMinMax() {
+        control.expectAndReturn(mock.floatReturningMethod(4), 12f, 2, 3);
+        control.replay();
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        assertEquals(12f, mock.floatReturningMethod(4), 0f);
+        control.verify();
+    }
+
+    @Test
+    public void doubleAndMinMax() {
+        control.expectAndReturn(mock.doubleReturningMethod(4), 12.0, 2, 3);
+        control.replay();
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        assertEquals(12.0, mock.doubleReturningMethod(4), 0.0);
+        control.verify();
+    }
+
+    @Test
+    public void objectAndMinMax() {
+        control.expectAndReturn(mock.objectReturningMethod(4), "12", 2, 3);
+        control.replay();
+        assertEquals("12", mock.objectReturningMethod(4));
+        assertEquals("12", mock.objectReturningMethod(4));
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/UsageExpectAndThrowTest.java b/tests/org/easymock/tests/UsageExpectAndThrowTest.java
new file mode 100644
index 0000000..d5d9125
--- /dev/null
+++ b/tests/org/easymock/tests/UsageExpectAndThrowTest.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageExpectAndThrowTest {
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    private static RuntimeException EXCEPTION = new RuntimeException();
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void booleanType() {
+        control.expectAndThrow(mock.booleanReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void longType() {
+        control.expectAndThrow(mock.longReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void floatType() {
+        control.expectAndThrow(mock.floatReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void doubleType() {
+        control.expectAndThrow(mock.doubleReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void object() {
+        control.expectAndThrow(mock.objectReturningMethod(4), EXCEPTION);
+        control.replay();
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void booleanAndRange() {
+        control.expectAndThrow(mock.booleanReturningMethod(4), EXCEPTION,
+                MockControl.ONE);
+        control.replay();
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void longAndRange() {
+        control.expectAndThrow(mock.longReturningMethod(4), EXCEPTION,
+                MockControl.ONE);
+        control.replay();
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void floatAndRange() {
+        control.expectAndThrow(mock.floatReturningMethod(4), EXCEPTION,
+                MockControl.ONE);
+        control.replay();
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void doubleAndRange() {
+        control.expectAndThrow(mock.doubleReturningMethod(4), EXCEPTION,
+                MockControl.ONE);
+        control.replay();
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void objectAndRange() {
+        control.expectAndThrow(mock.objectReturningMethod(4), EXCEPTION,
+                MockControl.ONE);
+        control.replay();
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void booleanAndCount() {
+        control.expectAndThrow(mock.booleanReturningMethod(4), EXCEPTION, 2);
+        control.replay();
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void longAndCount() {
+        control.expectAndThrow(mock.longReturningMethod(4), EXCEPTION, 2);
+        control.replay();
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void floatAndCount() {
+        control.expectAndThrow(mock.floatReturningMethod(4), EXCEPTION, 2);
+        control.replay();
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void doubleAndCount() {
+        control.expectAndThrow(mock.doubleReturningMethod(4), EXCEPTION, 2);
+        control.replay();
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void objectAndCount() {
+        control.expectAndThrow(mock.objectReturningMethod(4), EXCEPTION, 2);
+        control.replay();
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void booleanAndMinMax() {
+        control.expectAndThrow(mock.booleanReturningMethod(4), EXCEPTION, 2, 3);
+        control.replay();
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+        try {
+            mock.booleanReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void longAndMinMax() {
+        control.expectAndThrow(mock.longReturningMethod(4), EXCEPTION, 2, 3);
+        control.replay();
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+        try {
+            mock.longReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void floatAndMinMax() {
+        control.expectAndThrow(mock.floatReturningMethod(4), EXCEPTION, 2, 3);
+        control.replay();
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+        try {
+            mock.floatReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void doubleAndMinMax() {
+        control.expectAndThrow(mock.doubleReturningMethod(4), EXCEPTION, 2, 3);
+        control.replay();
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+        try {
+            mock.doubleReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+    @Test
+    public void objectAndMinMax() {
+        control.expectAndThrow(mock.objectReturningMethod(4), EXCEPTION, 2, 3);
+        control.replay();
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+        try {
+            mock.objectReturningMethod(4);
+            fail();
+        } catch (RuntimeException exception) {
+            assertSame(EXCEPTION, exception);
+        }
+        control.verify();
+    }
+
+}
diff --git a/tests/org/easymock/tests/UsageFloatingPointReturnValueTest.java b/tests/org/easymock/tests/UsageFloatingPointReturnValueTest.java
new file mode 100644
index 0000000..d4faed5
--- /dev/null
+++ b/tests/org/easymock/tests/UsageFloatingPointReturnValueTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageFloatingPointReturnValueTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void returnFloat() {
+        mock.floatReturningMethod(0);
+        control.setReturnValue(25.0F);
+        control.setDefaultReturnValue(34.0F);
+
+        control.replay();
+
+        assertEquals(25.0F, mock.floatReturningMethod(0), 0.0F);
+        assertEquals(34.0F, mock.floatReturningMethod(-4), 0.0F);
+        assertEquals(34.0F, mock.floatReturningMethod(12), 0.0F);
+
+        control.verify();
+    }
+
+    @Test
+    public void returnDouble() {
+        mock.doubleReturningMethod(0);
+        control.setReturnValue(25.0);
+        control.setDefaultReturnValue(34.0);
+
+        control.replay();
+
+        assertEquals(25.0, mock.doubleReturningMethod(0), 0.0);
+        assertEquals(34.0, mock.doubleReturningMethod(-4), 0.0);
+        assertEquals(34.0, mock.doubleReturningMethod(12), 0.0);
+
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/UsageLongCompatibleReturnValueTest.java b/tests/org/easymock/tests/UsageLongCompatibleReturnValueTest.java
new file mode 100644
index 0000000..3f43802
--- /dev/null
+++ b/tests/org/easymock/tests/UsageLongCompatibleReturnValueTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageLongCompatibleReturnValueTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void returnByte() {
+        mock.byteReturningMethod(0);
+        control.setReturnValue(25);
+        control.setDefaultReturnValue(34);
+
+        control.replay();
+
+        assertEquals((byte) 25, mock.byteReturningMethod(0));
+        assertEquals((byte) 34, mock.byteReturningMethod(-4));
+        assertEquals((byte) 34, mock.byteReturningMethod(12));
+
+        control.verify();
+    }
+
+    @Test
+    public void returnShort() {
+        mock.shortReturningMethod(0);
+        control.setReturnValue(25);
+        control.setDefaultReturnValue(34);
+
+        control.replay();
+
+        assertEquals((short) 25, mock.shortReturningMethod(0));
+        assertEquals((short) 34, mock.shortReturningMethod(-4));
+        assertEquals((short) 34, mock.shortReturningMethod(12));
+
+        control.verify();
+    }
+
+    @Test
+    public void returnChar() {
+        mock.charReturningMethod(0);
+        control.setReturnValue(25);
+        control.setDefaultReturnValue(34);
+
+        control.replay();
+
+        assertEquals((char) 25, mock.charReturningMethod(0));
+        assertEquals((char) 34, mock.charReturningMethod(-4));
+        assertEquals((char) 34, mock.charReturningMethod(12));
+
+        control.verify();
+    }
+
+    @Test
+    public void returnInt() {
+        mock.intReturningMethod(0);
+        control.setReturnValue(25);
+        control.setDefaultReturnValue(34);
+
+        control.replay();
+
+        assertEquals(25, mock.intReturningMethod(0));
+        assertEquals(34, mock.intReturningMethod(-4));
+        assertEquals(34, mock.intReturningMethod(12));
+
+        control.verify();
+    }
+
+    @Test
+    public void returnLong() {
+        mock.longReturningMethod(0);
+        control.setReturnValue(25);
+        control.setDefaultReturnValue(34);
+
+        control.replay();
+
+        assertEquals((long) 25, mock.longReturningMethod(0));
+        assertEquals((long) 34, mock.longReturningMethod(-4));
+        assertEquals((long) 34, mock.longReturningMethod(12));
+
+        control.verify();
+    }
+}
diff --git a/tests/org/easymock/tests/UsageOverloadedDefaultValueTest.java b/tests/org/easymock/tests/UsageOverloadedDefaultValueTest.java
new file mode 100644
index 0000000..aeb3e95
--- /dev/null
+++ b/tests/org/easymock/tests/UsageOverloadedDefaultValueTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageOverloadedDefaultValueTest {
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void overloading() {
+
+        mock.oneArg(true);
+        control.setReturnValue("true");
+        control.setDefaultReturnValue("false");
+
+        mock.oneArg((byte) 0);
+        control.setReturnValue("byte 0");
+        control.setDefaultReturnValue("byte 1");
+
+        mock.oneArg((short) 0);
+        control.setReturnValue("short 0");
+        control.setDefaultReturnValue("short 1");
+
+        mock.oneArg((char) 0);
+        control.setReturnValue("char 0");
+        control.setDefaultReturnValue("char 1");
+
+        mock.oneArg(0);
+        control.setReturnValue("int 0");
+        control.setDefaultReturnValue("int 1");
+
+        mock.oneArg((long) 0);
+        control.setReturnValue("long 0");
+        control.setDefaultReturnValue("long 1");
+
+        mock.oneArg((float) 0);
+        control.setReturnValue("float 0");
+        control.setDefaultReturnValue("float 1");
+
+        mock.oneArg(0.0);
+        control.setReturnValue("double 0");
+        control.setDefaultReturnValue("double 1");
+
+        mock.oneArg("Object 0");
+        control.setReturnValue("String 0");
+        control.setDefaultReturnValue("String 1");
+
+        control.replay();
+
+        assertEquals("true", mock.oneArg(true));
+        assertEquals("false", mock.oneArg(false));
+
+        assertEquals("byte 0", mock.oneArg((byte) 0));
+        assertEquals("byte 1", mock.oneArg((byte) 1));
+
+        assertEquals("short 0", mock.oneArg((short) 0));
+        assertEquals("short 1", mock.oneArg((short) 1));
+
+        assertEquals("char 0", mock.oneArg((char) 0));
+        assertEquals("char 1", mock.oneArg((char) 1));
+
+        assertEquals("int 0", mock.oneArg(0));
+        assertEquals("int 1", mock.oneArg(1));
+
+        assertEquals("long 0", mock.oneArg((long) 0));
+        assertEquals("long 1", mock.oneArg((long) 1));
+
+        assertEquals("float 0", mock.oneArg((float) 0.0));
+        assertEquals("float 1", mock.oneArg((float) 1.0));
+
+        assertEquals("double 0", mock.oneArg(0.0));
+        assertEquals("double 1", mock.oneArg(1.0));
+
+        assertEquals("String 0", mock.oneArg("Object 0"));
+        assertEquals("String 1", mock.oneArg("Object 1"));
+
+        control.verify();
+    }
+
+    @Test
+    public void defaultThrowable() {
+
+        mock.oneArg("Object");
+        RuntimeException expected = new RuntimeException();
+        control.setDefaultThrowable(expected);
+
+        control.replay();
+
+        try {
+            mock.oneArg("Something else");
+            fail("runtime exception expected");
+        } catch (RuntimeException expectedException) {
+            assertSame(expected, expectedException);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/UsageOverloadedMethodTest.java b/tests/org/easymock/tests/UsageOverloadedMethodTest.java
new file mode 100644
index 0000000..9692a50
--- /dev/null
+++ b/tests/org/easymock/tests/UsageOverloadedMethodTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageOverloadedMethodTest {
+
+    MockControl<IMethods> controller;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        controller = MockControl.createControl(IMethods.class);
+        mock = controller.getMock();
+    }
+
+    @Test
+    public void overloading() {
+
+        mock.oneArg(true);
+        controller.setReturnValue("true");
+        mock.oneArg(false);
+        controller.setReturnValue("false");
+
+        mock.oneArg((byte) 0);
+        controller.setReturnValue("byte 0");
+        mock.oneArg((byte) 1);
+        controller.setReturnValue("byte 1");
+
+        mock.oneArg((short) 0);
+        controller.setReturnValue("short 0");
+        mock.oneArg((short) 1);
+        controller.setReturnValue("short 1");
+
+        mock.oneArg((char) 0);
+        controller.setReturnValue("char 0");
+        mock.oneArg((char) 1);
+        controller.setReturnValue("char 1");
+
+        mock.oneArg(0);
+        controller.setReturnValue("int 0");
+        mock.oneArg(1);
+        controller.setReturnValue("int 1");
+
+        mock.oneArg((long) 0);
+        controller.setReturnValue("long 0");
+        mock.oneArg((long) 1);
+        controller.setReturnValue("long 1");
+
+        mock.oneArg((float) 0);
+        controller.setReturnValue("float 0");
+        mock.oneArg((float) 1);
+        controller.setReturnValue("float 1");
+
+        mock.oneArg(0.0);
+        controller.setReturnValue("double 0");
+        mock.oneArg(1.0);
+        controller.setReturnValue("double 1");
+
+        mock.oneArg("Object 0");
+        controller.setReturnValue("1");
+        mock.oneArg("Object 1");
+        controller.setReturnValue("2");
+
+        controller.replay();
+
+        assertEquals("true", mock.oneArg(true));
+        assertEquals("false", mock.oneArg(false));
+
+        assertEquals("byte 0", mock.oneArg((byte) 0));
+        assertEquals("byte 1", mock.oneArg((byte) 1));
+
+        assertEquals("short 0", mock.oneArg((short) 0));
+        assertEquals("short 1", mock.oneArg((short) 1));
+
+        assertEquals("char 0", mock.oneArg((char) 0));
+        assertEquals("char 1", mock.oneArg((char) 1));
+
+        assertEquals("int 0", mock.oneArg(0));
+        assertEquals("int 1", mock.oneArg(1));
+
+        assertEquals("long 0", mock.oneArg((long) 0));
+        assertEquals("long 1", mock.oneArg((long) 1));
+
+        assertEquals("float 0", mock.oneArg((float) 0.0));
+        assertEquals("float 1", mock.oneArg((float) 1.0));
+
+        assertEquals("double 1", mock.oneArg(1.0));
+        assertEquals("double 0", mock.oneArg(0.0));
+
+        assertEquals("1", mock.oneArg("Object 0"));
+        assertEquals("2", mock.oneArg("Object 1"));
+
+        controller.verify();
+    }
+
+    @Test
+    public void nullReturnValue() {
+
+        mock.oneArg("Object");
+        controller.setReturnValue(null);
+
+        controller.replay();
+
+        assertNull(mock.oneArg("Object"));
+
+    }
+
+    @Test
+    public void moreThanOneResultAndOpenCallCount() {
+        mock.oneArg(true);
+        controller.setReturnValue("First Result", 4);
+        controller.setReturnValue("Second Result", 2);
+        controller.setThrowable(new RuntimeException("Third Result"), 3);
+        controller.setReturnValue("Following Result", MockControl.ONE_OR_MORE);
+
+        controller.replay();
+
+        assertEquals("First Result", mock.oneArg(true));
+        assertEquals("First Result", mock.oneArg(true));
+        assertEquals("First Result", mock.oneArg(true));
+        assertEquals("First Result", mock.oneArg(true));
+
+        assertEquals("Second Result", mock.oneArg(true));
+        assertEquals("Second Result", mock.oneArg(true));
+
+        try {
+            mock.oneArg(true);
+            fail("expected exception");
+        } catch (RuntimeException expected) {
+            assertEquals("Third Result", expected.getMessage());
+        }
+
+        try {
+            mock.oneArg(true);
+            fail("expected exception");
+        } catch (RuntimeException expected) {
+            assertEquals("Third Result", expected.getMessage());
+        }
+
+        try {
+            mock.oneArg(true);
+            fail("expected exception");
+        } catch (RuntimeException expected) {
+            assertEquals("Third Result", expected.getMessage());
+        }
+
+        assertEquals("Following Result", mock.oneArg(true));
+        assertEquals("Following Result", mock.oneArg(true));
+        assertEquals("Following Result", mock.oneArg(true));
+        assertEquals("Following Result", mock.oneArg(true));
+        assertEquals("Following Result", mock.oneArg(true));
+
+        controller.verify();
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/UsageRangeTest.java b/tests/org/easymock/tests/UsageRangeTest.java
new file mode 100644
index 0000000..f9c7029
--- /dev/null
+++ b/tests/org/easymock/tests/UsageRangeTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.util.Iterator;
+
+import org.easymock.MockControl;
+import org.easymock.internal.Range;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageRangeTest {
+
+    private Iterator<String> mock;
+
+    private MockControl<Iterator<String>> control;
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setup() {
+        control = MockControl.createStrictControl((Class)Iterator.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void zeroOrMoreNoCalls() {
+        mock.hasNext();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        control.replay();
+        control.verify();
+    }
+
+    @Test
+    public void zeroOrMoreOneCall() {
+        mock.hasNext();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        control.replay();
+        assertFalse(mock.hasNext());
+        control.verify();
+    }
+
+    @Test
+    public void zeroOrMoreThreeCalls() {
+        mock.hasNext();
+        control.setReturnValue(false, MockControl.ZERO_OR_MORE);
+        control.replay();
+        assertFalse(mock.hasNext());
+        assertFalse(mock.hasNext());
+        assertFalse(mock.hasNext());
+        control.verify();
+    }
+
+    @Test
+    public void combination() {
+        mock.hasNext();
+        control.setReturnValue(true, MockControl.ONE_OR_MORE);
+        mock.next();
+        control.setReturnValue("1");
+
+        mock.hasNext();
+        control.setReturnValue(true, MockControl.ONE_OR_MORE);
+        mock.next();
+        control.setReturnValue("2");
+
+        mock.hasNext();
+        control.setReturnValue(false, MockControl.ONE_OR_MORE);
+
+        control.replay();
+
+        assertTrue(mock.hasNext());
+        assertTrue(mock.hasNext());
+        assertTrue(mock.hasNext());
+
+        assertEquals("1", mock.next());
+
+        try {
+            mock.next();
+            fail();
+        } catch (AssertionError expected) {
+        }
+
+        assertTrue(mock.hasNext());
+
+        assertEquals("2", mock.next());
+
+        assertFalse(mock.hasNext());
+
+        control.verify();
+
+    }
+
+    @Test
+    public void withIllegalOwnRange() {
+        mock.hasNext();
+        try {
+            control.setReturnValue(true, new Range(2, 7));
+        } catch (IllegalArgumentException e) {
+            assertEquals("Unexpected Range", e.getMessage());
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/UsageStrictMockTest.java b/tests/org/easymock/tests/UsageStrictMockTest.java
new file mode 100644
index 0000000..1e133e8
--- /dev/null
+++ b/tests/org/easymock/tests/UsageStrictMockTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.easymock.internal.ReplayState;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageStrictMockTest {
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createStrictControl(IMethods.class);
+        mock = control.getMock();
+
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+
+        control.replay();
+    }
+
+    @Test
+    public void verify() {
+        control.reset();
+        control.replay();
+        control.verify();
+    }
+
+    @Test
+    public void orderedCallsSucces() {
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+
+        control.verify();
+    }
+
+    @Test
+    public void unorderedCallsFailure() {
+        boolean failed = false;
+        try {
+            mock.simpleMethodWithArgument("2");
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed) {
+            fail("unordered calls accepted");
+        }
+    }
+
+    @Test
+    public void tooManyCallsFailure() {
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+
+        boolean failed = false;
+        try {
+            mock.simpleMethodWithArgument("2");
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed) {
+            fail("too many calls accepted");
+        }
+    }
+
+    @Test
+    public void tooFewCallsFailure() {
+        mock.simpleMethodWithArgument("1");
+        boolean failed = false;
+        try {
+            control.verify();
+        } catch (AssertionError expected) {
+            failed = true;
+            assertTrue("stack trace must be filled in", Util.getStackTrace(
+                    expected).indexOf(ReplayState.class.getName()) == -1);
+        }
+        if (!failed) {
+            fail("too few calls accepted");
+        }
+    }
+
+    @Test
+    public void differentMethods() {
+
+        control.reset();
+
+        mock.booleanReturningMethod(0);
+        control.setReturnValue(true);
+        mock.simpleMethod();
+        mock.booleanReturningMethod(1);
+        control.setReturnValue(false, 2, 3);
+        mock.simpleMethod();
+        control.setVoidCallable(MockControl.ONE_OR_MORE);
+
+        control.replay();
+        assertEquals(true, mock.booleanReturningMethod(0));
+        mock.simpleMethod();
+
+        boolean failed = false;
+        try {
+            control.verify();
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    simpleMethod(): expected: 1, actual: 1"
+                            + "\n    booleanReturningMethod(1): expected: between 2 and 3, actual: 0"
+                            + "\n    simpleMethod(): expected: at least 1, actual: 0",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("too few calls accepted");
+        }
+
+        assertEquals(false, mock.booleanReturningMethod(1));
+
+        failed = false;
+        try {
+            mock.simpleMethod();
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Unexpected method call simpleMethod():"
+                            + "\n    booleanReturningMethod(1): expected: between 2 and 3, actual: 1",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("wrong call accepted");
+        }
+    }
+
+    @Test
+    public void range() {
+
+        control.reset();
+
+        mock.booleanReturningMethod(0);
+        control.setReturnValue(true);
+        mock.simpleMethod();
+        mock.booleanReturningMethod(1);
+        control.setReturnValue(false, 2, 3);
+        mock.simpleMethod();
+        control.setVoidCallable(MockControl.ONE_OR_MORE);
+        mock.booleanReturningMethod(1);
+        control.setReturnValue(false);
+
+        control.replay();
+
+        mock.booleanReturningMethod(0);
+        mock.simpleMethod();
+
+        mock.booleanReturningMethod(1);
+        mock.booleanReturningMethod(1);
+        mock.booleanReturningMethod(1);
+
+        boolean failed = false;
+
+        try {
+            mock.booleanReturningMethod(1);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Unexpected method call booleanReturningMethod(1):"
+                            + "\n    booleanReturningMethod(1): expected: between 2 and 3, actual: 3 (+1)"
+                            + "\n    simpleMethod(): expected: at least 1, actual: 0",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("too many calls accepted");
+        }
+    }
+
+    @Test
+    public void defaultBehavior() {
+        control.reset();
+
+        mock.booleanReturningMethod(1);
+        control.setReturnValue(true);
+        control.setReturnValue(false);
+        control.setReturnValue(true);
+        control.setDefaultReturnValue(true);
+
+        control.replay();
+
+        assertEquals(true, mock.booleanReturningMethod(2));
+        assertEquals(true, mock.booleanReturningMethod(3));
+        assertEquals(true, mock.booleanReturningMethod(1));
+        assertEquals(false, mock.booleanReturningMethod(1));
+        assertEquals(true, mock.booleanReturningMethod(3));
+
+        boolean failed = false;
+        try {
+            control.verify();
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    booleanReturningMethod(1): expected: 3, actual: 2",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("too few calls accepted");
+        }
+    }
+
+    @Test
+    public void unexpectedCallWithArray() {
+        control.reset();
+        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+        mock.arrayMethod(new String[] { "Test", "Test 2" });
+        control.replay();
+        boolean failed = false;
+        String[] strings = new String[] { "Test" };
+        try {
+            mock.arrayMethod(strings);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Unexpected method call arrayMethod("
+                            + strings.toString()
+                            + "):"
+                            + "\n    arrayMethod([\"Test\", \"Test 2\"]): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("exception expected");
+        }
+
+    }
+}
diff --git a/tests/org/easymock/tests/UsageTest.java b/tests/org/easymock/tests/UsageTest.java
new file mode 100644
index 0000000..6f49c2d
--- /dev/null
+++ b/tests/org/easymock/tests/UsageTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageTest {
+
+    MockControl<IMethods> control;
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void exactCallCountByLastCall() {
+        mock.oneArg(false);
+        control.setReturnValue("Test");
+        control.setReturnValue("Test2");
+
+        control.replay();
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+
+        boolean failed = false;
+        try {
+            mock.oneArg(false);
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed)
+            fail("expected AssertionError");
+    }
+
+    @Test
+    public void openCallCountByLastCall() {
+        mock.oneArg(false);
+        control.setReturnValue("Test");
+        control.setReturnValue("Test2", MockControl.ONE_OR_MORE);
+
+        control.replay();
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+    }
+
+    @Test
+    public void exactCallCountByLastThrowable() {
+        mock.oneArg(false);
+        control.setReturnValue("Test");
+        control.setReturnValue("Test2");
+        control.setThrowable(new IndexOutOfBoundsException(), 1);
+
+        control.replay();
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+
+        try {
+            mock.oneArg(false);
+        } catch (IndexOutOfBoundsException expected) {
+        }
+
+        boolean failed = true;
+        try {
+            try {
+                mock.oneArg(false);
+            } catch (IndexOutOfBoundsException expected) {
+            }
+            failed = false;
+        } catch (AssertionError expected) {
+        }
+        if (!failed)
+            fail("expected AssertionError");
+    }
+
+    @Test
+    public void openCallCountByLastThrowable() {
+        mock.oneArg(false);
+        control.setReturnValue("Test");
+        control.setReturnValue("Test2");
+        control.setThrowable(new IndexOutOfBoundsException(),
+                MockControl.ONE_OR_MORE);
+
+        control.replay();
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+
+        try {
+            mock.oneArg(false);
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            mock.oneArg(false);
+        } catch (IndexOutOfBoundsException expected) {
+        }
+    }
+
+    @Test
+    public void moreThanOneArgument() {
+        mock.threeArgumentMethod(1, "2", "3");
+        control.setReturnValue("Test", 2);
+
+        control.replay();
+
+        assertEquals("Test", mock.threeArgumentMethod(1, "2", "3"));
+
+        boolean failed = true;
+        try {
+            control.verify();
+            failed = false;
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    threeArgumentMethod(1, \"2\", \"3\"): expected: 2, actual: 1",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("exception expected");
+        }
+    }
+
+    @Test
+    public void unexpectedCallWithArray() {
+        control.reset();
+        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
+        control.replay();
+        boolean failed = false;
+        String[] strings = new String[] { "Test" };
+        try {
+            mock.arrayMethod(strings);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals("\n  Unexpected method call arrayMethod("
+                    + strings.toString() + "):", expected.getMessage());
+        }
+        if (!failed) {
+            fail("exception expected");
+        }
+
+    }
+
+    @Test
+    public void wrongArguments() {
+        mock.simpleMethodWithArgument("3");
+        control.replay();
+
+        try {
+            mock.simpleMethodWithArgument("5");
+            fail();
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Unexpected method call simpleMethodWithArgument(\"5\"):"
+                            + "\n    simpleMethodWithArgument(\"3\"): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+
+    }
+
+    @Test
+    public void summarizeSameObjectArguments() {
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("3");
+        control.replay();
+
+        try {
+            mock.simpleMethodWithArgument("5");
+            fail();
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Unexpected method call simpleMethodWithArgument(\"5\"):"
+                            + "\n    simpleMethodWithArgument(\"3\"): expected: 2, actual: 0",
+                    expected.getMessage());
+        }
+
+    }
+
+    @Test
+    public void argumentsOrdered() {
+        mock.simpleMethodWithArgument("4");
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("2");
+        mock.simpleMethodWithArgument("0");
+        mock.simpleMethodWithArgument("1");
+        control.replay();
+
+        try {
+            mock.simpleMethodWithArgument("5");
+            fail();
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Unexpected method call simpleMethodWithArgument(\"5\"):"
+                            + "\n    simpleMethodWithArgument(\"4\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"3\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"2\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"0\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"1\"): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/UsageThrowableTest.java b/tests/org/easymock/tests/UsageThrowableTest.java
new file mode 100644
index 0000000..a6fc3be
--- /dev/null
+++ b/tests/org/easymock/tests/UsageThrowableTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageThrowableTest {
+
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void noUpperLimit() {
+        mock.simpleMethodWithArgument("1");
+        control.setVoidCallable(MockControl.ONE_OR_MORE);
+        mock.simpleMethodWithArgument("2");
+        control.replay();
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("1");
+        control.verify();
+    }
+
+    @Test
+    public void throwRuntimeException() {
+        testThrowUncheckedException(new RuntimeException());
+    }
+
+    @Test
+    public void throwSubclassOfRuntimeException() {
+        testThrowUncheckedException(new RuntimeException() {
+            private static final long serialVersionUID = 1L;
+        });
+    }
+
+    @Test
+    public void throwError() {
+        testThrowUncheckedException(new Error());
+    }
+
+    @Test
+    public void throwSubclassOfError() {
+        testThrowUncheckedException(new Error() {
+            private static final long serialVersionUID = 1L;
+        });
+    }
+
+    private void testThrowUncheckedException(Throwable throwable) {
+        mock.throwsNothing(true);
+        control.setReturnValue("true");
+        mock.throwsNothing(false);
+        control.setThrowable(throwable);
+
+        control.replay();
+
+        try {
+            mock.throwsNothing(false);
+            fail("Trowable expected");
+        } catch (Throwable expected) {
+            assertSame(throwable, expected);
+        }
+
+        assertEquals("true", mock.throwsNothing(true));
+    }
+
+    @Test
+    public void throwCheckedException() throws IOException {
+        testThrowCheckedException(new IOException());
+    }
+
+    @Test
+    public void throwSubclassOfCheckedException() throws IOException {
+        testThrowCheckedException(new IOException() {
+            private static final long serialVersionUID = 1L;
+        });
+    }
+
+    private void testThrowCheckedException(IOException expected)
+            throws IOException {
+        try {
+            mock.throwsIOException(0);
+            control.setReturnValue("Value 0");
+            mock.throwsIOException(1);
+            control.setThrowable(expected);
+            mock.throwsIOException(2);
+            control.setReturnValue("Value 2");
+        } catch (IOException e) {
+            fail("Unexpected Exception");
+        }
+
+        control.replay();
+
+        assertEquals("Value 0", mock.throwsIOException(0));
+        assertEquals("Value 2", mock.throwsIOException(2));
+
+        try {
+            mock.throwsIOException(1);
+            fail("IOException expected");
+        } catch (IOException expectedException) {
+            assertSame(expectedException, expected);
+        }
+    }
+
+    @Test
+    public void throwAfterReturnValue() {
+        mock.throwsNothing(false);
+        control.setReturnValue("");
+        RuntimeException expectedException = new RuntimeException();
+        control.setThrowable(expectedException);
+
+        control.replay();
+
+        assertEquals("", mock.throwsNothing(false));
+
+        try {
+            mock.throwsNothing(false);
+            fail("RuntimeException expected");
+        } catch (RuntimeException actualException) {
+            assertSame(expectedException, actualException);
+        }
+
+        control.verify();
+    }
+
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/UsageUnorderedTest.java b/tests/org/easymock/tests/UsageUnorderedTest.java
new file mode 100644
index 0000000..c93bd2a
--- /dev/null
+++ b/tests/org/easymock/tests/UsageUnorderedTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import org.easymock.MockControl;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageUnorderedTest {
+
+    public interface Interface {
+        void method(int number);
+    }
+
+    @Test
+    public void message() {
+        MockControl<Interface> control = MockControl
+                .createControl(Interface.class);
+        Interface mock = control.getMock();
+
+        mock.method(0);
+        control.setMatcher(MockControl.ALWAYS_MATCHER);
+        control.setVoidCallable(1);
+        mock.method(0);
+        control.setVoidCallable(2);
+        mock.method(1);
+
+        control.replay();
+
+        mock.method(6);
+        mock.method(7);
+        mock.method(1);
+        mock.method(25);
+
+        try {
+            mock.method(42);
+            fail();
+        } catch (AssertionError expected) {
+            assertEquals("\n  Unexpected method call method(42):"
+                    + "\n    method(<any>): expected: 3, actual: 3 (+1)"
+                    + "\n    method(<any>): expected: 1, actual: 1 (+1)",
+                    expected.getMessage());
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/UsageVarargTest.java b/tests/org/easymock/tests/UsageVarargTest.java
new file mode 100644
index 0000000..df84c68
--- /dev/null
+++ b/tests/org/easymock/tests/UsageVarargTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.easymock.MockControl;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageVarargTest {
+
+    MockControl<IVarArgs> control;
+
+    IVarArgs mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createStrictControl(IVarArgs.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void varargObjectAccepted() {
+        mock.withVarargsString(1, "1");
+        mock.withVarargsString(2, "1", "2");
+        mock.withVarargsString(2, "1", "2");
+        mock.withVarargsObject(3, "1");
+        mock.withVarargsObject(4, "1", "2");
+
+        control.replay();
+        mock.withVarargsString(1, "1");
+        mock.withVarargsString(2, "1", "2");
+        mock.withVarargsString(2, "1", "2");
+        mock.withVarargsObject(3, "1");
+        mock.withVarargsObject(4, "1", "2");
+        control.verify();
+    }
+
+    @Test
+    public void varargBooleanAccepted() {
+        mock.withVarargsBoolean(1, true);
+        mock.withVarargsBoolean(2, true, false);
+
+        control.replay();
+        mock.withVarargsBoolean(1, true);
+        mock.withVarargsBoolean(2, true, false);
+        control.verify();
+    }
+
+    @Test
+    public void varargByteAccepted() {
+        mock.withVarargsByte(1, (byte) 1);
+        mock.withVarargsByte(2, (byte) 1, (byte) 2);
+
+        control.replay();
+        mock.withVarargsByte(1, (byte) 1);
+        mock.withVarargsByte(2, (byte) 1, (byte) 2);
+        control.verify();
+    }
+
+    @Test
+    public void varargCharAccepted() {
+        mock.withVarargsChar(1, 'a');
+        mock.withVarargsChar(1, 'a', 'b');
+
+        control.replay();
+        mock.withVarargsChar(1, 'a');
+        mock.withVarargsChar(1, 'a', 'b');
+        control.verify();
+    }
+
+    @Test
+    public void varargDoubleAccepted() {
+        mock.withVarargsDouble(1, 1.0d);
+        mock.withVarargsDouble(1, 1.0d, 2.0d);
+
+        control.replay();
+        mock.withVarargsDouble(1, 1.0d);
+        mock.withVarargsDouble(1, 1.0d, 2.0d);
+        control.verify();
+    }
+
+    @Test
+    public void varargFloatAccepted() {
+        mock.withVarargsFloat(1, 1.0f);
+        mock.withVarargsFloat(1, 1.0f, 2.0f);
+
+        control.replay();
+        mock.withVarargsFloat(1, 1.0f);
+        mock.withVarargsFloat(1, 1.0f, 2.0f);
+        control.verify();
+    }
+
+    @Test
+    public void varargIntAccepted() {
+        mock.withVarargsInt(1, 1);
+        mock.withVarargsInt(1, 1, 2);
+
+        control.replay();
+        mock.withVarargsInt(1, 1);
+        mock.withVarargsInt(1, 1, 2);
+        control.verify();
+    }
+
+    @Test
+    public void varargLongAccepted() {
+        mock.withVarargsLong(1, (long) 1);
+        mock.withVarargsLong(1, 1, 2);
+
+        control.replay();
+        mock.withVarargsLong(1, (long) 1);
+        mock.withVarargsLong(1, 1, 2);
+        control.verify();
+    }
+
+    @Test
+    public void varargShortAccepted() {
+        mock.withVarargsShort(1, (short) 1);
+        mock.withVarargsShort(1, (short) 1, (short) 2);
+
+        control.replay();
+        mock.withVarargsShort(1, (short) 1);
+        mock.withVarargsShort(1, (short) 1, (short) 2);
+        control.verify();
+    }
+    
+    @Test
+    public void varargAcceptedIfArrayIsGiven() {
+        IVarArgs object = (IVarArgs) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { IVarArgs.class }, new InvocationHandler() {
+        
+            public Object invoke(Object proxy, Method method, Object[] args)
+                    throws Throwable {
+                return null;
+            }
+        });
+        object.withVarargsObject(1);
+        object.withVarargsObject(1, (Object) null);
+        object.withVarargsObject(1, (Object[]) null);
+        object.withVarargsObject(1, (Object[]) new Object[0] );
+        object.withVarargsObject(1, false);
+        object.withVarargsObject(1, new boolean[] {true, false});
+    }
+}
\ No newline at end of file
diff --git a/tests/org/easymock/tests/UsageVerifyTest.java b/tests/org/easymock/tests/UsageVerifyTest.java
new file mode 100644
index 0000000..4072a63
--- /dev/null
+++ b/tests/org/easymock/tests/UsageVerifyTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.easymock.MockControl;
+import org.easymock.internal.ReplayState;
+import org.junit.Before;
+import org.junit.Test;
+
+ at SuppressWarnings("deprecation")
+public class UsageVerifyTest {
+    private MockControl<IMethods> control;
+
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        control = MockControl.createControl(IMethods.class);
+        mock = control.getMock();
+    }
+
+    @Test
+    public void twoReturns() {
+        mock.throwsNothing(true);
+        control.setReturnValue("Test");
+        control.setReturnValue("Test2");
+
+        control.replay();
+
+        assertEquals("Test", mock.throwsNothing(true));
+
+        boolean failed = true;
+
+        try {
+            control.verify();
+            failed = false;
+        } catch (AssertionError expected) {
+            assertEquals("\n  Expectation failure on verify:"
+                    + "\n    throwsNothing(true): expected: 2, actual: 1",
+                    expected.getMessage());
+            assertTrue("stack trace must be filled in", Util.getStackTrace(
+                    expected).indexOf(ReplayState.class.getName()) == -1);
+        }
+
+        if (!failed)
+            fail("AssertionError expected");
+
+        assertEquals("Test2", mock.throwsNothing(true));
+
+        control.verify();
+
+        try {
+            mock.throwsNothing(true);
+            fail("AssertionError expected");
+        } catch (AssertionError expected) {
+            assertEquals("\n  Unexpected method call throwsNothing(true):"
+                    + "\n    throwsNothing(true): expected: 2, actual: 2 (+1)",
+                    expected.getMessage());
+        }
+    }
+
+    @Test
+    public void atLeastTwoReturns() {
+        mock.throwsNothing(true);
+        control.setReturnValue("Test");
+        control.setReturnValue("Test2", MockControl.ONE_OR_MORE);
+
+        control.replay();
+
+        assertEquals("Test", mock.throwsNothing(true));
+
+        try {
+            control.verify();
+            fail("AssertionError expected");
+        } catch (AssertionError expected) {
+
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    throwsNothing(true): expected: at least 2, actual: 1",
+                    expected.getMessage());
+        }
+
+        assertEquals("Test2", mock.throwsNothing(true));
+        assertEquals("Test2", mock.throwsNothing(true));
+
+        control.verify();
+    }
+
+    @Test
+    public void twoThrows() throws IOException {
+        mock.throwsIOException(0);
+        control.setThrowable(new IOException());
+        control.setThrowable(new IOException());
+        mock.throwsIOException(1);
+        control.setThrowable(new IOException());
+
+        control.replay();
+
+        try {
+            mock.throwsIOException(0);
+            fail("IOException expected");
+        } catch (IOException expected) {
+        }
+
+        try {
+            control.verify();
+            fail("AssertionError expected");
+        } catch (AssertionError expected) {
+            assertEquals("\n  Expectation failure on verify:"
+                    + "\n    throwsIOException(0): expected: 2, actual: 1"
+                    + "\n    throwsIOException(1): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+
+        try {
+            mock.throwsIOException(0);
+            fail("IOException expected");
+        } catch (IOException expected) {
+        }
+
+        try {
+            control.verify();
+            fail("AssertionError expected");
+        } catch (AssertionError expected) {
+            assertEquals("\n  Expectation failure on verify:"
+                    + "\n    throwsIOException(1): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+
+        try {
+            mock.throwsIOException(1);
+            fail("IOException expected");
+        } catch (IOException expected) {
+        }
+
+        control.verify();
+
+        try {
+            mock.throwsIOException(0);
+            fail("AssertionError expected");
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Unexpected method call throwsIOException(0):"
+                            + "\n    throwsIOException(0): expected: 2, actual: 2 (+1)",
+                    expected.getMessage());
+        }
+    }
+}
diff --git a/tests/org/easymock/tests/Util.java b/tests/org/easymock/tests/Util.java
new file mode 100644
index 0000000..b3fd0e7
--- /dev/null
+++ b/tests/org/easymock/tests/Util.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+public class Util {
+    public static String getStackTrace(Throwable throwable) {
+        StringWriter stackTrace = new StringWriter();
+        throwable.printStackTrace(new PrintWriter(stackTrace));
+        return stackTrace.getBuffer().toString();
+    }
+}
diff --git a/tests/org/easymock/tests2/AnswerTest.java b/tests/org/easymock/tests2/AnswerTest.java
new file mode 100644
index 0000000..c39a76f
--- /dev/null
+++ b/tests/org/easymock/tests2/AnswerTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.IAnswer;
+import org.easymock.tests.IMethods;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AnswerTest {
+
+    private IMethods mock;
+
+    @Before
+    public void setUp() {
+        mock = createMock(IMethods.class);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void answer() {
+        IAnswer firstAnswer = new IAnswer() {
+            public Object answer() {
+                assertArrayEquals(new Object[] { 1, "2", "3" },
+                        getCurrentArguments());
+                return "Call answered";
+            }
+        };
+
+        IAnswer secondAnswer = new IAnswer() {
+            public Object answer() {
+                assertArrayEquals(new Object[] { 1, "2", "3" },
+                        getCurrentArguments());
+                throw new IllegalStateException("Call answered");
+            }
+        };
+
+        expect(mock.threeArgumentMethod(1, "2", "3")).andAnswer(firstAnswer)
+                .andReturn("Second call").andAnswer(secondAnswer).andReturn(
+                        "Fourth call");
+
+        replay(mock);
+
+        assertEquals("Call answered", mock.threeArgumentMethod(1, "2", "3"));
+        assertEquals("Second call", mock.threeArgumentMethod(1, "2", "3"));
+        try {
+            mock.threeArgumentMethod(1, "2", "3");
+            fail();
+        } catch (IllegalStateException expected) {
+            assertEquals("Call answered", expected.getMessage());
+        }
+        assertEquals("Fourth call", mock.threeArgumentMethod(1, "2", "3"));
+
+        verify(mock);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void stubAnswer() {
+        IAnswer firstAnswer = new IAnswer() {
+            public Object answer() {
+                assertArrayEquals(new Object[] { 1, "2", "3" },
+                        getCurrentArguments());
+                return "Call answered";
+            }
+        };
+
+        IAnswer secondAnswer = new IAnswer() {
+            public Object answer() {
+                assertArrayEquals(new Object[] { 1, "2", "4" },
+                        getCurrentArguments());
+                return "Call answered";
+            }
+        };
+
+        expect(mock.threeArgumentMethod(1, "2", "3")).andReturn(42)
+                .andStubAnswer(firstAnswer);
+        expect(mock.threeArgumentMethod(1, "2", "4")).andStubAnswer(
+                secondAnswer);
+
+        replay(mock);
+
+        assertEquals(42, mock.threeArgumentMethod(1, "2", "3"));
+        assertEquals("Call answered", mock.threeArgumentMethod(1, "2", "3"));
+        assertEquals("Call answered", mock.threeArgumentMethod(1, "2", "4"));
+        assertEquals("Call answered", mock.threeArgumentMethod(1, "2", "3"));
+        assertEquals("Call answered", mock.threeArgumentMethod(1, "2", "3"));
+
+        verify(mock);
+    }
+
+    @Test
+    public void nullAnswerNotAllowed() {
+        try {
+            expect(mock.threeArgumentMethod(1, "2", "3")).andAnswer(null);
+            fail();
+        } catch (NullPointerException expected) {
+            assertEquals("answer object must not be null", expected
+                    .getMessage());
+        }
+    }
+
+    @Test
+    public void nullStubAnswerNotAllowed() {
+        try {
+            expect(mock.threeArgumentMethod(1, "2", "3")).andStubAnswer(null);
+            fail();
+        } catch (NullPointerException expected) {
+            assertEquals("answer object must not be null", expected
+                    .getMessage());
+        }
+    }
+
+    public static class A {}
+    public static class B extends A{}
+    
+    public static interface C {
+        A foo();
+    }
+    
+    @Test
+    public void testGenericityFlexibility() {
+        
+        final C c = createMock(C.class);
+        final B b = new B();
+        
+        IAnswer<B> answer = new IAnswer<B>() {
+
+            public B answer() throws Throwable {
+                return b;
+            }
+            
+        };
+
+        expect(c.foo()).andAnswer(answer);
+        expect(c.foo()).andStubAnswer(answer);
+        
+        replay(c);
+        assertSame(b, c.foo());
+        assertSame(b, c.foo());
+        verify(c);
+    }
+}
diff --git a/tests/org/easymock/tests2/CallbackAndArgumentsTest.java b/tests/org/easymock/tests2/CallbackAndArgumentsTest.java
new file mode 100644
index 0000000..f6b5e18
--- /dev/null
+++ b/tests/org/easymock/tests2/CallbackAndArgumentsTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.IAnswer;
+import org.easymock.tests.IMethods;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CallbackAndArgumentsTest {
+
+    private IMethods mock;
+
+    @Before
+    public void setUp() {
+        mock = createStrictMock(IMethods.class);
+    }
+
+    @Test
+    public void callbackGetsArguments() {
+
+        final StringBuffer buffer = new StringBuffer();
+
+        mock.simpleMethodWithArgument((String) notNull());
+        expectLastCall().andAnswer(new IAnswer<Object>() {
+            public Object answer() {
+                buffer.append((String) getCurrentArguments()[0]);
+                return null;
+            }
+        }).times(2);
+
+        replay(mock);
+
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+
+        verify(mock);
+
+        assertEquals("12", buffer.toString());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void currentArgumentsFailsOutsideCallbacks() {
+        getCurrentArguments();
+    }
+
+    @Test
+    public void callbackGetsArgumentsEvenIfAMockCallsAnother() {
+
+        final StringBuffer buffer = new StringBuffer();
+
+        final IMethods mock2 = createStrictMock(IMethods.class);
+        mock2.simpleMethod();
+        expectLastCall().andAnswer(new IAnswer<Object>() {
+            public Object answer() {
+                // empty, only needed to force deletion of arguments
+                return null;
+            }
+        }).times(2);
+
+        mock.simpleMethodWithArgument((String) notNull());
+        expectLastCall().andAnswer(new IAnswer<Object>() {
+            public Object answer() {
+                mock2.simpleMethod();
+                buffer.append((String) getCurrentArguments()[0]);
+                return null;
+            }
+        }).times(2);
+
+        replay(mock);
+        replay(mock2);
+
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+
+        verify(mock);
+        verify(mock2);
+
+        assertEquals("12", buffer.toString());
+    }
+}
diff --git a/tests/org/easymock/tests2/CallbackTest.java b/tests/org/easymock/tests2/CallbackTest.java
new file mode 100644
index 0000000..62c517b
--- /dev/null
+++ b/tests/org/easymock/tests2/CallbackTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.IAnswer;
+import org.easymock.tests.IMethods;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CallbackTest {
+
+    private IMethods mock;
+
+    private static class Callback<T> implements IAnswer<T> {
+        private int callCount;
+
+        private T result;
+
+        public Callback(T result) {
+            this.result = result;
+        }
+
+        public void run() {
+        }
+
+        public int getCallCount() {
+            return callCount;
+        }
+
+        public T answer() throws Throwable {
+            callCount++;
+            return result;
+        }
+    }
+
+    @Before
+    public void setUp() {
+        mock = createStrictMock(IMethods.class);
+    }
+
+    @Test
+    public void callback() {
+        Callback<String> c1 = new Callback<String>("1");
+        Callback<Object> c2 = new Callback<Object>(null);
+        Callback<Object> c3 = new Callback<Object>(null);
+
+        expect(mock.oneArg("2")).andAnswer(c1).times(2);
+        mock.simpleMethodWithArgument("One");
+        expectLastCall().andAnswer(c2);
+        mock.simpleMethodWithArgument("Two");
+        expectLastCall().andAnswer(c3).times(2);
+
+        replay(mock);
+
+        mock.oneArg("2");
+        mock.oneArg("2");
+        try {
+            mock.oneArg("2");
+        } catch (AssertionError ignored) {
+        }
+        try {
+            mock.simpleMethodWithArgument("Two");
+        } catch (AssertionError ignored) {
+        }
+        mock.simpleMethodWithArgument("One");
+        try {
+            mock.simpleMethodWithArgument("One");
+        } catch (AssertionError ignored) {
+        }
+        mock.simpleMethodWithArgument("Two");
+        mock.simpleMethodWithArgument("Two");
+        try {
+            mock.simpleMethodWithArgument("Two");
+        } catch (AssertionError ignored) {
+        }
+        verify(mock);
+
+        assertEquals(2, c1.getCallCount());
+        assertEquals(1, c2.getCallCount());
+        assertEquals(2, c3.getCallCount());
+    }
+}
diff --git a/tests/org/easymock/tests2/CaptureTest.java b/tests/org/easymock/tests2/CaptureTest.java
new file mode 100644
index 0000000..04bab19
--- /dev/null
+++ b/tests/org/easymock/tests2/CaptureTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2003-2008 OFFIS, Henri Tremblay. 
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.Capture;
+import org.easymock.tests.IMethods;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CaptureTest {
+
+    public static class A {
+        public String foo(IMethods methods) {
+            return methods.oneArg(2);
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+    }
+
+    @After
+    public void tearDown() throws Exception {
+    }
+
+    // capture in thread
+    // after replay issue?
+
+    @Test
+    public void testCaptureRightOne() {
+        Capture<String> captured = new Capture<String>();
+        IMethods mock = createMock(IMethods.class);
+
+        expect(mock.oneArg(and(eq("test"), capture(captured)))).andReturn(
+                "answer1");
+        expect(mock.oneArg("a")).andReturn("answer2");
+
+        replay(mock);
+
+        assertEquals("answer2", mock.oneArg("a"));
+        assertFalse(captured.hasCaptured());
+
+        assertEquals("answer1", mock.oneArg("test"));
+        assertEquals("test", captured.getValue());
+
+        verify(mock);
+    }
+
+    @Test
+    public void testPrimitiveVsObject() {
+        Capture<Integer> capture = new Capture<Integer>();
+        IMethods mock = createMock(IMethods.class);
+
+        expect(mock.oneArg(capture(capture))).andReturn("answer");
+        expect(mock.oneArg((Integer) capture(capture))).andReturn("answer");
+
+        replay(mock);
+
+        assertEquals("answer", mock.oneArg(2));
+        assertEquals(2, capture.getValue().intValue());
+
+        assertEquals("answer", mock.oneArg(Integer.valueOf(3)));
+        assertEquals(3, capture.getValue().intValue());
+
+        verify(mock);
+    }
+
+    @Test
+    public void testAnd() {
+        Capture<String> captured = new Capture<String>();
+        IMethods mock = createMock(IMethods.class);
+
+        expect(mock.oneArg(and(capture(captured), eq("test")))).andReturn(
+                "answer");
+
+        replay(mock);
+
+        assertEquals("answer", mock.oneArg("test"));
+        assertEquals("test", captured.getValue());
+
+        verify(mock);
+    }
+    
+    @Test
+    public void testPrimitive() {
+        Capture<Integer> captureI = new Capture<Integer>();
+        Capture<Long> captureL = new Capture<Long>();
+        Capture<Float> captureF = new Capture<Float>();
+        Capture<Double> captureD = new Capture<Double>();
+        Capture<Byte> captureB = new Capture<Byte>();
+        Capture<Character> captureC = new Capture<Character>();
+
+        IMethods mock = createMock(IMethods.class);
+
+        expect(mock.oneArg(capture(captureI))).andReturn("answerI");
+        expect(mock.oneArg(capture(captureL))).andReturn("answerL");
+        expect(mock.oneArg(capture(captureF))).andReturn("answerF");
+        expect(mock.oneArg(capture(captureD))).andReturn("answerD");
+        expect(mock.oneArg(capture(captureB))).andReturn("answerB");
+        expect(mock.oneArg(capture(captureC))).andReturn("answerC");
+
+        replay(mock);
+
+        assertEquals("answerI", mock.oneArg(1));
+        assertEquals("answerL", mock.oneArg(2l));
+        assertEquals("answerF", mock.oneArg(3.0f));
+        assertEquals("answerD", mock.oneArg(4.0));
+        assertEquals("answerB", mock.oneArg((byte) 5));
+        assertEquals("answerC", mock.oneArg((char) 6));
+
+        assertEquals(1, captureI.getValue().intValue());
+        assertEquals(2l, captureL.getValue().longValue());
+        assertEquals(3.0f, captureF.getValue().floatValue(), 0.0);
+        assertEquals(4.0, captureD.getValue().doubleValue(), 0.0);
+        assertEquals((byte) 5, captureB.getValue().byteValue());
+        assertEquals((char) 6, captureC.getValue().charValue());
+        
+        verify(mock);
+    }
+    
+    @Test
+    public void testCapture() {
+        Capture<String> capture = new Capture<String>();
+        assertFalse(capture.hasCaptured());
+        try {
+            capture.getValue();
+            fail("Should not be allowed");
+        }
+        catch(AssertionError e) {
+            assertEquals("Nothing captured yet", e.getMessage());
+        }
+        assertEquals("Nothing captured yet", capture.toString());
+        capture.setValue("s");
+        assertTrue(capture.hasCaptured());
+        assertEquals("s", capture.getValue());
+        assertEquals("s", capture.toString());
+        capture.reset();
+        assertFalse(capture.hasCaptured());
+        try {
+            capture.getValue();
+            fail("Should not be allowed");
+        }
+        catch(AssertionError e) {
+            assertEquals("Nothing captured yet", e.getMessage());
+        }
+        
+        capture.setValue(null);
+        assertTrue(capture.hasCaptured());
+        assertNull(capture.getValue());
+        assertNull(capture.toString());
+    }
+}
diff --git a/tests/org/easymock/tests2/CompareToTest.java b/tests/org/easymock/tests2/CompareToTest.java
new file mode 100644
index 0000000..b89e2b7
--- /dev/null
+++ b/tests/org/easymock/tests2/CompareToTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.junit.Assert.*;
+
+import java.math.BigDecimal;
+
+import org.easymock.internal.matchers.*;
+import org.junit.Test;
+
+public class CompareToTest {
+
+    @Test
+    public void testNotComparable() {
+        CompareTo<Long> cmpTo = new CompareTo<Long>(5L) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected String getName() {
+                return null;
+            }
+
+            @Override
+            protected boolean matchResult(int result) {
+                fail("Shouldn't be called since the passed argument is not Comparable");
+                return true;
+            }
+            
+        };
+        
+        assertFalse(cmpTo.matches(new Object()));
+    }
+    @Test
+    public void testLessThan() {
+        test(new LessThan<String>("b"), true, false, false, "lt");
+    }
+
+    @Test
+    public void testGreateThan() {
+        test(new GreaterThan<String>("b"), false, true, false, "gt");
+    }
+
+    @Test
+    public void testLessOrEqual() {
+        test(new LessOrEqual<String>("b"), true, false, true, "leq");
+    }
+
+    @Test
+    public void testGreateOrEqual() {
+        test(new GreaterOrEqual<String>("b"), false, true, true, "geq");
+    }
+
+    @Test
+    public void testCompareEqual() {
+        test(new CompareEqual<String>("b"), false, false, true, "cmpEq");
+
+        // Make sure it works when equals provide a different result than
+        // compare
+        CompareEqual<BigDecimal> cmpEq = new CompareEqual<BigDecimal>(
+                new BigDecimal("5.00"));
+        assertTrue(cmpEq.matches(new BigDecimal("5")));
+    }
+
+    private void test(CompareTo<String> cmpTo, boolean lower, boolean higher,
+            boolean equals, String name) {
+
+        assertEquals(lower, cmpTo.matches("a"));
+        assertEquals(equals, cmpTo.matches("b"));
+        assertEquals(higher, cmpTo.matches("c"));
+
+        StringBuffer sb = new StringBuffer();
+        cmpTo.appendTo(sb);
+        assertEquals(name + "(b)", sb.toString());
+    }
+}
diff --git a/tests/org/easymock/tests2/ConstraintsToStringTest.java b/tests/org/easymock/tests2/ConstraintsToStringTest.java
new file mode 100644
index 0000000..87aa9ef
--- /dev/null
+++ b/tests/org/easymock/tests2/ConstraintsToStringTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.easymock.IArgumentMatcher;
+import org.easymock.internal.matchers.*;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ConstraintsToStringTest {
+    private StringBuffer buffer;
+
+    @Before
+    public void setup() {
+        buffer = new StringBuffer();
+    }
+
+    @Test
+    public void sameToStringWithString() {
+        new Same("X").appendTo(buffer);
+        assertEquals("same(\"X\")", buffer.toString());
+
+    }
+
+    @Test
+    public void nullToString() {
+        Null.NULL.appendTo(buffer);
+        assertEquals("isNull()", buffer.toString());
+    }
+
+    @Test
+    public void notNullToString() {
+        NotNull.NOT_NULL.appendTo(buffer);
+        assertEquals("notNull()", buffer.toString());
+    }
+
+    @Test
+    public void anyToString() {
+        Any.ANY.appendTo(buffer);
+        assertEquals("<any>", buffer.toString());
+    }
+
+    @Test
+    public void sameToStringWithChar() {
+        new Same('x').appendTo(buffer);
+        assertEquals("same('x')", buffer.toString());
+    }
+
+    @Test
+    public void sameToStringWithObject() {
+        Object o = new Object() {
+            @Override
+            public String toString() {
+                return "X";
+            }
+        };
+        new Same(o).appendTo(buffer);
+        assertEquals("same(X)", buffer.toString());
+    }
+
+    @Test
+    public void equalsToStringWithString() {
+        new Equals("X").appendTo(buffer);
+        assertEquals("\"X\"", buffer.toString());
+
+    }
+
+    @Test
+    public void equalsToStringWithChar() {
+        new Equals('x').appendTo(buffer);
+        assertEquals("'x'", buffer.toString());
+    }
+
+    @Test
+    public void equalsToStringWithObject() {
+        Object o = new Object() {
+            @Override
+            public String toString() {
+                return "X";
+            }
+        };
+        new Equals(o).appendTo(buffer);
+        assertEquals("X", buffer.toString());
+    }
+
+    @Test
+    public void orToString() {
+        List<IArgumentMatcher> matchers = new ArrayList<IArgumentMatcher>();
+        matchers.add(new Equals(1));
+        matchers.add(new Equals(2));
+        new Or(matchers).appendTo(buffer);
+        assertEquals("or(1, 2)", buffer.toString());
+    }
+
+    @Test
+    public void notToString() {
+        new Not(new Equals(1)).appendTo(buffer);
+        assertEquals("not(1)", buffer.toString());
+    }
+
+    @Test
+    public void andToString() {
+        List<IArgumentMatcher> matchers = new ArrayList<IArgumentMatcher>();
+        matchers.add(new Equals(1));
+        matchers.add(new Equals(2));
+        new And(matchers).appendTo(buffer);
+        assertEquals("and(1, 2)", buffer.toString());
+    }
+
+    @Test
+    public void startsWithToString() {
+        new StartsWith("AB").appendTo(buffer);
+        assertEquals("startsWith(\"AB\")", buffer.toString());
+    }
+
+    @Test
+    public void endsWithToString() {
+        new EndsWith("AB").appendTo(buffer);
+        assertEquals("endsWith(\"AB\")", buffer.toString());
+    }
+
+    @Test
+    public void containsToString() {
+        new Contains("AB").appendTo(buffer);
+        assertEquals("contains(\"AB\")", buffer.toString());
+    }
+
+    @Test
+    public void findToString() {
+        new Find("\\s+").appendTo(buffer);
+        assertEquals("find(\"\\\\s+\")", buffer.toString());
+    }
+
+    @Test
+    public void matchesToString() {
+        new Matches("\\s+").appendTo(buffer);
+        assertEquals("matches(\"\\\\s+\")", buffer.toString());
+    }
+
+}
diff --git a/tests/org/easymock/tests2/NameTest.java b/tests/org/easymock/tests2/NameTest.java
new file mode 100644
index 0000000..917ee00
--- /dev/null
+++ b/tests/org/easymock/tests2/NameTest.java
@@ -0,0 +1,75 @@
+package org.easymock.tests2;
+
+import org.easymock.IMocksControl;
+import org.easymock.tests.IMethods;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+public class NameTest {
+    @Test
+    public void nameForMock() {
+        IMethods mock = createMock("mock", IMethods.class);
+        mock.simpleMethod();
+        replay(mock);
+        try {
+            verify(mock);
+        } catch (AssertionError expected) {
+            String actualMessage = expected.getMessage();
+            String expectedMessage = "\n  Expectation failure on verify:\n    mock.simpleMethod(): expected: 1, actual: 0";
+            assertEquals(expectedMessage, actualMessage);         
+        }
+    }
+    @Test
+    public void nameForStrictMock() {
+        IMethods mock = createStrictMock("mock", IMethods.class);
+        mock.simpleMethod();
+        replay(mock);
+        try {
+            verify(mock);
+        } catch (AssertionError expected) {
+            String actualMessage = expected.getMessage();
+            String expectedMessage = "\n  Expectation failure on verify:\n    mock.simpleMethod(): expected: 1, actual: 0";
+            assertEquals(expectedMessage, actualMessage);         
+        }
+    }
+    @Test
+    public void nameForNiceMock() {
+        IMethods mock = createNiceMock("mock", IMethods.class);
+        mock.simpleMethod();
+        replay(mock);
+        try {
+            verify(mock);
+        } catch (AssertionError expected) {
+            String actualMessage = expected.getMessage();
+            String expectedMessage = "\n  Expectation failure on verify:\n    mock.simpleMethod(): expected: 1, actual: 0";
+            assertEquals(expectedMessage, actualMessage);         
+        }
+    }
+    @Test
+    public void nameForMocksControl() {
+        IMocksControl control = createControl();
+        IMethods mock = control.createMock("mock", IMethods.class);
+        mock.simpleMethod();
+        replay(mock);
+        try {
+            verify(mock);
+        } catch (AssertionError expected) {
+            String actualMessage = expected.getMessage();
+            String expectedMessage = "\n  Expectation failure on verify:\n    mock.simpleMethod(): expected: 1, actual: 0";
+            assertEquals(expectedMessage, actualMessage);         
+        }
+    }
+    
+    @Test
+    public void shouldThrowIllegalArgumentExceptionIfNameIsNoValidJavaIdentifier() {
+        try {
+            createMock("no-valid-java-identifier", IMethods.class);
+            throw new AssertionError();
+        } catch (IllegalArgumentException expected) {
+            assertEquals("'no-valid-java-identifier' is not a valid Java identifier.", expected.getMessage());
+        }
+    }
+
+}
diff --git a/tests/org/easymock/tests2/NiceMockTest.java b/tests/org/easymock/tests2/NiceMockTest.java
new file mode 100644
index 0000000..0bcd1ce
--- /dev/null
+++ b/tests/org/easymock/tests2/NiceMockTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.tests.IMethods;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NiceMockTest {
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        mock = createNiceMock(IMethods.class);
+        replay(mock);
+    }
+
+    @Test
+    public void defaultReturnValueBoolean() {
+        assertEquals(false, mock.booleanReturningMethod(12));
+        verify(mock);
+    }
+
+    @Test
+    public void defaultReturnValueFloat() {
+        assertEquals(0.0f, mock.floatReturningMethod(12), 0.0f);
+        verify(mock);
+    }
+
+    @Test
+    public void defaultReturnValueDouble() {
+        assertEquals(0.0d, mock.doubleReturningMethod(12), 0.0d);
+        verify(mock);
+    }
+
+    @Test
+    public void defaultReturnValueObject() {
+        assertEquals(null, mock.objectReturningMethod(12));
+        verify(mock);
+    }
+}
diff --git a/tests/org/easymock/tests2/SerializationTest.java b/tests/org/easymock/tests2/SerializationTest.java
new file mode 100644
index 0000000..99ed23c
--- /dev/null
+++ b/tests/org/easymock/tests2/SerializationTest.java
@@ -0,0 +1,49 @@
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import java.io.*;
+import java.util.List;
+
+import org.junit.Test;
+
+public class SerializationTest {
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test() throws Exception {
+        List<String> mock = createMock(List.class);
+        
+        mock = serialize(mock);
+        
+        expect(mock.get(1)).andReturn("a");
+        
+        mock = serialize(mock);
+        
+        replay(mock);
+        
+        mock = serialize(mock);
+        
+        assertEquals("a", mock.get(1));
+        
+        mock = serialize(mock);
+        
+        verify(mock);
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T serialize(T o) throws IOException, ClassNotFoundException {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(bOut);
+        out.writeObject(o);
+        out.close();
+        
+        ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bIn);
+        o = (T) in.readObject();
+        in.close();
+        
+        return o;
+    }
+}
diff --git a/tests/org/easymock/tests2/StubTest.java b/tests/org/easymock/tests2/StubTest.java
new file mode 100644
index 0000000..450cf6a
--- /dev/null
+++ b/tests/org/easymock/tests2/StubTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.tests.IMethods;
+import org.junit.Before;
+import org.junit.Test;
+
+public class StubTest {
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        mock = createStrictMock(IMethods.class);
+    }
+
+    @Test
+    public void stub() {
+        mock.simpleMethodWithArgument("1");
+        expectLastCall().anyTimes();
+        mock.simpleMethodWithArgument("2");
+        expectLastCall().anyTimes();
+        mock.simpleMethodWithArgument("3");
+        expectLastCall().asStub();
+
+        replay(mock);
+
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("3");
+
+        verify(mock);
+
+    }
+
+    @Test
+    public void stubWithReturnValue() {
+        expect(mock.oneArg("1")).andReturn("A").andStubReturn("B");
+        expect(mock.oneArg("2")).andThrow(new IllegalArgumentException())
+                .andStubThrow(new IllegalStateException());
+
+        replay(mock);
+
+        assertEquals("A", mock.oneArg("1"));
+        assertEquals("B", mock.oneArg("1"));
+        assertEquals("B", mock.oneArg("1"));
+        try {
+            mock.oneArg("2");
+        } catch (IllegalArgumentException ignored) {
+        }
+        assertEquals("B", mock.oneArg("1"));
+        try {
+            mock.oneArg("2");
+        } catch (IllegalStateException ignored) {
+        }
+        assertEquals("B", mock.oneArg("1"));
+        try {
+            mock.oneArg("2");
+        } catch (IllegalStateException ignored) {
+        }
+        verify(mock);
+    }
+
+}
diff --git a/tests/org/easymock/tests2/ThreadingTest.java b/tests/org/easymock/tests2/ThreadingTest.java
new file mode 100644
index 0000000..21348d9
--- /dev/null
+++ b/tests/org/easymock/tests2/ThreadingTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Henri Tremblay.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.*;
+
+import org.easymock.tests.IMethods;
+import org.junit.Test;
+
+/**
+ * Test that EasyMock works in replay state in a multithreaded
+ * environment. Note that sadly this test isn't sure to fail all
+ * the time. Only if there's a concurrency issue and we're lucky
+ * enough to fell on it during testing.
+ */
+public class ThreadingTest {
+
+    private static final int THREAD_COUNT = 10;
+
+    @Test
+    public void testThreadSafe() throws Throwable {
+
+        final IMethods mock = createMock(IMethods.class);
+        expect(mock.oneArg("test")).andReturn("result").times(THREAD_COUNT);
+        
+        makeThreadSafe(mock, true);
+        
+        replay(mock);
+        
+        Callable<String> replay = new Callable<String>() {
+            public String call() throws Exception {
+                return mock.oneArg("test");
+            }
+        };
+        
+        ExecutorService service = Executors.newFixedThreadPool(THREAD_COUNT);
+
+        List<Callable<String>> tasks = Collections.nCopies(THREAD_COUNT, replay);
+
+        List<Future<String>> results = service.invokeAll(tasks);
+
+        for (Future<String> future : results) {
+            assertEquals("result", future.get());
+        }
+
+        verify(mock);
+    }
+    
+    @Test
+    public void testThreadNotSafe() throws Throwable {
+
+        final IMethods mock = createMock(IMethods.class);
+        expect(mock.oneArg("test")).andReturn("result").times(THREAD_COUNT);
+        
+        replay(mock);
+        
+        Callable<String> replay = new Callable<String>() {
+            public String call() throws Exception {
+                return mock.oneArg("test");
+            }
+        };
+        
+        ExecutorService service = Executors.newFixedThreadPool(THREAD_COUNT);
+
+        List<Callable<String>> tasks = Collections.nCopies(THREAD_COUNT, replay);
+
+        List<Future<String>> results = service.invokeAll(tasks);
+        
+        boolean exceptionThrown = false;
+
+        for (Future<String> future : results) {
+            try {
+                assertEquals("result", future.get());
+            }
+            catch(ExecutionException e) {
+                assertEquals("\n  Un-thread-safe mock called from multiple threads", e.getCause().getMessage());
+                exceptionThrown = true;
+            }
+        }
+        
+        assertTrue(exceptionThrown);
+    }    
+}
+
diff --git a/tests/org/easymock/tests2/UsageConstraintsTest.java b/tests/org/easymock/tests2/UsageConstraintsTest.java
new file mode 100644
index 0000000..cb90768
--- /dev/null
+++ b/tests/org/easymock/tests2/UsageConstraintsTest.java
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.easymock.EasyMock;
+import org.easymock.LogicalOperator;
+import org.easymock.internal.matchers.Equals;
+import org.easymock.tests.IMethods;
+import org.junit.Before;
+import org.junit.Test;
+
+public class UsageConstraintsTest {
+    private IMethods mock;
+
+    @Before
+    public void setUp() {
+        mock = createMock(IMethods.class);
+    }
+
+    @Test
+    public void equalsMissing() {
+        mock.simpleMethodWithArgument(not(eq("asd")));
+        try {
+            mock.simpleMethodWithArgument(not("jkl"));
+            fail();
+        } catch (IllegalStateException e) {
+            assertEquals("no matchers found.", e.getMessage());
+        }
+        try {
+            mock.simpleMethodWithArgument(or(eq("jkl"), "asd"));
+            fail();
+        } catch (IllegalStateException e) {
+            assertEquals("2 matchers expected, 1 recorded.", e.getMessage());
+        }
+        try {
+            mock.threeArgumentMethod(1, "asd", eq("asd"));
+            fail();
+        } catch (IllegalStateException e) {
+            assertEquals("3 matchers expected, 1 recorded.", e.getMessage());
+        }
+
+    }
+
+    @Test
+    public void differentConstraintsOnSameCall() {
+        mock.simpleMethodWithArgument((String) isNull());
+        mock.simpleMethodWithArgument((String) notNull());
+        replay(mock);
+        mock.simpleMethodWithArgument(null);
+        mock.simpleMethodWithArgument("2");
+    }
+
+    @Test
+    public void equals() {
+        assertEquals(new Equals(null), new Equals(null));
+        assertEquals(new Equals(new Integer(2)), new Equals(new Integer(2)));
+        assertFalse(new Equals(null).equals(null));
+        assertFalse(new Equals(null).equals("Test"));
+        try {
+            new Equals(null).hashCode();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test
+    public void constraints() {
+        expect(
+                mock.threeArgumentMethod(and(geq(7), leq(10)),
+                        isA(String.class), contains("123"))).andReturn("456")
+                .atLeastOnce();
+        replay(mock);
+        boolean failed = false;
+        try {
+            mock.threeArgumentMethod(11, "", "01234");
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed) {
+            fail();
+        }
+        failed = false;
+        try {
+            mock.threeArgumentMethod(8, new Object(), "01234");
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed) {
+            fail();
+        }
+        failed = false;
+        try {
+            mock.threeArgumentMethod(8, "", "no match");
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed) {
+            fail();
+        }
+        assertEquals("456", mock.threeArgumentMethod(8, "", "01234"));
+        verify(mock);
+    }
+
+    @Test
+    public void andOverloaded() {
+        expect(mock.oneArg(and(eq(false), eq(false)))).andReturn("0");
+        expect(mock.oneArg(and(eq((byte) 1), eq((byte) 1)))).andReturn("1");
+        expect(mock.oneArg(and(eq('a'), eq('a')))).andReturn("2");
+        expect(mock.oneArg(and(eq((double) 1), eq((double) 1)))).andReturn("3");
+        expect(mock.oneArg(and(eq((float) 1), eq((float) 1)))).andReturn("4");
+        expect(mock.oneArg(and(eq((int) 1), eq((int) 1)))).andReturn("5");
+        expect(mock.oneArg(and(eq((long) 1), eq((long) 1)))).andReturn("6");
+        expect(mock.oneArg(and(eq((short) 1), eq((short) 1)))).andReturn("7");
+        expect(mock.oneArg(and(contains("a"), contains("d")))).andReturn("8");
+        expect(mock.oneArg(and(isA(Class.class), eq(Object.class)))).andReturn(
+                "9");
+        replay(mock);
+        assertEquals("9", mock.oneArg(Object.class));
+        assertEquals("0", mock.oneArg(false));
+        assertEquals("1", mock.oneArg((byte) 1));
+        assertEquals("2", mock.oneArg('a'));
+        assertEquals("3", mock.oneArg((double) 1));
+        assertEquals("7", mock.oneArg((short) 1));
+        assertEquals("8", mock.oneArg("abcde"));
+        assertEquals("4", mock.oneArg((float) 1));
+        assertEquals("5", mock.oneArg((int) 1));
+        assertEquals("6", mock.oneArg((long) 1));
+        verify(mock);
+    }
+
+    @Test
+    public void orOverloaded() {
+        expect(mock.oneArg(or(eq(false), eq(true)))).andReturn("0");
+        expect(mock.oneArg(or(eq((byte) 1), eq((byte) 2)))).andReturn("1");
+        expect(mock.oneArg(or(eq((char) 1), eq((char) 2)))).andReturn("2");
+        expect(mock.oneArg(or(eq((double) 1), eq((double) 2)))).andReturn("3");
+        expect(mock.oneArg(or(eq((float) 1), eq((float) 2)))).andReturn("4");
+        expect(mock.oneArg(or(eq((int) 1), eq((int) 2)))).andReturn("5");
+        expect(mock.oneArg(or(eq((long) 1), eq((long) 2)))).andReturn("6");
+        expect(mock.oneArg(or(eq((short) 1), eq((short) 2)))).andReturn("7");
+        expect(mock.oneArg(or(eq("asd"), eq("jkl")))).andReturn("8");
+        expect(mock.oneArg(or(eq(this.getClass()), eq(Object.class))))
+                .andReturn("9");
+        replay(mock);
+        assertEquals("9", mock.oneArg(Object.class));
+        assertEquals("0", mock.oneArg(true));
+        assertEquals("1", mock.oneArg((byte) 2));
+        assertEquals("2", mock.oneArg((char) 1));
+        assertEquals("3", mock.oneArg((double) 2));
+        assertEquals("7", mock.oneArg((short) 1));
+        assertEquals("8", mock.oneArg("jkl"));
+        assertEquals("4", mock.oneArg((float) 1));
+        assertEquals("5", mock.oneArg((int) 2));
+        assertEquals("6", mock.oneArg((long) 1));
+        verify(mock);
+    }
+
+    @Test
+    public void notOverloaded() {
+        expect(mock.oneArg(not(eq(false)))).andReturn("0");
+        expect(mock.oneArg(not(eq((byte) 1)))).andReturn("1");
+        expect(mock.oneArg(not(eq('a')))).andReturn("2");
+        expect(mock.oneArg(not(eq((double) 1)))).andReturn("3");
+        expect(mock.oneArg(not(eq((float) 1)))).andReturn("4");
+        expect(mock.oneArg(not(eq((int) 1)))).andReturn("5");
+        expect(mock.oneArg(not(eq((long) 1)))).andReturn("6");
+        expect(mock.oneArg(not(eq((short) 1)))).andReturn("7");
+        expect(mock.oneArg(not(contains("a")))).andReturn("8");
+        expect(mock.oneArg(not(isA(Class.class)))).andReturn("9");
+        replay(mock);
+        assertEquals("9", mock.oneArg(new Object()));
+        assertEquals("0", mock.oneArg(true));
+        assertEquals("1", mock.oneArg((byte) 2));
+        assertEquals("2", mock.oneArg('b'));
+        assertEquals("3", mock.oneArg((double) 2));
+        assertEquals("7", mock.oneArg((short) 2));
+        assertEquals("8", mock.oneArg("bcde"));
+        assertEquals("4", mock.oneArg((float) 2));
+        assertEquals("5", mock.oneArg((int) 2));
+        assertEquals("6", mock.oneArg((long) 2));
+        verify(mock);
+    }
+
+    @Test
+    public void lessOrEqualOverloaded() {
+        expect(mock.oneArg(leq((byte) 1))).andReturn("1");
+        expect(mock.oneArg(leq((double) 1))).andReturn("3");
+        expect(mock.oneArg(leq((float) 1))).andReturn("4");
+        expect(mock.oneArg(leq((int) 1))).andReturn("5");
+        expect(mock.oneArg(leq((long) 1))).andReturn("6");
+        expect(mock.oneArg(leq((short) 1))).andReturn("7");
+        expect(mock.oneArg(leq(new BigDecimal("1")))).andReturn("8");
+        replay(mock);
+        assertEquals("1", mock.oneArg((byte) 1));
+        assertEquals("3", mock.oneArg((double) 1));
+        assertEquals("7", mock.oneArg((short) 0));
+        assertEquals("4", mock.oneArg((float) -5));
+        assertEquals("5", mock.oneArg((int) -2));
+        assertEquals("6", mock.oneArg((long) -3));
+        assertEquals("8", mock.oneArg(new BigDecimal("0.5")));
+        verify(mock);
+    }
+
+    @Test
+    public void lessThanOverloaded() {
+        expect(mock.oneArg(lt((byte) 1))).andReturn("1");
+        expect(mock.oneArg(lt((double) 1))).andReturn("3");
+        expect(mock.oneArg(lt((float) 1))).andReturn("4");
+        expect(mock.oneArg(lt((int) 1))).andReturn("5");
+        expect(mock.oneArg(lt((long) 1))).andReturn("6");
+        expect(mock.oneArg(lt((short) 1))).andReturn("7");
+        expect(mock.oneArg(lt(new BigDecimal("1")))).andReturn("8");
+        replay(mock);
+        assertEquals("1", mock.oneArg((byte) 0));
+        assertEquals("3", mock.oneArg((double) 0));
+        assertEquals("7", mock.oneArg((short) 0));
+        assertEquals("4", mock.oneArg((float) -4));
+        assertEquals("5", mock.oneArg((int) -34));
+        assertEquals("6", mock.oneArg((long) -6));
+        assertEquals("8", mock.oneArg(new BigDecimal("0.5")));
+        verify(mock);
+    }
+
+    @Test
+    public void greaterOrEqualOverloaded() {
+        expect(mock.oneArg(geq((byte) 1))).andReturn("1");
+        expect(mock.oneArg(geq((double) 1))).andReturn("3");
+        expect(mock.oneArg(geq((float) 1))).andReturn("4");
+        expect(mock.oneArg(geq((int) 1))).andReturn("5");
+        expect(mock.oneArg(geq((long) 1))).andReturn("6");
+        expect(mock.oneArg(geq((short) 1))).andReturn("7");
+        expect(mock.oneArg(geq(new BigDecimal("1")))).andReturn("8");
+        replay(mock);
+        assertEquals("1", mock.oneArg((byte) 2));
+        assertEquals("3", mock.oneArg((double) 1));
+        assertEquals("7", mock.oneArg((short) 2));
+        assertEquals("4", mock.oneArg((float) 3));
+        assertEquals("5", mock.oneArg((int) 4));
+        assertEquals("6", mock.oneArg((long) 5));
+        assertEquals("8", mock.oneArg(new BigDecimal("1.5")));
+        verify(mock);
+    }
+
+    @Test
+    public void greaterThanOverloaded() {
+        expect(mock.oneArg(gt((byte) 1))).andReturn("1");
+        expect(mock.oneArg(gt((double) 1))).andReturn("3");
+        expect(mock.oneArg(gt((float) 1))).andReturn("4");
+        expect(mock.oneArg(gt((int) 1))).andReturn("5");
+        expect(mock.oneArg(gt((long) 1))).andReturn("6");
+        expect(mock.oneArg(gt((short) 1))).andReturn("7");
+        expect(mock.oneArg(gt(new BigDecimal("1")))).andReturn("8");
+        replay(mock);
+        assertEquals("1", mock.oneArg((byte) 2));
+        assertEquals("3", mock.oneArg((double) 2));
+        assertEquals("7", mock.oneArg((short) 2));
+        assertEquals("4", mock.oneArg((float) 3));
+        assertEquals("5", mock.oneArg((int) 2));
+        assertEquals("6", mock.oneArg((long) 5));
+        assertEquals("8", mock.oneArg(new BigDecimal("1.5")));
+        verify(mock);
+    }
+
+    @Test
+    public void cmpTo() {
+        expect(mock.oneArg(cmpEq(new BigDecimal("1.5")))).andReturn("0");
+        replay(mock);
+        assertEquals("0", mock.oneArg(new BigDecimal("1.50")));
+        verify(mock);
+    }
+
+    public static class A {
+        private int value;
+
+        public A(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+    @Test
+    public void compareWithComparator() {
+        // Undertype just to make sure the generic typing works
+        Comparator<Object> comparator = new Comparator<Object>() {
+            private int compare(A a1, A a2) {
+                return a1.getValue() - a2.getValue();
+            }
+
+            public int compare(Object o1, Object o2) {
+                return compare((A)o1, (A)o2);
+            }
+        };
+
+        // Check my comparator works
+        assertTrue(comparator.compare(new A(1), new A(2)) < 0);
+        assertTrue(comparator.compare(new A(2), new A(1)) > 0);
+        assertTrue(comparator.compare(new A(1), new A(1)) == 0);
+
+        // Now test EasyMock.cmp
+        checkOrder(mock, true);
+        
+        expect(mock.oneArg(cmp(new A(5), comparator, 
+                LogicalOperator.EQUAL))).andReturn("0");
+        
+        expect(mock.oneArg(cmp(new A(5), comparator, 
+                LogicalOperator.GREATER))).andReturn("1");
+        
+        expect(mock.oneArg(cmp(new A(5), comparator, 
+                LogicalOperator.GREATER_OR_EQUAL))).andReturn("2");
+        expect(mock.oneArg(cmp(new A(5), comparator, 
+                LogicalOperator.GREATER_OR_EQUAL))).andReturn("2");
+        
+        expect(mock.oneArg(cmp(new A(5), comparator, 
+                LogicalOperator.LESS_OR_EQUAL))).andReturn("3");
+        expect(mock.oneArg(cmp(new A(5), comparator, 
+                LogicalOperator.LESS_OR_EQUAL))).andReturn("3");
+        
+        expect(mock.oneArg(cmp(new A(5), comparator, 
+                LogicalOperator.LESS_THAN))).andReturn("4");
+                
+        replay(mock);
+        
+        checkItFails(null); // null is not comparable so always return false
+        try {
+            mock.oneArg("");
+            fail();
+        }
+        catch(AssertionError e) {} // different type isn't either
+        
+        checkItFails(new A(4));
+        checkItFails(new A(6));
+        assertEquals("0", mock.oneArg(new A(5)));
+
+        checkItFails(new A(4));
+        checkItFails(new A(5));        
+        assertEquals("1", mock.oneArg(new A(6)));
+        
+        checkItFails(new A(4));
+        assertEquals("2", mock.oneArg(new A(6)));
+        assertEquals("2", mock.oneArg(new A(5)));
+        
+        checkItFails(new A(6));
+        assertEquals("3", mock.oneArg(new A(4)));
+        assertEquals("3", mock.oneArg(new A(5)));
+
+        checkItFails(new A(5));
+        checkItFails(new A(6));
+        assertEquals("4", mock.oneArg(new A(4)));
+        
+        verify(mock);
+    }
+
+    private void checkItFails(A a) {
+        try {
+            mock.oneArg(a);
+            fail();
+        }
+        catch(AssertionError e) {}
+    }
+
+    @Test
+    public void any() {
+        expect(mock.oneArg(anyBoolean())).andReturn("0");
+        expect(mock.oneArg(anyByte())).andReturn("1");
+        expect(mock.oneArg(anyChar())).andReturn("2");
+        expect(mock.oneArg(anyDouble())).andReturn("3");
+        expect(mock.oneArg(anyFloat())).andReturn("4");
+        expect(mock.oneArg(anyInt())).andReturn("5");
+        expect(mock.oneArg(anyLong())).andReturn("6");
+        expect(mock.oneArg(anyShort())).andReturn("7");
+        expect(mock.oneArg((String) anyObject())).andReturn("8");
+        expect(mock.oneArg((List<String>) EasyMock.<List<String>>anyObject())).andReturn("9"); // make sure there's no warning on the cast
+        replay(mock);
+        assertEquals("9", mock.oneArg(Collections.emptyList()));
+        assertEquals("0", mock.oneArg(true));
+        assertEquals("1", mock.oneArg((byte) 1));
+        assertEquals("2", mock.oneArg((char) 1));
+        assertEquals("3", mock.oneArg((double) 1));
+        assertEquals("7", mock.oneArg((short) 1));
+        assertEquals("8", mock.oneArg("Test"));
+        assertEquals("4", mock.oneArg((float) 1));
+        assertEquals("5", mock.oneArg((int) 1));
+        assertEquals("6", mock.oneArg((long) 1));
+        verify(mock);
+    }    
+
+    @Test
+    public void arrayEquals() {
+        expect(mock.oneArray(aryEq(new boolean[] { true }))).andReturn("0");
+        expect(mock.oneArray(aryEq(new byte[] { 1 }))).andReturn("1");
+        expect(mock.oneArray(aryEq(new char[] { 1 }))).andReturn("2");
+        expect(mock.oneArray(aryEq(new double[] { 1 }))).andReturn("3");
+        expect(mock.oneArray(aryEq(new float[] { 1 }))).andReturn("4");
+        expect(mock.oneArray(aryEq(new int[] { 1 }))).andReturn("5");
+        expect(mock.oneArray(aryEq(new long[] { 1 }))).andReturn("6");
+        expect(mock.oneArray(aryEq(new short[] { 1 }))).andReturn("7");
+        expect(mock.oneArray(aryEq(new String[] { "Test" }))).andReturn("8");
+        expect(mock.oneArray(aryEq(new Object[] { "Test" }))).andReturn("9");
+        replay(mock);
+        assertEquals("9", mock.oneArray(new Object[] { "Test" }));
+        assertEquals("0", mock.oneArray(new boolean[] { true }));
+        assertEquals("1", mock.oneArray(new byte[] { 1 }));
+        assertEquals("2", mock.oneArray(new char[] { 1 }));
+        assertEquals("3", mock.oneArray(new double[] { 1 }));
+        assertEquals("7", mock.oneArray(new short[] { 1 }));
+        assertEquals("8", mock.oneArray(new String[] { "Test" }));
+        assertEquals("4", mock.oneArray(new float[] { 1 }));
+        assertEquals("5", mock.oneArray(new int[] { 1 }));
+        assertEquals("6", mock.oneArray(new long[] { 1 }));
+        verify(mock);
+    }
+
+    @Test
+    public void greaterOrEqual() {
+        expect(mock.oneArg(geq(7))).andReturn("1").times(3);
+        expect(mock.oneArg(lt(7))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg(7));
+        assertEquals("2", mock.oneArg(6));
+        assertEquals("1", mock.oneArg(8));
+        assertEquals("2", mock.oneArg(6));
+        assertEquals("1", mock.oneArg(9));
+
+        verify(mock);
+    }
+
+    @Test
+    public void greaterThan() {
+        expect(mock.oneArg(gt(7))).andReturn("1").times(3);
+        expect(mock.oneArg(leq(7))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg(8));
+        assertEquals("2", mock.oneArg(7));
+        assertEquals("1", mock.oneArg(9));
+        assertEquals("2", mock.oneArg(6));
+        assertEquals("1", mock.oneArg(10));
+
+        verify(mock);
+    }
+
+    @Test
+    public void lessOrEqual() {
+        expect(mock.oneArg(leq(7))).andReturn("1").times(3);
+        expect(mock.oneArg(gt(7))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg(7));
+        assertEquals("2", mock.oneArg(8));
+        assertEquals("1", mock.oneArg(6));
+        assertEquals("2", mock.oneArg(9));
+        assertEquals("1", mock.oneArg(5));
+
+        verify(mock);
+    }
+
+    @Test
+    public void lessThan() {
+        expect(mock.oneArg(lt(7))).andReturn("1").times(3);
+        expect(mock.oneArg(geq(7))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg(5));
+        assertEquals("2", mock.oneArg(7));
+        assertEquals("1", mock.oneArg(6));
+        assertEquals("2", mock.oneArg(8));
+        assertEquals("1", mock.oneArg(4));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testOr() {
+        expect(mock.oneArg(or(eq(7), eq(9)))).andReturn("1").atLeastOnce();
+        expect(mock.oneArg(anyInt())).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg(7));
+        assertEquals("1", mock.oneArg(9));
+        assertEquals("2", mock.oneArg(10));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testNull() {
+        expect(mock.threeArgumentMethod(eq(1), isNull(), eq("")))
+                .andReturn("1").atLeastOnce();
+        expect(mock.threeArgumentMethod(eq(1), not(isNull()), eq("")))
+                .andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.threeArgumentMethod(1, null, ""));
+        assertEquals("2", mock.threeArgumentMethod(1, new Object(), ""));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testNotNull() {
+        expect(mock.threeArgumentMethod(eq(1), notNull(), eq(""))).andReturn(
+                "1").atLeastOnce();
+        expect(mock.threeArgumentMethod(eq(1), not(notNull()), eq("")))
+                .andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.threeArgumentMethod(1, new Object(), ""));
+        assertEquals("2", mock.threeArgumentMethod(1, null, ""));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testFind() {
+        expect(mock.oneArg(find("[a-z]+\\d"))).andReturn("1").atLeastOnce();
+        expect(mock.oneArg(find("\\d\\d"))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg("1ab12"));
+        assertEquals("2", mock.oneArg("312xx"));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testMatches() {
+        expect(mock.oneArg(matches("[a-z]+\\d\\d"))).andReturn("1")
+                .atLeastOnce();
+        expect(mock.oneArg(matches("\\d\\d\\d"))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg("a12"));
+        assertEquals("2", mock.oneArg("131"));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testContains() {
+        expect(mock.oneArg(contains("ab"))).andReturn("1").atLeastOnce();
+        expect(mock.oneArg(contains("bc"))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg("xabcx"));
+        assertEquals("2", mock.oneArg("xdbcx"));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testStartsWith() {
+        expect(mock.oneArg(startsWith("ab"))).andReturn("1").atLeastOnce();
+        expect(mock.oneArg(startsWith("bc"))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg("abcx"));
+        assertEquals("2", mock.oneArg("bcxe"));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testEndsWith() {
+        expect(mock.oneArg(endsWith("ab"))).andReturn("1").atLeastOnce();
+        expect(mock.oneArg(endsWith("bc"))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg("xab"));
+        assertEquals("2", mock.oneArg("xbc"));
+
+        verify(mock);
+    }
+
+    @Test
+    public void equalsWithDelta() {
+        expect(mock.oneArg(eq(1.0D, 0.1D))).andReturn("1").atLeastOnce();
+        expect(mock.oneArg(eq(2.0D, 0.1D))).andStubReturn("2");
+        expect(mock.oneArg(eq(1.0F, 0.1F))).andReturn("3").atLeastOnce();
+        expect(mock.oneArg(eq(2.0F, 0.1F))).andStubReturn("4");
+        expect(mock.oneArg(eq(2.0F, 0.1F))).andStubReturn("4");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg(1.0));
+        assertEquals("1", mock.oneArg(0.91));
+        assertEquals("1", mock.oneArg(1.09));
+        assertEquals("2", mock.oneArg(2.0));
+
+        assertEquals("3", mock.oneArg(1.0F));
+        assertEquals("3", mock.oneArg(0.91F));
+        assertEquals("3", mock.oneArg(1.09F));
+        assertEquals("4", mock.oneArg(2.0F));
+
+        verify(mock);
+    }
+
+    @Test
+    public void testSame() {
+        Object one = new String("1243");
+        Object two = new String("1243");
+
+        assertNotSame(one, two);
+        assertEquals(one, two);
+
+        expect(mock.oneArg(same(one))).andReturn("1").atLeastOnce();
+        expect(mock.oneArg(same(two))).andStubReturn("2");
+
+        replay(mock);
+
+        assertEquals("1", mock.oneArg(one));
+        assertEquals("2", mock.oneArg(two));
+
+        verify(mock);
+    }
+}
diff --git a/tests/org/easymock/tests2/UsageMatchersTest.java b/tests/org/easymock/tests2/UsageMatchersTest.java
new file mode 100644
index 0000000..d6696fc
--- /dev/null
+++ b/tests/org/easymock/tests2/UsageMatchersTest.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+
+import org.easymock.tests.IMethods;
+import org.junit.Test;
+
+public class UsageMatchersTest {
+    @Test(expected = IllegalStateException.class)
+    public void additionalMatchersFailAtReplay() {
+
+        IMethods mock = createMock(IMethods.class);
+        lt(5);
+
+        replay(mock);
+    }
+
+}
diff --git a/tests/org/easymock/tests2/UsageStrictMockTest.java b/tests/org/easymock/tests2/UsageStrictMockTest.java
new file mode 100644
index 0000000..655e3f2
--- /dev/null
+++ b/tests/org/easymock/tests2/UsageStrictMockTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.internal.ReplayState;
+import org.easymock.tests.IMethods;
+import org.easymock.tests.Util;
+import org.junit.Before;
+import org.junit.Test;
+
+public class UsageStrictMockTest {
+    private IMethods mock;
+
+    @Before
+    public void setup() {
+        mock = createStrictMock(IMethods.class);
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+        replay(mock);
+    }
+
+    @Test
+    public void orderedCallsSucces() {
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+        verify(mock);
+    }
+
+    @Test
+    public void unorderedCallsFailure() {
+        boolean failed = false;
+        try {
+            mock.simpleMethodWithArgument("2");
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed) {
+            fail("unordered calls accepted");
+        }
+    }
+
+    @Test
+    public void tooManyCallsFailure() {
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+
+        boolean failed = false;
+        try {
+            mock.simpleMethodWithArgument("2");
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed) {
+            fail("too many calls accepted");
+        }
+    }
+
+    @Test
+    public void tooFewCallsFailure() {
+        mock.simpleMethodWithArgument("1");
+        boolean failed = false;
+        try {
+            verify(mock);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertTrue("stack trace must be filled in", Util.getStackTrace(
+                    expected).indexOf(ReplayState.class.getName()) == -1);
+        }
+        if (!failed) {
+            fail("too few calls accepted");
+        }
+    }
+
+    @Test
+    public void differentMethods() {
+
+        reset(mock);
+
+        mock.booleanReturningMethod(0);
+        expectLastCall().andReturn(true);
+        mock.simpleMethod();
+        mock.booleanReturningMethod(1);
+        expectLastCall().andReturn(false).times(2, 3);
+        mock.simpleMethod();
+        expectLastCall().atLeastOnce();
+
+        replay(mock);
+        assertEquals(true, mock.booleanReturningMethod(0));
+        mock.simpleMethod();
+
+        boolean failed = false;
+        try {
+            verify(mock);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    simpleMethod(): expected: 1, actual: 1"
+                            + "\n    booleanReturningMethod(1): expected: between 2 and 3, actual: 0"
+                            + "\n    simpleMethod(): expected: at least 1, actual: 0",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("too few calls accepted");
+        }
+
+        assertEquals(false, mock.booleanReturningMethod(1));
+
+        failed = false;
+        try {
+            mock.simpleMethod();
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Unexpected method call simpleMethod():"
+                            + "\n    booleanReturningMethod(1): expected: between 2 and 3, actual: 1",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("wrong call accepted");
+        }
+    }
+
+    @Test
+    public void range() {
+
+        reset(mock);
+
+        mock.booleanReturningMethod(0);
+        expectLastCall().andReturn(true);
+        mock.simpleMethod();
+        mock.booleanReturningMethod(1);
+        expectLastCall().andReturn(false).times(2, 3);
+        mock.simpleMethod();
+        expectLastCall().atLeastOnce();
+        expect(mock.booleanReturningMethod(1)).andReturn(false);
+
+        replay(mock);
+
+        mock.booleanReturningMethod(0);
+        mock.simpleMethod();
+
+        mock.booleanReturningMethod(1);
+        mock.booleanReturningMethod(1);
+        mock.booleanReturningMethod(1);
+
+        boolean failed = false;
+
+        try {
+            mock.booleanReturningMethod(1);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Unexpected method call booleanReturningMethod(1):"
+                            + "\n    booleanReturningMethod(1): expected: between 2 and 3, actual: 3 (+1)"
+                            + "\n    simpleMethod(): expected: at least 1, actual: 0",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("too many calls accepted");
+        }
+    }
+
+    @Test
+    public void stubBehavior() {
+        reset(mock);
+
+        mock.booleanReturningMethod(1);
+        expectLastCall().andReturn(true).andReturn(false).andReturn(true);
+        mock.booleanReturningMethod(anyInt());
+        expectLastCall().andStubReturn(true);
+
+        replay(mock);
+
+        assertEquals(true, mock.booleanReturningMethod(2));
+        assertEquals(true, mock.booleanReturningMethod(3));
+        assertEquals(true, mock.booleanReturningMethod(1));
+        assertEquals(false, mock.booleanReturningMethod(1));
+        assertEquals(true, mock.booleanReturningMethod(3));
+
+        boolean failed = false;
+        try {
+            verify(mock);
+        } catch (AssertionError expected) {
+            failed = true;
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    booleanReturningMethod(1): expected: 3, actual: 2",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("too few calls accepted");
+        }
+    }
+}
diff --git a/tests/org/easymock/tests2/UsageTest.java b/tests/org/easymock/tests2/UsageTest.java
new file mode 100644
index 0000000..988fb41
--- /dev/null
+++ b/tests/org/easymock/tests2/UsageTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2001-2008 OFFIS, Tammo Freese.
+ * This program is made available under the terms of the MIT License.
+ */
+package org.easymock.tests2;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import org.easymock.tests.IMethods;
+import org.junit.Before;
+import org.junit.Test;
+
+public class UsageTest {
+
+    IMethods mock;
+
+    @Before
+    public void setup() {
+        mock = createMock(IMethods.class);
+    }
+
+    @Test
+    public void exactCallCountByLastCall() {
+        expect(mock.oneArg(false)).andReturn("Test").andReturn("Test2");
+        replay(mock);
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+
+        boolean failed = false;
+        try {
+            mock.oneArg(false);
+        } catch (AssertionError expected) {
+            failed = true;
+        }
+        if (!failed)
+            fail("expected AssertionError");
+    }
+
+    @Test
+    public void openCallCountByLastCall() {
+        expect(mock.oneArg(false)).andReturn("Test").andReturn("Test2")
+                .atLeastOnce();
+
+        replay(mock);
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+    }
+
+    @Test
+    public void exactCallCountByLastThrowable() {
+        expect(mock.oneArg(false)).andReturn("Test").andReturn("Test2")
+                .andThrow(new IndexOutOfBoundsException());
+
+        replay(mock);
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+
+        try {
+            mock.oneArg(false);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+        }
+
+        boolean failed = true;
+        try {
+            mock.oneArg(false);
+            failed = false;
+        } catch (AssertionError expected) {
+        }
+        if (!failed)
+            fail("expected AssertionError");
+    }
+
+    @Test
+    public void openCallCountByLastThrowable() {
+        expect(mock.oneArg(false)).andReturn("Test").andReturn("Test2")
+                .andThrow(new IndexOutOfBoundsException()).atLeastOnce();
+
+        replay(mock);
+
+        assertEquals("Test", mock.oneArg(false));
+        assertEquals("Test2", mock.oneArg(false));
+
+        try {
+            mock.oneArg(false);
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            mock.oneArg(false);
+        } catch (IndexOutOfBoundsException expected) {
+        }
+    }
+
+    @Test
+    public void moreThanOneArgument() {
+        expect(mock.threeArgumentMethod(1, "2", "3")).andReturn("Test")
+                .times(2);
+
+        replay(mock);
+
+        assertEquals("Test", mock.threeArgumentMethod(1, "2", "3"));
+
+        boolean failed = true;
+        try {
+            verify(mock);
+            failed = false;
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Expectation failure on verify:"
+                            + "\n    threeArgumentMethod(1, \"2\", \"3\"): expected: 2, actual: 1",
+                    expected.getMessage());
+        }
+        if (!failed) {
+            fail("exception expected");
+        }
+    }
+
+    @Test
+    public void wrongArguments() {
+        mock.simpleMethodWithArgument("3");
+        replay(mock);
+
+        try {
+            mock.simpleMethodWithArgument("5");
+            fail();
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Unexpected method call simpleMethodWithArgument(\"5\"):"
+                            + "\n    simpleMethodWithArgument(\"3\"): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+
+    }
+
+    @Test
+    public void summarizeSameObjectArguments() {
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("3");
+        replay(mock);
+
+        try {
+            mock.simpleMethodWithArgument("5");
+            fail();
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Unexpected method call simpleMethodWithArgument(\"5\"):"
+                            + "\n    simpleMethodWithArgument(\"3\"): expected: 2, actual: 0",
+                    expected.getMessage());
+        }
+
+    }
+
+    @Test
+    public void argumentsOrdered() {
+        mock.simpleMethodWithArgument("4");
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("2");
+        mock.simpleMethodWithArgument("0");
+        mock.simpleMethodWithArgument("1");
+        replay(mock);
+
+        try {
+            mock.simpleMethodWithArgument("5");
+            fail("exception expected");
+        } catch (AssertionError expected) {
+            assertEquals(
+                    "\n  Unexpected method call simpleMethodWithArgument(\"5\"):"
+                            + "\n    simpleMethodWithArgument(\"4\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"3\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"2\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"0\"): expected: 1, actual: 0"
+                            + "\n    simpleMethodWithArgument(\"1\"): expected: 1, actual: 0",
+                    expected.getMessage());
+        }
+
+    }
+
+    @Test
+    public void mixingOrderedAndUnordered() {
+        mock.simpleMethodWithArgument("2");
+        mock.simpleMethodWithArgument("1");
+        checkOrder(mock, true);
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("4");
+        checkOrder(mock, false);
+        mock.simpleMethodWithArgument("6");
+        mock.simpleMethodWithArgument("7");
+        mock.simpleMethodWithArgument("5");
+
+        replay(mock);
+
+        mock.simpleMethodWithArgument("1");
+        mock.simpleMethodWithArgument("2");
+
+        boolean failed = false;
+        try {
+            mock.simpleMethodWithArgument("4");
+        } catch (AssertionError e) {
+            failed = true;
+        }
+        if (!failed) {
+            fail();
+        }
+
+        mock.simpleMethodWithArgument("3");
+        mock.simpleMethodWithArgument("4");
+        mock.simpleMethodWithArgument("5");
+        mock.simpleMethodWithArgument("6");
+        mock.simpleMethodWithArgument("7");
+
+        verify(mock);
+
+    }
+
+    @Test
+    public void resumeIfFailure() {
+        IMethods mock = createMock(IMethods.class);
+        expect(mock.oneArg(true)).andReturn("foo").anyTimes();
+        replay(mock);
+
+        mock.oneArg(true);
+
+        try {
+            mock.simpleMethod();
+        } catch (AssertionError error) {
+        }
+
+        mock.oneArg(true);
+
+        verify(mock);
+    }
+
+    @Test
+    public void defaultResetToNice() {
+        IMethods mock = createMock(IMethods.class);
+
+        expect(mock.oneArg(true)).andReturn("foo");
+        replay(mock);
+
+        resetToNice(mock);
+
+        replay(mock);
+
+        assertNull(mock.oneArg(true));
+
+        verify(mock);
+    }
+
+    @Test
+    public void strictResetToDefault() {
+        IMethods mock = createStrictMock(IMethods.class);
+
+        expect(mock.oneArg(true)).andReturn("foo");
+        expect(mock.oneArg(false)).andReturn("foo");
+        
+        replay(mock);
+
+        resetToDefault(mock);
+        
+        expect(mock.oneArg(false)).andReturn("foo");
+        expect(mock.oneArg(true)).andReturn("foo");
+
+        replay(mock);
+        
+        assertEquals("foo", mock.oneArg(false));
+        assertEquals("foo", mock.oneArg(true));
+
+        verify(mock);
+    }
+
+    @Test
+    public void niceToStrict() {
+        IMethods mock = createNiceMock(IMethods.class);
+
+        expect(mock.oneArg(false)).andReturn("foo");
+        
+        replay(mock);
+        
+        assertNull(mock.oneArg(true));
+
+        resetToStrict(mock);
+        
+        expect(mock.oneArg(false)).andReturn("foo");
+        expect(mock.oneArg(true)).andReturn("foo");
+
+        replay(mock);
+        
+        try {
+            mock.oneArg(true);
+            fail();
+        }
+        catch(AssertionError e) {            
+        }
+        
+        assertEquals("foo", mock.oneArg(false));
+        assertEquals("foo", mock.oneArg(true));
+
+        verify(mock);
+    }
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/easymock.git



More information about the pkg-java-commits mailing list