blob: a47796bb783cbc76dc4a9f1e90624c4a97ddba0a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Lucas Koehler - initial API and implementation
******************************************************************************/
package org.eclipse.emf.ecp.test.common;
import java.text.MessageFormat;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* This JUnit rule allows to try unit tests a given number of times. If at least one of the tries succeeds, the test
* counts as passed. Every try executes all {@link org.junit.Before Before} and {@link org.junit.After After} methods
* of the test. However, it does not re-execute {@link org.junit.BeforeClass BeforeClass} and
* {@link org.junit.AfterClass AfterClass} methods.
*
* @author Lucas Koehler
*
*/
public class MultiTryTestRule implements TestRule {
private final int maxTries;
private boolean executeAll = true;
/**
* Create a new {@link MultiTryTestRule} which allows the given number of tries for all test cases of a test class.
* The number of tries is never less than 1 even if the given number of tries is lower.
*
* @param maxTries The maximum number of tries
*/
public MultiTryTestRule(int maxTries) {
this.maxTries = Integer.max(1, maxTries);
}
/**
* Create a new {@link MultiTryTestRule} which allows the given number of tries for test cases of a test class.
* The number of tries is never less than 1 even if the given number of tries is lower.
*
* @param maxTries The maximum number of tries
* @param executeAll <code>true</code> if all test cases of the test class should use multiple tries.
* <code>false</code> if only test cases annotated with {@link MultiTry} should use multiple tries.
*/
public MultiTryTestRule(int maxTries, boolean executeAll) {
this.maxTries = Integer.max(1, maxTries);
this.executeAll = executeAll;
}
@Override
public Statement apply(Statement base, Description description) {
final MultiTry multiTry = description.getAnnotation(MultiTry.class);
if (!executeAll && multiTry == null) {
// no annotation and not all tests are multi tried => no multi try for this test
return base;
}
final int tries = Integer.max(maxTries, multiTry == null ? 1 : multiTry.maxTries());
return new Statement() {
// CHECKSTYLE.OFF: IllegalCatch
@Override
public void evaluate() throws Throwable {
Throwable lastCaughtThrowable = null;
for (int i = 1; i <= tries; i++) {
try {
base.evaluate();
return;
} catch (final Throwable t) {
System.err
.println(MessageFormat.format("{0}: Try {1} failed.", description.getDisplayName(), i)); //$NON-NLS-1$
lastCaughtThrowable = t;
}
}
System.err.println(MessageFormat.format("{0} finally failed after {1} tries.", //$NON-NLS-1$
description.getDisplayName(), tries));
throw lastCaughtThrowable;
}
// CHECKSTYLE.ON: IllegalCatch
};
}
}