blob: cc4295314b19ddb47c39fc744b7c94a83511f55d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.tests.resources;
import java.util.Random;
import org.eclipse.core.tests.harness.FussyProgressMonitor;
import org.junit.Assert;
/**
* Abstract superclass of inner classes used for black-box testing
* For debugging certain failure cases, insert a breakpoint in performTestRecursiveLoop
* according to the comment in that method.
*/
abstract public class TestPerformer {
private int count = 0;
String name = null;
/**
* TestPerformer constructor comment.
*/
public TestPerformer(String name) {
super();
this.name = name;
}
public void cleanUp(Object[] args, int count) {
// do nothing
}
public Object[] interestingOldState(Object[] args) throws Exception {
//subclasses should override to hold onto interesting old state
return null;
}
abstract public Object invokeMethod(Object[] args, int count) throws Exception;
final public void performTest(Object[][] inputs) {
// call helper method
int permutations = 1;
for (Object[] input : inputs) {
permutations = permutations * input.length;
if (input.length > 2) {
scramble(input);
}
}
// System.out.println("\nTesting " + permutations + " permutations of " + name);
performTestRecursiveLoop(inputs, new Object[inputs.length], 0);
}
/**
* Loop through imaginary (nth) index variable, setting args[nth] to inputs[nth][i].
* Then invoke method if nth==inputs.length-1, otherwise do recursive call
* with incremented nth.
*/
private void performTestRecursiveLoop(Object[][] inputs, Object[] args, int nth) {
for (int i = 0; i < inputs[nth].length; i++) {
args[nth] = inputs[nth][i];
if (nth == inputs.length - 1) {
// breakpoint goes here, may be conditional on name and count, e.g.:
// name.equals("IResourceTest.testMove") && count==2886
if (shouldFail(args, count)) {
try {
invokeMethod(args, count);
StringBuffer buffer = new StringBuffer();
buffer.append("invocation " + count + " should fail, but it doesn't [");
for (Object arg : args) {
buffer.append(arg);
buffer.append(',');
}
buffer.deleteCharAt(buffer.length() - 1);
buffer.append(']');
Assert.assertTrue(buffer.toString(), false);
} catch (Exception ex) {
}
} else {
Object[] oldState = null;
try {
oldState = interestingOldState(args);
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException("call to interestingOldState failed");
}
Object result = null;
try {
result = invokeMethod(args, count);
} catch (FussyProgressMonitor.FussyProgressAssertionFailed fussyEx) {
Assert.assertTrue("invocation " + count + ": " + fussyEx.getMessage(), false);
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue("invocation " + count + " failed with " + ex, false);
}
boolean success = false;
try {
success = wasSuccess(args, result, oldState);
} catch (Exception ex) {
ex.printStackTrace();
}
Assert.assertTrue("invocation " + count + " did not produce desired result", success);
}
cleanUp(args, count);
count++;
} else {
performTestRecursiveLoop(inputs, args, nth + 1);
}
}
}
/**
* scrambles an array in a deterministic manner (note the constant seed...).
*/
static protected void scramble(Object[] first) {
Random random = new Random(4711);
final int len = first.length;
for (int i = 0; i < len * 100; i++) {
/* get any array offset */
int off1 = (int) (random.nextFloat() * len);
if (off1 == len) {
continue;
}
/* get another array offset */
int off2 = (int) (random.nextFloat() * len);
if (off2 == len) {
continue;
}
/* switch */
Object temp = first[off1];
first[off1] = first[off2];
first[off2] = temp;
}
}
abstract public boolean shouldFail(Object[] args, int count);
abstract public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception;
}