/****************************************************************************** * 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(); } } }