package com.squareup.instrumentation;

import android.app.Instrumentation;
import android.test.AndroidTestRunner;
import java.lang.reflect.Method;
import java.util.Enumeration;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import static com.squareup.instrumentation.TestSuiteUtils.maybeExplodeTest;

/**
 * Our own test runner which explodes tests annotated with @Variations.
 */
public class ExplodingTestRunner extends AndroidTestRunner {
  private final Instrumentation instrumentation;

  public ExplodingTestRunner(Instrumentation instrumentation) {
    this.instrumentation = instrumentation;
  }

  @Override
  public void setInstrumentation(Instrumentation instr) {
    super.setInstrumentation(instrumentation);
  }

  @Override
  public void setInstrumentaiton(Instrumentation instr) {
    super.setInstrumentation(instrumentation);
  }

  @Override public void setTest(Test test) {
    if (!(test instanceof TestSuite)) {
      throw new UnsupportedOperationException("Expected instance of TestSuite.");
    }

    TestSuite godTestSuite = new TestSuite();
    try {
      explodeSuite((TestSuite) test, godTestSuite);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    super.setTest(godTestSuite);
  }

  private void explodeSuite(TestSuite testSuite, TestSuite result) throws Exception {
    ClassLoader classLoader = instrumentation.getTargetContext().getClassLoader();
    Class<?> testCaseClass = classLoader.loadClass(testSuite.getName());
    Enumeration<Test> testEnumerator = testSuite.tests();
    while (testEnumerator.hasMoreElements()) {
      Test test = testEnumerator.nextElement();
      if (test instanceof TestCase) {
        TestCase testCase = (TestCase) test;
        Method method = testCaseClass.getMethod(testCase.getName());
        result.addTest(maybeExplodeTest(testCaseClass, method));
      } else {
        explodeSuite((TestSuite) test, result); // Recursively explode this suite's tests.
      }
    }
  }
}

@@ -107,16 +107,169 @@
 Runner;%0A
+import com.squareup.ShowTabletUi;%0Aimport com.squareup.instrumentation.constraints.PhoneOnly;%0Aimport com.squareup.instrumentation.constraints.TabletOnly;%0A
 import j
@@ -1979,24 +1979,67 @@
 getName());%0A
+        if (!shouldSkipMethod(method)) %7B%0A  
         resu
@@ -2087,24 +2087,34 @@
 , method));%0A
+        %7D%0A
       %7D else
@@ -2211,24 +2211,24 @@
 ts.%0A      %7D%0A
-
     %7D%0A  %7D%0A%7D%0A
@@ -2224,11 +2224,301 @@
    %7D%0A  %7D
+%0A%0A  private boolean shouldSkipMethod(Method method) %7B%0A    boolean tablet = instrumentation.getTargetContext().getResources().getBoolean(ShowTabletUi.ID);%0A    return method.isAnnotationPresent(PhoneOnly.class) && tablet%0A        %7C%7C method.isAnnotationPresent(TabletOnly.class) && !tablet;%0A  %7D
 %0A%7D%0A

Support phone- and tablet-specific UI tests