Stop holding object references in JUnit3 tests.

Bug: 15115037
Change-Id: Icfc0de62f7e1a38e277a5563313ec89132ddb8eb
diff --git a/support/src/android/support/test/internal/runner/junit3/AndroidTestSuite.java b/support/src/android/support/test/internal/runner/junit3/AndroidTestSuite.java
index 5cfed8f..a236235 100644
--- a/support/src/android/support/test/internal/runner/junit3/AndroidTestSuite.java
+++ b/support/src/android/support/test/internal/runner/junit3/AndroidTestSuite.java
@@ -26,7 +26,9 @@
 
 /**
  * An extension of {@link TestSuite} that supports Android construct injection into test cases,
- * and properly supports annotation filtering of test cases
+ * and properly supports annotation filtering of test cases.
+ * <p/>
+ * Also tries to use {@link NonLeakyTestSuite} where possible to save memory.
  */
 @Ignore
 class AndroidTestSuite extends DelegatingFilterableTestSuite {
@@ -34,9 +36,8 @@
     private final Bundle mBundle;
     private final Instrumentation mInstr;
 
-    public AndroidTestSuite(Class<?> testClass,
-            Bundle bundle, Instrumentation instr) {
-        this(new TestSuite(testClass), bundle, instr);
+    public AndroidTestSuite(Class<?> testClass, Bundle bundle, Instrumentation instr) {
+        this(new NonLeakyTestSuite(testClass), bundle, instr);
     }
 
     public AndroidTestSuite(TestSuite s, Bundle bundle, Instrumentation instr) {
@@ -50,4 +51,5 @@
         // wrap the result in a new AndroidTestResult to do the bundle and instrumentation injection
         super.run(new AndroidTestResult(mBundle, mInstr, result));
     }
+
 }
diff --git a/support/src/android/support/test/internal/runner/junit3/NonLeakyTestSuite.java b/support/src/android/support/test/internal/runner/junit3/NonLeakyTestSuite.java
new file mode 100644
index 0000000..2421647
--- /dev/null
+++ b/support/src/android/support/test/internal/runner/junit3/NonLeakyTestSuite.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package android.support.test.internal.runner.junit3;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.junit.Ignore;
+import org.junit.runner.Describable;
+import org.junit.runner.Description;
+
+/**
+ * A {@link TestSuite} that discards references to included tests when execution is complete.
+ * Done so tests can be garbage collected and memory freed.
+ */
+@Ignore
+public class NonLeakyTestSuite extends TestSuite {
+    public NonLeakyTestSuite(Class<?> testClass) {
+        super(testClass);
+    }
+
+    @Override
+    public void addTest(Test test) {
+        super.addTest(new NonLeakyTest(test));
+    }
+
+    private static class NonLeakyTest implements Test, Describable {
+        private Test mDelegate;
+        private final Description mDesc;
+
+        NonLeakyTest(Test delegate) {
+            this.mDelegate = delegate;
+            // cache description so it's available after execution
+            this.mDesc = JUnit38ClassRunner.makeDescription(mDelegate);
+        }
+
+        @Override
+        public int countTestCases() {
+            if (mDelegate != null) {
+                return mDelegate.countTestCases();
+            } else {
+                return 0;
+            }
+        }
+
+        @Override
+        public void run(TestResult result) {
+            mDelegate.run(result);
+            mDelegate = null;
+        }
+
+        @Override
+        public Description getDescription() {
+            return mDesc;
+        }
+
+        @Override
+        public String toString() {
+            if (mDelegate != null) {
+                return mDelegate.toString();
+            } else {
+                return mDesc.toString();
+            }
+        }
+    }
+}
diff --git a/support/tests/src/android/support/test/JUnit3HogTest.java b/support/tests/src/android/support/test/JUnit3HogTest.java
new file mode 100644
index 0000000..82096e0
--- /dev/null
+++ b/support/tests/src/android/support/test/JUnit3HogTest.java
@@ -0,0 +1,65 @@
+package android.support.test;
+/*
+ * Copyright (C) 2014 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.
+ */
+
+
+import junit.framework.TestCase;
+
+/**
+ * A set of JUnit3 tests that allocates substantial memory into a member variable.
+ * <p/>
+ * Intended to ensure test objects references are not retained by runner (unlike upstream junit3),
+ * and can get garbage collected.
+ */
+public class JUnit3HogTest extends TestCase {
+
+    @SuppressWarnings("unused")
+    private byte[] mByteBuffer;
+
+    @Override
+    public void setUp() {
+        mByteBuffer = new byte[20 * 1024 * 1024];
+    }
+
+    // have 10 sample tests - means 200MB total mem if mByteBuffer not freed
+
+    public void test1() {
+    }
+
+    public void test2() {
+    }
+
+    public void test3() {
+    }
+
+    public void test4() {
+    }
+
+    public void test5() {
+    }
+
+    public void test6() {
+    }
+
+    public void test7() {
+    }
+
+    public void test8() {
+    }
+
+    public void test9() {
+    }
+}
diff --git a/support/tests/src/android/support/test/JUnit4HogTest.java b/support/tests/src/android/support/test/JUnit4HogTest.java
new file mode 100644
index 0000000..6a875f6
--- /dev/null
+++ b/support/tests/src/android/support/test/JUnit4HogTest.java
@@ -0,0 +1,75 @@
+package android.support.test;
+/*
+ * Copyright (C) 2014 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.
+ */
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * A set of JUnit4 tests that allocates substantial memory into a member variable.
+ * <p/>
+ * Intended to ensure test objects references are not retained by runner, and can get garbage
+ * collected.
+ */
+public class JUnit4HogTest {
+
+    @SuppressWarnings("unused")
+    private byte[] mByteBuffer;
+
+    @Before
+    public void setUp() {
+        mByteBuffer = new byte[20 * 1024 * 1024];
+    }
+
+    // have 10 sample tests - means 200MB total mem if mByteBuffer not freed
+
+    @Test
+    public void test1() {
+    }
+
+    @Test
+    public void test2() {
+    }
+
+    @Test
+    public void test3() {
+    }
+
+    @Test
+    public void test4() {
+    }
+
+    @Test
+    public void test5() {
+    }
+
+    @Test
+    public void test6() {
+    }
+
+    @Test
+    public void test7() {
+    }
+
+    @Test
+    public void test8() {
+    }
+
+    @Test
+    public void test9() {
+    }
+}