/******************************************************************************
* Copyright (c) 2009 - 2015 IBM Corporation.
* 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 test.transform;
import static com.ibm.wala.memsat.util.Graphs.graph;
import static test.TestUtil.method;
import static test.TestUtil.threadMethods;
import static test.TestUtil.typeReference;
import java.io.File;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import org.junit.Test;
import com.ibm.wala.memsat.Miniatur;
import com.ibm.wala.types.MethodReference;
import data.transforms.IrrelevantReadIntroduction;
import data.transforms.RedundantReadAfterReadElimination;
import data.transforms.RedundantWriteAfterReadElimination;
import data.transforms.ReorderingWithExternalActions;
import data.transforms.RoachMotelSemantics;
import test.ConcurrentTests;
import test.TestUtil;
/**
* Runs the transformation tests.
* @author etorlak
*/
public abstract class TransformTests extends ConcurrentTests {
private static final File TRANSFORM_TESTS = new File("source/data/transforms");
/**
* Checks that the result produced by applying the given miniatur instance to the untransformed
* {@linkplain TestUtil#threadMethods(Class) thread methods } in the given
* methods is satisfiable or unsatisfiable, depending on the value of the specified flag.
* This method assumes that the thread methods in the class testCase are named
* "thread\d+" or "thread\d+T" where \d+ stands for a (non-empty) string of digits. Only methods
* with names of the form "thread\d+" are analyzed.
*/
final void testOriginal(Miniatur miniatur, Class<?> testCase, boolean sat) {
final Set<MethodReference> threadMethods = threadMethods(testCase);
for(Iterator<MethodReference> itr = threadMethods.iterator(); itr.hasNext();) {
final MethodReference ref = itr.next();
if (ref.getName().toString().matches("thread\\d+T")) {
itr.remove();
}
}
test(miniatur, TRANSFORM_TESTS, graph(threadMethods), sat);
}
/**
* Checks that the result produced by applying the given miniatur instance to the transformed
* {@linkplain TestUtil#threadMethods(Class) thread methods } in the given
* methods is satisfiable or unsatisfiable, depending on the value of the specified flag.
* This method assumes that the thread methods in the class testCase are named
* "thread\d+" or "thread\d+T" where \d+ stands for a string of digits. A method named
* "thread\d+" is analyzed only if no corresponding method
* with the name "thread\d+T" exists. If such a method exists, it is used instead.
*/
final void testTransformed(Miniatur miniatur, Class<?> testCase, boolean sat) {
final Set<MethodReference> threadMethods = threadMethods(testCase);
final Set<MethodReference> untransformed = new LinkedHashSet<MethodReference>();
for(MethodReference ref : threadMethods) {
final String name = ref.getName().toString();
if (name.matches("thread\\d+T")) {
final MethodReference uref =
MethodReference.findOrCreate(typeReference(testCase), name.substring(0, name.length()-1), "()V");
untransformed.add(uref);
}
}
threadMethods.removeAll(untransformed);
test(miniatur, TRANSFORM_TESTS, graph(threadMethods), sat);
}
/**
* Returns a miniatur analysis engine that uses the memory model generated by calling
* {@linkplain #memoryModel(int, Set) memoryModel(maxSpeculations, special)} and that treats user assertions as assumes.
* @return a miniatur analysis engine that uses the memory model generated by calling
* {@linkplain #memoryModel(int, Set) memoryModel(maxSpeculations, special)} and that treats user assertions as assumes.
*/
protected Miniatur miniatur(int maxSpeculations, Set<MethodReference> special) {
final Miniatur miniatur = super.miniatur(maxSpeculations, special);
miniatur.options().kodkodOptions().setBitwidth(8);
return miniatur;
}
// @Test
// public final void testInit() {
// testOriginal(miniatur(7), RedundantReadAfterReadElimination.class, false);
// }
@Test
public final void testRedundantWriteAfterRead() {
testOriginal(miniatur(6), RedundantWriteAfterReadElimination.class, false);
}
@Test
public final void testRedundantWriteAfterReadElimination() {
testTransformed(miniatur(5), RedundantWriteAfterReadElimination.class, true);
}
@Test
public final void testRedundantReadAfterRead() {
testOriginal(miniatur(7), RedundantReadAfterReadElimination.class, false);
}
@Test
public final void testRedundantReadAfterReadElimination() {
testTransformed(miniatur(7), RedundantReadAfterReadElimination.class, true);
}
@Test
public final void testRoachMotelSemantics() {
testOriginal(miniatur(9), RoachMotelSemantics.class, false);
}
@Test
public final void testRoachMotelSemanticsTransformed() {
testTransformed(miniatur(9), RoachMotelSemantics.class, true);
}
@Test
public final void testIrrelevantReadIntroduction() {
testOriginal(miniatur(8), IrrelevantReadIntroduction.class, false);
}
@Test
public final void testIrrelevantReadIntroductionTransformed() {
testTransformed(miniatur(9), IrrelevantReadIntroduction.class, true);
}
@Test
public void testReorderingWithExernalActions() {
try {
testOriginal(miniatur(6, Collections.singleton(method(ReorderingWithExternalActions.class, "print"))),
ReorderingWithExternalActions.class, false);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Test
public final void testReorderingWithExernalActionsTransformed() {
try {
testTransformed(miniatur(6, Collections.singleton(method(ReorderingWithExternalActions.class, "print"))),
ReorderingWithExternalActions.class, true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}