summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis Sigal <luissigal@google.com>2011-02-24 17:22:33 +0000
committerLuis Sigal <luissigal@google.com>2011-02-24 19:37:22 +0000
commit8da3e6ec64b991f5aa1e6561941d130683eba753 (patch)
treeaccbe7584ca1f0c14d0d28b2083abd3a5d5b14d0
parentf80b03ef62a5afecdaf17e8ac9f05aa3ed21307b (diff)
downloadandroid_external_android-mock-8da3e6ec64b991f5aa1e6561941d130683eba753.tar.gz
android_external_android-mock-8da3e6ec64b991f5aa1e6561941d130683eba753.tar.bz2
android_external_android-mock-8da3e6ec64b991f5aa1e6561941d130683eba753.zip
Add android-mock to external
Android mock is used by QuickSearchBox to mock classes instead of creating tons of interfaces. Change-Id: Ib53ca3a6c5e8e27f42b66cc9e39bbf0d55ed2170
-rw-r--r--Android.mk41
-rw-r--r--HOWTO.txt1
-rw-r--r--LICENSE.txt202
-rw-r--r--build.properties8
-rw-r--r--build.xml108
-rw-r--r--livetests/com/google/android/testing/mocking/test/AndroidManifest.xml30
-rw-r--r--livetests/com/google/android/testing/mocking/test/MockingTest.java62
-rw-r--r--livetests/com/google/android/testing/mocking/test/res/layout/main.xml13
-rw-r--r--livetests/com/google/android/testing/mocking/test/res/values/strings.xml5
-rw-r--r--livetests/com/google/android/testing/mocking/testapp/AndroidManifest.xml33
-rw-r--r--livetests/com/google/android/testing/mocking/testapp/ClassToMock.java31
-rw-r--r--livetests/com/google/android/testing/mocking/testapp/TestAppActivity.java36
-rw-r--r--livetests/com/google/android/testing/mocking/testapp/res/layout/main.xml13
-rw-r--r--livetests/com/google/android/testing/mocking/testapp/res/values/strings.xml5
-rw-r--r--regenerate_from_source.sh17
-rw-r--r--src/build-framework-gen.xml66
-rw-r--r--src/build-mockgen.xml82
-rw-r--r--src/build-runtime.xml55
-rw-r--r--src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java170
-rw-r--r--src/com/google/android/testing/mocking/AndroidMock.java2804
-rw-r--r--src/com/google/android/testing/mocking/AndroidMockGenerator.java480
-rw-r--r--src/com/google/android/testing/mocking/FileUtils.java77
-rw-r--r--src/com/google/android/testing/mocking/GeneratedClassFile.java54
-rw-r--r--src/com/google/android/testing/mocking/GeneratedMockJar.readme32
-rw-r--r--src/com/google/android/testing/mocking/MockObject.java32
-rw-r--r--src/com/google/android/testing/mocking/ProcessorLogger.java106
-rw-r--r--src/com/google/android/testing/mocking/SdkVersion.java106
-rw-r--r--src/com/google/android/testing/mocking/UsesMocks.java33
-rw-r--r--src/com/google/android/testing/mocking/UsesMocksProcessor.java240
-rw-r--r--tests/com/google/android/testing/mocking/AndroidFrameworkMockGeneratorTest.java165
-rw-r--r--tests/com/google/android/testing/mocking/AndroidMockGeneratorTest.java575
-rw-r--r--tests/com/google/android/testing/mocking/AndroidMockTest.java927
-rw-r--r--tests/com/google/android/testing/mocking/ClassDoesWorkInConstructor.java77
-rw-r--r--tests/com/google/android/testing/mocking/ClassHasDelegateMethods.java38
-rw-r--r--tests/com/google/android/testing/mocking/ClassHasFinalMethods.java35
-rw-r--r--tests/com/google/android/testing/mocking/ClassHasNoDefaultConstructor.java31
-rw-r--r--tests/com/google/android/testing/mocking/ClassHasNoPublicConstructors.java27
-rw-r--r--tests/com/google/android/testing/mocking/ClassHasOverloadedMethods.java30
-rw-r--r--tests/com/google/android/testing/mocking/ClassHasStaticMethods.java31
-rw-r--r--tests/com/google/android/testing/mocking/ClassIsAnnotation.java25
-rw-r--r--tests/com/google/android/testing/mocking/ClassIsEnum.java25
-rw-r--r--tests/com/google/android/testing/mocking/ClassIsFinal.java27
-rw-r--r--tests/com/google/android/testing/mocking/ClassIsInterface.java25
-rw-r--r--tests/com/google/android/testing/mocking/ClassTypeTests.java269
-rw-r--r--tests/com/google/android/testing/mocking/ConstructorCreationTests.java131
-rw-r--r--tests/com/google/android/testing/mocking/FileUtilsTest.java70
-rw-r--r--tests/com/google/android/testing/mocking/SdkVersionTest.java75
-rw-r--r--tests/com/google/android/testing/mocking/UsesMocksProcessorTest.java275
48 files changed, 7800 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..6734347
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := 8
+LOCAL_STATIC_JAVA_LIBRARIES := easymocklib
+LOCAL_MODULE := android-mock-runtimelib
+LOCAL_MOCKING_PATH := src/com/google/android/testing/mocking/
+LOCAL_SRC_FILES := \
+ $(LOCAL_MOCKING_PATH)/AndroidMock.java \
+ $(LOCAL_MOCKING_PATH)/SdkVersion.java \
+ $(LOCAL_MOCKING_PATH)/FileUtils.java \
+ $(LOCAL_MOCKING_PATH)/GeneratedClassFile.java \
+ $(LOCAL_MOCKING_PATH)/MockObject.java \
+ $(LOCAL_MOCKING_PATH)/UsesMocks.java
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := android-mock-generatorlib
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := easymock javassist
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/HOWTO.txt b/HOWTO.txt
new file mode 100644
index 0000000..3821d83
--- /dev/null
+++ b/HOWTO.txt
@@ -0,0 +1 @@
+This is a copy from the android mock project, http://code.google.com/p/android-mock/. To regenerate, use the regenerate_from_source.sh; full instructions about this script are there.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..75b5248
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/build.properties b/build.properties
new file mode 100644
index 0000000..2e10482
--- /dev/null
+++ b/build.properties
@@ -0,0 +1,8 @@
+easymock-jar=easymock.jar
+framework.mock-bin=bin
+framework.mock-jar=android_framework_mocks.jar
+java-package=com/google/android/testing/mocking
+javassist-jar=javassist.jar
+lib-folder=lib
+source-base=src
+staging=staging
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..bad7e25
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Android Mock" default="all-tests" basedir=".">
+ <description>
+Android Mock is a wrapper for EasyMock (2.4) which allows for real Class mocking on
+an Android (Dalvik) VM.
+
+All methods on Android Mock are syntactically equivalent to EasyMock method
+calls, and will delegate calls to EasyMock, while performing the required
+transformations to avoid Dalvik VM troubles.
+
+Calls directly to EasyMock will work correctly only if the Class being mocked
+is in fact an Interface. Calls to Android Mock will work correctly for both
+Interfaces and concrete Classes.
+
+Android Mock requires that the code being mocked be instrumented prior to
+loading to the Dalvik VM by having called the MockGenerator.jar file. Try
+running java -jar MockGenerator.jar --help for more information.
+ </description>
+
+ <!-- Global Build Properties -->
+ <property file="build.properties"/>
+
+ <!-- Imports -->
+ <import file="src/build-runtime.xml"/>
+ <import file="src/build-mockgen.xml"/>
+ <import file="src/build-framework-gen.xml"/>
+
+ <!-- Android Mock Source Jar Properties -->
+ <property name="source-bin" value="bin/source"/>
+ <property name="source-lib-jar" value="AndroidMock-src.jar"/>
+
+ <!-- Android Mock Test Properties -->
+ <property name="junit-jar" value="junit.jar"/>
+ <property name="test-bin" value="bin/tests"/>
+ <property name="test-results-folder" value="${test-bin}/results"/>
+ <property name="test-source-base" value="tests"/>
+
+ <!-- Classpaths -->
+ <path id="tests.path">
+ <pathelement location="${lib-folder}/${easymock-jar}"/>
+ <pathelement location="${lib-folder}/${javassist-jar}"/>
+ <pathelement location="${runtime.bin}/${runtime.deploy-jar}"/>
+ <pathelement location="${mockgen.bin}/${mockgen.deploy-jar}"/>
+ <pathelement location="${lib-folder}/${junit-jar}"/>
+ </path>
+
+ <!-- Private Build Targets -->
+ <target name="-dirs">
+ <mkdir dir="${source-bin}"/>
+ <mkdir dir="${test-bin}"/>
+ <mkdir dir="${staging}"/>
+ <mkdir dir="${test-results-folder}"/>
+ </target>
+
+ <target name="-clean-staging">
+ <delete dir="${staging}"/>
+ </target>
+
+ <!-- Public Build Targets -->
+ <target name="clean" depends="-clean-staging,mockgen.clean,runtime.clean">
+ <delete dir="${source-bin}"/>
+ <delete dir="${framework-mock-staging}"/>
+ <delete dir="${test-results-folder}" failonerror="false"/>
+ <delete dir="${test-bin}" failonerror="false"/>
+ </target>
+
+ <target name="build-dist"
+ depends="mockgen.build-deploy, runtime.build-deploy, build-source-lib"/>
+
+ <target name="build-source-lib" depends="-dirs"
+ description="Builds a jar file containing the Android Mock source files (no dependencies)">
+ <jar destfile="${source-bin}/${source-lib-jar}" basedir="${source-base}" includes="**/*.java"/>
+ </target>
+
+ <!-- Public Test Targets -->
+ <target name="all-tests" depends="-test-base"
+ description="Builds the full distribution package and runs all tests storing results in ${test-results-folder}">
+ <junit printsummary="no" showoutput="no" reloading="false" failureproperty="testsFailed">
+ <formatter type="xml"/>
+ <classpath location="${test-bin}"/>
+ <classpath refid="tests.path"/>
+ <batchtest todir="${test-results-folder}">
+ <fileset dir="${test-bin}">
+ <include name="**/*Test.class"/>
+ <include name="**/*Tests.class"/>
+ </fileset>
+ </batchtest>
+ </junit>
+ <echo>Test Results are available in ${test-results-folder}</echo>
+ <junitreport todir="${test-results-folder}">
+ <fileset dir="${test-results-folder}">
+ <include name="TEST-*.xml"/>
+ </fileset>
+ <report format="frames" todir="${test-results-folder}/html"/>
+ </junitreport>
+ <fail if="testsFailed" message="Tests failed"/>
+ </target>
+
+ <!-- Private Test Targets -->
+ <target name="-test-base" depends="build-dist">
+ <javac destdir="${test-bin}" target="1.5" srcdir="${test-source-base}"
+ debug="true" >
+ <compilerarg value="-proc:none"/>
+ <classpath refid="tests.path"/>
+ </javac>
+ </target>
+
+</project>
diff --git a/livetests/com/google/android/testing/mocking/test/AndroidManifest.xml b/livetests/com/google/android/testing/mocking/test/AndroidManifest.xml
new file mode 100644
index 0000000..a35c31e
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/test/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<!--
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.testing.mocking.test"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:label="@string/app_name">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <uses-sdk android:minSdkVersion="3"/>
+ <instrumentation android:targetPackage="com.google.android.testing.mocking.test"
+ android:name="android.test.InstrumentationTestRunner" />
+</manifest>
+
diff --git a/livetests/com/google/android/testing/mocking/test/MockingTest.java b/livetests/com/google/android/testing/mocking/test/MockingTest.java
new file mode 100644
index 0000000..ee527a9
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/test/MockingTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking.test;
+
+import android.content.Context;
+
+import com.google.android.testing.mocking.AndroidMock;
+import com.google.android.testing.mocking.SdkVersion;
+import com.google.android.testing.mocking.UsesMocks;
+import com.google.android.testing.mocking.testapp.ClassToMock;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that Android Mock provides correct mocks when running on a Dalvik VM.
+ *
+ * @author swoodward (Stephen Woodward)
+ */
+public class MockingTest extends TestCase {
+ /**
+ * Test that an SDK class is mocked correctly, that is to say the mock
+ * comes from the pre-generated set, and it corresponds to the correct
+ * runtime environment
+ */
+ @UsesMocks(Context.class)
+ public void testFrameworkMock() {
+ Context mockContext = AndroidMock.createMock(Context.class);
+ String packageName = mockContext.getClass().getPackage().getName();
+ assertEquals(SdkVersion.getCurrentVersion().getPackagePrefix(),
+ packageName.substring(0, packageName.indexOf('.') + 1));
+ }
+
+ /**
+ * Test that a non-SDK class is mocked correctly
+ */
+ @UsesMocks(ClassToMock.class)
+ public void testNormalMock() {
+ ClassToMock myMockClass = AndroidMock.createMock(ClassToMock.class);
+ AndroidMock.expect(myMockClass.getString()).andReturn(
+ "I'm the king of the world, king of the -- d'oh!");
+ AndroidMock.expect(myMockClass.getInt()).andReturn(42);
+ AndroidMock.replay(myMockClass);
+ assertEquals("I'm the king of the world, king of the -- d'oh!",
+ myMockClass.getString());
+ assertEquals(42, myMockClass.getInt());
+ AndroidMock.verify(myMockClass);
+ }
+}
+
diff --git a/livetests/com/google/android/testing/mocking/test/res/layout/main.xml b/livetests/com/google/android/testing/mocking/test/res/layout/main.xml
new file mode 100644
index 0000000..c1fe411
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/test/res/layout/main.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+<TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/hello"
+ />
+</LinearLayout>
+
diff --git a/livetests/com/google/android/testing/mocking/test/res/values/strings.xml b/livetests/com/google/android/testing/mocking/test/res/values/strings.xml
new file mode 100644
index 0000000..224fc4a
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/test/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="hello">Hello World!</string>
+ <string name="app_name">AndroidMockTestAppTest</string>
+</resources>
diff --git a/livetests/com/google/android/testing/mocking/testapp/AndroidManifest.xml b/livetests/com/google/android/testing/mocking/testapp/AndroidManifest.xml
new file mode 100644
index 0000000..02fdb20
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/testapp/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<!--
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.testing.mocking.testapp"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:label="@string/app_name">
+ <activity android:name=".TestAppActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ <uses-sdk android:minSdkVersion="3" />
+</manifest>
diff --git a/livetests/com/google/android/testing/mocking/testapp/ClassToMock.java b/livetests/com/google/android/testing/mocking/testapp/ClassToMock.java
new file mode 100644
index 0000000..8c51220
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/testapp/ClassToMock.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking.testapp;
+
+/**
+ * Dummy class to be mocked.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassToMock {
+ public String getString() {
+ return "foo";
+ }
+
+ public int getInt() {
+ return -1;
+ }
+}
diff --git a/livetests/com/google/android/testing/mocking/testapp/TestAppActivity.java b/livetests/com/google/android/testing/mocking/testapp/TestAppActivity.java
new file mode 100644
index 0000000..c1d6756
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/testapp/TestAppActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking.testapp;
+
+import com.google.android.testing.mocking.testapp.R;
+import com.google.android.testing.mocking.testapp.R.layout;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Extremely simple Activity to give our Mocking Test something to test.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class TestAppActivity extends Activity {
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+}
diff --git a/livetests/com/google/android/testing/mocking/testapp/res/layout/main.xml b/livetests/com/google/android/testing/mocking/testapp/res/layout/main.xml
new file mode 100644
index 0000000..c1fe411
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/testapp/res/layout/main.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+<TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/hello"
+ />
+</LinearLayout>
+
diff --git a/livetests/com/google/android/testing/mocking/testapp/res/values/strings.xml b/livetests/com/google/android/testing/mocking/testapp/res/values/strings.xml
new file mode 100644
index 0000000..e53d336
--- /dev/null
+++ b/livetests/com/google/android/testing/mocking/testapp/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="hello">Hello World, TestAppActivity!</string>
+ <string name="app_name">AndroidMockTestApp</string>
+</resources>
diff --git a/regenerate_from_source.sh b/regenerate_from_source.sh
new file mode 100644
index 0000000..0dacd87
--- /dev/null
+++ b/regenerate_from_source.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright (C) 2011 The Android Open Source Project.
+# This script imports the src, test, etc. from android-mock It DOESN'T commit
+# to git giving you a chance to review the changes. Remember that changes in
+# bin are normally ignored by git, but we need to force them this case.
+# This script doesn't take any parameter.
+
+svn export --force http://android-mock.googlecode.com/svn/trunk/ .
+rm lib/easymock.jar
+rm lib/junit.jar
+rm lib/javassist.jar
+rm lib/android/*
+# I don't check if there is something on lib on purpose; that way, if
+# anything new is added, we will get a visible error.
+rmdir lib/android
+rmdir lib
diff --git a/src/build-framework-gen.xml b/src/build-framework-gen.xml
new file mode 100644
index 0000000..c23ba7e
--- /dev/null
+++ b/src/build-framework-gen.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="AndroidMockGenerator" default="frameworkgen.build" basedir="..">
+ <!-- Global Properties -->
+ <property file="../build.properties"/>
+
+ <!-- Imports -->
+ <import file="build-mockgen.xml"/>
+
+ <!-- Android Framework Mockgen Properties -->
+ <property name="android-lib-folder" value="${lib-folder}/android"/>
+ <property name="framework.mock-staging" value="staging/android_framework_mocks"/>
+ <property name="android-15-jar" value="android_v15.jar"/>
+ <property name="android-16-jar" value="android_v16.jar"/>
+ <property name="android-201-jar" value="android_v201.jar"/>
+ <property name="android-21-jar" value="android_v21.jar"/>
+ <property name="android-22-jar" value="android_v22.jar"/>
+
+ <!-- property name="framework.mock-bin" value=see build.properties -->
+ <!-- property name="framework.mock-jar" value=see build.properties -->
+
+ <!-- Private Targets -->
+ <target name="-frameworkgen.dirs">
+ <mkdir dir="${framework.mock-bin}"/>
+ <mkdir dir="${framework.mock-staging}"/>
+ </target>
+
+ <target name="-frameworkgen.clean-staging">
+ <delete dir="${staging}"/>
+ </target>
+
+ <!-- Public Targets -->
+ <target name="frameworkgen.clean" depends="-frameworkgen.clean-staging">
+ <delete dir="${framework.mock-bin}/${framework.mock-jar}"/>
+ <delete dir="${framework.mock-staging}"/>
+ </target>
+
+ <target name="frameworkgen.build"
+ depends="-frameworkgen.clean-staging,-frameworkgen.dirs,mockgen.build-deploy"
+ description="Builds the mock support files for mocking Android Framework classes.">
+
+ <generate-framework-mocks api-jar-file="${android-15-jar}" api-level="3"/>
+ <generate-framework-mocks api-jar-file="${android-16-jar}" api-level="4"/>
+ <generate-framework-mocks api-jar-file="${android-201-jar}" api-level="6"/>
+ <generate-framework-mocks api-jar-file="${android-21-jar}" api-level="7"/>
+ <generate-framework-mocks api-jar-file="${android-22-jar}" api-level="8"/>
+ <jar destfile="${framework.mock-bin}/${framework.mock-jar}"
+ basedir="${framework.mock-staging}" includes="**/*.class" index="true"/>
+ </target>
+
+ <!-- Macros -->
+ <macrodef name="generate-framework-mocks">
+ <attribute name="api-jar-file"/>
+ <attribute name="api-level"/>
+ <sequential>
+ <java classname="com.google.android.testing.mocking.AndroidFrameworkMockGenerator" fork="true">
+ <classpath>
+ <pathelement location="${mockgen.bin}/${mockgen.deploy-jar}"/>
+ <pathelement location="${android-lib-folder}/@{api-jar-file}"/>
+ </classpath>
+ <arg value="${framework.mock-staging}"/>
+ <arg value="@{api-level}"/>
+ </java>
+ </sequential>
+ </macrodef>
+
+</project> \ No newline at end of file
diff --git a/src/build-mockgen.xml b/src/build-mockgen.xml
new file mode 100644
index 0000000..3a9a9c4
--- /dev/null
+++ b/src/build-mockgen.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="AndroidMockGenerator" default="mockgen.build" basedir="..">
+ <!-- Global Properties -->
+ <property file="../build.properties"/>
+
+ <!-- Android Mock Generator Properties -->
+ <property name="mockgen.bin" value="bin"/>
+ <property name="mockgen.class-bin" value="bin/classes"/>
+ <property name="mockgen.deploy-jar" value="AndroidMockGenerator.jar"/>
+ <property name="mockgen.includes" value="${java-package}/GeneratedMockJar.readme"/>
+ <property name="mockgen.java-files" value="com/google/android/testing/mocking/*.java"/>
+ <property name="mockgen.nodeps-jar" value="AndroidMockGenerator-nodeps.jar"/>
+ <property name="meta-service-folder" value="META-INF/services"/>
+ <property name="annotations-meta-file"
+ value="${meta-service-folder}/javax.annotation.processing.Processor"/>
+
+ <!-- Classpaths -->
+ <path id="generator.path">
+ <pathelement location="${lib-folder}/${easymock-jar}"/>
+ <pathelement location="${lib-folder}/${javassist-jar}"/>
+ </path>
+
+ <!-- Private Targets -->
+ <target name="-mockgen.dirs">
+ <mkdir dir="${mockgen.bin}"/>
+ <mkdir dir="${mockgen.class-bin}"/>
+ <mkdir dir="${mockgen.class-bin}/${meta-service-folder}"/>
+ </target>
+
+ <target name="-mockgen.clean-staging">
+ <delete dir="${staging}"/>
+ </target>
+
+ <!-- Public Targets -->
+ <target name="mockgen.clean" depends="-mockgen.clean-staging">
+ <delete file="${mockgen.deploy-jar}"/>
+ <delete file="${mockgen.nodeps-jar}"/>
+ <delete dir="${mockgen.class-bin}"/>
+ </target>
+
+ <target name="mockgen.build" depends="-mockgen.clean-staging,-mockgen.dirs"
+ description="Builds the Mock Generator jar file">
+ <javac destdir="${mockgen.class-bin}" srcdir="${source-base}"
+ includes="${mockgen.java-files}" debug="true">
+ <classpath refid="generator.path"/>
+ </javac>
+ <copy todir="${mockgen.class-bin}">
+ <fileset dir="${source-base}" includes="${mockgen.includes}"/>
+ </copy>
+ <echo file="${mockgen.class-bin}/${annotations-meta-file}"
+ message="com.google.android.testing.mocking.UsesMocksProcessor"/>
+ <manifestclasspath property="frameworkjar.classpath"
+ jarfile="${mockgen.bin}/${mockgen.nodeps-jar}">
+ <classpath location="${framework.mock-bin}/${framework.mock-jar}"/>
+ </manifestclasspath>
+ <tstamp>
+ <format property="build.time" pattern="dd-MMMM-yyyy hh:mm aa"/>
+ </tstamp>
+ <jar destfile="${mockgen.bin}/${mockgen.nodeps-jar}" basedir="${mockgen.class-bin}">
+ <manifest>
+ <attribute name="Built-On" value="${build.time}"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="mockgen.build-deploy" depends="mockgen.build"
+ description="Builds the Mock Generator jar file with dependencies included.">
+ <unjar dest="${staging}">
+ <fileset dir=".">
+ <include name="${mockgen.bin}/${mockgen.nodeps-jar}"/>
+ <include name="${lib-folder}/${easymock-jar}"/>
+ <include name="${lib-folder}/${javassist-jar}"/>
+ </fileset>
+ </unjar>
+ <tstamp/>
+ <jar destfile="${mockgen.bin}/${mockgen.deploy-jar}" basedir="${staging}">
+ <manifest>
+ <attribute name="Built-On" value="${build.time}"/>
+ </manifest>
+ </jar>
+ </target>
+</project> \ No newline at end of file
diff --git a/src/build-runtime.xml b/src/build-runtime.xml
new file mode 100644
index 0000000..5516985
--- /dev/null
+++ b/src/build-runtime.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="AndroidMockRuntime" default="runtime.build" basedir="..">
+ <!-- Global Properties -->
+ <property file="../build.properties"/>
+
+ <!-- Android Mock Runtime Properties -->
+ <property name="runtime.bin" value="bin"/>
+ <property name="runtime.class-bin" value="bin/classes"/>
+ <property name="runtime.deploy-jar" value="AndroidMockRuntime.jar"/>
+ <property name="runtime.java-files" value="${java-package}/AndroidMock.java
+ ${java-package}/MockObject.java ${java-package}/UsesMocks.java"/>
+ <property name="runtime.nodeps-jar" value="AndroidMockRuntime-nodeps.jar"/>
+
+ <!-- Classpaths -->
+ <path id="path">
+ <pathelement location="${lib-folder}/${easymock-jar}"/>
+ </path>
+
+ <!-- Private Build Targets -->
+ <target name="-runtime.dirs">
+ <mkdir dir="${runtime.bin}"/>
+ <mkdir dir="${runtime.class-bin}"/>
+ </target>
+
+ <target name="-runtime.clean-staging">
+ <delete dir="${staging}"/>
+ </target>
+
+ <!-- Public Build Targets -->
+ <target name="runtime.clean" depends="-runtime.clean-staging">
+ <delete file="${runtime.deploy-jar}"/>
+ <delete file="${runtime.nodeps-jar}"/>
+ <delete dir="${runtime.class-bin}"/>
+ </target>
+
+ <target name="runtime.build" depends="-runtime.clean-staging,-runtime.dirs"
+ description="Builds the Android Mock Runtime library jar file without dependencies included.">
+ <javac destdir="${runtime.class-bin}" target="1.5" srcdir="${source-base}"
+ includes="${runtime.java-files}" debug="true">
+ <classpath refid="path"/>
+ </javac>
+ <jar destfile="${runtime.bin}/${runtime.nodeps-jar}" basedir="${runtime.class-bin}"/>
+ </target>
+
+ <target name="runtime.build-deploy" depends="runtime.build"
+ description="Builds the Android Mock Runtime library jar file with dependencies included.">
+ <unjar dest="${staging}">
+ <fileset dir=".">
+ <include name="${runtime.bin}/${runtime.nodeps-jar}"/>
+ <include name="${lib-folder}/${easymock-jar}"/>
+ </fileset>
+ </unjar>
+ <jar destfile="${runtime.bin}/${runtime.deploy-jar}" basedir="${staging}"/>
+ </target>
+</project> \ No newline at end of file
diff --git a/src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java b/src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java
new file mode 100644
index 0000000..d634c24
--- /dev/null
+++ b/src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.NotFoundException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Mock Generator for Android Framework classes.
+ *
+ * <p>
+ * This class will pull pre-defined mocks for Android framework classes. This is
+ * needed because a project might build against version X and then run against
+ * version Y, where the specification of the class being mocked will have
+ * changed, rendering the mock invalid.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class AndroidFrameworkMockGenerator {
+ private static final String LIB_FOLDER = "lib";
+ private static final String JAR_NAME = "android_";
+
+ /**
+ * Returns a set of mock support classes for the specified Class for all versions of
+ * the Android SDK. If the requested class is not part of the Android framework, then the class
+ * will not be found and an exception will be thrown.
+ *
+ * @param clazz the class to mock.
+ * @return All available mock support classes (for all known Android SDKs) for
+ * the requested Class.
+ */
+ public List<GeneratedClassFile> getMocksForClass(Class<?> clazz) throws ClassNotFoundException,
+ IOException {
+ List<Class<?>> prebuiltClasses = getPrebuiltClassesFor(clazz);
+ List<GeneratedClassFile> classList = new ArrayList<GeneratedClassFile>();
+ for (Class<?> prebuiltClass : prebuiltClasses) {
+ try {
+ CtClass ctClass = AndroidMockGenerator.getClassPool().get(prebuiltClass.getName());
+ classList.add(new GeneratedClassFile(ctClass.getName(), ctClass.toBytecode()));
+ } catch (NotFoundException e) {
+ throw new ClassNotFoundException("Missing class while fetching prebuilt mocks: "
+ + prebuiltClass.getName(), e);
+ } catch (CannotCompileException e) {
+ throw new RuntimeException("Internal Error copying a prebuilt mock: "
+ + prebuiltClass.getName(), e);
+ }
+ }
+ return classList;
+ }
+
+ private List<Class<?>> getPrebuiltClassesFor(Class<?> clazz) throws ClassNotFoundException {
+ List<Class<?>> classes = new ArrayList<Class<?>>();
+ SdkVersion[] versions = SdkVersion.getAllVersions();
+ for (SdkVersion sdkVersion : versions) {
+ classes.add(Class.forName(FileUtils.getSubclassNameFor(clazz, sdkVersion)));
+ classes.add(Class.forName(FileUtils.getInterfaceNameFor(clazz, sdkVersion)));
+ }
+ return classes;
+ }
+
+ /**
+ * @return a List of {@link GeneratedClassFile} objects representing the mocks for the specified
+ * class for a single version of the Android SDK.
+ */
+ public List<GeneratedClassFile> createMocksForClass(Class<?> clazz, SdkVersion version)
+ throws ClassNotFoundException, IOException, CannotCompileException {
+ AndroidMockGenerator mockGenerator = new AndroidMockGenerator();
+ List<GeneratedClassFile> mocks = new ArrayList<GeneratedClassFile>();
+ mocks.addAll(mockGenerator.createMocksForClass(clazz, version));
+ return mocks;
+ }
+
+ /**
+ * @return A list of all class files inside the provided jar file.
+ */
+ List<Class<?>> getClassList(JarFile jar) throws ClassNotFoundException {
+ return getClassList(Collections.list(jar.entries()));
+ }
+
+ List<Class<?>> getClassList(Collection<JarEntry> jarEntries) throws ClassNotFoundException {
+ List<Class<?>> classList = new ArrayList<Class<?>>();
+ for (JarEntry jarEntry : jarEntries) {
+ if (jarEntryIsClassFile(jarEntry)) {
+ classList.add(Class.forName(FileUtils.getClassNameFor(jarEntry.getName())));
+ }
+ }
+ return classList;
+ }
+
+ /**
+ * @return true if the provided JarEntry represents a class file.
+ */
+ boolean jarEntryIsClassFile(JarEntry jarEntry) {
+ return jarEntry.getName().endsWith(".class");
+ }
+
+ /**
+ * @return the Android framework jar file for the specified {@link SdkVersion}.
+ */
+ static String getJarFileNameForVersion(SdkVersion version) {
+ return new StringBuilder()
+ .append(LIB_FOLDER)
+ .append(File.separator)
+ .append("android")
+ .append(File.separator)
+ .append(JAR_NAME)
+ .append(version.getVersionName())
+ .append(".jar").toString();
+ }
+
+ private static Set<GeneratedClassFile> generateMocks(
+ SdkVersion version, JarFile jar)
+ throws ClassNotFoundException, IOException, CannotCompileException {
+ AndroidFrameworkMockGenerator mockGenerator = new AndroidFrameworkMockGenerator();
+ List<Class<?>> classList = mockGenerator.getClassList(jar);
+ Set<GeneratedClassFile> classes = new HashSet<GeneratedClassFile>();
+ for (Class<?> clazz : classList) {
+ classes.addAll(mockGenerator.createMocksForClass(clazz, version));
+ }
+ return classes;
+ }
+
+ private static JarFile getJarFile(SdkVersion version) throws IOException {
+ File jarFile = new File(getJarFileNameForVersion(version)).getAbsoluteFile();
+ System.out.println("Using Jar File: " + jarFile.getAbsolutePath());
+ return new JarFile(jarFile);
+ }
+
+ public static void main(String[] args) {
+ try {
+ String outputFolderName = args[0];
+ SdkVersion version = SdkVersion.getVersionFor(Integer.parseInt(args[1]));
+ System.out.println("Generating files for " + version.getPackagePrefix());
+
+ JarFile jar = getJarFile(version);
+
+ Set<GeneratedClassFile> classes = generateMocks(version, jar);
+ for (GeneratedClassFile clazz : classes) {
+ FileUtils.saveClassToFolder(clazz, outputFolderName);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Internal error generating framework mocks", e);
+ }
+ }
+}
diff --git a/src/com/google/android/testing/mocking/AndroidMock.java b/src/com/google/android/testing/mocking/AndroidMock.java
new file mode 100644
index 0000000..88f79b1
--- /dev/null
+++ b/src/com/google/android/testing/mocking/AndroidMock.java
@@ -0,0 +1,2804 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IArgumentMatcher;
+import org.easymock.IExpectationSetters;
+import org.easymock.LogicalOperator;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Android Mock is a wrapper for EasyMock (2.4) which allows for real Class mocking on
+ * an Android (Dalvik) VM.
+ *
+ * All methods on Android Mock are syntactically equivalent to EasyMock method
+ * calls, and will delegate calls to EasyMock, while performing the required
+ * transformations to avoid Dalvik VM troubles.
+ *
+ * Calls directly to EasyMock will work correctly only if the Class being mocked
+ * is in fact an Interface. Calls to Android Mock will work correctly for both
+ * Interfaces and concrete Classes.
+ *
+ * Android Mock requires that the code being mocked be instrumented prior to
+ * loading to the Dalvik VM by having called the MockGenerator.jar file. Try
+ * running {@code java -jar MockGenerator.jar --help} for more information.
+ *
+ * An example usage pattern is:
+ *
+ * {@code &#64;UsesMocks(MyClass.class) public void testFoo() &#123; MyClass
+ * mockObject = AndroidMock.createMock(MyClass.class);
+ * AndroidMock.expect(mockObject.foo(0)).andReturn(42);
+ * AndroidMock.replay(mockObject); assertEquals(42, mockObject.foo(0));
+ * AndroidMock.verify(mockObject); &#125; * }
+ *
+ *
+ * <b>A note about parameter and return types for the <i>expects</i> style of methods.</b>
+ * The various expectation methods such as {@link #eq(boolean)}, {@link #and(boolean, boolean)},
+ * and {@link #leq(byte)} all have nonsense return values. Each of the expectation methods may only
+ * be executed under strict conditions (in order to set expectations of incoming method parameters
+ * during record mode) and thus their return types are in fact never used. The return types are set
+ * only to satisfy the compile-time parameter requirements of the methods being mocked in order to
+ * allow code such as: {@code mockObject.doFoo(anyInt());}. If {@link #anyInt()} did not return
+ * {@code int} then the compiler would not accept the preceding code fragment.
+ *
+ * Similarly, the complex expectation methods ({@code #and}, {@code #or}, and {@code not}) take
+ * various parameter types, but will throw an {@link java.lang.IllegalStateException} if anything
+ * other than an expectation method is provided. E.g. {@code mockObject.doFoo(and(gt(5), lt(10));}
+ *
+ * The benefit of this is to make it very easy to read the test code after it has been written.
+ * Additionally, the test code is protected by type safety at compile time.
+ *
+ * The downside of this is that when writing the test code in the record phase, how to use the
+ * expectation APIs is not made clear by the method signatures of these expectation methods. In
+ * particular, it's not at all clear that {@link #and(byte, byte)} takes as parameters other
+ * expectation methods, and not just any random method that returns a {@literal byte} or even a
+ * {@literal byte} literal.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class AndroidMock {
+ private AndroidMock() {
+ }
+
+ /**
+ * Creates a mock object for the specified class, order checking
+ * is enabled by default. The difference between a strict mock and a normal mock is that a strict
+ * mock will not allow for invocations of the mock object to occur other than in the exact order
+ * specified during record mode.
+ *
+ * The parameter {@literal args} allows the caller to choose which constructor on the Class
+ * specified by {@literal toMock} to be called when constructing the Mock object. If a constructor
+ * takes primitive values, Java Auto-boxing/unboxing will take care of it automatically, allowing
+ * the caller to make calls such as {@literal createStrictMock(MyObject.class, 42, "hello!")},
+ * where {@literal MyObject} defines a constructor such as
+ * {@literal public MyObject(int answer, String greeting)}.
+ *
+ * @param <T> the class type to be mocked.
+ * @param toMock the class of the object to be mocked.
+ * @param args the arguments to pass to the constructor.
+ * @return the mock object.
+ */
+ public static <T> T createStrictMock(Class<T> toMock, Object... args) {
+ return createStrictMock(null, toMock, args);
+ }
+
+ /**
+ * Creates a mock object for the specified class, order checking
+ * is enabled by default. The difference between a strict mock and a normal mock is that a strict
+ * mock will not allow for invocations of the mock object to occur other than in the exact order
+ * specified during record mode.
+ *
+ * The parameter {@literal args} allows the caller to choose which constructor on the Class
+ * specified by {@literal toMock} to be called when constructing the Mock object. If a constructor
+ * takes primitive values, Java Auto-boxing/unboxing will take care of it automatically, allowing
+ * the caller to make calls such as
+ * {@literal createStrictMock("NameMyMock", MyObject.class, 42, "hello!")},
+ * where {@literal MyObject} defines a constructor such as
+ * {@literal public MyObject(int answer, String greeting)}.
+ *
+ * @param <T> the class type to be mocked.
+ * @param name the name of the mock object. This must be a valid Java identifier. This value is
+ * used as the return value from {@link #toString()} when invoked on the mock object.
+ * @param toMock the class of the object to be mocked.
+ * @param args the arguments to pass to the constructor.
+ * @return the mock object.
+ * @throws IllegalArgumentException if the name is not a valid Java identifier.
+ */
+ @SuppressWarnings("cast")
+ public static <T> T createStrictMock(String name, Class<T> toMock, Object... args) {
+ if (toMock.isInterface()) {
+ return EasyMock.createStrictMock(name, toMock);
+ }
+ Object mockedInterface = EasyMock.createStrictMock(name, getInterfaceFor(toMock));
+ return (T) getSubclassFor(toMock, getInterfaceFor(toMock), mockedInterface, args);
+ }
+
+ /**
+ * Creates a mock object for the specified class, order checking
+ * is disabled by default. A normal mock with order checking disabled will allow you to record
+ * the method invocations during record mode in any order. If order is important, use
+ * {@link #createStrictMock(Class, Object...)} instead.
+ *
+ * The parameter {@literal args} allows the caller to choose which constructor on the Class
+ * specified by {@literal toMock} to be called when constructing the Mock object. If a constructor
+ * takes primitive values, Java Auto-boxing/unboxing will take care of it automatically, allowing
+ * the caller to make calls such as
+ * {@literal createMock(MyObject.class, 42, "hello!")},
+ * where {@literal MyObject} defines a constructor such as
+ * {@literal public MyObject(int answer, String greeting)}.
+ *
+ * @param <T> the type of the class to be mocked.
+ * @param toMock the class object representing the class to be mocked.
+ * @param args the arguments to pass to the constructor.
+ * @return the mock object.
+ */
+ public static <T> T createMock(Class<T> toMock, Object... args) {
+ return createMock(null, toMock, args);
+ }
+
+ /**
+ * Creates a mock object for the specified class, order checking
+ * is disabled by default. A normal mock with order checking disabled will allow you to record
+ * the method invocations during record mode in any order. If order is important, use
+ * {@link #createStrictMock(Class, Object...)} instead.
+ *
+ * The parameter {@literal args} allows the caller to choose which constructor on the Class
+ * specified by {@literal toMock} to be called when constructing the Mock object. If a constructor
+ * takes primitive values, Java Auto-boxing/unboxing will take care of it automatically, allowing
+ * the caller to make calls such as
+ * {@literal createMock("NameMyMock", MyObject.class, 42, "hello!")},
+ * where {@literal MyObject} defines a constructor such as
+ * {@literal public MyObject(int answer, String greeting)}.
+ *
+ * @param <T> the type of the class to be mocked.
+ * @param name the name of the mock object. This must be a valid Java identifier. This value is
+ * used as the return value from {@link #toString()} when invoked on the mock object.
+ * @param toMock the class object representing the class to be mocked.
+ * @param args the arguments to pass to the constructor.
+ * @return the mock object.
+ * @throws IllegalArgumentException if the name is not a valid Java identifier.
+ */
+ @SuppressWarnings("cast")
+ public static <T> T createMock(String name, Class<T> toMock, Object... args) {
+ if (toMock.isInterface()) {
+ return EasyMock.createMock(name, toMock);
+ }
+ Object mockedInterface = EasyMock.createMock(name, getInterfaceFor(toMock));
+ return (T) getSubclassFor(toMock, getInterfaceFor(toMock), mockedInterface, args);
+ }
+
+ /**
+ * Creates a mock object for the specified class, order checking
+ * is disabled by default, and the mock object will return {@code 0},
+ * {@code null} or {@code false} for unexpected invocations.
+ *
+ * The parameter {@literal args} allows the caller to choose which constructor on the Class
+ * specified by {@literal toMock} to be called when constructing the Mock object. If a constructor
+ * takes primitive values, Java Auto-boxing/unboxing will take care of it automatically, allowing
+ * the caller to make calls such as
+ * {@literal createNiceMock(MyObject.class, 42, "hello!")},
+ * where {@literal MyObject} defines a constructor such as
+ * {@literal public MyObject(int answer, String greeting)}.
+ *
+ * @param <T> the type of the class to be mocked.
+ * @param toMock the class object representing the class to be mocked.
+ * @param args the arguments to pass to the constructor.
+ * @return the mock object.
+ */
+ public static <T> T createNiceMock(Class<T> toMock, Object... args) {
+ return createNiceMock(null, toMock, args);
+ }
+
+ /**
+ * Creates a mock object for the specified class, order checking
+ * is disabled by default, and the mock object will return {@code 0},
+ * {@code null} or {@code false} for unexpected invocations.
+ *
+ * The parameter {@literal args} allows the caller to choose which constructor on the Class
+ * specified by {@literal toMock} to be called when constructing the Mock object. If a constructor
+ * takes primitive values, Java Auto-boxing/unboxing will take care of it automatically, allowing
+ * the caller to make calls such as
+ * {@literal createNiceMock("NameMyMock", MyObject.class, 42, "hello!")},
+ * where {@literal MyObject} defines a constructor such as
+ * {@literal public MyObject(int answer, String greeting)}.
+ *
+ * @param <T> the type of the class to be mocked.
+ * @param name the name of the mock object. This must be a valid Java identifier. This value is
+ * used as the return value from {@link #toString()} when invoked on the mock object.
+ * @param toMock the class object representing the class to be mocked.
+ * @param args the arguments to pass to the constructor.
+ * @throws IllegalArgumentException if the name is not a valid Java identifier.
+ */
+ @SuppressWarnings("cast")
+ public static <T> T createNiceMock(String name, Class<T> toMock, Object... args) {
+ if (toMock.isInterface()) {
+ return EasyMock.createNiceMock(name, toMock);
+ }
+ Object mockedInterface = EasyMock.createNiceMock(name, getInterfaceFor(toMock));
+ return (T) getSubclassFor(toMock, getInterfaceFor(toMock), mockedInterface, args);
+ }
+
+ /**
+ * Returns the expectation setter for the last expected invocation in the current thread.
+ * Expectation setters are used during the recording phase to specify what method calls
+ * will be expected during the replay phase, and with which parameters. Parameters may be
+ * specified as literal values (e.g. {@code expect(mock.foo(42)); expect(mock.foo("hello"));})
+ * or according to parameter expectation criteria. Some examples of parameter expectation
+ * criteria include {@link #anyObject()}, {@link #leq(int)}, {@link #contains(String)},
+ * {@link #isA(Class)} and also the more complex {@link #and(char, char)},
+ * {@link #or(boolean, boolean)}, and {@link #not(double)}.
+ *
+ * An {@link org.easymock.IExpectationSetters} object has methods which allow you to define
+ * the expected behaviour of the mocked method and the expected number of invocations,
+ * e.g. {@link org.easymock.IExpectationSetters#andReturn(Object)},
+ * {@link org.easymock.IExpectationSetters#andThrow(Throwable)}, and
+ * {@link org.easymock.IExpectationSetters#atLeastOnce()}.
+ *
+ * @param expectedValue the parameter is used to transport the type to the ExpectationSetter.
+ * It allows writing the expected call as an argument,
+ * e.g. {@code expect(mock.getName()).andReturn("John Doe")}.
+ * @return the expectation setter.
+ */
+ public static <T> IExpectationSetters<T> expect(T expectedValue) {
+ return EasyMock.expect(expectedValue);
+ }
+
+ /**
+ * Returns the expectation setter for the last expected invocation in the
+ * current thread. This method is used for expected invocations on void
+ * methods. Use this for things such as
+ * {@link org.easymock.IExpectationSetters#andThrow(Throwable)}
+ * on void methods.
+ * E.g.
+ * {@code mock.doFoo();
+ * AndroidMock.expectLastCall().andThrow(new IllegalStateException());}
+ *
+ * @see #expect(Object) for more details about {@link org.easymock.IExpectationSetters}
+ * @return the expectation setter.
+ */
+ public static <T> IExpectationSetters<T> expectLastCall() {
+ return EasyMock.expectLastCall();
+ }
+
+ /**
+ * Expects any {@code boolean} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyBoolean())).andReturn("hello world");}
+ *
+ * @return {@code false}. The return value is always ignored.
+ */
+ public static boolean anyBoolean() {
+ return EasyMock.anyBoolean();
+ }
+
+ /**
+ * Expects any {@code byte} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyByte())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte anyByte() {
+ return EasyMock.anyByte();
+ }
+
+ /**
+ * Expects any {@code char} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyChar())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static char anyChar() {
+ return EasyMock.anyChar();
+ }
+
+ /**
+ * Expects any {@code int} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyInt())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int anyInt() {
+ return EasyMock.anyInt();
+ }
+
+ /**
+ * Expects any {@code long} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyLong())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long anyLong() {
+ return EasyMock.anyLong();
+ }
+
+ /**
+ * Expects any {@code float} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyFloat())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float anyFloat() {
+ return EasyMock.anyFloat();
+ }
+
+ /**
+ * Expects any {@code double} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyDouble())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored. */
+ public static double anyDouble() {
+ return EasyMock.anyDouble();
+ }
+
+ /**
+ * Expects any {@code short} argument as a parameter to a mocked method.
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyShort())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored. */
+ public static short anyShort() {
+ return EasyMock.anyShort();
+ }
+
+ /**
+ * Expects any {@code java.lang.Object} (or subclass) argument as a parameter to a mocked method.
+ * Note that this includes Arrays (since an array {@literal is an Object})
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.anyLong())).andReturn("hello world");}
+ *
+ * @return {@code 0}. The return value is always ignored.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T anyObject() {
+ return (T) EasyMock.anyObject();
+ }
+
+ /**
+ * Expects a {@code Comparable} argument greater than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.geq("hi"))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than or equal.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T extends Comparable<T>> T geq(Comparable<T> expectedValue) {
+ return EasyMock.geq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code byte} argument greater than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.geq((byte)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte geq(byte expectedValue) {
+ return EasyMock.geq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code double} argument greater than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.geq(42.0))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double geq(double expectedValue) {
+ return EasyMock.geq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code float} argument greater than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.geq(42.0f))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float geq(float expectedValue) {
+ return EasyMock.geq(expectedValue);
+ }
+
+ /**
+ * Expects an {@code int} argument greater than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.geq(42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int geq(int expectedValue) {
+ return EasyMock.geq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code long} argument greater than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.geq(42l))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long geq(long expectedValue) {
+ return EasyMock.geq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code short} argument greater than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.geq((short)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short geq(short expectedValue) {
+ return EasyMock.geq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code Comparable} argument less than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.leq("hi"))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than or equal.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T extends Comparable<T>> T leq(Comparable<T> expectedValue) {
+ return EasyMock.leq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code byte} argument less than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.leq((byte)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte leq(byte expectedValue) {
+ return EasyMock.leq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code double} argument less than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.leq(42.0))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double leq(double expectedValue) {
+ return EasyMock.leq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code float} argument less than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.leq(42.0f))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float leq(float expectedValue) {
+ return EasyMock.leq(expectedValue);
+ }
+
+ /**
+ * Expects an {@code int} argument less than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.leq(42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int leq(int expectedValue) {
+ return EasyMock.leq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code long} argument less than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.leq(42l))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long leq(long expectedValue) {
+ return EasyMock.leq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code short} argument less than or equal to the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.leq((short)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than or equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short leq(short expectedValue) {
+ return EasyMock.leq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code Comparable} argument greater than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.gt("hi"))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T extends Comparable<T>> T gt(Comparable<T> expectedValue) {
+ return EasyMock.gt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code byte} argument greater than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.gt((byte)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte gt(byte expectedValue) {
+ return EasyMock.gt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code double} argument greater than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.gt(42.0))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double gt(double expectedValue) {
+ return EasyMock.gt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code float} argument greater than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.gt(42.0f))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float gt(float expectedValue) {
+ return EasyMock.gt(expectedValue);
+ }
+
+ /**
+ * Expects an {@code int} argument greater than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.gt(42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int gt(int expectedValue) {
+ return EasyMock.gt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code long} argument greater than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.gt(42l))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long gt(long expectedValue) {
+ return EasyMock.gt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code short} argument greater than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.gt((short)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be greater than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short gt(short expectedValue) {
+ return EasyMock.gt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code Comparable} argument less than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.lt("hi"))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T extends Comparable<T>> T lt(Comparable<T> expectedValue) {
+ return EasyMock.lt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code byte} argument less than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.lt((byte)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte lt(byte expectedValue) {
+ return EasyMock.lt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code double} argument less than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.lt(42.0))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double lt(double expectedValue) {
+ return EasyMock.lt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code float} argument less than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.lt(42.0f))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float lt(float expectedValue) {
+ return EasyMock.lt(expectedValue);
+ }
+
+ /**
+ * Expects an {@code int} argument less than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.lt(42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int lt(int expectedValue) {
+ return EasyMock.lt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code long} argument less than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.lt(42l))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long lt(long expectedValue) {
+ return EasyMock.lt(expectedValue);
+ }
+
+ /**
+ * Expects a {@code short} argument less than the given value as a parameter
+ * to a mocked method.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.lt((short)42))).andReturn("hello");}
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be less than.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short lt(short expectedValue) {
+ return EasyMock.lt(expectedValue);
+ }
+
+ /**
+ * Expects an object implementing the given class as a parameter to a mocked method. During
+ * replay mode, the mocked method call will accept any {@code Object} that is an instance of
+ * the specified class or one of its subclasses. Specifically, any {@code non-null} parameter for
+ * which the {@code java.lang.Class.isAssignableFrom(Class)} will return true will be accepted by
+ * this matcher during the replay phase.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.isA(HashMap.class))).andReturn("hello");}
+ *
+ * @param <T> the expected Class type.
+ * @param clazz the class of the accepted type.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T> T isA(Class<T> clazz) {
+ return EasyMock.isA(clazz);
+ }
+
+ /**
+ * Expects a string that contains the given substring as a parameter to a mocked method.
+ * During replay mode, the mocked method will accept any {@code non-null String} which contains
+ * the provided {@code substring}.
+ *
+ * Use this to loosen the expectations of acceptable parameters for a mocked method call.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.substring("hi"))).andReturn("hello");}
+ *
+ * @param substring the substring which any incoming parameter to the mocked method must contain.
+ * @return {@code null}.
+ */
+ public static String contains(String substring) {
+ return EasyMock.contains(substring);
+ }
+
+ /**
+ * Expects a {@code boolean} parameter that matches both of the provided expectations. During
+ * replay mode, the mocked method will accept any {@code boolean} that matches both of the
+ * provided expectations. Possible expectations for {@code first} and {@code second} include (but
+ * are not limited to) {@link #anyBoolean()} and {@link #eq(boolean)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.and(AndroidMock.anyBoolean(), AndroidMock.eq(true)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(anyBoolean(), eq(true)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code false}. The return value is always ignored.
+ */
+ public static boolean and(boolean first, boolean second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects a {@code byte} parameter that matches both of the provided expectations. During replay
+ * mode, the mocked method will accept any {@code byte} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyByte()}, {@link #leq(byte)} and {@link #eq(byte)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.and(
+ * AndroidMock.gt((byte)0), AndroidMock.lt((byte)42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(gt((byte)0), lt((byte)42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte and(byte first, byte second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects a {@code char} parameter that matches both of the provided expectations. During replay
+ * mode, the mocked method will accept any {@code char} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyChar()} and {@link #eq(char)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.and(AndroidMock.geq('a'), AndroidMock.lt('q')))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(eq('a'), anyChar()))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static char and(char first, char second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects a {@code double} parameter that matches both of the provided expectations. During
+ * replay mode, the mocked method will accept any {@code double} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyDouble()}, {@link #leq(double)} and {@link #eq(double)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.and(AndroidMock.gt(0.0), AndroidMock.lt(42.0)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(gt(0.0), lt(42.0)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double and(double first, double second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects a {@code float} parameter that matches both of the provided expectations. During
+ * replay mode, the mocked method will accept any {@code float} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyFloat()}, {@link #leq(float)} and {@link #eq(float)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.and(AndroidMock.gt(0.0f), AndroidMock.lt(42.0f)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(gt(0.0f), lt(42.0f)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float and(float first, float second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects an {@code int} parameter that matches both of the provided expectations. During
+ * replay mode, the mocked method will accept any {@code int} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyInt()}, {@link #leq(int)} and {@link #eq(int)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.and(AndroidMock.gt(0), AndroidMock.lt(42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(gt(0), lt(42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int and(int first, int second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects a {@code long} parameter that matches both of the provided expectations. During
+ * replay mode, the mocked method will accept any {@code long} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyLong()}, {@link #leq(long)} and {@link #eq(long)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.and(AndroidMock.gt(0l), AndroidMock.lt(42l)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(gt(0l), lt(42l)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long and(long first, long second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects a {@code short} parameter that matches both of the provided expectations. During
+ * replay mode, the mocked method will accept any {@code short} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyShort()}, {@link #leq(short)} and {@link #eq(short)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.and(
+ * AndroidMock.gt((short)0), AndroidMock.lt((short)42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(gt((short)0), lt((short)42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short and(short first, short second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects an {@code Object} parameter that matches both of the provided expectations. During
+ * replay mode, the mocked method will accept any {@code Object} that matches both of the provided
+ * expectations. Possible expectations for {@code first} and {@code second} include (but are not
+ * limited to) {@link #anyObject()}, {@link #isA(Class)} and {@link #contains(String)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.and(
+ * AndroidMock.contains("hi"), AndroidMock.contains("world")))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(contains("hi"), contains("world")))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static <T> T and(T first, T second) {
+ return EasyMock.and(first, second);
+ }
+
+ /**
+ * Expects a {@code boolean} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code boolean} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyBoolean()} and {@link #eq(boolean)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.or(AndroidMock.eq(true), AndroidMock.anyBoolean()))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(and(eq(true), anyBoolean()))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code false}. The return value is always ignored.
+ */
+ public static boolean or(boolean first, boolean second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects a {@code byte} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code byte} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyByte()}, {@link #eq(byte)},
+ * and {@link #lt(byte)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.geq((byte)0), AndroidMock.lt((byte)42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(geq((byte)0), lt((byte)42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte or(byte first, byte second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects a {@code char} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code char} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyChar()} and {@link #eq(char)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.eq('a'), AndroidMock.eq('z')))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(eq('a'), eq('z')))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static char or(char first, char second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects a {@code double} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code double} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyDouble()}, {@link #eq(double)}
+ * and {@link #lt(double)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.eq(0.0), AndroidMock.geq(42.0)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(eq(0.0), geq(42.0)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double or(double first, double second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects a {@code float} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code float} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyFloat()}, {@link #eq(float)}
+ * and {@link #lt(float)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.eq(0.0f), AndroidMock.geq(42.0f)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(eq(0.0f), geq(42.0f)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float or(float first, float second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects an {@code int} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code int} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyInt()}, {@link #eq(int)}
+ * and {@link #lt(int)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.eq(0), AndroidMock.geq(42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(eq(0), geq(42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int or(int first, int second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects a {@code long} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code long} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyLong()}, {@link #eq(long)}
+ * and {@link #lt(long)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.eq(0l), AndroidMock.geq(42l)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(eq(0l), geq(42l)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long or(long first, long second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects a {@code short} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code short} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyShort()}, {@link #eq(short)}
+ * and {@link #lt(short)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.eq((short)0), AndroidMock.geq((short)42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(eq((short)0), geq((short)42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short or(short first, short second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects an {@code Object} parameter that matches one or both of the provided expectations.
+ * During replay mode, the mocked method will accept any {@code Object} that matches one of the
+ * provided expectations, or both of them. Possible expectations for {@code first} and
+ * {@code second} include (but are not limited to) {@link #anyObject()}, {@link #eq(Class)}
+ * and {@link #lt(Comparable)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.or(
+ * AndroidMock.notNull(), AndroidMock.geq(fortyTwo)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(or(notNull(), geq(fortyTwo)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param first the first expectation to test.
+ * @param second the second expectation to test.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T> T or(T first, T second) {
+ return EasyMock.or(first, second);
+ }
+
+ /**
+ * Expects a {@code boolean} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code boolean} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyBoolean()} and {@link #eq(boolean)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq(true)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq(true)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code false}. The return value is always ignored.
+ */
+ public static boolean not(boolean expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code byte} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code byte} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyByte()}, {@link #eq(byte)} and
+ * {@link #lt(byte)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq((byte)42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq((byte)42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static byte not(byte expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code char} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code char} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyChar()} and {@link #eq(char)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq('a')))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq('a')))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static char not(char expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code double} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code double} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyDouble()}, {@link #eq(double)} and
+ * {@link #lt(double)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq(42.0)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq(42.0)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double not(double expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code float} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code float} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyFloat()}, {@link #eq(float)} and
+ * {@link #lt(float)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq(42.0f)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq(42.0f)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float not(float expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code int} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code int} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyInt()}, {@link #eq(int)} and
+ * {@link #lt(int)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq(42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq(42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int not(int expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code long} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code long} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyLong()}, {@link #eq(long)} and
+ * {@link #lt(long)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq(42l)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq(42l)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long not(long expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code short} parameter that does not match the provided expectation.
+ * During replay mode, the mocked method will accept any {@code short} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyShort()}, {@link #eq(short)} and
+ * {@link #lt(short)}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq((short)42)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq((short)42)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short not(short expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects an {@code Object} parameter that does not match the given expectation.
+ * During replay mode, the mocked method will accept any {@code Object} that does not match
+ * the provided expectation. Possible expectations for {@code expectation}
+ * include (but are not limited to) {@link #anyObject()}, {@link #leq(Comparable)} and
+ * {@link #isNull()}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(
+ * AndroidMock.not(AndroidMock.eq(fortyTwo)))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(not(eq(fortyTwo)))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectation the expectation to test.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static <T> T not(T expectation) {
+ return EasyMock.not(expectation);
+ }
+
+ /**
+ * Expects a {@code boolean} parameter that is equal to the provided {@code value}.
+ * During replay mode, the mocked method will accept any {@code boolean} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(true))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(true))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code false}. The return value is always ignored.
+ */
+ public static boolean eq(boolean expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code byte} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code byte} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq((byte)0))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq((byte)0))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code false}. The return value is always ignored.
+ */
+ public static byte eq(byte expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code char} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code char} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq('a'))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq('a'))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static char eq(char expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code double} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code double} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(0.0))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(0.0))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double eq(double expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code float} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code float} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(0.0f))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(0.0f))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float eq(float expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects an {@code int} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code int} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(0))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(0))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int eq(int expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code long} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code long} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(0l))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(0l))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long eq(long expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code short} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code short} that matches the
+ * value of {@code expectedValue}.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq((short)0))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq((short)0))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static short eq(short expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects an {@code Object} parameter that is equal to the provided {@code expectedValue}.
+ * During replay mode, the mocked method will accept any {@code Object} that matches the
+ * value of {@code expectedValue} according to its {@code equals(Object)} method.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq("hi"))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq("hi"))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the value to which the specified incoming parameter to the mocked method
+ * must be equal.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static <T> T eq(T expectedValue) {
+ return EasyMock.eq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code boolean} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myBooleanArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myBooleanArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static boolean[] aryEq(boolean[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code byte} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myByteArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myByteArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static byte[] aryEq(byte[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code char} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myCharArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myCharArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static char[] aryEq(char[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code double} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myDoubleArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myDoubleArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static double[] aryEq(double[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code float} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myFloatrArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myFloatArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static float[] aryEq(float[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects an {@code int} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myIntArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myIntArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static int[] aryEq(int[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code long} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myLongArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myLongArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static long[] aryEq(long[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code short} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myShortArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myShortArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static short[] aryEq(short[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects a {@code Object} array parameter that is equal to the given array, i.e. it has to
+ * have the same length, and each element has to be equal.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mock.getString(AndroidMock.eq(myObjectArray))).andReturn("hello");}
+ *
+ * Or, for illustration purposes (using static imports)
+ *
+ * {@code expect(mock.getString(eq(myObjectArray))).andReturn("hello");}
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param <T> the type of the array, it is passed through to prevent casts.
+ * @param expectedValue the array to which the specified incoming parameter to the mocked method
+ * must have equal contents.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T> T[] aryEq(T[] expectedValue) {
+ return EasyMock.aryEq(expectedValue);
+ }
+
+ /**
+ * Expects any {@code null} Object as a parameter.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @return {@code null}. The return value is always ignored.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T isNull() {
+ return (T) EasyMock.isNull();
+ }
+
+ /**
+ * Expects any {@code non-null} Object parameter.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @return {@code null}. The return value is always ignored.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T notNull() {
+ return (T) EasyMock.notNull();
+ }
+
+ /**
+ * Expects a {@code String} that contains a substring that matches the given regular
+ * expression as a parameter to the mocked method.
+ *
+ * See {@link java.util.regex.Matcher#find()} for more details.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param regex the regular expression which must match some substring of the incoming parameter
+ * to the mocked method.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static String find(String regex) {
+ return EasyMock.find(regex);
+ }
+
+ /**
+ * Expects a {@code String} as a parameter to the mocked method, the entire length of which must
+ * match the given regular expression. This is not to be confused with {@link #find(String)} which
+ * matches the regular expression against any substring of the incoming parameter to the mocked
+ * method.
+ *
+ * See {@link java.util.regex.Matcher#matches()} for more details.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param regex the regular expression against which the entire incoming parameter to the
+ * mocked method must match.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static String matches(String regex) {
+ return EasyMock.matches(regex);
+ }
+
+ /**
+ * Expects a {@code String} as a parameter to the mocked method that starts with the given prefix.
+ *
+ * See {@link java.lang.String#startsWith(String)} for more details.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param prefix the string that is expected to match against the start of any incoming
+ * parameter to the mocked method.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static String startsWith(String prefix) {
+ return EasyMock.startsWith(prefix);
+ }
+
+ /**
+ * Expects a {@code String} as a parameter to the mocked method that ends with the given
+ * {@code suffix}.
+ *
+ * See {@link java.lang.String#startsWith(String)} for more details.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param suffix the string that is expected to match against the end of any incoming
+ * parameter to the mocked method.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static String endsWith(String suffix) {
+ return EasyMock.endsWith(suffix);
+ }
+
+ /**
+ * Expects a {@code double} as a parameter to the mocked method that has an absolute difference to
+ * the given {@code expectedValue} that is less than the given {@code delta}.
+ *
+ * The acceptable range of values is theoretically defined as any value {@code x} which satisfies
+ * the following inequality: {@code expectedValue - delta &lt;= x &lt;= expectedValue + delta}.
+ *
+ * In practice, this is only true when {@code expectedValue + delta} and
+ * {@code expectedValue - delta} fall exactly on a precisely representable {@code double} value.
+ * Normally, the acceptable range of values is defined as any value {@code x} which satisfies the
+ * following inequality:
+ * {@code expectedValue - delta &lt; x &lt; expectedValue + delta}.
+ *
+ * E.g. {@code AndroidMock.expect(mockObject.getString(
+ * AndroidMock.eq(42.0, 0.1))).andReturn("hello world");}
+ *
+ * The code snippet above will expect any {@code double} value greater than 41.9 and
+ * less than 42.1.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the center value of the expected range of values.
+ * @param delta the acceptable level of inaccuracy before this expectation fails.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double eq(double expectedValue, double delta) {
+ return EasyMock.eq(expectedValue, delta);
+ }
+
+ /**
+ * Expects a {@code float} as a parameter to the mocked method that has an absolute difference to
+ * the given {@code expectedValue} that is less than the given {@code delta}.
+ *
+ * The acceptable range of values is theoretically defined as any value {@code x} which satisfies
+ * the following inequality: {@code expectedValue - delta &lt;= x &lt;= expectedValue + delta}.
+ *
+ * In practice, this is only true when {@code expectedValue + delta} and
+ * {@code expectedValue - delta} fall exactly on a precisely representable {@code float} value.
+ * Normally, the acceptable range of values is defined as any value {@code x} which satisfies the
+ * following inequality:
+ * {@code expectedValue - delta &lt; x &lt; expectedValue + delta}.
+ *
+ * E.g. {@code AndroidMock.expect(mockObject.getString(
+ * AndroidMock.eq(42.0f, 0.1f))).andReturn("hello world");}
+ *
+ * The code snippet above will expect any {@code float} value greater than 41.9 and
+ * less than 42.1.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the center value of the expected range of values.
+ * @param delta the acceptable level of inaccuracy before this expectation fails.
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float eq(float expectedValue, float delta) {
+ return EasyMock.eq(expectedValue, delta);
+ }
+
+ /**
+ * Expects an {@code Object} as a parameter to the mocked method that is the same as the given
+ * value. This expectation will fail unless the incoming parameter is {@code ==} to the
+ * {@code expectedValue} provided (i.e. the same {@code Object} reference).
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param <T> the type of the object, it is passed through to prevent casts.
+ * @param expectedValue the exact object which is expected during replay.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T> T same(T expectedValue) {
+ return EasyMock.same(expectedValue);
+ }
+
+ /**
+ * Expects a {@link java.lang.Comparable} argument equal to the given value according to
+ * its {@link java.lang.Comparable#compareTo(Object)} method.
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the {@link java.lang.Comparable} value which is expected to be equal to
+ * the incoming parameter to the mocked method according to the
+ * {@link java.lang.Comparable#compareTo(Object)} method.
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T extends Comparable<T>> T cmpEq(Comparable<T> expectedValue) {
+ return EasyMock.cmpEq(expectedValue);
+ }
+
+ /**
+ * Expects an argument that will be compared using the provided {@link java.util.Comparator}, the
+ * result of which will then be applied to the provided {@link org.easymock.LogicalOperator}
+ * (e.g. {@link org.easymock.LogicalOperator#LESS_THAN},
+ * {@link org.easymock.LogicalOperator#EQUAL},
+ * {@link org.easymock.LogicalOperator#GREATER_OR_EQUAL}).
+ *
+ * The following comparison will take place:
+ * {@code comparator.compare(actual, expected) operator 0}
+ *
+ * E.g.
+ * For illustration purposes (using static imports):
+ *
+ * {@code
+ * expect(mockObject.getString(cmp("hi", CASE_INSENSITIVE_ORDER, LESS_THAN))).andReturn("hello");}
+ *
+ * {@code
+ * AndroidMock.expect(mockObject.getString(AndroidMock.cmp("hi", String.CASE_INSENSITIVE_ORDER,
+ * LogicalOperator.LESS_THAN))).andReturn("hello");}
+ *
+ *
+ * The above invocation indicates that the call to {@code mockObject.getString(String)} is
+ * expecting any String which is lexically before "hi" (in a case insensitive ordering).
+ *
+ * If this method is used for anything other than to set a parameter expectation as part of a
+ * mock object's recording phase, then an {@code IllegalStateException} will be thrown.
+ *
+ * @param expectedValue the expected value against which the incoming method parameter will be
+ * compared.
+ * @param comparator {@link java.util.Comparator} used to perform the comparison between the
+ * expected value and the incoming parameter to the mocked method.
+ * @param operator The comparison operator, usually one of
+ * {@link org.easymock.LogicalOperator#LESS_THAN},
+ * {@link org.easymock.LogicalOperator#LESS_OR_EQUAL},
+ * {@link org.easymock.LogicalOperator#EQUAL}, {@link org.easymock.LogicalOperator#GREATER},
+ * {@link org.easymock.LogicalOperator#GREATER_OR_EQUAL}
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T> T cmp(T expectedValue, Comparator<? super T> comparator,
+ LogicalOperator operator) {
+ return EasyMock.cmp(expectedValue, comparator, operator);
+ }
+
+ /**
+ * Expect any {@code Object} as a parameter to the mocked method, but capture it for later use.
+ *
+ * {@link org.easymock.Capture} allows for capturing of the incoming value. Use
+ * {@link org.easymock.Capture#getValue()} to retrieve the captured value.
+ *
+ * @param <T> Type of the captured object
+ * @param captured a container to hold the captured value, retrieved by
+ * {@link org.easymock.Capture#getValue()}
+ * @return {@code null}. The return value is always ignored.
+ */
+ public static <T> T capture(Capture<T> captured) {
+ return EasyMock.capture(captured);
+ }
+
+ /**
+ * Expect any {@code int/Integer} as a parameter to the mocked method, but capture it for later
+ * use.
+ *
+ * {@link org.easymock.Capture} allows for capturing of the incoming value. Use
+ * {@link org.easymock.Capture#getValue()} to retrieve the captured value.
+ *
+ * @param captured a container to hold the captured value, retrieved by
+ * {@link org.easymock.Capture#getValue()}
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static int capture(Capture<Integer> captured) {
+ return EasyMock.capture(captured);
+ }
+
+ /**
+ * Expect any {@code long/Long} as a parameter to the mocked method, but capture it for later
+ * use.
+ *
+ * {@link org.easymock.Capture} allows for capturing of the incoming value. Use
+ * {@link org.easymock.Capture#getValue()} to retrieve the captured value.
+ *
+ * @param captured a container to hold the captured value, retrieved by
+ * {@link org.easymock.Capture#getValue()}
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static long capture(Capture<Long> captured) {
+ return EasyMock.capture(captured);
+ }
+
+ /**
+ * Expect any {@code float/Float} as a parameter to the mocked method, but capture it for later
+ * use.
+ *
+ * {@link org.easymock.Capture} allows for capturing of the incoming value. Use
+ * {@link org.easymock.Capture#getValue()} to retrieve the captured value.
+ *
+ * @param captured a container to hold the captured value, retrieved by
+ * {@link org.easymock.Capture#getValue()}
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static float capture(Capture<Float> captured) {
+ return EasyMock.capture(captured);
+ }
+
+ /**
+ * Expect any {@code double/Double} as a parameter to the mocked method, but capture it for later
+ * use.
+ *
+ * {@link org.easymock.Capture} allows for capturing of the incoming value. Use
+ * {@link org.easymock.Capture#getValue()} to retrieve the captured value.
+ *
+ * @param captured a container to hold the captured value, retrieved by
+ * {@link org.easymock.Capture#getValue()}
+ * @return {@code 0}. The return value is always ignored.
+ */
+ public static double capture(Capture<Double> captured) {
+ return EasyMock.capture(captured);
+ }
+
+ /**
+ * Expect any {@code byte/Byte} as a parameter to the mocked method, but capture it for later
+ * use.
+ *
+ * {@link org.easymock.Capture} allows for capturing of the incoming value. Use
+ * {@link org.easymock.Capture#getValue()} to retrieve the captured value.
+ *
+ * @param captured a container to hold the captured value, retrieved by
+ * {@link org.easymock.Capture#getValue()}
+ * @return {@code 0}
+ */
+ public static byte capture(Capture<Byte> captured) {
+ return EasyMock.capture(captured);
+ }
+
+ /**
+ * Expect any {@code char/Character} as a parameter to the mocked method, but capture it for later
+ * use.
+ *
+ * {@link org.easymock.Capture} allows for capturing of the incoming value. Use
+ * {@link org.easymock.Capture#getValue()} to retrieve the captured value.
+ *
+ * @param captured a container to hold the captured value, retrieved by
+ * {@link org.easymock.Capture#getValue()}
+ * @return {@code 0}
+ */
+ public static char capture(Capture<Character> captured) {
+ return EasyMock.capture(captured);
+ }
+
+ /**
+ * Switches the given mock objects (more exactly: the controls of the mock
+ * objects) to replay mode.
+ *
+ * @param mocks the mock objects.
+ */
+ public static void replay(Object... mocks) {
+ for (Object mockObject : mocks) {
+ if (mockObject instanceof MockObject) {
+ EasyMock.replay(((MockObject) mockObject).getDelegate___AndroidMock());
+ } else {
+ EasyMock.replay(mockObject);
+ }
+ }
+ }
+
+ /**
+ * Resets the given mock objects (more exactly: the controls of the mock
+ * objects) allowing the mock objects to be reused.
+ *
+ * @param mocks the mock objects.
+ */
+ public static void reset(Object... mocks) {
+ for (Object mockObject : mocks) {
+ if (mockObject instanceof MockObject) {
+ EasyMock.reset(((MockObject) mockObject).getDelegate___AndroidMock());
+ } else {
+ EasyMock.reset(mockObject);
+ }
+ }
+ }
+
+ /**
+ * Resets the given mock objects (more exactly: the controls of the mock
+ * objects) and change them in to mocks with nice behavior.
+ * {@link #createNiceMock(Class, Object...)} has more details.
+ *
+ * @param mocks the mock objects
+ */
+ public static void resetToNice(Object... mocks) {
+ for (Object mockObject : mocks) {
+ if (mockObject instanceof MockObject) {
+ EasyMock.resetToNice(((MockObject) mockObject).getDelegate___AndroidMock());
+ } else {
+ EasyMock.resetToNice(mockObject);
+ }
+ }
+ }
+
+ /**
+ * Resets the given mock objects (more exactly: the controls of the mock
+ * objects) and turn them to a mock with default behavior. {@link #createMock(Class, Object...)}
+ * has more details.
+ *
+ * @param mocks the mock objects
+ */
+ public static void resetToDefault(Object... mocks) {
+ for (Object mockObject : mocks) {
+ if (mockObject instanceof MockObject) {
+ EasyMock.resetToDefault(((MockObject) mockObject).getDelegate___AndroidMock());
+ } else {
+ EasyMock.resetToDefault(mockObject);
+ }
+ }
+ }
+
+ /**
+ * Resets the given mock objects (more exactly: the controls of the mock
+ * objects) and turn them to a mock with strict behavior.
+ * {@link #createStrictMock(Class, Object...)} has more details.
+ *
+ * @param mocks the mock objects
+ */
+ public static void resetToStrict(Object... mocks) {
+ for (Object mockObject : mocks) {
+ if (mockObject instanceof MockObject) {
+ EasyMock.resetToStrict(((MockObject) mockObject).getDelegate___AndroidMock());
+ } else {
+ EasyMock.resetToStrict(mockObject);
+ }
+ }
+ }
+
+ /**
+ * Verifies that all of the expected method calls for the given mock objects (more exactly: the
+ * controls of the mock objects) have been executed.
+ *
+ * The {@code verify} method captures the scenario where several methods were invoked correctly,
+ * but some invocations did not occur. Typically, the {@code verify} method is the final thing
+ * invoked in a test.
+ *
+ * @param mocks the mock objects.
+ */
+ public static void verify(Object... mocks) {
+ for (Object mockObject : mocks) {
+ if (mockObject instanceof MockObject) {
+ EasyMock.verify(((MockObject) mockObject).getDelegate___AndroidMock());
+ } else {
+ EasyMock.verify(mockObject);
+ }
+ }
+ }
+
+ /**
+ * Switches order checking of the given mock object (more exactly: the control
+ * of the mock object) on or off. When order checking is on, the mock will expect the method
+ * invokations to occur exactly in the order in which they appeared during the recording phase.
+ *
+ * @param mock the mock object.
+ * @param orderCheckingOn {@code true} to turn order checking on, {@code false} to turn it off.
+ */
+ public static void checkOrder(Object mock, boolean orderCheckingOn) {
+ if (mock instanceof MockObject) {
+ EasyMock.checkOrder(((MockObject) mock).getDelegate___AndroidMock(), orderCheckingOn);
+ } else {
+ EasyMock.checkOrder(mock, orderCheckingOn);
+ }
+ }
+
+ /**
+ * Reports an argument matcher. This method is needed to define custom argument
+ * matchers.
+ *
+ * For example:
+ *
+ * {@code
+ * AndroidMock.reportMatcher(new IntIsFortyTwo());
+ * AndroidMock.expect(mockObject.getString(null)).andReturn("hello world");}
+ *
+ * This example will expect a parameter for {@code mockObject.getString(int)} that matches the
+ * conditions required by the {@code matches} method as defined by
+ * {@link org.easymock.IArgumentMatcher#matches(Object)}.
+ *
+ * @param matcher the matcher whose {@code matches} method will be applied to the incoming
+ * parameter to the mocked method.
+ */
+ public static void reportMatcher(IArgumentMatcher matcher) {
+ EasyMock.reportMatcher(matcher);
+ }
+
+ /**
+ * Returns the arguments of the current mock method call, if inside an
+ * {@code IAnswer} callback - be careful here, reordering parameters of a
+ * method changes the semantics of your tests.
+ *
+ * This method is only usable within an {@link org.easymock.IAnswer} instance. Attach an
+ * {@link org.easymock.IAnswer} to an expectation by using the
+ * {@link org.easymock.IExpectationSetters#andAnswer(org.easymock.IAnswer)} method.
+ *
+ * E.g.
+ * {@code AndroidMock.expect(mockObject.getString()).andAnswer(myAnswerCallback);}
+ *
+ * @return the arguments of the current mock method call.
+ * @throws IllegalStateException if called outside of {@code IAnswer}
+ * callbacks.
+ */
+ public static Object[] getCurrentArguments() {
+ return EasyMock.getCurrentArguments();
+ }
+
+ /**
+ * 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) {
+ if (mock instanceof MockObject) {
+ EasyMock.makeThreadSafe(((MockObject) mock).getDelegate___AndroidMock(), threadSafe);
+ } else {
+ EasyMock.makeThreadSafe(mock, threadSafe);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T, S> T getSubclassFor(Class<? super T> clazz, Class<S> delegateInterface,
+ Object realMock, Object... args) {
+ Class<T> subclass;
+ String className = null;
+ try {
+ if (isAndroidClass(clazz)) {
+ className = FileUtils.getSubclassNameFor(clazz, SdkVersion.getCurrentVersion());
+ } else {
+ className = FileUtils.getSubclassNameFor(clazz, SdkVersion.UNKNOWN);
+ }
+ subclass = (Class<T>) Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Could not find class for " + className
+ + " which likely means that the mock-instrumented jar has not been created or else"
+ + " is not being used in the current runtime environment. Try running MockGeneratorMain"
+ + " in MockGenerator_deploy.jar or using the output of that execution as the input to"
+ + " the dex/apk generation.", e);
+ }
+ Constructor<T> constructor = getConstructorFor(subclass, args);
+ T newObject;
+ try {
+ newObject = constructor.newInstance(args);
+ } catch (InstantiationException e) {
+ throw new RuntimeException("Internal error instantiating new mock subclass"
+ + subclass.getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "Internal error - the new mock subclass' constructor was inaccessible", e);
+ } catch (InvocationTargetException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ Method[] methods = subclass.getMethods();
+ Method setMethod;
+ try {
+ setMethod = subclass.getMethod("setDelegate___AndroidMock", delegateInterface);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Internal error - No setDelegate method found for " + "class "
+ + subclass.getName() + " and param " + delegateInterface.getName(), e);
+ }
+ try {
+ setMethod.invoke(newObject, realMock);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Internal error setting the delegate, expected "
+ + newObject.getClass() + " to be subclass of " + clazz.getName());
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("Severe internal error, setDelegate threw an exception", e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Internal error, setDelegate method was inaccessible", e);
+ }
+ return newObject;
+ }
+
+ static boolean isUnboxableToPrimitive(Class<?> clazz, Object arg, boolean exactMatch) {
+ if (!clazz.isPrimitive()) {
+ throw new IllegalArgumentException(
+ "Internal Error - The class to test against is not a primitive");
+ }
+ Class<?> unboxedType = null;
+ if (arg.getClass().equals(Integer.class)) {
+ unboxedType = Integer.TYPE;
+ } else if (arg.getClass().equals(Long.class)) {
+ unboxedType = Long.TYPE;
+ } else if (arg.getClass().equals(Byte.class)) {
+ unboxedType = Byte.TYPE;
+ } else if (arg.getClass().equals(Short.class)) {
+ unboxedType = Short.TYPE;
+ } else if (arg.getClass().equals(Character.class)) {
+ unboxedType = Character.TYPE;
+ } else if (arg.getClass().equals(Float.class)) {
+ unboxedType = Float.TYPE;
+ } else if (arg.getClass().equals(Double.class)) {
+ unboxedType = Double.TYPE;
+ } else if (arg.getClass().equals(Boolean.class)) {
+ unboxedType = Boolean.TYPE;
+ } else {
+ return false;
+ }
+ if (exactMatch) {
+ return clazz == unboxedType;
+ }
+ return isAssignable(clazz, unboxedType);
+ }
+
+ private static boolean isAssignable(Class<?> to, Class<?> from) {
+ if (to == Byte.TYPE) {
+ return from == Byte.TYPE;
+ } else if (to == Short.TYPE){
+ return from == Byte.TYPE || from == Short.TYPE || from == Character.TYPE;
+ } else if (to == Integer.TYPE || to == Character.TYPE) {
+ return from == Byte.TYPE || from == Short.TYPE || from == Integer.TYPE
+ || from == Character.TYPE;
+ } else if (to == Long.TYPE) {
+ return from == Byte.TYPE || from == Short.TYPE || from == Integer.TYPE || from == Long.TYPE
+ || from == Character.TYPE;
+ } else if (to == Float.TYPE) {
+ return from == Byte.TYPE || from == Short.TYPE || from == Integer.TYPE
+ || from == Character.TYPE || from == Float.TYPE;
+ } else if (to == Double.TYPE) {
+ return from == Byte.TYPE || from == Short.TYPE || from == Integer.TYPE || from == Long.TYPE
+ || from == Character.TYPE || from == Float.TYPE || from == Double.TYPE;
+ } else if (to == Boolean.TYPE) {
+ return from == Boolean.TYPE;
+ } else {
+ return to.isAssignableFrom(from);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ static <T> Constructor<T> getConstructorFor(Class<T> clazz, Object... args)
+ throws SecurityException {
+ Constructor<T>[] constructors = (Constructor<T>[]) clazz.getConstructors();
+ Constructor<T> compatibleConstructor = null;
+ for (Constructor<T> constructor : constructors) {
+ Class<?>[] params = constructor.getParameterTypes();
+ if (params.length == args.length) {
+ boolean exactMatch = true;
+ boolean compatibleMatch = true;
+ for (int i = 0; i < params.length; ++i) {
+ Object arg = args[i];
+ if (arg == null) {
+ arg = Void.TYPE;
+ }
+ if (!params[i].isAssignableFrom(arg.getClass())) {
+ if (params[i].isPrimitive()) {
+ exactMatch &= isUnboxableToPrimitive(params[i], arg, true);
+ compatibleMatch &= isUnboxableToPrimitive(params[i], arg, false);
+ } else {
+ exactMatch = false;
+ compatibleMatch = false;
+ }
+ }
+ }
+ if (exactMatch) {
+ return constructor;
+ } else if (compatibleMatch) {
+ compatibleConstructor = constructor;
+ }
+ }
+ }
+ if (compatibleConstructor != null) {
+ return compatibleConstructor;
+ }
+ List<String> argTypes = new ArrayList<String>(args.length);
+ for (Object arg : args) {
+ argTypes.add(arg == null ? "<null>" : arg.getClass().toString());
+ }
+ throw new IllegalArgumentException("Could not find the specified Constructor: "
+ + clazz.getName() + "(" + argTypes + ")");
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> Class<T> getInterfaceFor(Class<T> clazz) {
+ try {
+ String className;
+ if (isAndroidClass(clazz)) {
+ className = FileUtils.getInterfaceNameFor(clazz, SdkVersion.getCurrentVersion());
+ } else {
+ className = FileUtils.getInterfaceNameFor(clazz, SdkVersion.UNKNOWN);
+ }
+ return (Class<T>) Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Could not find mock for " + clazz.getName()
+ + " -- Make sure to run the MockGenerator.jar on your test jar, and to "
+ + "build the Android test APK using the modified jar created by MockGenerator", e);
+ }
+ }
+
+ static boolean isAndroidClass(Class<?> clazz) {
+ String packageName = clazz.getPackage().getName();
+ return packageName.startsWith("android.") || packageName.startsWith("dalvik.")
+ || packageName.startsWith("java.") || packageName.startsWith("javax.")
+ || packageName.startsWith("org.xml.sax") || packageName.startsWith("org.xmlpull.v1")
+ || packageName.startsWith("org.w3c.dom") || packageName.startsWith("org.apache.http")
+ || packageName.startsWith("junit.");
+ }
+}
diff --git a/src/com/google/android/testing/mocking/AndroidMockGenerator.java b/src/com/google/android/testing/mocking/AndroidMockGenerator.java
new file mode 100644
index 0000000..1a557a6
--- /dev/null
+++ b/src/com/google/android/testing/mocking/AndroidMockGenerator.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+import javassist.ClassClassPath;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.CtNewConstructor;
+import javassist.NotFoundException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * AndroidMockGenerator creates the subclass and interface required for mocking
+ * a given Class.
+ *
+ * The only public method of AndroidMockGenerator is createMocksForClass. See
+ * the javadocs for this method for more information about AndroidMockGenerator.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+class AndroidMockGenerator {
+ public AndroidMockGenerator() {
+ ClassPool.doPruning = false;
+ ClassPool.getDefault().insertClassPath(new ClassClassPath(MockObject.class));
+ }
+
+ /**
+ * Creates a List of javassist.CtClass objects representing all of the
+ * interfaces and subclasses required to meet the Mocking requests of the
+ * Class specified by {@code clazz}.
+ *
+ * A test class can request that a Class be prepared for mocking by using the
+ * {@link UsesMocks} annotation at either the Class or Method level. All
+ * classes specified by these annotations will have exactly two CtClass
+ * objects created, one for a generated interface, and one for a generated
+ * subclass. The interface and subclass both define the same methods which
+ * comprise all of the mockable methods of the provided class. At present, for
+ * a method to be mockable, it must be non-final and non-static, although this
+ * may expand in the future.
+ *
+ * The class itself must be mockable, otherwise this method will ignore the
+ * requested mock and print a warning. At present, a class is mockable if it
+ * is a non-final publicly-instantiable Java class that is assignable from the
+ * java.lang.Object class. See the javadocs for
+ * {@link java.lang.Class#isAssignableFrom(Class)} for more information about
+ * what "is assignable from the Object class" means. As a non-exhaustive
+ * example, if a given Class represents an Enum, Annotation, Primitive or
+ * Array, then it is not assignable from Object. Interfaces are also ignored
+ * since these need no modifications in order to be mocked.
+ *
+ * @param clazz the Class object to have all of its UsesMocks annotations
+ * processed and the corresponding Mock Classes created.
+ * @return a List of CtClass objects representing the Classes and Interfaces
+ * required for mocking the classes requested by {@code clazz}
+ * @throws ClassNotFoundException
+ * @throws CannotCompileException
+ * @throws IOException
+ */
+ public List<GeneratedClassFile> createMocksForClass(Class<?> clazz)
+ throws ClassNotFoundException, IOException, CannotCompileException {
+ return this.createMocksForClass(clazz, SdkVersion.UNKNOWN);
+ }
+
+ public List<GeneratedClassFile> createMocksForClass(Class<?> clazz, SdkVersion sdkVersion)
+ throws ClassNotFoundException, IOException, CannotCompileException {
+ if (!classIsSupportedType(clazz)) {
+ reportReasonForUnsupportedType(clazz);
+ return Arrays.asList(new GeneratedClassFile[0]);
+ }
+ CtClass newInterfaceCtClass = generateInterface(clazz, sdkVersion);
+ GeneratedClassFile newInterface = new GeneratedClassFile(newInterfaceCtClass.getName(),
+ newInterfaceCtClass.toBytecode());
+ CtClass mockDelegateCtClass = generateSubClass(clazz, newInterfaceCtClass, sdkVersion);
+ GeneratedClassFile mockDelegate = new GeneratedClassFile(mockDelegateCtClass.getName(),
+ mockDelegateCtClass.toBytecode());
+ return Arrays.asList(new GeneratedClassFile[] {newInterface, mockDelegate});
+ }
+
+ private void reportReasonForUnsupportedType(Class<?> clazz) {
+ String reason = null;
+ if (clazz.isInterface()) {
+ // do nothing to make sure none of the other conditions apply.
+ } else if (clazz.isEnum()) {
+ reason = "Cannot mock an Enum";
+ } else if (clazz.isAnnotation()) {
+ reason = "Cannot mock an Annotation";
+ } else if (clazz.isArray()) {
+ reason = "Cannot mock an Array";
+ } else if (Modifier.isFinal(clazz.getModifiers())) {
+ reason = "Cannot mock a Final class";
+ } else if (clazz.isPrimitive()) {
+ reason = "Cannot mock primitives";
+ } else if (!Object.class.isAssignableFrom(clazz)) {
+ reason = "Cannot mock non-classes";
+ } else if (!containsUsableConstructor(clazz)) {
+ reason = "Cannot mock a class with no public constructors";
+ } else {
+ // Whatever the reason is, it's not one that we care about.
+ }
+ if (reason != null) {
+ // Sometimes we want to be silent, so check 'reason' against null.
+ System.err.println(reason + ": " + clazz.getName());
+ }
+ }
+
+ private boolean containsUsableConstructor(Class<?> clazz) {
+ Constructor<?>[] constructors = clazz.getDeclaredConstructors();
+ for (Constructor<?> constructor : constructors) {
+ if (Modifier.isPublic(constructor.getModifiers()) ||
+ Modifier.isProtected(constructor.getModifiers())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean classIsSupportedType(Class<?> clazz) {
+ return (containsUsableConstructor(clazz)) && Object.class.isAssignableFrom(clazz)
+ && !clazz.isInterface() && !clazz.isEnum() && !clazz.isAnnotation() && !clazz.isArray()
+ && !Modifier.isFinal(clazz.getModifiers());
+ }
+
+ void saveCtClass(CtClass clazz) throws ClassNotFoundException, IOException {
+ try {
+ clazz.writeFile();
+ } catch (NotFoundException e) {
+ throw new ClassNotFoundException("Error while saving modified class " + clazz.getName(), e);
+ } catch (CannotCompileException e) {
+ throw new RuntimeException("Internal Error: Attempt to save syntactically incorrect code "
+ + "for class " + clazz.getName(), e);
+ }
+ }
+
+ CtClass generateInterface(Class<?> originalClass, SdkVersion sdkVersion) {
+ ClassPool classPool = getClassPool();
+ try {
+ return classPool.getCtClass(FileUtils.getInterfaceNameFor(originalClass, sdkVersion));
+ } catch (NotFoundException e) {
+ CtClass newInterface =
+ classPool.makeInterface(FileUtils.getInterfaceNameFor(originalClass, sdkVersion));
+ addInterfaceMethods(originalClass, newInterface);
+ return newInterface;
+ }
+ }
+
+ String getInterfaceMethodSource(Method method) throws UnsupportedOperationException {
+ StringBuilder methodBody = getMethodSignature(method);
+ methodBody.append(";");
+ return methodBody.toString();
+ }
+
+ private StringBuilder getMethodSignature(Method method) {
+ int modifiers = method.getModifiers();
+ if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) {
+ throw new UnsupportedOperationException(
+ "Cannot specify final or static methods in an interface");
+ }
+ StringBuilder methodSignature = new StringBuilder("public ");
+ methodSignature.append(getClassName(method.getReturnType()));
+ methodSignature.append(" ");
+ methodSignature.append(method.getName());
+ methodSignature.append("(");
+ int i = 0;
+ for (Class<?> arg : method.getParameterTypes()) {
+ methodSignature.append(getClassName(arg));
+ methodSignature.append(" arg");
+ methodSignature.append(i);
+ if (i < method.getParameterTypes().length - 1) {
+ methodSignature.append(",");
+ }
+ i++;
+ }
+ methodSignature.append(")");
+ if (method.getExceptionTypes().length > 0) {
+ methodSignature.append(" throws ");
+ }
+ i = 0;
+ for (Class<?> exception : method.getExceptionTypes()) {
+ methodSignature.append(getClassName(exception));
+ if (i < method.getExceptionTypes().length - 1) {
+ methodSignature.append(",");
+ }
+ i++;
+ }
+ return methodSignature;
+ }
+
+ private String getClassName(Class<?> clazz) {
+ return clazz.getCanonicalName();
+ }
+
+ static ClassPool getClassPool() {
+ return ClassPool.getDefault();
+ }
+
+ private boolean classExists(String name) {
+ // The following line is the ideal, but doesn't work (bug in library).
+ // return getClassPool().find(name) != null;
+ try {
+ getClassPool().get(name);
+ return true;
+ } catch (NotFoundException e) {
+ return false;
+ }
+ }
+
+ CtClass generateSubClass(Class<?> superClass, CtClass newInterface, SdkVersion sdkVersion)
+ throws ClassNotFoundException {
+ if (classExists(FileUtils.getSubclassNameFor(superClass, sdkVersion))) {
+ try {
+ return getClassPool().get(FileUtils.getSubclassNameFor(superClass, sdkVersion));
+ } catch (NotFoundException e) {
+ throw new ClassNotFoundException("This should be impossible, since we just checked for "
+ + "the existence of the class being created", e);
+ }
+ }
+ CtClass newClass = generateSkeletalClass(superClass, newInterface, sdkVersion);
+ if (!newClass.isFrozen()) {
+ newClass.addInterface(newInterface);
+ try {
+ newClass.addInterface(getClassPool().get(MockObject.class.getName()));
+ } catch (NotFoundException e) {
+ throw new ClassNotFoundException("Could not find " + MockObject.class.getName(), e);
+ }
+ addMethods(superClass, newClass);
+ addGetDelegateMethod(newClass);
+ addSetDelegateMethod(newClass, newInterface);
+ addConstructors(newClass, superClass);
+ }
+ return newClass;
+ }
+
+ private void addConstructors(CtClass clazz, Class<?> superClass) throws ClassNotFoundException {
+ CtClass superCtClass = getCtClassForClass(superClass);
+
+ CtConstructor[] constructors = superCtClass.getDeclaredConstructors();
+ for (CtConstructor constructor : constructors) {
+ int modifiers = constructor.getModifiers();
+ if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
+ CtConstructor ctConstructor;
+ try {
+ ctConstructor = CtNewConstructor.make(constructor.getParameterTypes(),
+ constructor.getExceptionTypes(), clazz);
+ clazz.addConstructor(ctConstructor);
+ } catch (CannotCompileException e) {
+ throw new RuntimeException("Internal Error - Could not add constructors.", e);
+ } catch (NotFoundException e) {
+ throw new RuntimeException("Internal Error - Constructor suddenly could not be found", e);
+ }
+ }
+ }
+ }
+
+ CtClass getCtClassForClass(Class<?> clazz) throws ClassNotFoundException {
+ ClassPool classPool = getClassPool();
+ try {
+ return classPool.get(clazz.getName());
+ } catch (NotFoundException e) {
+ throw new ClassNotFoundException("Class not found when finding the class to be mocked: "
+ + clazz.getName(), e);
+ }
+ }
+
+ private void addSetDelegateMethod(CtClass clazz, CtClass newInterface) {
+ try {
+ clazz.addMethod(CtMethod.make(getSetDelegateMethodSource(newInterface), clazz));
+ } catch (CannotCompileException e) {
+ throw new RuntimeException("Internal error while creating the setDelegate() method", e);
+ }
+ }
+
+ String getSetDelegateMethodSource(CtClass newInterface) {
+ return "public void setDelegate___AndroidMock(" + newInterface.getName() + " obj) { this."
+ + getDelegateFieldName() + " = obj;}";
+ }
+
+ private void addGetDelegateMethod(CtClass clazz) {
+ try {
+ CtMethod newMethod = CtMethod.make(getGetDelegateMethodSource(), clazz);
+ try {
+ CtMethod existingMethod = clazz.getMethod(newMethod.getName(), newMethod.getSignature());
+ clazz.removeMethod(existingMethod);
+ } catch (NotFoundException e) {
+ // expected path... sigh.
+ }
+ clazz.addMethod(newMethod);
+ } catch (CannotCompileException e) {
+ throw new RuntimeException("Internal error while creating the getDelegate() method", e);
+ }
+ }
+
+ private String getGetDelegateMethodSource() {
+ return "public Object getDelegate___AndroidMock() { return this." + getDelegateFieldName()
+ + "; }";
+ }
+
+ String getDelegateFieldName() {
+ return "delegateMockObject";
+ }
+
+ void addInterfaceMethods(Class<?> originalClass, CtClass newInterface) {
+ Method[] methods = getAllMethods(originalClass);
+ for (Method method : methods) {
+ try {
+ if (isMockable(method)) {
+ CtMethod newMethod = CtMethod.make(getInterfaceMethodSource(method), newInterface);
+ newInterface.addMethod(newMethod);
+ }
+ } catch (UnsupportedOperationException e) {
+ // Can't handle finals and statics.
+ } catch (CannotCompileException e) {
+ throw new RuntimeException(
+ "Internal error while creating a new Interface method for class "
+ + originalClass.getName() + ". Method name: " + method.getName(), e);
+ }
+ }
+ }
+
+ void addMethods(Class<?> superClass, CtClass newClass) {
+ Method[] methods = getAllMethods(superClass);
+ if (newClass.isFrozen()) {
+ newClass.defrost();
+ }
+ List<CtMethod> existingMethods = Arrays.asList(newClass.getDeclaredMethods());
+ for (Method method : methods) {
+ try {
+ if (isMockable(method)) {
+ CtMethod newMethod = CtMethod.make(getDelegateMethodSource(method), newClass);
+ if (!existingMethods.contains(newMethod)) {
+ newClass.addMethod(newMethod);
+ }
+ }
+ } catch (UnsupportedOperationException e) {
+ // Can't handle finals and statics.
+ } catch (CannotCompileException e) {
+ throw new RuntimeException("Internal Error while creating subclass methods for "
+ + newClass.getName() + " method: " + method.getName(), e);
+ }
+ }
+ }
+
+ Method[] getAllMethods(Class<?> clazz) {
+ Map<String, Method> methodMap = getAllMethodsMap(clazz);
+ return methodMap.values().toArray(new Method[0]);
+ }
+
+ private Map<String, Method> getAllMethodsMap(Class<?> clazz) {
+ Map<String, Method> methodMap = new HashMap<String, Method>();
+ Class<?> superClass = clazz.getSuperclass();
+ if (superClass != null) {
+ methodMap.putAll(getAllMethodsMap(superClass));
+ }
+ List<Method> methods = new ArrayList<Method>(Arrays.asList(clazz.getDeclaredMethods()));
+ for (Method method : methods) {
+ String key = method.getName();
+ for (Class<?> param : method.getParameterTypes()) {
+ key += param.getCanonicalName();
+ }
+ methodMap.put(key, method);
+ }
+ return methodMap;
+ }
+
+ boolean isMockable(Method method) {
+ if (isForbiddenMethod(method)) {
+ return false;
+ }
+ int modifiers = method.getModifiers();
+ return !Modifier.isFinal(modifiers) && !Modifier.isStatic(modifiers) && !method.isBridge()
+ && (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers));
+ }
+
+ boolean isForbiddenMethod(Method method) {
+ if (method.getName().equals("equals")) {
+ return method.getParameterTypes().length == 1
+ && method.getParameterTypes()[0].equals(Object.class);
+ } else if (method.getName().equals("toString")) {
+ return method.getParameterTypes().length == 0;
+ } else if (method.getName().equals("hashCode")) {
+ return method.getParameterTypes().length == 0;
+ }
+ return false;
+ }
+
+ private String getReturnDefault(Method method) {
+ Class<?> returnType = method.getReturnType();
+ if (!returnType.isPrimitive()) {
+ return "null";
+ } else if (returnType == Boolean.TYPE) {
+ return "false";
+ } else if (returnType == Void.TYPE) {
+ return "";
+ } else {
+ return "(" + returnType.getName() + ")0";
+ }
+ }
+
+ String getDelegateMethodSource(Method method) {
+ StringBuilder methodBody = getMethodSignature(method);
+ methodBody.append("{");
+ methodBody.append("if(this.");
+ methodBody.append(getDelegateFieldName());
+ methodBody.append("==null){return ");
+ methodBody.append(getReturnDefault(method));
+ methodBody.append(";}");
+ if (!method.getReturnType().equals(Void.TYPE)) {
+ methodBody.append("return ");
+ }
+ methodBody.append("this.");
+ methodBody.append(getDelegateFieldName());
+ methodBody.append(".");
+ methodBody.append(method.getName());
+ methodBody.append("(");
+ for (int i = 0; i < method.getParameterTypes().length; ++i) {
+ methodBody.append("arg");
+ methodBody.append(i);
+ if (i < method.getParameterTypes().length - 1) {
+ methodBody.append(",");
+ }
+ }
+ methodBody.append(");}");
+ return methodBody.toString();
+ }
+
+ CtClass generateSkeletalClass(Class<?> superClass, CtClass newInterface, SdkVersion sdkVersion)
+ throws ClassNotFoundException {
+ ClassPool classPool = getClassPool();
+ CtClass superCtClass = getCtClassForClass(superClass);
+ String subclassName = FileUtils.getSubclassNameFor(superClass, sdkVersion);
+
+ CtClass newClass;
+ try {
+ newClass = classPool.makeClass(subclassName, superCtClass);
+ } catch (RuntimeException e) {
+ if (e.getMessage().contains("frozen class")) {
+ try {
+ return classPool.get(subclassName);
+ } catch (NotFoundException ex) {
+ throw new ClassNotFoundException("Internal Error: could not find class", ex);
+ }
+ }
+ throw e;
+ }
+
+ try {
+ newClass.addField(new CtField(newInterface, getDelegateFieldName(), newClass));
+ } catch (CannotCompileException e) {
+ throw new RuntimeException("Internal error adding the delegate field to "
+ + newClass.getName(), e);
+ }
+ return newClass;
+ }
+}
diff --git a/src/com/google/android/testing/mocking/FileUtils.java b/src/com/google/android/testing/mocking/FileUtils.java
new file mode 100644
index 0000000..f759c57
--- /dev/null
+++ b/src/com/google/android/testing/mocking/FileUtils.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class FileUtils {
+
+ /**
+ * @param clazz
+ * @param sdkVersion
+ * @return the appropriate interface name for the interface mock support file.
+ */
+ static String getInterfaceNameFor(Class<?> clazz, SdkVersion sdkVersion) {
+ return sdkVersion.getPackagePrefix() + "genmocks." + clazz.getName() + "DelegateInterface";
+ }
+ /**
+ * @param clazz
+ * @param sdkVersion
+ * @return the appropriate subclass name for the subclass mock support file.
+ */
+ static String getSubclassNameFor(Class<?> clazz, SdkVersion sdkVersion) {
+ return sdkVersion.getPackagePrefix() + "genmocks." + clazz.getName() + "DelegateSubclass";
+ }
+
+ /**
+ * Converts a class name into the a .class filename.
+ *
+ * @param className
+ * @return the file name for the specified class name.
+ */
+ static String getFilenameFor(String className) {
+ return className.replace('.', File.separatorChar) + ".class";
+ }
+
+ /**
+ * Converts a filename into a class name.
+ *
+ * @param filename
+ * @return the class name for the specified file name.
+ */
+ static String getClassNameFor(String filename) {
+ if (!filename.endsWith(".class")) {
+ throw new IllegalArgumentException("Argument provided is not a class filename: " + filename);
+ }
+ return filename.replace(File.separatorChar, '.').substring(0, filename.length() - 6);
+ }
+
+ static void saveClassToFolder(GeneratedClassFile clazz, String outputFolderName)
+ throws FileNotFoundException, IOException {
+ File classFolder = new File(outputFolderName);
+ File targetFile = new File(classFolder, getFilenameFor(clazz.getClassName()));
+ targetFile.getParentFile().mkdirs();
+ FileOutputStream outputStream = new FileOutputStream(targetFile);
+ outputStream.write(clazz.getContents());
+ outputStream.close();
+ }
+}
diff --git a/src/com/google/android/testing/mocking/GeneratedClassFile.java b/src/com/google/android/testing/mocking/GeneratedClassFile.java
new file mode 100644
index 0000000..1ef01ed
--- /dev/null
+++ b/src/com/google/android/testing/mocking/GeneratedClassFile.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Represents the contents of a Class file.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class GeneratedClassFile {
+ private final String className;
+ private final byte[] contents;
+
+ /**
+ * @param name the fully qualified name of the class.
+ * @param classFileContents the binary contents of the file.
+ */
+ public GeneratedClassFile(String name, byte[] classFileContents) {
+ className = name;
+ contents = classFileContents;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public byte[] getContents() {
+ return contents;
+ }
+
+ @Override
+ public int hashCode() {
+ return (this.getClass().getName() + className).hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof GeneratedClassFile)
+ && className.equals(((GeneratedClassFile) obj).getClassName());
+ }
+}
diff --git a/src/com/google/android/testing/mocking/GeneratedMockJar.readme b/src/com/google/android/testing/mocking/GeneratedMockJar.readme
new file mode 100644
index 0000000..858ec6f
--- /dev/null
+++ b/src/com/google/android/testing/mocking/GeneratedMockJar.readme
@@ -0,0 +1,32 @@
+Android Mock
+
+Copyright 2010 Google Inc.
+All Rights Reserved.
+Author: swoodward@google.com (Stephen Woodward)
+
+
+Android Mock is a wrapper for EasyMock (2.4) which allows for real Class mocking on
+an Android (Dalvik) VM.
+
+All methods on Android Mock are syntactically equivalent to EasyMock method
+calls, and will delegate calls to EasyMock, while performing the required
+transformations to avoid Dalvik VM troubles.
+
+Calls directly to EasyMock will work correctly only if the Class being mocked
+is in fact an Interface. Calls to Android Mock will work correctly for both
+Interfaces and concrete Classes.
+
+Android Mock requires that the code being mocked be instrumented prior to
+loading to the Dalvik VM by having called the MockGenerator.jar file. Try
+running java -jar MockGenerator.jar --help for more information.
+
+An example usage pattern is:
+
+@UsesMocks(MyClass.class)
+public void testFoo() MyClass {
+ mockObject = AndroidMock.createMock(MyClass.class);
+ AndroidMock.expect(mockObject.foo(0)).andReturn(42);
+ AndroidMock.replay(mockObject); assertEquals(42, mockObject.foo(0));
+ AndroidMock.verify(mockObject);
+}
+
diff --git a/src/com/google/android/testing/mocking/MockObject.java b/src/com/google/android/testing/mocking/MockObject.java
new file mode 100644
index 0000000..513c900
--- /dev/null
+++ b/src/com/google/android/testing/mocking/MockObject.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Defines the getDelegate___AndroidMock method used by Android Mock for
+ * delegating Android Mock calls to the EasyMock generated MockObject.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public interface MockObject {
+ /**
+ * Accessor method to get the wrapped EasyMock mock object.
+ *
+ * @return a mock object created by EasyMock and wrapped by the object
+ * implementing this method.
+ */
+ Object getDelegate___AndroidMock();
+}
diff --git a/src/com/google/android/testing/mocking/ProcessorLogger.java b/src/com/google/android/testing/mocking/ProcessorLogger.java
new file mode 100644
index 0000000..d2d853c
--- /dev/null
+++ b/src/com/google/android/testing/mocking/ProcessorLogger.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.tools.Diagnostic.Kind;
+
+/**
+ * @author swoodward@google.com (Stephen Woodward)
+ *
+ */
+class ProcessorLogger {
+ private final OutputStream logFile;
+ private final ProcessingEnvironment processingEnv;
+
+ ProcessorLogger(OutputStream logFile, ProcessingEnvironment processingEnv) {
+ this.logFile = logFile;
+ this.processingEnv = processingEnv;
+ }
+
+ ProcessorLogger(String logFileName, ProcessingEnvironment processingEnv) {
+ this.logFile = openLogFile(logFileName);
+ this.processingEnv = processingEnv;
+ }
+
+ void reportClasspathError(String clazz, Throwable e) {
+ printMessage(Kind.ERROR, "Could not find " + clazz);
+ printMessage(Kind.ERROR, e);
+ printMessage(Kind.NOTE, "Known Classpath: ");
+ URL[] allUrls = ((URLClassLoader) this.getClass().getClassLoader()).getURLs();
+ for (URL url : allUrls) {
+ printMessage(Kind.NOTE, url.toString());
+ }
+ }
+
+ void printMessage(Kind kind, String message) {
+ processingEnv.getMessager().printMessage(kind, message);
+ if (logFile != null) {
+ try {
+ logFile.write((SimpleDateFormat.getDateTimeInstance().format(new Date()) + " - "
+ + kind.toString() + " : " + message + "\n").getBytes());
+ } catch (IOException e) {
+ // That's unfortunate, but not much to do about it.
+ processingEnv.getMessager().printMessage(Kind.WARNING,
+ "IOException logging to file" + e.toString());
+ }
+ }
+ }
+
+ void printMessage(Kind kind, Throwable e) {
+ ByteArrayOutputStream stackTraceByteStream = new ByteArrayOutputStream();
+ PrintStream stackTraceStream = new PrintStream(stackTraceByteStream);
+ e.printStackTrace(stackTraceStream);
+ printMessage(kind, stackTraceByteStream.toString());
+ }
+
+ FileOutputStream openLogFile(String logFileName) {
+ try {
+ if (logFileName != null) {
+ File log = new File(logFileName);
+ if (!log.exists() && log.getParentFile() != null) {
+ log.getParentFile().mkdirs();
+ }
+ return new FileOutputStream(log, true);
+ }
+ } catch (FileNotFoundException e) {
+ printMessage(Kind.WARNING, e);
+ }
+ return null;
+ }
+
+ void close() {
+ if (logFile != null) {
+ try {
+ logFile.close();
+ } catch (IOException e) {
+ // That's ok
+ }
+ }
+ }
+}
diff --git a/src/com/google/android/testing/mocking/SdkVersion.java b/src/com/google/android/testing/mocking/SdkVersion.java
new file mode 100644
index 0000000..ee61707
--- /dev/null
+++ b/src/com/google/android/testing/mocking/SdkVersion.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Represents different SDK versions of the Android SDK.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public enum SdkVersion {
+ UNKNOWN("", -1), CUPCAKE("v15", 3), DONUT("v16", 4), ECLAIR_0_1("v201", 6),
+ ECLAIR_MR1("v21", 7), FROYO("v22", 8);
+
+ private static final int SDK_VERSION;
+
+ static {
+ String sdkString = null;
+ int sdkInt;
+ try {
+ Class<?> buildClass = Class.forName("android.os.Build$VERSION");
+ Field sdkField = buildClass.getField("SDK");
+ sdkString = (String) sdkField.get(null);
+ sdkInt = Integer.parseInt(sdkString);
+ } catch (Exception e) {
+ // This will always happen on the desktop side. No big deal.
+ if (sdkString != null) {
+ // But this is unexpected
+ System.out.println(e.toString());
+ e.printStackTrace();
+ }
+ sdkInt = -1;
+ }
+ SDK_VERSION = sdkInt;
+ }
+
+ private final String prefix;
+ private final String versionName;
+ private final int apiLevel;
+
+ private SdkVersion(String packagePrefix, int apiLevel) {
+ versionName = packagePrefix;
+ prefix = packagePrefix.length() == 0 ? "" : packagePrefix + ".";
+ this.apiLevel = apiLevel;
+ }
+
+ /**
+ * Returns an array of SdkVersion objects. This is to be favoured over the
+ * {@link #values()} method, since that method will also return the UNKNOWN
+ * SDK version, which is not usually a valid version on which to operate.
+ *
+ * @return an array of SdkVersion objects.
+ */
+ public static SdkVersion[] getAllVersions() {
+ List<SdkVersion> versions = new ArrayList<SdkVersion>();
+ for (SdkVersion version : values()) {
+ if (!version.equals(UNKNOWN)) {
+ versions.add(version);
+ }
+ }
+ return versions.toArray(new SdkVersion[versions.size()]);
+ }
+
+ public String getVersionName() {
+ return versionName;
+ }
+
+ public String getPackagePrefix() {
+ return prefix;
+ }
+
+ /**
+ * Returns the current SDK version, or UNKNOWN if the version cannot be determined (for instance
+ * if this method is invoked from within a J2SE environment).
+ * @return the current SDK version.
+ */
+ public static SdkVersion getCurrentVersion() {
+ return getVersionFor(SDK_VERSION);
+ }
+
+ static SdkVersion getVersionFor(int apiLevel) {
+ for (SdkVersion version : values()) {
+ if (version.apiLevel == apiLevel) {
+ return version;
+ }
+ }
+ return UNKNOWN;
+ }
+}
diff --git a/src/com/google/android/testing/mocking/UsesMocks.java b/src/com/google/android/testing/mocking/UsesMocks.java
new file mode 100644
index 0000000..55cd1de
--- /dev/null
+++ b/src/com/google/android/testing/mocking/UsesMocks.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation that indicates that a Class should be prepared for Mocking.
+ *
+ * E.g. {@code &#64;UsesMocks(ClassToMock.class)} will indicate that ClassToMock should be prepared
+ * for mocking. Preparation for mocking involves the creation of new classes that will then be
+ * available at runtime on the Dalvik VM (assuming that the Jar file generated by MockGenerator is
+ * added to the APK uploaded to the device/emulator).
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UsesMocks {
+ Class<?>[] value();
+}
diff --git a/src/com/google/android/testing/mocking/UsesMocksProcessor.java b/src/com/google/android/testing/mocking/UsesMocksProcessor.java
new file mode 100644
index 0000000..0ca5c48
--- /dev/null
+++ b/src/com/google/android/testing/mocking/UsesMocksProcessor.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedOptions;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.JavaFileObject;
+
+
+/**
+ * Annotation Processor to generate the mocks for Android Mock.
+ *
+ * This processor will automatically create mocks for all classes
+ * specified by {@link UsesMocks} annotations.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+@SupportedAnnotationTypes("com.google.android.testing.mocking.UsesMocks")
+@SupportedSourceVersion(SourceVersion.RELEASE_5)
+@SupportedOptions({
+ UsesMocksProcessor.REGENERATE_FRAMEWORK_MOCKS,
+ UsesMocksProcessor.LOGFILE,
+ UsesMocksProcessor.BIN_DIR
+})
+public class UsesMocksProcessor extends AbstractProcessor {
+ public static final String LOGFILE = "logfile";
+ public static final String REGENERATE_FRAMEWORK_MOCKS = "RegenerateFrameworkMocks";
+ public static final String BIN_DIR = "bin_dir";
+ private AndroidMockGenerator mockGenerator = new AndroidMockGenerator();
+ private AndroidFrameworkMockGenerator frameworkMockGenerator =
+ new AndroidFrameworkMockGenerator();
+ ProcessorLogger logger;
+
+ /**
+ * Main entry point of the processor. This is called by the Annotation framework.
+ * {@link javax.annotation.processing.AbstractProcessor} for more details.
+ */
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) {
+ try {
+ prepareLogger();
+ List<Class<?>> classesToMock = getClassesToMock(environment);
+ Set<GeneratedClassFile> mockedClassesSet = getMocksFor(classesToMock);
+ writeMocks(mockedClassesSet);
+ } catch (Exception e) {
+ logger.printMessage(Kind.ERROR, e);
+ } finally {
+ logger.close();
+ }
+ return false;
+ }
+
+ /**
+ * Returns a Set of GeneratedClassFile objects which represent all of the classes to be mocked.
+ *
+ * @param classesToMock the list of classes which need to be mocked.
+ * @return a set of mock support classes to support the mocking of all the classes specified in
+ * {@literal classesToMock}.
+ */
+ private Set<GeneratedClassFile> getMocksFor(List<Class<?>> classesToMock) throws IOException,
+ CannotCompileException {
+ logger.printMessage(Kind.NOTE, "Found " + classesToMock.size() + " classes to mock");
+ boolean regenerateFrameworkMocks = processingEnv.getOptions().get(
+ REGENERATE_FRAMEWORK_MOCKS) != null;
+ if (regenerateFrameworkMocks) {
+ logger.printMessage(Kind.NOTE, "Regenerating Framework Mocks on Request");
+ }
+ Set<GeneratedClassFile> mockedClassesSet =
+ getClassMocks(classesToMock, regenerateFrameworkMocks);
+ logger.printMessage(Kind.NOTE, "Found " + mockedClassesSet.size()
+ + " mocked classes to save");
+ return mockedClassesSet;
+ }
+
+ /**
+ * @param environment the environment for this round of processing as provided to the main
+ * {@link #process(Set, RoundEnvironment)} method.
+ * @return a List of Class objects for the classes that need to be mocked.
+ */
+ private List<Class<?>> getClassesToMock(RoundEnvironment environment) {
+ logger.printMessage(Kind.NOTE, "Start Processing Annotations");
+ List<Class<?>> classesToMock = new ArrayList<Class<?>>();
+ classesToMock.addAll(
+ findClassesToMock(environment.getElementsAnnotatedWith(UsesMocks.class)));
+ return classesToMock;
+ }
+
+ private void prepareLogger() {
+ if (logger == null) {
+ logger = new ProcessorLogger(processingEnv.getOptions().get(LOGFILE), processingEnv);
+ }
+ }
+
+ /**
+ * Finds all of the classes that should be mocked, based on {@link UsesMocks} annotations
+ * in the various source files being compiled.
+ *
+ * @param annotatedElements a Set of all elements holding {@link UsesMocks} annotations.
+ * @return all of the classes that should be mocked.
+ */
+ List<Class<?>> findClassesToMock(Set<? extends Element> annotatedElements) {
+ logger.printMessage(Kind.NOTE, "Processing " + annotatedElements);
+ List<Class<?>> classList = new ArrayList<Class<?>>();
+ for (Element annotation : annotatedElements) {
+ List<? extends AnnotationMirror> mirrors = annotation.getAnnotationMirrors();
+ for (AnnotationMirror mirror : mirrors) {
+ if (mirror.getAnnotationType().toString().equals(UsesMocks.class.getName())) {
+ for (AnnotationValue annotationValue : mirror.getElementValues().values()) {
+ for (Object classFileName : (Iterable<?>) annotationValue.getValue()) {
+ String className = classFileName.toString();
+ if (className.endsWith(".class")) {
+ className = className.substring(0, className.length() - 6);
+ }
+ logger.printMessage(Kind.NOTE, "Adding Class to Mocking List: " + className);
+ try {
+ classList.add(Class.forName(className, false, getClass().getClassLoader()));
+ } catch (ClassNotFoundException e) {
+ logger.reportClasspathError(className, e);
+ }
+ }
+ }
+ }
+ }
+ }
+ return classList;
+ }
+
+ /**
+ * Gets a set of GeneratedClassFiles to represent all of the support classes required to
+ * mock the List of classes provided in {@code classesToMock}.
+ * @param classesToMock the list of classes to be mocked.
+ * @param regenerateFrameworkMocks if true, then mocks for the framework classes will be created
+ * instead of pulled from the existing set of framework support classes.
+ * @return a Set of {@link GeneratedClassFile} for all of the mocked classes.
+ */
+ Set<GeneratedClassFile> getClassMocks(List<Class<?>> classesToMock,
+ boolean regenerateFrameworkMocks) throws IOException, CannotCompileException {
+ Set<GeneratedClassFile> mockedClassesSet = new HashSet<GeneratedClassFile>();
+ for (Class<?> clazz : classesToMock) {
+ try {
+ logger.printMessage(Kind.NOTE, "Mocking " + clazz);
+ if (!AndroidMock.isAndroidClass(clazz) || regenerateFrameworkMocks) {
+ mockedClassesSet.addAll(getAndroidMockGenerator().createMocksForClass(clazz));
+ } else {
+ mockedClassesSet.addAll(getAndroidFrameworkMockGenerator().getMocksForClass(clazz));
+ }
+ } catch (ClassNotFoundException e) {
+ logger.reportClasspathError(clazz.getName(), e);
+ } catch (NoClassDefFoundError e) {
+ logger.reportClasspathError(clazz.getName(), e);
+ }
+ }
+ return mockedClassesSet;
+ }
+
+ private AndroidFrameworkMockGenerator getAndroidFrameworkMockGenerator() {
+ return frameworkMockGenerator;
+ }
+
+ /**
+ * Writes the provided mocks from {@code mockedClassesSet} to the bin folder alongside the
+ * .class files being generated by the javac call which invoked this annotation processor.
+ * In Eclipse, additional information is needed as the Eclipse annotation processor framework
+ * is missing key functionality required by this method. Instead the classes are saved using
+ * a FileOutputStream and the -Abin_dir processor option must be set.
+ * @param mockedClassesSet the set of mocks to be saved.
+ */
+ void writeMocks(Set<GeneratedClassFile> mockedClassesSet) {
+ for (GeneratedClassFile clazz : mockedClassesSet) {
+ OutputStream classFileStream;
+ try {
+ logger.printMessage(Kind.NOTE, "Saving " + clazz.getClassName());
+ JavaFileObject classFile = processingEnv.getFiler().createClassFile(clazz.getClassName());
+ classFileStream = classFile.openOutputStream();
+ classFileStream.write(clazz.getContents());
+ classFileStream.close();
+ } catch (IOException e) {
+ logger.printMessage(Kind.ERROR, "Internal Error saving mock: " + clazz.getClassName());
+ logger.printMessage(Kind.ERROR, e);
+ } catch (UnsupportedOperationException e) {
+ // Eclipse annotation processing doesn't support class creation.
+ logger.printMessage(Kind.NOTE, "Saving via Eclipse " + clazz.getClassName());
+ saveMocksEclipse(clazz, processingEnv.getOptions().get(BIN_DIR).toString().trim());
+ }
+ }
+ logger.printMessage(Kind.NOTE, "Finished Processing Mocks");
+ }
+
+ /**
+ * Workaround to save the mocks for Eclipse's annotation processing framework which doesn't
+ * support the JavaFileObject object.
+ * @param clazz the class to save.
+ * @param outputFolderName the output folder where the class will be saved.
+ */
+ private void saveMocksEclipse(GeneratedClassFile clazz, String outputFolderName) {
+ try {
+ FileUtils.saveClassToFolder(clazz, outputFolderName);
+ } catch (FileNotFoundException e) {
+ logger.printMessage(Kind.ERROR, e);
+ } catch (IOException e) {
+ logger.printMessage(Kind.ERROR, e);
+ }
+ }
+
+ private AndroidMockGenerator getAndroidMockGenerator() {
+ return mockGenerator;
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/AndroidFrameworkMockGeneratorTest.java b/tests/com/google/android/testing/mocking/AndroidFrameworkMockGeneratorTest.java
new file mode 100644
index 0000000..813063f
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/AndroidFrameworkMockGeneratorTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.NotFoundException;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Vector;
+import java.util.jar.JarEntry;
+
+/**
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class AndroidFrameworkMockGeneratorTest extends TestCase {
+ private void cleanupGeneratedClasses(CtClass... classes) {
+ for (CtClass clazz : classes) {
+ clazz.detach();
+ }
+ }
+
+ private Collection<JarEntry> getMockJarEntries() {
+ JarEntry firstEntry = new JarEntry("java/lang/Object.class");
+ JarEntry secondEntry = new JarEntry(
+ "com/google/android/testing/mocking/AndroidFrameworkMockGeneratorTest$Inner.class");
+ List<JarEntry> entryList = new ArrayList<JarEntry>();
+ entryList.add(firstEntry);
+ entryList.add(secondEntry);
+ return entryList;
+ }
+
+ private <T> void assertUnorderedContentsSame(Iterable<T> expected, Iterable<T> actual) {
+ List<T> missingItems = new ArrayList<T>();
+ List<T> extraItems = new ArrayList<T>();
+ for (T item : expected) {
+ missingItems.add(item);
+ }
+ for (T item : actual) {
+ missingItems.remove(item);
+ extraItems.add(item);
+ }
+ for (T item : expected) {
+ extraItems.remove(item);
+ }
+ if (missingItems.size() + extraItems.size() != 0) {
+ String errorMessage =
+ "Contents were different. Missing: " + Arrays.toString(missingItems.toArray())
+ + " Extra: " + Arrays.toString(extraItems.toArray());
+ fail(errorMessage);
+ }
+ }
+
+ private List<String> getClassNames(List<GeneratedClassFile> classes) {
+ List<String> classNames = new ArrayList<String>();
+ for (GeneratedClassFile clazz : classes) {
+ classNames.add(clazz.getClassName());
+ }
+ return classNames;
+ }
+
+ private AndroidFrameworkMockGenerator getMockGenerator() {
+ return new AndroidFrameworkMockGenerator();
+ }
+
+ public void testCreateMockForClass() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidFrameworkMockGenerator mockGenerator = getMockGenerator();
+ for (SdkVersion version : SdkVersion.getAllVersions()) {
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object.class, version);
+
+ List<String> expectedNames = new ArrayList<String>();
+ expectedNames.addAll(Arrays.asList(new String[] {
+ version.getPackagePrefix() + "genmocks.java.lang.ObjectDelegateSubclass",
+ version.getPackagePrefix() + "genmocks.java.lang.ObjectDelegateInterface"}));
+ List<String> actualNames = getClassNames(classes);
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ }
+ }
+
+ public void testGetClassList() throws ClassNotFoundException {
+ Collection<JarEntry> jarEntries = getMockJarEntries();
+ List<String> expectedClassNames =
+ new ArrayList<String>(Arrays.asList(new String[] {
+ "java.lang.Object",
+ "com.google.android.testing.mocking.AndroidFrameworkMockGeneratorTest$Inner"}));
+ List<Class<?>> list = getMockGenerator().getClassList(jarEntries);
+ assertEquals(expectedClassNames.size(), list.size());
+ for (Class<?> clazz : list) {
+ assertTrue(clazz.getName(), expectedClassNames.contains(clazz.getName()));
+ }
+ }
+
+ public void testIsClassFile() {
+ assertTrue(getMockGenerator().jarEntryIsClassFile(new JarEntry("something.class")));
+ assertTrue(getMockGenerator().jarEntryIsClassFile(new JarEntry("/Foo/Bar.class")));
+ assertFalse(getMockGenerator().jarEntryIsClassFile(new JarEntry("/Foo/Bar.clas")));
+ assertFalse(getMockGenerator().jarEntryIsClassFile(new JarEntry("/Foo/Bar.class ")));
+ assertFalse(getMockGenerator().jarEntryIsClassFile(new JarEntry("/Foo/Bar")));
+ }
+
+ public void testGetJarFileNameForVersion() {
+ for (SdkVersion version : SdkVersion.getAllVersions()) {
+ getMockGenerator();
+ assertEquals("lib/android/android_" + version.getVersionName() + ".jar",
+ AndroidFrameworkMockGenerator.getJarFileNameForVersion(version));
+ }
+ }
+
+ public void testGetMocksForClass() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<CtClass> createdClasses = new ArrayList<CtClass>();
+ AndroidFrameworkMockGenerator mockGenerator = getMockGenerator();
+ for (SdkVersion version : SdkVersion.getAllVersions()) {
+ List<GeneratedClassFile> createdMocks = mockGenerator.createMocksForClass(
+ Vector.class, version);
+ for (GeneratedClassFile mock : createdMocks) {
+ CtClass ctClass = ClassPool.getDefault().get(mock.getClassName());
+ createdClasses.add(ctClass);
+ ctClass.toClass();
+ }
+ }
+ List<GeneratedClassFile> mocks = mockGenerator.getMocksForClass(Vector.class);
+ String[] expectedClassNames = new String[] {
+ "v15.genmocks.java.util.VectorDelegateSubclass",
+ "v15.genmocks.java.util.VectorDelegateInterface",
+ "v16.genmocks.java.util.VectorDelegateSubclass",
+ "v16.genmocks.java.util.VectorDelegateInterface",
+ "v201.genmocks.java.util.VectorDelegateSubclass",
+ "v201.genmocks.java.util.VectorDelegateInterface",
+ "v21.genmocks.java.util.VectorDelegateSubclass",
+ "v21.genmocks.java.util.VectorDelegateInterface",
+ "v22.genmocks.java.util.VectorDelegateSubclass",
+ "v22.genmocks.java.util.VectorDelegateInterface"
+ };
+ assertEquals(expectedClassNames.length, mocks.size());
+ for (int i = 0; i < mocks.size(); ++i) {
+ assertEquals(expectedClassNames[i], mocks.get(i).getClassName());
+ }
+ cleanupGeneratedClasses(createdClasses.toArray(new CtClass[0]));
+ }
+
+ class Inner {
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/AndroidMockGeneratorTest.java b/tests/com/google/android/testing/mocking/AndroidMockGeneratorTest.java
new file mode 100644
index 0000000..ef36b24
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/AndroidMockGeneratorTest.java
@@ -0,0 +1,575 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * Tests for the AndroidMockGenerator class.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class AndroidMockGeneratorTest extends TestCase {
+ private AndroidMockGenerator getAndroidMockGenerator() {
+ return new AndroidMockGenerator();
+ }
+
+ private NoFileAndroidMockGenerator getNoFileMockGenerator() {
+ return new NoFileAndroidMockGenerator();
+ }
+
+ private void cleanupGeneratedClasses(CtClass... classes) {
+ for (CtClass clazz : classes) {
+ clazz.detach();
+ }
+ }
+
+ private <T> void assertUnorderedContentsSame(Iterable<T> expected, Iterable<T> actual) {
+ List<T> missingItems = new ArrayList<T>();
+ List<T> extraItems = new ArrayList<T>();
+ for (T item : expected) {
+ missingItems.add(item);
+ }
+ for (T item : actual) {
+ missingItems.remove(item);
+ extraItems.add(item);
+ }
+ for (T item : expected) {
+ extraItems.remove(item);
+ }
+ if (missingItems.size() + extraItems.size() != 0) {
+ String errorMessage =
+ "Contents were different. Missing: " + Arrays.toString(missingItems.toArray())
+ + " Extra: " + Arrays.toString(extraItems.toArray());
+ fail(errorMessage);
+ }
+ }
+
+ private List<String> getExpectedNamesForNumberClass() {
+ return getExpectedNamesForNumberClass(false);
+ }
+
+ private List<String> getExpectedNamesForObjectClass() {
+ List<String> expectedNames = new ArrayList<String>();
+ expectedNames.addAll(Arrays.asList(new String[] {"clone", "finalize"}));
+ return expectedNames;
+ }
+
+ private List<String> getExpectedNamesForNumberClass(boolean includeDelegateMethods) {
+ List<String> expectedNames = getExpectedNamesForObjectClass();
+ expectedNames.addAll(Arrays.asList(new String[] {"byteValue", "doubleValue", "floatValue",
+ "intValue", "longValue", "shortValue"}));
+ if (includeDelegateMethods) {
+ expectedNames.addAll(Arrays.asList(new String[] {"getDelegate___AndroidMock",
+ "setDelegate___AndroidMock"}));
+ }
+ return expectedNames;
+ }
+
+ private List<String> getExpectedNamesForBigIntegerClass() {
+ List<String> expectedNames = getExpectedNamesForNumberClass();
+ expectedNames.addAll(Arrays.asList(new String[] {"abs", "add", "and", "andNot", "bitCount",
+ "bitLength", "clearBit", "compareTo", "divide", "divideAndRemainder", "flipBit", "gcd",
+ "getLowestSetBit", "isProbablePrime", "max", "min", "mod", "modInverse", "modPow",
+ "multiply", "negate", "nextProbablePrime", "not", "or", "pow", "remainder", "setBit",
+ "shiftLeft", "shiftRight", "signum", "subtract", "testBit", "toByteArray", "toString",
+ "xor"}));
+ return expectedNames;
+ }
+
+ private List<String> getMethodNames(CtMethod[] methods) {
+ List<String> methodNames = new ArrayList<String>();
+ for (CtMethod method : methods) {
+ methodNames.add(method.getName());
+ }
+ return methodNames;
+ }
+
+ private List<String> getClassNames(List<GeneratedClassFile> classes) {
+ List<String> classNames = new ArrayList<String>();
+ for (GeneratedClassFile clazz : classes) {
+ classNames.add(clazz.getClassName());
+ }
+ return classNames;
+ }
+
+ private List<String> getExpectedSignaturesForBigIntegerClass() {
+ List<String> expectedNames = new ArrayList<String>();
+ expectedNames.addAll(Arrays.asList(new String[] {
+ "public int java.math.BigInteger.getLowestSetBit()",
+ "public java.math.BigInteger java.math.BigInteger.abs()",
+ "protected void java.lang.Object.finalize() throws java.lang.Throwable",
+ "public java.math.BigInteger java.math.BigInteger.modPow(java.math.BigInteger,"
+ + "java.math.BigInteger)",
+ "protected native java.lang.Object java.lang.Object.clone() throws "
+ + "java.lang.CloneNotSupportedException",
+ "public java.math.BigInteger java.math.BigInteger.setBit(int)",
+ "public java.math.BigInteger java.math.BigInteger.shiftRight(int)",
+ "public int java.math.BigInteger.bitLength()",
+ "public java.math.BigInteger java.math.BigInteger.not()",
+ "public java.math.BigInteger java.math.BigInteger.subtract(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.flipBit(int)",
+ "public boolean java.math.BigInteger.isProbablePrime(int)",
+ "public java.math.BigInteger java.math.BigInteger.add(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.modInverse(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.clearBit(int)",
+ "public java.math.BigInteger java.math.BigInteger.multiply(java.math.BigInteger)",
+ "public byte java.lang.Number.byteValue()",
+ "public java.math.BigInteger java.math.BigInteger.gcd(java.math.BigInteger)",
+ "public float java.math.BigInteger.floatValue()",
+ "public java.lang.String java.math.BigInteger.toString(int)",
+ "public java.math.BigInteger java.math.BigInteger.min(java.math.BigInteger)",
+ "public int java.math.BigInteger.intValue()",
+ "public java.math.BigInteger java.math.BigInteger.or(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.remainder(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.divide(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.xor(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.and(java.math.BigInteger)",
+ "public int java.math.BigInteger.signum()",
+ "public java.math.BigInteger[] java.math.BigInteger.divideAndRemainder("
+ + "java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.max(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.shiftLeft(int)",
+ "public double java.math.BigInteger.doubleValue()",
+ "public java.math.BigInteger java.math.BigInteger.pow(int)",
+ "public short java.lang.Number.shortValue()",
+ "public java.math.BigInteger java.math.BigInteger.andNot(java.math.BigInteger)",
+ "public byte[] java.math.BigInteger.toByteArray()",
+ "public java.math.BigInteger java.math.BigInteger.negate()",
+ "public int java.math.BigInteger.compareTo(java.math.BigInteger)",
+ "public boolean java.math.BigInteger.testBit(int)",
+ "public int java.math.BigInteger.bitCount()",
+ "public long java.math.BigInteger.longValue()",
+ "public java.math.BigInteger java.math.BigInteger.mod(java.math.BigInteger)",
+ "public java.math.BigInteger java.math.BigInteger.nextProbablePrime()",
+ }));
+ return expectedNames;
+ }
+
+ private List<String> getMethodSignatures(Method[] methods) {
+ List<String> methodSignatures = new ArrayList<String>();
+ for (Method method : methods) {
+ if (getAndroidMockGenerator().isMockable(method)) {
+ methodSignatures.add(method.toGenericString());
+ }
+ }
+ return methodSignatures;
+ }
+
+ public void testIsSupportedType() {
+ Class<?>[] unsupportedClasses =
+ new Class[] {ClassIsAnnotation.class, ClassIsEnum.class, ClassIsFinal.class,
+ ClassIsInterface.class};
+ Class<?>[] supportedClasses = new Class[] {Object.class};
+
+ for (Class<?> clazz : unsupportedClasses) {
+ assertFalse(getAndroidMockGenerator().classIsSupportedType(clazz));
+ }
+ for (Class<?> clazz : supportedClasses) {
+ assertTrue(getAndroidMockGenerator().classIsSupportedType(clazz));
+ }
+ }
+
+ public void testGetDelegateFieldName() {
+ assertEquals("delegateMockObject", getAndroidMockGenerator().getDelegateFieldName());
+ }
+
+ public void testGetInterfaceMethodSource() throws SecurityException, NoSuchMethodException {
+ Method method = Object.class.getMethod("equals", Object.class);
+ assertEquals("public boolean equals(java.lang.Object arg0);", getAndroidMockGenerator()
+ .getInterfaceMethodSource(method));
+ }
+
+ public void testGetInterfaceMethodSourceMultipleExceptions() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Class.class.getDeclaredMethod("newInstance");
+ assertEquals("public java.lang.Object newInstance() throws java.lang.InstantiationException,"
+ + "java.lang.IllegalAccessException;", getAndroidMockGenerator().getInterfaceMethodSource(
+ method));
+ }
+
+ public void testGetInterfaceMethodSourceProtectedMethod() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Object.class.getDeclaredMethod("finalize");
+ assertEquals("public void finalize() throws java.lang.Throwable;", getAndroidMockGenerator()
+ .getInterfaceMethodSource(method));
+ }
+
+ public void testGetInterfaceMethodSourceNoParams() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Object.class.getMethod("toString");
+ assertEquals("public java.lang.String toString();", getAndroidMockGenerator()
+ .getInterfaceMethodSource(method));
+ }
+
+ public void testGetInterfaceMethodSourceVoidReturn() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Thread.class.getMethod("run");
+ assertEquals("public void run();", getAndroidMockGenerator().getInterfaceMethodSource(method));
+ }
+
+ public void testGetInterfaceMethodSourceFinal() throws SecurityException, NoSuchMethodException {
+ Method method = Object.class.getMethod("notify");
+ try {
+ getAndroidMockGenerator().getInterfaceMethodSource(method);
+ fail("Exception not thrown on a final method");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+
+ public void testGetInterfaceMethodSourceStatic() throws SecurityException, NoSuchMethodException {
+ Method method = Thread.class.getMethod("currentThread");
+ try {
+ getAndroidMockGenerator().getInterfaceMethodSource(method);
+ fail("Exception not thrown on a static method");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+
+ public void testGetInterfaceName() {
+ AndroidMockGenerator r = getAndroidMockGenerator();
+ assertEquals("genmocks.java.lang.ObjectDelegateInterface",
+ FileUtils.getInterfaceNameFor(Object.class, SdkVersion.UNKNOWN));
+ }
+
+ public void testGetSubclassName() {
+ AndroidMockGenerator r = getAndroidMockGenerator();
+ assertEquals("genmocks.java.lang.ObjectDelegateSubclass",
+ FileUtils.getSubclassNameFor(Object.class, SdkVersion.UNKNOWN));
+ }
+
+ public void testGetDelegateMethodSource() throws SecurityException, NoSuchMethodException {
+ Method method = Object.class.getMethod("equals", Object.class);
+ assertEquals("public boolean equals(java.lang.Object arg0){if(this.delegateMockObject==null){"
+ + "return false;}return this.delegateMockObject.equals(arg0);}", getAndroidMockGenerator()
+ .getDelegateMethodSource(method));
+ }
+
+ public void testGetDelegateMethodSourceAllTypes() throws SecurityException,
+ NoSuchMethodException {
+ String[] returnTypes =
+ new String[] {"boolean", "byte", "short", "int", "long", "char", "float", "double"};
+ String[] castTypes =
+ new String[] {"false", "(byte)0", "(short)0", "(int)0", "(long)0", "(char)0", "(float)0",
+ "(double)0"};
+ for (int i = 0; i < returnTypes.length; ++i) {
+ Method method = AllTypes.class.getMethod(returnTypes[i] + "Foo");
+ assertEquals("public " + returnTypes[i] + " " + returnTypes[i]
+ + "Foo(){if(this.delegateMockObject==null){return " + castTypes[i]
+ + ";}return this.delegateMockObject." + returnTypes[i] + "Foo();}",
+ getAndroidMockGenerator().getDelegateMethodSource(method));
+ }
+ Method method = AllTypes.class.getMethod("objectFoo");
+ assertEquals("public java.lang.Object objectFoo(){if(this.delegateMockObject==null){return "
+ + "null;}return this.delegateMockObject.objectFoo();}", getAndroidMockGenerator()
+ .getDelegateMethodSource(method));
+ method = AllTypes.class.getMethod("voidFoo");
+ assertEquals("public void voidFoo(){if(this.delegateMockObject==null){return ;"
+ + "}this.delegateMockObject.voidFoo();}", getAndroidMockGenerator()
+ .getDelegateMethodSource(method));
+ }
+
+ private class AllTypes {
+ @SuppressWarnings("unused")
+ public void voidFoo() {
+ }
+
+ @SuppressWarnings("unused")
+ public boolean booleanFoo() {
+ return false;
+ }
+
+ @SuppressWarnings("unused")
+ public byte byteFoo() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ public short shortFoo() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ public int intFoo() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ public long longFoo() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ public char charFoo() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ public float floatFoo() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ public double doubleFoo() {
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ public Object objectFoo() {
+ return null;
+ }
+ }
+
+ public void testGetDelegateMethodSourceMultipleExceptions() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Class.class.getDeclaredMethod("newInstance");
+ assertEquals(
+ "public java.lang.Object newInstance() throws java.lang.InstantiationException,"
+ + "java.lang.IllegalAccessException{if(this.delegateMockObject==null){return null;}"
+ + "return this.delegateMockObject.newInstance();}", getAndroidMockGenerator()
+ .getDelegateMethodSource(method));
+ }
+
+ public void testGetDelegateMethodSourceProtectedMethod() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Object.class.getDeclaredMethod("finalize");
+ assertEquals("public void finalize() throws java.lang.Throwable{if(this.delegateMockObject=="
+ + "null){return ;}this.delegateMockObject.finalize();}", getAndroidMockGenerator()
+ .getDelegateMethodSource(method));
+ }
+
+ public void testGetDelegateMethodSourceMultiParams() throws SecurityException,
+ NoSuchMethodException {
+ Method method =
+ String.class.getMethod("getChars", Integer.TYPE, Integer.TYPE, char[].class, Integer.TYPE);
+ assertEquals(
+ "public void getChars(int arg0,int arg1,char[] arg2,int arg3){if(this."
+ + "delegateMockObject==null){return ;}this.delegateMockObject.getChars(arg0,arg1,arg2,"
+ + "arg3);}", getAndroidMockGenerator().getDelegateMethodSource(method));
+ }
+
+ public void testGetDelegateMethodSourceNoParams() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Object.class.getMethod("toString");
+ assertEquals(
+ "public java.lang.String toString(){if(this.delegateMockObject==null){return null;"
+ + "}return this.delegateMockObject.toString();}", getAndroidMockGenerator()
+ .getDelegateMethodSource(method));
+ }
+
+ public void testGetDelegateMethodSourceVoidReturn() throws SecurityException,
+ NoSuchMethodException {
+ Method method = Thread.class.getMethod("run");
+ assertEquals("public void run(){if(this.delegateMockObject==null){return ;}this."
+ + "delegateMockObject.run();}", getAndroidMockGenerator().getDelegateMethodSource(method));
+ }
+
+ public void testGetDelegateMethodSourceFinal() throws SecurityException, NoSuchMethodException {
+ Method method = Object.class.getMethod("notify");
+ try {
+ getAndroidMockGenerator().getDelegateMethodSource(method);
+ fail("Exception not thrown on a final method");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+
+ public void testGetDelegateMethodSourceStatic() throws SecurityException, NoSuchMethodException {
+ Method method = Thread.class.getMethod("currentThread");
+ try {
+ getAndroidMockGenerator().getDelegateMethodSource(method);
+ fail("Exception not thrown on a static method");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+
+ public void testGenerateEmptySubclass() throws ClassNotFoundException, NotFoundException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(String.class, SdkVersion.UNKNOWN);
+ CtClass generatedClass = getAndroidMockGenerator().generateSkeletalClass(
+ String.class, generatedInterface, SdkVersion.UNKNOWN);
+
+ assertEquals("genmocks.java.lang", generatedClass.getPackageName());
+ assertEquals("StringDelegateSubclass", generatedClass.getSimpleName());
+ assertEquals("java.lang.String", generatedClass.getSuperclass().getName());
+ cleanupGeneratedClasses(generatedInterface, generatedClass);
+ }
+
+ public void testAddMethods() throws ClassNotFoundException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(Number.class, SdkVersion.UNKNOWN);
+ CtClass generatedClass =
+ mockGenerator.generateSkeletalClass(Number.class, generatedInterface, SdkVersion.UNKNOWN);
+
+ mockGenerator.addMethods(Number.class, generatedClass);
+
+ List<String> expectedNames = getExpectedNamesForNumberClass();
+ List<String> actualNames = getMethodNames(generatedClass.getDeclaredMethods());
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(generatedInterface, generatedClass);
+ }
+
+ public void testAddMethodsObjectClass() throws ClassNotFoundException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(Object.class, SdkVersion.UNKNOWN);
+ CtClass generatedClass =
+ mockGenerator.generateSkeletalClass(Object.class, generatedInterface, SdkVersion.UNKNOWN);
+
+ mockGenerator.addMethods(Object.class, generatedClass);
+
+ List<String> expectedNames = getExpectedNamesForObjectClass();
+ List<String> actualNames = getMethodNames(generatedClass.getDeclaredMethods());
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(generatedInterface, generatedClass);
+ }
+
+ public void testAddMethodsUsesSuperclass() throws ClassNotFoundException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(
+ BigInteger.class, SdkVersion.UNKNOWN);
+ CtClass generatedClass = mockGenerator.generateSkeletalClass(
+ BigInteger.class, generatedInterface, SdkVersion.UNKNOWN);
+
+ mockGenerator.addMethods(BigInteger.class, generatedClass);
+
+ List<String> expectedNames = getExpectedNamesForBigIntegerClass();
+ List<String> actualNames = getMethodNames(generatedClass.getDeclaredMethods());
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(generatedInterface, generatedClass);
+ }
+
+ public void testGetAllMethods() throws ClassNotFoundException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(
+ BigInteger.class, SdkVersion.UNKNOWN);
+ CtClass generatedClass = mockGenerator.generateSkeletalClass(
+ BigInteger.class, generatedInterface, SdkVersion.UNKNOWN);
+
+ Method[] methods = mockGenerator.getAllMethods(BigInteger.class);
+
+ List<String> expectedNames = getExpectedSignaturesForBigIntegerClass();
+ List<String> actualNames = getMethodSignatures(methods);
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(generatedInterface, generatedClass);
+ }
+
+ public void testGenerateInterface() {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(Number.class, SdkVersion.UNKNOWN);
+
+ List<String> expectedNames = getExpectedNamesForNumberClass();
+ List<String> actualNames = getMethodNames(generatedInterface.getDeclaredMethods());
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(generatedInterface);
+ }
+
+ public void testAddInterfaceMethods() {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = AndroidMockGenerator.getClassPool().makeInterface("testInterface");
+
+ mockGenerator.addInterfaceMethods(Number.class, generatedInterface);
+
+ List<String> expectedNames = getExpectedNamesForNumberClass();
+ List<String> actualNames = getMethodNames(generatedInterface.getDeclaredMethods());
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(generatedInterface);
+ }
+
+ public void testGenerateSubclass() throws ClassNotFoundException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(Number.class, SdkVersion.UNKNOWN);
+
+ CtClass generatedClass =
+ mockGenerator.generateSubClass(Number.class, generatedInterface, SdkVersion.UNKNOWN);
+
+ List<String> expectedNames = getExpectedNamesForNumberClass(true);
+ List<String> actualNames = getMethodNames(generatedClass.getDeclaredMethods());
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(generatedInterface, generatedClass);
+ }
+
+ public void testCreateMockForClass() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ NoFileAndroidMockGenerator mockGenerator = getNoFileMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object.class);
+
+ List<String> expectedNames = new ArrayList<String>();
+ String subclassName = "genmocks.java.lang.ObjectDelegateSubclass";
+ String interfaceName = "genmocks.java.lang.ObjectDelegateInterface";
+ expectedNames.addAll(Arrays.asList(new String[] {subclassName,
+ interfaceName}));
+ List<String> actualNames = getClassNames(classes);
+ assertUnorderedContentsSame(expectedNames, actualNames);
+ cleanupGeneratedClasses(
+ ClassPool.getDefault().get(subclassName),
+ ClassPool.getDefault().get(interfaceName));
+ }
+
+ public void testGetSetDelegateMethodSource() {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ CtClass generatedInterface = mockGenerator.generateInterface(Object.class, SdkVersion.UNKNOWN);
+ String expectedSource =
+ "public void setDelegate___AndroidMock(genmocks.java.lang.ObjectDelegateInterface obj) {"
+ + " this.delegateMockObject = obj;}";
+
+ assertEquals(expectedSource, mockGenerator.getSetDelegateMethodSource(generatedInterface));
+ }
+
+ public void testIsForbiddenMethod() throws SecurityException, NoSuchMethodException {
+ Method[] forbiddenMethods =
+ new Method[] {Object.class.getMethod("equals", Object.class),
+ Object.class.getMethod("toString"), Object.class.getMethod("hashCode")};
+ Method[] allowedMethods = new Method[] {BigInteger.class.getMethod("toString", Integer.TYPE)};
+ for (Method method : forbiddenMethods) {
+ assertTrue(getAndroidMockGenerator().isForbiddenMethod(method));
+ }
+ for (Method method : allowedMethods) {
+ assertFalse(getAndroidMockGenerator().isForbiddenMethod(method));
+ }
+ }
+
+ /**
+ * Support test class for capturing the names of files that would have been
+ * saved to a jar file.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+ class NoFileAndroidMockGenerator extends AndroidMockGenerator {
+ List<CtClass> savedClasses = new ArrayList<CtClass>();
+
+ @Override
+ void saveCtClass(CtClass clazz) {
+ savedClasses.add(clazz);
+ }
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/AndroidMockTest.java b/tests/com/google/android/testing/mocking/AndroidMockTest.java
new file mode 100644
index 0000000..56fcbb3
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/AndroidMockTest.java
@@ -0,0 +1,927 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.Modifier;
+import javassist.NotFoundException;
+import javassist.expr.ExprEditor;
+import javassist.expr.MethodCall;
+
+import junit.framework.TestCase;
+
+import org.easymock.Capture;
+import org.easymock.IAnswer;
+import org.easymock.LogicalOperator;
+import org.easymock.internal.matchers.Equals;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.SimpleTimeZone;
+import java.util.Vector;
+
+
+/**
+ * Tests for the AndroidMock class.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class AndroidMockTest extends TestCase {
+ private List<String> notForwardedMethods =
+ new ArrayList<String>(Arrays.asList(new String[] {
+ "com.google.android.testing.mocking.AndroidMock.getInterfaceFor(java.lang.Class)",
+ "com.google.android.testing.mocking.AndroidMock.getSubclassNameFor(java.lang.Class)",
+ "com.google.android.testing.mocking.AndroidMock.getSubclassFor(java.lang.Class,"
+ + "java.lang.Class,java.lang.Object)",
+ "com.google.android.testing.mocking.AndroidMock.getInterfaceNameFor(java.lang.Class)",
+ "com.google.android.testing.mocking.AndroidMock.createStrictMock("
+ + "java.lang.Class,java.lang.Object[])",
+ "com.google.android.testing.mocking.AndroidMock.createStrictMock("
+ + "java.lang.String,java.lang.Class,java.lang.Object[])",
+ "com.google.android.testing.mocking.AndroidMock.createMock("
+ + "java.lang.Class,java.lang.Object[])",
+ "com.google.android.testing.mocking.AndroidMock.createMock("
+ + "java.lang.String,java.lang.Class,java.lang.Object[])",
+ "com.google.android.testing.mocking.AndroidMock.createNiceMock("
+ + "java.lang.Class,java.lang.Object[])",
+ "com.google.android.testing.mocking.AndroidMock.createNiceMock("
+ + "java.lang.String,java.lang.Class,java.lang.Object[])"}));
+
+ private CtMethod[] getForwardedMethods() throws NotFoundException {
+ List<CtMethod> methods =
+ new ArrayList<CtMethod>(Arrays.asList(getAndroidMockCtClass().getDeclaredMethods()));
+ // Get a copy for safe removal of elements during iteration.
+ for (CtMethod method : Arrays.asList(methods.toArray(new CtMethod[0]))) {
+ if (notForwardedMethods.contains(method.getLongName())
+ || !Modifier.isPublic(method.getModifiers())) {
+ methods.remove(method);
+ }
+ }
+ return methods.toArray(new CtMethod[0]);
+ }
+
+ private CtClass getAndroidMockCtClass() throws NotFoundException {
+ return ClassPool.getDefault().get("com.google.android.testing.mocking.AndroidMock");
+ }
+
+ private void compileClasses(List<GeneratedClassFile> mockClasses) throws NotFoundException {
+ for (GeneratedClassFile clazz : mockClasses) {
+ CtClass ctClass;
+ ctClass = ClassPool.getDefault().get(clazz.getClassName());
+ try {
+ ctClass.toClass();
+ } catch (CannotCompileException e) {
+ // Just ignore -- this will happen for every class used in more than one test.
+ }
+ }
+ }
+
+ public void testIsUnboxableToPrimitiveAllPrimitives() {
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Integer.TYPE, new Integer(42), true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Long.TYPE, new Long(42L), true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Short.TYPE, new Short((short) 42), true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Byte.TYPE, new Byte((byte) 42), true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Boolean.TYPE, Boolean.TRUE, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Float.TYPE, new Float(42.0f), true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Double.TYPE, new Double(42.0), true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Character.TYPE, new Character('a'), true));
+
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Integer.TYPE, 42, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Long.TYPE, 42L, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Short.TYPE, (short) 42, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Byte.TYPE, (byte) 42, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Boolean.TYPE, true, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Float.TYPE, 42.0f, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Double.TYPE, 42.0, true));
+ assertTrue(AndroidMock.isUnboxableToPrimitive(Character.TYPE, 'a', true));
+ }
+
+ public void testIsUnboxableToPrimitiveIsObject() {
+ assertFalse(AndroidMock.isUnboxableToPrimitive(Integer.TYPE, new Object(), false));
+ }
+
+ public void testIsUnboxableToPrimitiveAllWideningPrimitives() {
+ Object[] testValues =
+ new Object[] {new Byte((byte) 42), new Short((short) 42), new Integer(42), new Long(42L),
+ new Float(42.0f), new Double(42.0), new Character('a'), Boolean.TRUE};
+ boolean[] byteExpected = new boolean[] {true, false, false, false, false, false, false, false};
+ boolean[] shortExpected = new boolean[] {true, true, false, false, false, false, true, false};
+ boolean[] intExpected = new boolean[] {true, true, true, false, false, false, true, false};
+ boolean[] longExpected = new boolean[] {true, true, true, true, false, false, true, false};
+ boolean[] floatExpected = new boolean[] {true, true, true, false, true, false, true, false};
+ boolean[] doubleExpected = new boolean[] {true, true, true, true, true, true, true, false};
+ boolean[] charExpected = new boolean[] {true, true, true, false, false, false, true, false};
+ boolean[] booleanExpected =
+ new boolean[] {false, false, false, false, false, false, false, true};
+
+ for (int i = 0; i < testValues.length; ++i) {
+ assertEquals("Convert byte from " + testValues[i].getClass(), byteExpected[i], AndroidMock
+ .isUnboxableToPrimitive(Byte.TYPE, testValues[i], false));
+ assertEquals("Convert short from " + testValues[i].getClass(), shortExpected[i], AndroidMock
+ .isUnboxableToPrimitive(Short.TYPE, testValues[i], false));
+ assertEquals("Convert int from " + testValues[i].getClass(), intExpected[i], AndroidMock
+ .isUnboxableToPrimitive(Integer.TYPE, testValues[i], false));
+ assertEquals("Convert long from " + testValues[i].getClass(), longExpected[i], AndroidMock
+ .isUnboxableToPrimitive(Long.TYPE, testValues[i], false));
+ assertEquals("Convert float from " + testValues[i].getClass(), floatExpected[i], AndroidMock
+ .isUnboxableToPrimitive(Float.TYPE, testValues[i], false));
+ assertEquals("Convert double from " + testValues[i].getClass(), doubleExpected[i],
+ AndroidMock.isUnboxableToPrimitive(Double.TYPE, testValues[i], false));
+ assertEquals("Convert char from " + testValues[i].getClass(), charExpected[i], AndroidMock
+ .isUnboxableToPrimitive(Character.TYPE, testValues[i], false));
+ assertEquals("Convert boolean from " + testValues[i].getClass(), booleanExpected[i],
+ AndroidMock.isUnboxableToPrimitive(Boolean.TYPE, testValues[i], false));
+ }
+ }
+
+
+ public void testIsUnboxableToPrimitiveNotPrimitive() {
+ try {
+ AndroidMock.isUnboxableToPrimitive(Object.class, Object.class, false);
+ fail("Exception should have been thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void testCreateMock() throws ClassNotFoundException, IOException, CannotCompileException,
+ NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<String> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.expect(mockVector.get(0)).andReturn("Hello World");
+ AndroidMock.replay(mockVector);
+ assertEquals("Hello World", mockVector.get(0).toString());
+ AndroidMock.verify(mockVector);
+ }
+
+ public void testCreateMockUsingParameters() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+ compileClasses(mockClasses);
+ SimpleTimeZone mockTimeZone = AndroidMock.createMock(SimpleTimeZone.class, 0, "GMT");
+ AndroidMock.expect(mockTimeZone.getRawOffset()).andReturn(42);
+ AndroidMock.replay(mockTimeZone);
+ assertEquals(42, mockTimeZone.getRawOffset());
+ AndroidMock.verify(mockTimeZone);
+ }
+
+ public void testCreateMockUsingProtectedConstructors() throws ClassNotFoundException,
+ IOException, CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Calendar.class);
+ compileClasses(mockClasses);
+ Calendar mockCalendar = AndroidMock.createMock(Calendar.class);
+ AndroidMock.expect(mockCalendar.getGreatestMinimum(1)).andReturn(42);
+ AndroidMock.replay(mockCalendar);
+ assertEquals(42, mockCalendar.getGreatestMinimum(1));
+ AndroidMock.verify(mockCalendar);
+
+ // Just don't explode
+ Calendar newMockCalendar =
+ AndroidMock.createMock(Calendar.class, new SimpleTimeZone(1, "GMT"), Locale.UK);
+ }
+
+ public void testCreateMockUsingCastableParameters() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+ compileClasses(mockClasses);
+ SimpleTimeZone mockTimeZone = AndroidMock.createMock(SimpleTimeZone.class, 'a', "GMT");
+ AndroidMock.expect(mockTimeZone.getRawOffset()).andReturn(42);
+ AndroidMock.replay(mockTimeZone);
+ assertEquals(42, mockTimeZone.getRawOffset());
+ AndroidMock.verify(mockTimeZone);
+ }
+
+ public void testCreateMockUsingUnusableParameters() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+ compileClasses(mockClasses);
+ try {
+ SimpleTimeZone mockTimeZone = AndroidMock.createMock(SimpleTimeZone.class, "GMT");
+ fail("Excepted an IllegalArgumentException for incorrect number of constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ try {
+ SimpleTimeZone mockTimeZone = AndroidMock.createMock(SimpleTimeZone.class, 0, null);
+ fail("Excepted an IllegalArgumentException for indeterminate null constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ try {
+ SimpleTimeZone mockTimeZone = AndroidMock.createMock(SimpleTimeZone.class, 0, new Object());
+ fail("Excepted an IllegalArgumentException for incorrect constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ public void testCreateMockUsingInterface() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Map.class);
+ compileClasses(mockClasses);
+ Map<String, String> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get("key")).andReturn("Hello World");
+ AndroidMock.replay(mockMap);
+ assertEquals("Hello World", mockMap.get("key"));
+ AndroidMock.verify(mockMap);
+ }
+
+ public void testCreateMockUsingClass() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<String> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.expect(mockVector.get(0)).andReturn("Hello World");
+ AndroidMock.replay(mockVector);
+ assertEquals("Hello World", mockVector.get(0).toString());
+ AndroidMock.verify(mockVector);
+ }
+
+ public void testCreateNiceMock() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<String> mockVector = AndroidMock.createNiceMock(Vector.class);
+ AndroidMock.expect(mockVector.get(0)).andReturn("Hello World");
+ AndroidMock.replay(mockVector);
+ assertEquals("Hello World", mockVector.get(0).toString());
+ AndroidMock.verify(mockVector);
+ }
+
+ public void testCreateNiceMockUsingUnusableParameters() throws ClassNotFoundException,
+ IOException, CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+ compileClasses(mockClasses);
+ try {
+ SimpleTimeZone mockTimeZone = AndroidMock.createNiceMock(SimpleTimeZone.class, "GMT");
+ fail("Excepted an IllegalArgumentException for incorrect number of constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ try {
+ SimpleTimeZone mockTimeZone = AndroidMock.createNiceMock(SimpleTimeZone.class, 0, null);
+ fail("Excepted an IllegalArgumentException for indeterminate null constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ try {
+ SimpleTimeZone mockTimeZone =
+ AndroidMock.createNiceMock(SimpleTimeZone.class, 0, new Object());
+ fail("Excepted an IllegalArgumentException for incorrect constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ public void testCreateNiceMockUsingParameters() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+
+ compileClasses(mockClasses);
+ SimpleTimeZone mockTimeZone = AndroidMock.createNiceMock(SimpleTimeZone.class, 0, "GMT");
+ AndroidMock.expect(mockTimeZone.getRawOffset()).andReturn(42);
+ AndroidMock.replay(mockTimeZone);
+ assertEquals(42, mockTimeZone.getRawOffset());
+ AndroidMock.verify(mockTimeZone);
+ }
+
+ public void testCreateNiceMockUsingCastableParameters() throws ClassNotFoundException,
+ IOException, CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+
+ compileClasses(mockClasses);
+ SimpleTimeZone mockTimeZone = AndroidMock.createNiceMock(SimpleTimeZone.class, 'a', "GMT");
+ AndroidMock.expect(mockTimeZone.getRawOffset()).andReturn(42);
+ AndroidMock.replay(mockTimeZone);
+ assertEquals(42, mockTimeZone.getRawOffset());
+ AndroidMock.verify(mockTimeZone);
+ }
+
+ public void testCreateNiceMockUsingInterface() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Map.class);
+
+ compileClasses(mockClasses);
+ Map<String, String> mockMap = AndroidMock.createNiceMock(Map.class);
+ AndroidMock.expect(mockMap.get("key")).andReturn("Hello World");
+ AndroidMock.replay(mockMap);
+ assertEquals("Hello World", mockMap.get("key"));
+ AndroidMock.verify(mockMap);
+ }
+
+ public void testCreateNiceMockUsingClass() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+
+ compileClasses(mockClasses);
+ Vector<String> mockVector = AndroidMock.createNiceMock(Vector.class);
+ AndroidMock.expect(mockVector.get(0)).andReturn("Hello World");
+ AndroidMock.replay(mockVector);
+ assertEquals("Hello World", mockVector.get(0).toString());
+ AndroidMock.verify(mockVector);
+ }
+
+ public void testCreateStrictMock() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+
+ compileClasses(mockClasses);
+ Vector<String> mockVector = AndroidMock.createStrictMock(Vector.class);
+ AndroidMock.expect(mockVector.get(0)).andReturn("Hello World");
+ AndroidMock.replay(mockVector);
+ assertEquals("Hello World", mockVector.get(0).toString());
+ AndroidMock.verify(mockVector);
+ }
+
+ public void testCreateStrictMockUsingUnusableParameters() throws ClassNotFoundException,
+ IOException, CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+
+ compileClasses(mockClasses);
+ try {
+ SimpleTimeZone mockTimeZone = AndroidMock.createStrictMock(SimpleTimeZone.class, "GMT");
+ fail("Excepted an IllegalArgumentException for incorrect number of constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ try {
+ SimpleTimeZone mockTimeZone = AndroidMock.createStrictMock(SimpleTimeZone.class, 0, null);
+ fail("Excepted an IllegalArgumentException for indeterminate null constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ try {
+ SimpleTimeZone mockTimeZone =
+ AndroidMock.createStrictMock(SimpleTimeZone.class, 0, new Object());
+ fail("Excepted an IllegalArgumentException for incorrect constructor parameters");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ public void testCreateStrictMockUsingParameters() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+
+ compileClasses(mockClasses);
+ SimpleTimeZone mockTimeZone = AndroidMock.createStrictMock(SimpleTimeZone.class, 0, "GMT");
+ AndroidMock.expect(mockTimeZone.getRawOffset()).andReturn(42);
+ AndroidMock.replay(mockTimeZone);
+ assertEquals(42, mockTimeZone.getRawOffset());
+ AndroidMock.verify(mockTimeZone);
+ }
+
+ public void testCreateStrictMockUsingCastableParameters() throws ClassNotFoundException,
+ IOException, CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(SimpleTimeZone.class);
+
+ compileClasses(mockClasses);
+ SimpleTimeZone mockTimeZone = AndroidMock.createStrictMock(SimpleTimeZone.class, 'a', "GMT");
+ AndroidMock.expect(mockTimeZone.getRawOffset()).andReturn(42);
+ AndroidMock.replay(mockTimeZone);
+ assertEquals(42, mockTimeZone.getRawOffset());
+ AndroidMock.verify(mockTimeZone);
+ }
+
+ public void testCreateStrictMockUsingInterface() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Map.class);
+
+ compileClasses(mockClasses);
+ Map<String, String> mockMap = AndroidMock.createStrictMock(Map.class);
+ AndroidMock.expect(mockMap.get("key")).andReturn("Hello World");
+ AndroidMock.replay(mockMap);
+ assertEquals("Hello World", mockMap.get("key"));
+ AndroidMock.verify(mockMap);
+ }
+
+ public void testCreateStrictMockUsingClass() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<String> mockVector = AndroidMock.createStrictMock(Vector.class);
+ AndroidMock.expect(mockVector.get(0)).andReturn("Hello World");
+ AndroidMock.replay(mockVector);
+ assertEquals("Hello World", mockVector.get(0).toString());
+ AndroidMock.verify(mockVector);
+ }
+
+ public void testCreateMockConstructorDoesWorkOnAllReturnTypes() throws ClassNotFoundException,
+ IOException, CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(ClassDoesWorkInConstructor.class);
+ compileClasses(mockClasses);
+ ClassDoesWorkInConstructor mock = AndroidMock.createMock(ClassDoesWorkInConstructor.class);
+ }
+
+ public void testAllForwardedMethods() throws CannotCompileException, NotFoundException {
+ for (CtMethod method : getForwardedMethods()) {
+ MethodVerifier verifier = new MethodVerifier(method);
+ // CtMethod.instrument Causes every instruction in the method to be
+ // inspected, and passed to
+ // the MethodVerifier callback (extends javassist.expr.ExprEditor). We
+ // want to verify that
+ // the expected EasyMock method is called at least once in each
+ // AndroidMock method.
+ method.instrument(verifier);
+ assertTrue(method.getLongName() + " not called.", verifier.expectedMethodCalled());
+ }
+ }
+
+ public void testCheckOrder() throws ClassNotFoundException, IOException, CannotCompileException,
+ NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<?> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.checkOrder(mockVector, false);
+ AndroidMock.checkOrder(AndroidMock.createMock(Map.class), false);
+ }
+
+ public void testVerify() throws ClassNotFoundException, IOException, CannotCompileException,
+ NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<?> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.replay(mockVector);
+ AndroidMock.verify(mockVector);
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.replay(mockMap);
+ AndroidMock.verify(mockMap);
+ }
+
+ public void testResetToStrict() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<?> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.resetToStrict(mockVector);
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.resetToStrict(mockMap);
+ }
+
+ public void testResetToDefault() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<?> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.resetToDefault(mockVector);
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.resetToDefault(mockMap);
+ }
+
+ public void testResetToNice() throws ClassNotFoundException, IOException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<?> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.resetToNice(mockVector);
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.resetToNice(mockMap);
+ }
+
+ public void testReset() throws ClassNotFoundException, IOException, CannotCompileException,
+ NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<?> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.reset(mockVector);
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.reset(mockMap);
+
+ }
+
+ public void testReplay() throws ClassNotFoundException, IOException, CannotCompileException,
+ NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(Vector.class);
+ compileClasses(mockClasses);
+ Vector<?> mockVector = AndroidMock.createMock(Vector.class);
+ AndroidMock.replay(mockVector);
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testExpect() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ mockMap.clear();
+ AndroidMock.expect(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testExpectLastCall() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ mockMap.clear();
+ AndroidMock.expectLastCall();
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyBoolean() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyBoolean())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyByte() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyByte())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyChar() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyChar())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyInt() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyInt())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyLong() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyLong())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyFloat() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyFloat())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyDouble() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyDouble())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyShort() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyShort())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnyObject() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.anyObject())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testGeq() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.geq((byte) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.geq((short) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.geq(0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.geq(0L))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.geq(0.0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.geq(0.0f))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.geq("Hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testLeq() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.leq((byte) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.leq((short) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.leq(0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.leq(0L))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.leq(0.0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.leq(0.0f))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.leq("Hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testGt() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.gt((byte) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.gt((short) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.gt(0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.gt(0L))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.gt(0.0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.gt(0.0f))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.gt("Hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testLt() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.lt((byte) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.lt((short) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.lt(0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.lt(0L))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.lt(0.0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.lt(0.0f))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.lt("Hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testIsA() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.isA(String.class))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testContains() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.contains("hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAnd() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.and(AndroidMock.eq(true), AndroidMock.eq(true))))
+ .andReturn(null);
+ AndroidMock.expect(
+ mockMap.get(AndroidMock.and(AndroidMock.eq((byte) 0), AndroidMock.eq((byte) 0))))
+ .andReturn(null);
+ AndroidMock.expect(
+ mockMap.get(AndroidMock.and(AndroidMock.eq((short) 0), AndroidMock.eq((short) 0))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.and(AndroidMock.eq(0), AndroidMock.eq(0))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.and(AndroidMock.eq(0L), AndroidMock.eq(0L))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.and(AndroidMock.eq(0.0), AndroidMock.eq(0.0))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.and(AndroidMock.eq(0.0f), AndroidMock.eq(0.0f))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.and(AndroidMock.eq("hi"), AndroidMock.eq("hi"))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.and(AndroidMock.eq('a'), AndroidMock.eq('a'))))
+ .andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testOr() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.or(AndroidMock.eq(true), AndroidMock.eq(true))))
+ .andReturn(null);
+ AndroidMock.expect(
+ mockMap.get(AndroidMock.or(AndroidMock.eq((byte) 0), AndroidMock.eq((byte) 0))))
+ .andReturn(null);
+ AndroidMock.expect(
+ mockMap.get(AndroidMock.or(AndroidMock.eq((short) 0), AndroidMock.eq((short) 0))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.or(AndroidMock.eq(0), AndroidMock.eq(0))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.or(AndroidMock.eq(0L), AndroidMock.eq(0L))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.or(AndroidMock.eq(0.0), AndroidMock.eq(0.0))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.or(AndroidMock.eq(0.0f), AndroidMock.eq(0.0f))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.or(AndroidMock.eq("hi"), AndroidMock.eq("hi"))))
+ .andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.or(AndroidMock.eq('a'), AndroidMock.eq('a'))))
+ .andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testNot() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq(true)))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq((byte) 0)))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq((short) 0)))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq(0)))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq(0L)))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq(0.0)))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq(0.0f)))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq("hi")))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.not(AndroidMock.eq('a')))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testEq() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq(true))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq((byte) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq((short) 0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq(0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq(0L))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq(0.0))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq(0.0f))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq(0.0, 0.1))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq(0.0f, 0.1f))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq("hi"))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.eq('a'))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAryEq() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new boolean[] {true}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new byte[] {(byte) 0}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new short[] {(short) 0}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new int[] {0}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new long[] {0L}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new double[] {0.0}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new float[] {0.0f}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new String[] {"hi"}))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.aryEq(new char[] {'a'}))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testIsNull() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.isNull())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testNotNull() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.notNull())).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testFind() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.find("hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testMatches() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.matches("hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testStartsWith() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.startsWith("hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testEndsWith() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.endsWith("hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testSame() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.same("hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testCmpEq() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.cmpEq("hi"))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testCmp() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(
+ mockMap.get(AndroidMock.cmp("hi", String.CASE_INSENSITIVE_ORDER, LogicalOperator.EQUAL)))
+ .andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testCapture() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(AndroidMock.capture(new Capture<Byte>()))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.capture(new Capture<Character>()))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.capture(new Capture<Double>()))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.capture(new Capture<Float>()))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.capture(new Capture<Integer>()))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.capture(new Capture<Long>()))).andReturn(null);
+ AndroidMock.expect(mockMap.get(AndroidMock.capture(new Capture<String>()))).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testReportMatcher() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.reportMatcher(new Equals(null));
+ AndroidMock.expect(mockMap.get(null)).andReturn(null);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testGetCurrentArguments() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.expect(mockMap.get(null)).andAnswer(new IAnswer() {
+ @Override
+ public Object answer() {
+ AndroidMock.getCurrentArguments();
+ return null;
+ }
+ });
+ AndroidMock.replay(mockMap);
+ mockMap.get(null);
+ }
+
+ public void testMakeThreadSafe() {
+ Map<?, ?> mockMap = AndroidMock.createMock(Map.class);
+ AndroidMock.makeThreadSafe(mockMap, false);
+ AndroidMock.replay(mockMap);
+ }
+
+ public void testAndThrowsOnMockedInterface() throws IOException {
+ ObjectInput mockInStream = AndroidMock.createMock(ObjectInput.class);
+ AndroidMock.expect(mockInStream.read()).andThrow(new IOException("foo"));
+ AndroidMock.replay(mockInStream);
+ try {
+ mockInStream.read();
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ assertEquals("foo", e.getMessage());
+ }
+ AndroidMock.verify(mockInStream);
+ }
+
+ public void testAndThrowsOnMockedClass() throws IOException, ClassNotFoundException,
+ CannotCompileException, NotFoundException {
+ List<GeneratedClassFile> mockClasses =
+ new AndroidMockGenerator().createMocksForClass(InputStream.class);
+ compileClasses(mockClasses);
+ InputStream mockInStream = AndroidMock.createMock(InputStream.class);
+ AndroidMock.expect(mockInStream.read()).andThrow(new IOException("foo"));
+ AndroidMock.replay(mockInStream);
+ try {
+ mockInStream.read();
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ assertEquals("foo", e.getMessage());
+ }
+ AndroidMock.verify(mockInStream);
+ }
+
+ /**
+ * Used for testing that a given method on Android Mock calls the equivalent
+ * method on EasyMock, to ensure that the method-wiring of Android Mock is
+ * correct.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+ class MethodVerifier extends ExprEditor {
+ private CtMethod expectedMethod;
+ private boolean methodCalled;
+
+ MethodVerifier(CtMethod expectedMethod) {
+ this.expectedMethod = expectedMethod;
+ }
+
+ @Override
+ public void edit(MethodCall calledMethod) {
+ try {
+ methodCalled = methodCalled || expectedMethod.equals(calledMethod.getMethod());
+ } catch (NotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean expectedMethodCalled() {
+ return methodCalled;
+ }
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassDoesWorkInConstructor.java b/tests/com/google/android/testing/mocking/ClassDoesWorkInConstructor.java
new file mode 100644
index 0000000..a8c6a55
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassDoesWorkInConstructor.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+
+/**
+ * Support class for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassDoesWorkInConstructor {
+ public ClassDoesWorkInConstructor() {
+ this.fooInt(1);
+ this.fooByte((byte) 1);
+ this.fooShort((short) 1);
+ this.fooChar('a');
+ this.fooLong(1L);
+ this.fooFloat(1.0f);
+ this.fooDouble(1.0);
+ this.fooBoolean(true);
+ this.fooObject("hello");
+ this.fooVoid();
+ }
+
+ public void fooVoid() {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public Object fooObject(String string) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public boolean fooBoolean(boolean b) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public double fooDouble(double d) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public float fooFloat(float f) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public long fooLong(long i) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public char fooChar(char c) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public short fooShort(short s) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public byte fooByte(byte b) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+
+ public int fooInt(int i) {
+ throw new IllegalStateException("I wasn't mocked!!");
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassHasDelegateMethods.java b/tests/com/google/android/testing/mocking/ClassHasDelegateMethods.java
new file mode 100644
index 0000000..6745b91
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassHasDelegateMethods.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Class with methods that match the delegate methods. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassHasDelegateMethods {
+ /**
+ * Test method.
+ * @param obj test obj.
+ */
+ public void setDelegate___AndroidMock(Object obj) {
+ }
+
+ /**
+ * Test method
+ * @return null
+ */
+ public Object getDelegate___AndroidMock() {
+ return null;
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassHasFinalMethods.java b/tests/com/google/android/testing/mocking/ClassHasFinalMethods.java
new file mode 100644
index 0000000..414f5f8
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassHasFinalMethods.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Class with final methods. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassHasFinalMethods {
+ public final int foo() {
+ return 0;
+ }
+
+ public int bar() {
+ return 0;
+ }
+
+ public final int foobar() {
+ return 0;
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassHasNoDefaultConstructor.java b/tests/com/google/android/testing/mocking/ClassHasNoDefaultConstructor.java
new file mode 100644
index 0000000..8b97cd8
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassHasNoDefaultConstructor.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Class with no default constructor. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassHasNoDefaultConstructor {
+ public ClassHasNoDefaultConstructor(int foo) {
+
+ }
+
+ public int foo() {
+ return 0;
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassHasNoPublicConstructors.java b/tests/com/google/android/testing/mocking/ClassHasNoPublicConstructors.java
new file mode 100644
index 0000000..20533ee
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassHasNoPublicConstructors.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Class with no public constructor. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassHasNoPublicConstructors {
+ private ClassHasNoPublicConstructors() {
+
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassHasOverloadedMethods.java b/tests/com/google/android/testing/mocking/ClassHasOverloadedMethods.java
new file mode 100644
index 0000000..f1b04fa
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassHasOverloadedMethods.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Class with overloaded methods. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassHasOverloadedMethods {
+ public int foo() {
+ return 0;
+ }
+
+ public void foo(int arg) {
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassHasStaticMethods.java b/tests/com/google/android/testing/mocking/ClassHasStaticMethods.java
new file mode 100644
index 0000000..29f4f52
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassHasStaticMethods.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Class with static methods. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassHasStaticMethods {
+ public static int staticFoo() {
+ return 0;
+ }
+
+ public int foo() {
+ return 1;
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassIsAnnotation.java b/tests/com/google/android/testing/mocking/ClassIsAnnotation.java
new file mode 100644
index 0000000..e42c8e1
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassIsAnnotation.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Annotation Class. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public @interface ClassIsAnnotation {
+
+}
diff --git a/tests/com/google/android/testing/mocking/ClassIsEnum.java b/tests/com/google/android/testing/mocking/ClassIsEnum.java
new file mode 100644
index 0000000..b7fa957
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassIsEnum.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Enum Class. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public enum ClassIsEnum {
+ One, Two, Three, Four;
+}
diff --git a/tests/com/google/android/testing/mocking/ClassIsFinal.java b/tests/com/google/android/testing/mocking/ClassIsFinal.java
new file mode 100644
index 0000000..88f8279
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassIsFinal.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Final Class. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public final class ClassIsFinal {
+ public int foo() {
+ return 0;
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ClassIsInterface.java b/tests/com/google/android/testing/mocking/ClassIsInterface.java
new file mode 100644
index 0000000..d48f512
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassIsInterface.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+/**
+ * Interface. Used only for testing.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public interface ClassIsInterface {
+ int foo();
+}
diff --git a/tests/com/google/android/testing/mocking/ClassTypeTests.java b/tests/com/google/android/testing/mocking/ClassTypeTests.java
new file mode 100644
index 0000000..a4d60c2
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ClassTypeTests.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Various tests that verify that different types of Classes are handled
+ * correctly.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ClassTypeTests extends TestCase {
+ private AndroidMockGenerator androidMockGenerator = new AndroidMockGenerator();
+
+ private AndroidMockGenerator getAndroidMockGenerator() {
+ return androidMockGenerator;
+ }
+
+ private void assertAllMethodNames(List<String> expectedNames,
+ Map<String, List<String>> expectedMethods, List<GeneratedClassFile> classes)
+ throws IOException {
+ for (GeneratedClassFile clazz : classes) {
+ assertTrue(expectedNames.contains(clazz.getClassName()));
+ assertUnorderedContentsSame(expectedMethods.get(clazz.getClassName()), getMethodNames(clazz));
+ }
+ }
+
+ private <T> void assertUnorderedContentsSame(Iterable<T> expected, Iterable<T> actual) {
+ List<T> missingItems = new ArrayList<T>();
+ List<T> extraItems = new ArrayList<T>();
+ for (T item : expected) {
+ missingItems.add(item);
+ }
+ for (T item : actual) {
+ missingItems.remove(item);
+ extraItems.add(item);
+ }
+ for (T item : expected) {
+ extraItems.remove(item);
+ }
+ if (missingItems.size() + extraItems.size() != 0) {
+ String errorMessage =
+ "Contents were different. Missing: " + Arrays.toString(missingItems.toArray())
+ + " Extra: " + Arrays.toString(extraItems.toArray());
+ fail(errorMessage);
+ }
+ }
+
+ private List<String> getExpectedNames(Class<?> clazz) {
+ return new ArrayList<String>(Arrays.asList(new String[] {
+ "genmocks." + clazz.getCanonicalName() + "DelegateInterface",
+ "genmocks." + clazz.getCanonicalName() + "DelegateSubclass"}));
+ }
+
+ private Iterable<String> getMethodNames(GeneratedClassFile clazz) throws IOException {
+ ByteArrayInputStream classInputStream = new ByteArrayInputStream(clazz.getContents());
+ CtClass ctClass;
+ try {
+ ctClass = ClassPool.getDefault().getCtClass(clazz.getClassName());
+ if (ctClass.isFrozen()) {
+ ctClass.defrost();
+ }
+ } catch (NotFoundException e) {
+ // That's ok, we're just defrosting any classes that affect us that were created
+ // by other tests. NotFoundException implies the class is not frozen.
+ }
+ ctClass = ClassPool.getDefault().makeClass(classInputStream);
+ return getMethodNames(ctClass.getDeclaredMethods());
+ }
+
+ private List<String> getMethodNames(CtMethod[] methods) {
+ List<String> methodNames = new ArrayList<String>();
+ for (CtMethod method : methods) {
+ methodNames.add(method.getName());
+ }
+ return methodNames;
+ }
+
+ private List<String> getMethodNames(Method[] methods, String[] exclusions) {
+ List<String> methodNames = new ArrayList<String>();
+ for (Method method : methods) {
+ if (!Arrays.asList(exclusions).contains(method.getName())) {
+ methodNames.add(method.getName());
+ }
+ }
+ return methodNames;
+ }
+
+ private Map<String, List<String>> getExpectedMethodsMap(List<String> expectedNames,
+ Class<?> clazz) {
+ return getExpectedMethodsMap(expectedNames, clazz, new String[0]);
+ }
+
+ private Map<String, List<String>> getExpectedMethodsMap(List<String> expectedNames,
+ Class<?> clazz, String[] exclusions) {
+ Map<String, List<String>> expectedMethods = new HashMap<String, List<String>>();
+ expectedMethods.put(expectedNames.get(0), new ArrayList<String>(Arrays.asList(new String[] {
+ "finalize", "clone"})));
+ expectedMethods.put(expectedNames.get(1), new ArrayList<String>(Arrays.asList(new String[] {
+ "finalize", "clone", "setDelegate___AndroidMock", "getDelegate___AndroidMock"})));
+ expectedMethods.get(expectedNames.get(0)).addAll(
+ getMethodNames(clazz.getDeclaredMethods(), exclusions));
+ expectedMethods.get(expectedNames.get(1)).addAll(
+ getMethodNames(clazz.getDeclaredMethods(), exclusions));
+ return expectedMethods;
+ }
+
+ public void testClassIsDuplicate() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ List<GeneratedClassFile> classList =
+ getAndroidMockGenerator().createMocksForClass(Object.class);
+ List<GeneratedClassFile> secondClassList =
+ getAndroidMockGenerator().createMocksForClass(Object.class);
+ assertEquals(classList, secondClassList);
+ }
+
+ public void testClassHasDelegateMethods() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ List<String> expectedNames = getExpectedNames(ClassHasDelegateMethods.class);
+ Map<String, List<String>> expectedMethods =
+ getExpectedMethodsMap(expectedNames, ClassHasDelegateMethods.class,
+ new String[] {"getDelegate___AndroidMock"});
+ // This use case doesn't fit our util in any nice way, so just tweak it.
+ expectedMethods.get(
+ "genmocks.com.google.android.testing.mocking.ClassHasDelegateMethodsDelegateInterface")
+ .add("getDelegate___AndroidMock");
+
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes =
+ mockGenerator.createMocksForClass(ClassHasDelegateMethods.class);
+ assertEquals(2, classes.size());
+ assertAllMethodNames(expectedNames, expectedMethods, classes);
+ }
+
+ public void testClassHasFinalMethods() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ List<String> expectedNames = getExpectedNames(ClassHasFinalMethods.class);
+ Map<String, List<String>> expectedMethods =
+ getExpectedMethodsMap(expectedNames, ClassHasFinalMethods.class, new String[] {"foo",
+ "foobar"});
+
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes =
+ mockGenerator.createMocksForClass(ClassHasFinalMethods.class);
+ assertEquals(2, classes.size());
+ assertAllMethodNames(expectedNames, expectedMethods, classes);
+ }
+
+ public void testClassHasNoDefaultConstructor() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes =
+ mockGenerator.createMocksForClass(ClassHasNoDefaultConstructor.class);
+ assertEquals(2, classes.size());
+ }
+
+ public void testClassHasNoPublicConstructors() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes =
+ mockGenerator.createMocksForClass(ClassHasNoPublicConstructors.class);
+ assertEquals(0, classes.size());
+ }
+
+ public void testClassHasOverloadedMethods() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ List<String> expectedNames = getExpectedNames(ClassHasOverloadedMethods.class);
+ Map<String, List<String>> expectedMethods =
+ getExpectedMethodsMap(expectedNames, ClassHasOverloadedMethods.class);
+
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes =
+ mockGenerator.createMocksForClass(ClassHasOverloadedMethods.class);
+ assertEquals(2, classes.size());
+ assertAllMethodNames(expectedNames, expectedMethods, classes);
+ }
+
+ public void testClassHasStaticMethods() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ List<String> expectedNames = getExpectedNames(ClassHasStaticMethods.class);
+ Map<String, List<String>> expectedMethods =
+ getExpectedMethodsMap(expectedNames, ClassHasStaticMethods.class,
+ new String[] {"staticFoo"});
+
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes =
+ mockGenerator.createMocksForClass(ClassHasStaticMethods.class);
+ assertEquals(2, classes.size());
+ assertAllMethodNames(expectedNames, expectedMethods, classes);
+ }
+
+ public void testClassIsAnnotation() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsAnnotation.class);
+ assertEquals(0, classes.size());
+ }
+
+ public void testClassIsEnum() throws ClassNotFoundException, IOException, CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsEnum.class);
+ assertEquals(0, classes.size());
+ }
+
+ public void testClassIsFinal() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsFinal.class);
+ assertEquals(0, classes.size());
+ }
+
+ public void testClassIsInterface() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsInterface.class);
+ assertEquals(0, classes.size());
+ }
+
+ public void testClassIsArray() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object[].class);
+ assertEquals(0, classes.size());
+ }
+
+ public void testClassIsNormal() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object.class);
+ assertEquals(2, classes.size());
+ }
+
+ public void testClassIsPrimitive() throws ClassNotFoundException, IOException,
+ CannotCompileException {
+ AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
+ List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Integer.TYPE);
+ assertEquals(0, classes.size());
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/ConstructorCreationTests.java b/tests/com/google/android/testing/mocking/ConstructorCreationTests.java
new file mode 100644
index 0000000..152918d
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/ConstructorCreationTests.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Type;
+
+
+/**
+ * Tests for mocked objects with non default constructors.
+ *
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class ConstructorCreationTests extends TestCase {
+ public static class Foo {
+ private int value;
+ Foo(int value) { this.value = value; }
+ int get() { return value; }
+ }
+
+ public static class Bar {
+ private double value;
+ Bar(double value) { this.value = value; }
+ double get() { return value; }
+ }
+
+ public static class TestClass {
+ public int v1;
+ public double v2;
+ public boolean usedFloatConstructor;
+
+ public TestClass(Foo foo) {
+ this(foo.get());
+ }
+
+ public TestClass(Foo foo, Bar bar) {
+ this(foo.get(), bar.get());
+ }
+
+ public TestClass(int v1) {
+ this(v1, 0);
+ }
+
+ public TestClass(int v1, float v2) {
+ this.v1 = v1;
+ this.v2 = v2;
+ usedFloatConstructor = true;
+ }
+
+ public TestClass(int v1, double v2) {
+ this.v1 = v1;
+ this.v2 = (int) v2;
+ usedFloatConstructor = false;
+ }
+ }
+
+ private void hasConstructor(Object... args) {
+ Constructor<TestClass> constructor =
+ AndroidMock.getConstructorFor(TestClass.class, args);
+ assertNotNull(constructor);
+ }
+
+ private void doesNotHaveConstructor(Object... args) {
+ try {
+ Constructor<TestClass> constructor =
+ AndroidMock.getConstructorFor(TestClass.class, args);
+ fail("A constructor was found: " + constructor);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void testConstructors() {
+ hasConstructor(new Foo(1));
+ doesNotHaveConstructor(new Bar(2));
+ hasConstructor(new Foo(1), new Bar(2));
+ hasConstructor(1);
+ hasConstructor(1, 2);
+ doesNotHaveConstructor(new Foo(1), 2);
+ hasConstructor(1, new Integer("2"));
+ hasConstructor(1, 2.0);
+ hasConstructor(1, 2.0f);
+ }
+
+ private void checkConstructor(Object[] args, Type[] expectedTypes) {
+ Constructor<TestClass> constructor =
+ AndroidMock.getConstructorFor(TestClass.class, args);
+ assertNotNull(constructor);
+ Type[] types = constructor.getGenericParameterTypes();
+ assertEquals(expectedTypes.length, types.length);
+ for (int i = 0; i < expectedTypes.length; ++i) {
+ assertEquals(expectedTypes[i], types[i]);
+ }
+ }
+
+ public void testCorrectConstructor() {
+ checkConstructor(
+ new Object[]{new Foo(1)},
+ new Type[]{Foo.class});
+ checkConstructor(
+ new Object[]{new Foo(1), new Bar(2)},
+ new Type[]{Foo.class, Bar.class});
+ checkConstructor(
+ new Object[]{1},
+ new Type[]{Integer.TYPE});
+ checkConstructor(
+ new Object[]{1, new Float("2")},
+ new Type[]{Integer.TYPE, Float.TYPE});
+ checkConstructor(
+ new Object[]{1, 2.0},
+ new Type[]{Integer.TYPE, Double.TYPE});
+ checkConstructor(
+ new Object[]{1, 2.0f},
+ new Type[]{Integer.TYPE, Float.TYPE});
+ }
+} \ No newline at end of file
diff --git a/tests/com/google/android/testing/mocking/FileUtilsTest.java b/tests/com/google/android/testing/mocking/FileUtilsTest.java
new file mode 100644
index 0000000..b1058e3
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/FileUtilsTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import junit.framework.TestCase;
+
+import java.util.Vector;
+
+/**
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class FileUtilsTest extends TestCase {
+ public void testGetFilenameForClass() {
+ assertEquals("java/lang/Object.class", FileUtils.getFilenameFor(Object.class.getName()));
+ assertEquals("com/google/android/testing/mocking/FileUtilsTest$InnerClass.class",
+ FileUtils.getFilenameFor(InnerClass.class.getName()));
+ }
+
+ public void testGetClassNameFor() {
+ assertEquals("java/lang/Object.class", FileUtils.getFilenameFor(Object.class.getName()));
+ assertEquals("com/google/android/testing/mocking/FileUtilsTest$InnerClass.class",
+ FileUtils.getFilenameFor(InnerClass.class.getName()));
+ }
+
+ public void testGetInterfaceNameFor() {
+ assertEquals("v15.genmocks.java.util.VectorDelegateInterface",
+ FileUtils.getInterfaceNameFor(Vector.class, SdkVersion.CUPCAKE));
+ assertEquals("v16.genmocks.java.util.VectorDelegateInterface",
+ FileUtils.getInterfaceNameFor(Vector.class, SdkVersion.DONUT));
+ assertEquals("v201.genmocks.java.util.VectorDelegateInterface",
+ FileUtils.getInterfaceNameFor(Vector.class, SdkVersion.ECLAIR_0_1));
+ assertEquals("v21.genmocks.java.util.VectorDelegateInterface",
+ FileUtils.getInterfaceNameFor(Vector.class, SdkVersion.ECLAIR_MR1));
+ assertEquals("v22.genmocks.java.util.VectorDelegateInterface",
+ FileUtils.getInterfaceNameFor(Vector.class, SdkVersion.FROYO));
+ assertEquals("genmocks.java.util.VectorDelegateInterface",
+ FileUtils.getInterfaceNameFor(Vector.class, SdkVersion.UNKNOWN));
+ }
+
+ public void testGetSubclassNameFor() {
+ assertEquals("v15.genmocks.java.util.VectorDelegateSubclass",
+ FileUtils.getSubclassNameFor(Vector.class, SdkVersion.CUPCAKE));
+ assertEquals("v16.genmocks.java.util.VectorDelegateSubclass",
+ FileUtils.getSubclassNameFor(Vector.class, SdkVersion.DONUT));
+ assertEquals("v201.genmocks.java.util.VectorDelegateSubclass",
+ FileUtils.getSubclassNameFor(Vector.class, SdkVersion.ECLAIR_0_1));
+ assertEquals("v21.genmocks.java.util.VectorDelegateSubclass",
+ FileUtils.getSubclassNameFor(Vector.class, SdkVersion.ECLAIR_MR1));
+ assertEquals("v22.genmocks.java.util.VectorDelegateSubclass",
+ FileUtils.getSubclassNameFor(Vector.class, SdkVersion.FROYO));
+ assertEquals("genmocks.java.util.VectorDelegateSubclass",
+ FileUtils.getSubclassNameFor(Vector.class, SdkVersion.UNKNOWN));
+ }
+
+ class InnerClass {
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/SdkVersionTest.java b/tests/com/google/android/testing/mocking/SdkVersionTest.java
new file mode 100644
index 0000000..eb7c764
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/SdkVersionTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.testing.mocking;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class SdkVersionTest extends TestCase {
+
+ public void testGetAllVersions() {
+ List<SdkVersion> versions = Arrays.asList(SdkVersion.getAllVersions());
+ List<SdkVersion> values = Arrays.asList(SdkVersion.values());
+ assertEquals(5, versions.size());
+ assertTrue(values.containsAll(versions));
+ assertFalse(versions.contains(SdkVersion.UNKNOWN));
+ }
+
+ public void testGetVersionName() {
+ assertEquals("v15", SdkVersion.CUPCAKE.getVersionName());
+ assertEquals("v16", SdkVersion.DONUT.getVersionName());
+ assertEquals("v201", SdkVersion.ECLAIR_0_1.getVersionName());
+ assertEquals("v21", SdkVersion.ECLAIR_MR1.getVersionName());
+ assertEquals("v22", SdkVersion.FROYO.getVersionName());
+ assertEquals("", SdkVersion.UNKNOWN.getVersionName());
+ assertEquals("Unknown new SDK has been added, update this test",
+ 6, SdkVersion.values().length);
+ }
+
+ public void testGetPackagePrefix() {
+ assertEquals("v15.", SdkVersion.CUPCAKE.getPackagePrefix());
+ assertEquals("v16.", SdkVersion.DONUT.getPackagePrefix());
+ assertEquals("v201.", SdkVersion.ECLAIR_0_1.getPackagePrefix());
+ assertEquals("v21.", SdkVersion.ECLAIR_MR1.getPackagePrefix());
+ assertEquals("v22.", SdkVersion.FROYO.getPackagePrefix());
+ assertEquals("", SdkVersion.UNKNOWN.getPackagePrefix());
+ assertEquals("Unknown new SDK has been added, update this test",
+ 6, SdkVersion.values().length);
+ }
+
+ public void testGetCurrentVersion() {
+ // Always UNKNOWN on the desktop
+ assertEquals(SdkVersion.UNKNOWN, SdkVersion.getCurrentVersion());
+ }
+
+ public void testGetVersionFor() {
+ assertEquals(SdkVersion.CUPCAKE, SdkVersion.getVersionFor(3));
+ assertEquals(SdkVersion.DONUT, SdkVersion.getVersionFor(4));
+ assertEquals(SdkVersion.ECLAIR_0_1, SdkVersion.getVersionFor(6));
+ assertEquals(SdkVersion.ECLAIR_MR1, SdkVersion.getVersionFor(7));
+ assertEquals(SdkVersion.FROYO, SdkVersion.getVersionFor(8));
+ assertEquals(SdkVersion.UNKNOWN, SdkVersion.getVersionFor(-1));
+ for (int i = 9; i < 50; ++i) {
+ assertEquals("Unknown new SDK has been added, update this test",
+ SdkVersion.UNKNOWN, SdkVersion.getVersionFor(i));
+ }
+ }
+}
diff --git a/tests/com/google/android/testing/mocking/UsesMocksProcessorTest.java b/tests/com/google/android/testing/mocking/UsesMocksProcessorTest.java
new file mode 100644
index 0000000..0b8961b
--- /dev/null
+++ b/tests/com/google/android/testing/mocking/UsesMocksProcessorTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.testing.mocking;
+
+import javassist.CannotCompileException;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.tools.JavaFileObject;
+
+/**
+ * @author swoodward@google.com (Stephen Woodward)
+ */
+public class UsesMocksProcessorTest extends TestCase {
+
+ private Set<? extends Element> getAnnotatedElementsSet(Class<?>... classes) {
+ Set<Element> set = new HashSet<Element>();
+ for (Class<?> clazz : classes) {
+ set.add(getMockElement(clazz));
+ }
+ return set;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Element getMockElement(Class<?> clazz) {
+ Element mockElement = EasyMock.createNiceMock(Element.class);
+ EasyMock.expect(mockElement.getAnnotationMirrors()).andReturn(getMockAnnotationMirrors(clazz))
+ .anyTimes();
+ EasyMock.replay(mockElement);
+ return mockElement;
+ }
+
+ @SuppressWarnings("unchecked")
+ private List getMockAnnotationMirrors(Class<?> clazz) {
+ List<AnnotationMirror> mockMirrorList = new ArrayList<AnnotationMirror>();
+ AnnotationMirror mockMirror = EasyMock.createNiceMock(AnnotationMirror.class);
+ EasyMock.expect(mockMirror.getAnnotationType()).andReturn(getMockAnnotationType()).anyTimes();
+ EasyMock.expect(mockMirror.getElementValues()).andReturn(getMockElementValuesMap(clazz))
+ .anyTimes();
+ EasyMock.replay(mockMirror);
+ mockMirrorList.add(mockMirror);
+ return mockMirrorList;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map getMockElementValuesMap(Class<?> clazz) {
+ Map mockValuesMap = new HashMap();
+ mockValuesMap.put(getMockExecutableElement(), getMockAnnotationValue(clazz));
+ return mockValuesMap;
+ }
+
+ private AnnotationValue getMockAnnotationValue(Class<?> clazz) {
+ AnnotationValue mockValue = EasyMock.createMock(AnnotationValue.class);
+ EasyMock.expect(mockValue.getValue()).andReturn(
+ Arrays.asList(new String[] {clazz.getName() + ".class"})).anyTimes();
+ EasyMock.replay(mockValue);
+ return mockValue;
+ }
+
+ private ExecutableElement getMockExecutableElement() {
+ ExecutableElement mockElement = EasyMock.createNiceMock(ExecutableElement.class);
+ EasyMock.replay(mockElement);
+ return mockElement;
+ }
+
+ private DeclaredType getMockAnnotationType() {
+ return new DeclaredType() {
+ @Override
+ public String toString() {
+ return UsesMocks.class.getName();
+ }
+
+ @Override
+ public Element asElement() {
+ return null;
+ }
+
+ @Override
+ public TypeMirror getEnclosingType() {
+ return null;
+ }
+
+ @Override
+ public List<? extends TypeMirror> getTypeArguments() {
+ return null;
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return null;
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return null;
+ }
+ };
+ }
+
+ private UsesMocksProcessor getProcessor() {
+ return getProcessor(getMockProcessingEnvironment());
+ }
+
+ private UsesMocksProcessor getProcessor(ProcessingEnvironment processingEnv) {
+ UsesMocksProcessor processor = new UsesMocksProcessor();
+ processor.init(processingEnv);
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ processor.logger = new ProcessorLogger(outputStream, processingEnv);
+ return processor;
+ }
+
+ private ProcessingEnvironment getMockProcessingEnvironment(Filer mockFiler) {
+ ProcessingEnvironment mockEnvironment = EasyMock.createNiceMock(ProcessingEnvironment.class);
+ EasyMock.expect(mockEnvironment.getMessager()).andReturn(getMockMessager()).anyTimes();
+ EasyMock.expect(mockEnvironment.getFiler()).andReturn(mockFiler).anyTimes();
+ EasyMock.expect(mockEnvironment.getOptions()).andReturn(getMockOptions()).anyTimes();
+ EasyMock.replay(mockEnvironment);
+ return mockEnvironment;
+ }
+
+ private Map<String, String> getMockOptions() {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("bin_dir", ".");
+ map.put("logfile", "logfile");
+ return map;
+ }
+
+ private ProcessingEnvironment getMockProcessingEnvironment() {
+ return getMockProcessingEnvironment(getMockFiler());
+ }
+
+ private Messager getMockMessager() {
+ Messager mockMessager = EasyMock.createNiceMock(Messager.class);
+ EasyMock.replay(mockMessager);
+ return mockMessager;
+ }
+
+ private Filer getMockFiler() {
+ try {
+ return getMockFiler(getMockFileObject());
+ } catch (IOException e) {
+ // Can't happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Filer getMockFiler(JavaFileObject mockFileObject) {
+ Filer mockFiler = EasyMock.createNiceMock(Filer.class);
+ try {
+ EasyMock.expect(mockFiler.createClassFile((CharSequence) EasyMock.anyObject())).andReturn(
+ mockFileObject).anyTimes();
+ } catch (IOException e) {
+ // Can't happen
+ throw new RuntimeException(e);
+ }
+ EasyMock.replay(mockFiler);
+ return mockFiler;
+ }
+
+ private JavaFileObject getMockFileObject() throws IOException {
+ return getMockFileObject(new ByteArrayOutputStream());
+ }
+
+ private JavaFileObject getMockFileObject(OutputStream outStream) throws IOException {
+ JavaFileObject mockFileObject = EasyMock.createNiceMock(JavaFileObject.class);
+ EasyMock.expect(mockFileObject.openOutputStream()).andReturn(outStream).anyTimes();
+ EasyMock.replay(mockFileObject);
+ return mockFileObject;
+ }
+
+ private RoundEnvironment getMockRoundEnvironment(Set<? extends Element> elementsWithAnnotation) {
+ return getMockRoundEnvironment(elementsWithAnnotation, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ private RoundEnvironment getMockRoundEnvironment(Set<? extends Element> elementsWithAnnotation,
+ boolean finishedProcessing) {
+ RoundEnvironment mockEnv = EasyMock.createNiceMock(RoundEnvironment.class);
+ EasyMock.expect(mockEnv.getElementsAnnotatedWith(UsesMocks.class)).andReturn(
+ (Set) elementsWithAnnotation).anyTimes();
+ EasyMock.expect(mockEnv.processingOver()).andReturn(finishedProcessing).anyTimes();
+ EasyMock.replay(mockEnv);
+ return mockEnv;
+ }
+
+ public void testGetClassMocks() throws IOException, CannotCompileException {
+ List<Class<?>> classesToMock = new ArrayList<Class<?>>();
+ classesToMock.add(TestCase.class);
+ List<String> expectedMocks =
+ new ArrayList<String>(Arrays.asList(new String[] {
+ "genmocks." + TestCase.class.getName() + "DelegateInterface",
+ "genmocks." + TestCase.class.getName() + "DelegateSubclass"}));
+ Set<GeneratedClassFile> mockedClasses =
+ getProcessor().getClassMocks(classesToMock, true);
+
+ assertEquals(2, mockedClasses.size());
+ for (GeneratedClassFile clazz : mockedClasses) {
+ assertTrue(expectedMocks.contains(clazz.getClassName()));
+ expectedMocks.remove(clazz.getClassName());
+ }
+ }
+
+ public void testWriteMocks() throws IOException, CannotCompileException {
+ List<Class<?>> classesToMock = new ArrayList<Class<?>>();
+ classesToMock.add(TestCase.class);
+ Set<GeneratedClassFile> mockedClassesSet =
+ getProcessor().getClassMocks(classesToMock, true);
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+ getProcessor(getMockProcessingEnvironment(getMockFiler(getMockFileObject(outputStream))))
+ .writeMocks(mockedClassesSet);
+
+ String output = new String(outputStream.toByteArray());
+ for (GeneratedClassFile mockClass : mockedClassesSet) {
+ String expected = new String(mockClass.getContents());
+ assertTrue(output.contains(expected));
+ output = output.replace(expected, "");
+ }
+ assertEquals(0, output.length());
+ }
+
+ public void testProcess() {
+ assertFalse(getProcessor().process(null,
+ getMockRoundEnvironment(getAnnotatedElementsSet(TestCase.class))));
+ assertFalse(getProcessor().process(null,
+ getMockRoundEnvironment(getAnnotatedElementsSet(TestCase.class), true)));
+ }
+
+ public void testFindClassesToMock() {
+ Set<? extends Element> annotatedElements = getAnnotatedElementsSet(Set.class, TestCase.class);
+ List<Class<?>> classesList = getProcessor().findClassesToMock(annotatedElements);
+
+ assertEquals(annotatedElements.size(), classesList.size());
+ assertTrue(classesList.contains(Set.class));
+ assertTrue(classesList.contains(TestCase.class));
+ }
+}