1/**
2 *
3 */
4package org.junit.internal.runners.statements;
5
6import org.junit.runners.model.Statement;
7
8public class FailOnTimeout extends Statement {
9	private final Statement fOriginalStatement;
10
11	private final long fTimeout;
12
13	public FailOnTimeout(Statement originalStatement, long timeout) {
14		fOriginalStatement= originalStatement;
15		fTimeout= timeout;
16	}
17
18	@Override
19	public void evaluate() throws Throwable {
20		StatementThread thread= evaluateStatement();
21		if (!thread.fFinished)
22			throwExceptionForUnfinishedThread(thread);
23	}
24
25	private StatementThread evaluateStatement() throws InterruptedException {
26		StatementThread thread= new StatementThread(fOriginalStatement);
27		thread.start();
28		thread.join(fTimeout);
29		thread.interrupt();
30		return thread;
31	}
32
33	private void throwExceptionForUnfinishedThread(StatementThread thread)
34			throws Throwable {
35		if (thread.fExceptionThrownByOriginalStatement != null)
36			throw thread.fExceptionThrownByOriginalStatement;
37		else
38			throwTimeoutException(thread);
39	}
40
41	private void throwTimeoutException(StatementThread thread) throws Exception {
42		Exception exception= new Exception(String.format(
43				"test timed out after %d milliseconds", fTimeout));
44		exception.setStackTrace(thread.getStackTrace());
45		throw exception;
46	}
47
48	private static class StatementThread extends Thread {
49		private final Statement fStatement;
50
51		private boolean fFinished= false;
52
53		private Throwable fExceptionThrownByOriginalStatement= null;
54
55		public StatementThread(Statement statement) {
56			fStatement= statement;
57		}
58
59		@Override
60		public void run() {
61			try {
62				fStatement.evaluate();
63				fFinished= true;
64			} catch (InterruptedException e) {
65				//don't log the InterruptedException
66			} catch (Throwable e) {
67				fExceptionThrownByOriginalStatement= e;
68			}
69		}
70	}
71}