Open Source Repository

Home /junit/junit-4.10 | Repository Home



org/junit/internal/runners/MethodRoadie.java
package org.junit.internal.runners;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.internal.AssumptionViolatedException;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;

/**
 @deprecated Included for backwards compatibility with JUnit 4.4. Will be
 *             removed in the next release. Please use
 *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
 */
@Deprecated
public class MethodRoadie {
  private final Object fTest;
  private final RunNotifier fNotifier;
  private final Description fDescription;
  private TestMethod fTestMethod;

  public MethodRoadie(Object test, TestMethod method, RunNotifier notifier, Description description) {
    fTest= test;
    fNotifier= notifier;
    fDescription= description;
    fTestMethod= method;
  }

  public void run() {
    if (fTestMethod.isIgnored()) {
      fNotifier.fireTestIgnored(fDescription);
      return;
    }
    fNotifier.fireTestStarted(fDescription);
    try {
      long timeout= fTestMethod.getTimeout();
      if (timeout > 0)
        runWithTimeout(timeout);
      else
        runTest();
    finally {
      fNotifier.fireTestFinished(fDescription);
    }
  }

  private void runWithTimeout(final long timeout) {
    runBeforesThenTestThenAfters(new Runnable() {
    
      public void run() {
        ExecutorService service= Executors.newSingleThreadExecutor();
        Callable<Object> callable= new Callable<Object>() {
          public Object call() throws Exception {
            runTestMethod();
            return null;
          }
        };
        Future<Object> result= service.submit(callable);
        service.shutdown();
        try {
          boolean terminated= service.awaitTermination(timeout,
              TimeUnit.MILLISECONDS);
          if (!terminated)
            service.shutdownNow();
          result.get(0, TimeUnit.MILLISECONDS)// throws the exception if one occurred during the invocation
        catch (TimeoutException e) {
          addFailure(new Exception(String.format("test timed out after %d milliseconds", timeout)));
        catch (Exception e) {
          addFailure(e);
        }        
      }
    });
  }
  
  public void runTest() {
    runBeforesThenTestThenAfters(new Runnable() {
      public void run() {
        runTestMethod();
      }
    });
  }

  public void runBeforesThenTestThenAfters(Runnable test) {
    try {
      runBefores();
      test.run();
    catch (FailedBefore e) {
    catch (Exception e) {
      throw new RuntimeException("test should never throw an exception to this level");
    finally {
      runAfters();
    }    
  }
  
  protected void runTestMethod() {
    try {
      fTestMethod.invoke(fTest);
      if (fTestMethod.expectsException())
        addFailure(new AssertionError("Expected exception: " + fTestMethod.getExpectedException().getName()));
    catch (InvocationTargetException e) {
      Throwable actual= e.getTargetException();
      if (actual instanceof AssumptionViolatedException)
        return;
      else if (!fTestMethod.expectsException())
        addFailure(actual);
      else if (fTestMethod.isUnexpected(actual)) {
        String message= "Unexpected exception, expected<" + fTestMethod.getExpectedException().getName() "> but was<"
          + actual.getClass().getName() ">";
        addFailure(new Exception(message, actual));
      }
    catch (Throwable e) {
      addFailure(e);
    }
  }
  
  private void runBefores() throws FailedBefore {
    try {
      try {
        List<Method> befores= fTestMethod.getBefores();
        for (Method before : befores)
          before.invoke(fTest);
      catch (InvocationTargetException e) {
        throw e.getTargetException();
      }
    catch (AssumptionViolatedException e) {
      throw new FailedBefore();
    catch (Throwable e) {
      addFailure(e);
      throw new FailedBefore();
    }
  }

  private void runAfters() {
    List<Method> afters= fTestMethod.getAfters();
    for (Method after : afters)
      try {
        after.invoke(fTest);
      catch (InvocationTargetException e) {
        addFailure(e.getTargetException());
      catch (Throwable e) {
        addFailure(e)// Untested, but seems impossible
      }
  }

  protected void addFailure(Throwable e) {
    fNotifier.fireTestFailure(new Failure(fDescription, e));
  }
}