package org.overture.codegen.tests.other;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.lex.Dialect;
import org.overture.ast.node.INode;
import org.overture.ast.statements.AIdentifierStateDesignator;
import org.overture.codegen.analysis.vdm.IdStateDesignatorDefCollector;
import org.overture.codegen.analysis.vdm.Renaming;
import org.overture.codegen.analysis.vdm.VarRenamer;
import org.overture.codegen.tests.util.TestUtils;
import org.overture.codegen.utils.GeneralUtils;
import org.overture.config.Release;
import org.overture.config.Settings;
import org.overture.interpreter.util.InterpreterUtil;
import org.overture.interpreter.values.Value;
import org.overture.parser.messages.VDMWarning;
import org.overture.typechecker.assistant.TypeCheckerAssistantFactory;
import org.overture.typechecker.util.TypeCheckerUtil;
import org.overture.typechecker.util.TypeCheckerUtil.TypeCheckResult;
@RunWith(Parameterized.class)
public class VarShadowingTest
{
public static final String EVAL_ENTRY_POINT = "Entry`Run()";
private File inputFile;
private static final TypeCheckerAssistantFactory af = new TypeCheckerAssistantFactory();
public static final String ROOT = "src" + File.separatorChar + "test"
+ File.separatorChar + "resources" + File.separatorChar
+ "var_shadowing_specs";
public VarShadowingTest(File inputFile)
{
this.inputFile = inputFile;
}
@Before
public void init() throws Exception
{
Settings.dialect = Dialect.VDM_PP;
Settings.release = Release.VDM_10;
}
@Parameters(name = "{index} : {0}")
public static Collection<Object[]> testData()
{
return TestUtils.collectFiles(ROOT);
}
@Test
public void test() throws Exception
{
try
{
TypeCheckResult<List<SClassDefinition>> originalSpecTcResult = TypeCheckerUtil.typeCheckPp(inputFile);
Map<AIdentifierStateDesignator, PDefinition> idDefs = IdStateDesignatorDefCollector.getIdDefs(originalSpecTcResult.result, af);
Assert.assertTrue(inputFile.getName()
+ " has type errors", originalSpecTcResult.errors.isEmpty());
Value orgSpecResult = evalSpec(originalSpecTcResult.result);
List<Renaming> renamings = new LinkedList<Renaming>(new VarRenamer().computeRenamings(originalSpecTcResult.result, af, idDefs));
// It is very important that renamings are performed from the bottom, right to left, in order
// not to mess up the location of the names!!
Collections.sort(renamings);
StringBuilder sb = GeneralUtils.readLines(inputFile, "\n");
// Perform the renaming in a string buffer
rename(renamings, sb);
// Type check the renamed specification
TypeCheckResult<List<SClassDefinition>> renamed = TypeCheckerUtil.typeCheckPp(sb.toString());
// The renamed specification must contain no type errors and no warnings about hidden variables
Assert.assertTrue("Renamed specification contains errors", renamed.errors.isEmpty());
Assert.assertTrue("Found hidden variable warnings in renamed specification", filter(renamed.warnings).isEmpty());
Value renamedSpecResult = evalSpec(renamed.result);
// The two specifications must evaluate to the same result
Assert.assertTrue("Expected same value to be produced "
+ "for the original specification and the specification with "
+ "renamed variables. Got values " + orgSpecResult + " and "
+ renamedSpecResult + " from the original and "
+ "the renamed specification, respectively", orgSpecResult.equals(renamedSpecResult));
} catch (Exception e)
{
e.printStackTrace();
Assert.fail("Test: " + inputFile.getName() + " did not parse!");
}
}
private void rename(List<Renaming> renamings, StringBuilder sb)
{
for (Renaming r : renamings)
{
int startOffset = r.getLoc().getStartOffset() - 1;
int endOffset = startOffset + r.getNewName().length() - 2;
sb.replace(startOffset, endOffset, r.getNewName());
}
}
private Value evalSpec(List<SClassDefinition> classes) throws Exception
{
return InterpreterUtil.interpret(new LinkedList<INode>(classes), EVAL_ENTRY_POINT, Settings.dialect);
}
private List<VDMWarning> filter(List<VDMWarning> warnings)
{
List<VDMWarning> filtered = new LinkedList<VDMWarning>();
for (VDMWarning w : warnings)
{
if (w.number == 5007 || w.number == 5008)
{
filtered.add(w);
}
}
return filtered;
}
}