/******************************************************************************
* 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.angelic;
import static test.TestUtil.method;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import com.ibm.wala.memsat.Miniatur;
import com.ibm.wala.memsat.Options;
import com.ibm.wala.memsat.Results;
import com.ibm.wala.memsat.translation.sequential.SequentialTranslation;
import com.ibm.wala.util.CancelException;
import data.angelic.Angelic;
import data.angelic.TokenizerClient;
import kodkod.ast.BinaryExpression;
import kodkod.ast.Expression;
import kodkod.ast.Formula;
import kodkod.ast.Node;
import kodkod.ast.Relation;
import kodkod.ast.operator.ExprOperator;
import kodkod.ast.visitor.AbstractReplacer;
import kodkod.engine.Solution;
import kodkod.engine.satlab.SATFactory;
import kodkod.engine.ucore.RCEStrategy;
import kodkod.instance.Bounds;
import kodkod.instance.TupleSet;
import kodkod.util.ints.IntIterator;
/**
* @author etorlak
*
*/
public class AngelicTests {
private static final File SRC_DATA = new File("source/data/angelic");
@SuppressWarnings("unchecked")
private Formula makeReadable(Formula formula) {
final List<Formula> replacements = new ArrayList<Formula>();
final Map<Expression, Integer> levels = new LinkedHashMap<Expression, Integer>();
final AbstractReplacer replacer = new AbstractReplacer(Collections.EMPTY_SET) {
protected <N extends Node> N cache(N node, N replacement) {
cache.put(node, replacement);
return replacement;
}
public Expression visit(BinaryExpression expr) {
Expression ret = lookup(expr);
if (ret!=null) return ret;
final Expression left = expr.left().accept(this);
final Expression right = expr.right().accept(this);
if (expr.op()==ExprOperator.OVERRIDE && left instanceof Relation) {
final int level = levels.containsKey(left) ? levels.get(left) : 0;
final Relation r = Relation.nary(((Relation)left).name()+"'", expr.arity());
replacements.add(r.eq(left.compose(expr.op(), right)));
levels.put(left, level+1);
return cache(expr, r);
}
return cache(expr, left.compose(expr.op(), right));
}
};
int size;
do {
size = replacements.size();
formula = formula.accept(replacer);
} while (size < replacements.size());
return formula.and(Formula.and(replacements));
}
private Solution test(File srcpath, Class<?> klass, String methodname, boolean expected){
return test(Collections.singletonList(srcpath), klass, methodname, expected);
}
protected Options getOptions() {
Options o = new Options();
o.setOpenWorldScopeSize(1);
o.setAssertsAreAssumptions(true);
o.setNumberOfIndexAtoms(3);
o.setloopUnrollDepth(3);
o.kodkodOptions().setSolver(SATFactory.MiniSatProver);
o.kodkodOptions().setCoreGranularity(2);
o.kodkodOptions().setLogTranslation(1);
return o;
}
private Solution test(List<File> srcpath, Class<?> klass, String methodname, boolean expected){
try {
final Miniatur miniatur = new Miniatur(getOptions());
final Results<SequentialTranslation> results = miniatur.analyze(method(klass, methodname), srcpath);
final Solution solution = results.solution();
final boolean actual = (solution.instance()!=null);
System.out.println("FORMULA: ");
// System.out.println(Strings.prettyPrint(makeReadable(results.translation().formula()), 2, 200, Collections.EMPTY_MAP));
System.out.println("BOUNDS: ");
final Bounds bounds = results.translation().bounds();
for(Relation r : bounds.relations()) {
final TupleSet lower = bounds.lowerBound(r);
final TupleSet upper = bounds.upperBound(r);
if (lower.equals(upper))
System.out.println(r + " = " + lower);
else
System.out.println(r + " : [" + lower + ", "+ upper +"]");
}
for(IntIterator itr = bounds.ints().iterator(); itr.hasNext(); ) {
final int i = itr.next();
System.out.println(i + " = " + bounds.exactBound(i));
}
System.out.println(results.toString());
if (!actual) { // get the core
final long corestart = System.currentTimeMillis();
solution.proof().minimize(new RCEStrategy(solution.proof().log()));
final long core = System.currentTimeMillis() - corestart;
System.out.println("CORE (" + core + " ms): " + solution.proof().highLevelCore().size());
// System.out.println(Strings.prettyPrint(solution.proof().highLevelCore().values(), 2, 200, Collections.EMPTY_MAP));
}
Assert.assertEquals(expected, actual);
return solution;
} catch (SecurityException e) {
e.printStackTrace();
} catch (CancelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
@Test
public void angelicTest00(){
test(SRC_DATA, Angelic.class, "test00", false);
}
@Test
public void angelicTest01(){
test(SRC_DATA, Angelic.class, "test01", true);
}
// @Test
public void angelicTest02(){
test(SRC_DATA, Angelic.class, "test02", true);
}
@Test
public void tokenizerTest00() {
test(SRC_DATA, TokenizerClient.class, "test00", false);
}
@Test
public void tokenizerTest01() {
test(SRC_DATA, TokenizerClient.class, "test01", true);
}
}