1package org.junit.internal.runners;
2
3import java.lang.reflect.InvocationTargetException;
4import java.lang.reflect.Method;
5import java.util.List;
6import java.util.concurrent.Callable;
7import java.util.concurrent.ExecutorService;
8import java.util.concurrent.Executors;
9import java.util.concurrent.Future;
10import java.util.concurrent.TimeUnit;
11import java.util.concurrent.TimeoutException;
12
13import org.junit.internal.AssumptionViolatedException;
14import org.junit.runner.Description;
15import org.junit.runner.notification.Failure;
16import org.junit.runner.notification.RunNotifier;
17import org.junit.runners.BlockJUnit4ClassRunner;
18
19/**
20 * @deprecated Included for backwards compatibility with JUnit 4.4. Will be
21 *             removed in the next release. Please use
22 *             {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
23 */
24@Deprecated
25public class MethodRoadie {
26	private final Object fTest;
27	private final RunNotifier fNotifier;
28	private final Description fDescription;
29	private TestMethod fTestMethod;
30
31	public MethodRoadie(Object test, TestMethod method, RunNotifier notifier, Description description) {
32		fTest= test;
33		fNotifier= notifier;
34		fDescription= description;
35		fTestMethod= method;
36	}
37
38	public void run() {
39		if (fTestMethod.isIgnored()) {
40			fNotifier.fireTestIgnored(fDescription);
41			return;
42		}
43		fNotifier.fireTestStarted(fDescription);
44		try {
45			long timeout= fTestMethod.getTimeout();
46			if (timeout > 0)
47				runWithTimeout(timeout);
48			else
49				runTest();
50		} finally {
51			fNotifier.fireTestFinished(fDescription);
52		}
53	}
54
55	private void runWithTimeout(final long timeout) {
56		runBeforesThenTestThenAfters(new Runnable() {
57
58			public void run() {
59				ExecutorService service= Executors.newSingleThreadExecutor();
60				Callable<Object> callable= new Callable<Object>() {
61					public Object call() throws Exception {
62						runTestMethod();
63						return null;
64					}
65				};
66				Future<Object> result= service.submit(callable);
67				service.shutdown();
68				try {
69					boolean terminated= service.awaitTermination(timeout,
70							TimeUnit.MILLISECONDS);
71					if (!terminated)
72						service.shutdownNow();
73					result.get(0, TimeUnit.MILLISECONDS); // throws the exception if one occurred during the invocation
74				} catch (TimeoutException e) {
75					addFailure(new Exception(String.format("test timed out after %d milliseconds", timeout)));
76				} catch (Exception e) {
77					addFailure(e);
78				}
79			}
80		});
81	}
82
83	public void runTest() {
84		runBeforesThenTestThenAfters(new Runnable() {
85			public void run() {
86				runTestMethod();
87			}
88		});
89	}
90
91	public void runBeforesThenTestThenAfters(Runnable test) {
92		try {
93			runBefores();
94			test.run();
95		} catch (FailedBefore e) {
96		} catch (Exception e) {
97			throw new RuntimeException("test should never throw an exception to this level");
98		} finally {
99			runAfters();
100		}
101	}
102
103	protected void runTestMethod() {
104		try {
105			fTestMethod.invoke(fTest);
106			if (fTestMethod.expectsException())
107				addFailure(new AssertionError("Expected exception: " + fTestMethod.getExpectedException().getName()));
108		} catch (InvocationTargetException e) {
109			Throwable actual= e.getTargetException();
110			if (actual instanceof AssumptionViolatedException)
111				return;
112			else if (!fTestMethod.expectsException())
113				addFailure(actual);
114			else if (fTestMethod.isUnexpected(actual)) {
115				String message= "Unexpected exception, expected<" + fTestMethod.getExpectedException().getName() + "> but was<"
116					+ actual.getClass().getName() + ">";
117				addFailure(new Exception(message, actual));
118			}
119		} catch (Throwable e) {
120			addFailure(e);
121		}
122	}
123
124	private void runBefores() throws FailedBefore {
125		try {
126			try {
127				List<Method> befores= fTestMethod.getBefores();
128				for (Method before : befores)
129					before.invoke(fTest);
130			} catch (InvocationTargetException e) {
131				throw e.getTargetException();
132			}
133		} catch (AssumptionViolatedException e) {
134			throw new FailedBefore();
135		} catch (Throwable e) {
136			addFailure(e);
137			throw new FailedBefore();
138		}
139	}
140
141	private void runAfters() {
142		List<Method> afters= fTestMethod.getAfters();
143		for (Method after : afters)
144			try {
145				after.invoke(fTest);
146			} catch (InvocationTargetException e) {
147				addFailure(e.getTargetException());
148			} catch (Throwable e) {
149				addFailure(e); // Untested, but seems impossible
150			}
151	}
152
153	protected void addFailure(Throwable e) {
154		fNotifier.fireTestFailure(new Failure(fDescription, e));
155	}
156}
157
158