package org.overture.vdm2jml.tests;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.overture.ast.modules.AModuleModules;
import org.overture.codegen.ir.types.ACharBasicTypeIR;
import org.overture.codegen.ir.types.ANatNumericBasicTypeIR;
import org.overture.codegen.utils.GeneralCodeGenUtils;
import org.overture.codegen.vdm2jml.JmlGenerator;
import org.overture.codegen.vdm2jml.predgen.info.LeafTypeInfo;
import org.overture.codegen.vdm2jml.predgen.info.NamedTypeInfo;
import org.overture.codegen.vdm2jml.predgen.info.NamedTypeInvDepCalculator;
import org.overture.typechecker.util.TypeCheckerUtil;
import org.overture.typechecker.util.TypeCheckerUtil.TypeCheckResult;
public class TypeDependencyTests extends AnnotationTestsBase
{
public static final String TEST_RES_TYPE_DEP_ROOT = AnnotationTestsBase.TEST_RESOURCES_ROOT
+ "type_dep" + File.separatorChar;
public static final String MODULE = "Entry";
private List<NamedTypeInfo> typeInfoList;
public void load(String filename)
{
try
{
List<File> files = new LinkedList<File>();
files.add(new File(TEST_RES_TYPE_DEP_ROOT + filename));
TypeCheckResult<List<AModuleModules>> tcResult = TypeCheckerUtil.typeCheckSl(files);
if (GeneralCodeGenUtils.hasErrors(tcResult))
{
Assert.fail("Could not parse/type check VDM model:\n"
+ GeneralCodeGenUtils.errorStr(tcResult));
}
List<AModuleModules> modules = tcResult.result;
Assert.assertTrue("Expected a single module but got "
+ modules.size(), modules.size() == 1);
AModuleModules module = modules.get(0);
JmlGenerator jmlGen = new JmlGenerator();
initJmlGen(jmlGen);
NamedTypeInvDepCalculator depCalc = new NamedTypeInvDepCalculator(jmlGen.getJavaGen().getInfo());
module.apply(depCalc);
this.typeInfoList = depCalc.getTypeDataList();
Assert.assertTrue("Could not load type info", this.typeInfoList != null);
for (NamedTypeInfo info : typeInfoList)
{
Assert.assertEquals("Expected the enclosing module to be '"
+ MODULE + "'", MODULE, info.getDefModule());
}
} catch (Exception e)
{
e.printStackTrace();
Assert.assertFalse("Problems loading test data: "
+ e.getMessage(), true);
}
}
private void assertTypeName(String typeName, NamedTypeInfo info)
{
Assert.assertEquals("Expected type name to be '" + typeName
+ "'", typeName, info.getTypeName());
}
private String infoStr(NamedTypeInfo info)
{
String message = info.getDefModule() + "." + info.getTypeName();
return message;
}
private void assertNoOfLeafs(NamedTypeInfo info, int no)
{
Assert.assertEquals("Number of actual leaf types differs from those expected", no, info.getLeafTypesRecursively().size());
}
private void assertLeafType(NamedTypeInfo info, Class<?> leafType,
boolean nullAllowed)
{
for (LeafTypeInfo leaf : info.getLeafTypesRecursively())
{
if (leafType == leaf.getType().getClass())
{
Assert.assertEquals("Found leaf type but 'allowsNull' does not equal", nullAllowed, leaf.isOptional());
return;
}
}
Assert.assertFalse("Could not find leaf type '" + leafType
+ " with ' nullAllowed: '" + nullAllowed
+ "' for named invariant type '" + infoStr(info) + "'", true);
}
private void assertNotOptional(NamedTypeInfo info)
{
Assert.assertTrue("Expected named type invariant '" + infoStr(info)
+ "' NOT to be optional", !info.isOptional());
}
private void assertTotalNoOfNamedInvTypes(int no)
{
Assert.assertTrue("Expected " + no + " named invariant types but got "
+ typeInfoList.size(), typeInfoList.size() == no);
}
private void assertNoInv(NamedTypeInfo info)
{
Assert.assertTrue("Expected named invariant type '" + infoStr(info)
+ "' to NOT have an invariant", !info.hasInv());
}
private void assertInv(NamedTypeInfo info)
{
Assert.assertTrue("Expected named invariant type '" + infoStr(info)
+ "' to have an invariant", info.hasInv());
}
private NamedTypeInfo getInfo(String typeName)
{
NamedTypeInfo info = NamedTypeInvDepCalculator.findTypeInfo(typeInfoList, MODULE, typeName);
assertTypeName(typeName, info);
return info;
}
@Test
public void namedInvTypeNat()
{
load("Nat.vdmsl");
// N = nat;
String typeName = "N";
NamedTypeInfo info = getInfo(typeName);
assertTotalNoOfNamedInvTypes(1);
assertNoOfLeafs(info, 1);
assertLeafType(info, ANatNumericBasicTypeIR.class, false);
assertNotOptional(info);
assertNoInv(info);
}
@Test
public void namedInvTypeNatOpt()
{
// N = [nat];
load("NatOpt.vdmsl");
String typeName = "N";
NamedTypeInfo info = getInfo(typeName);
assertTotalNoOfNamedInvTypes(1);
assertNoOfLeafs(info, 1);
assertLeafType(info, ANatNumericBasicTypeIR.class, true);
assertNotOptional(info);
assertNoInv(info);
}
@Test
public void unionOfBasicAndOptBasic()
{
// CN = nat|[char];
load("UnionOfBasicAndOptBasic.vdmsl");
String typeName = "CN";
NamedTypeInfo info = getInfo(typeName);
assertTotalNoOfNamedInvTypes(1);
assertNoOfLeafs(info, 2);
assertLeafType(info, ANatNumericBasicTypeIR.class, false);
assertLeafType(info, ACharBasicTypeIR.class, true);
assertNotOptional(info);
assertNoInv(info);
}
@Test
public void unionOfNamedInvTypes()
{
// CN = C|N;
// N = nat;
// C = [char];
load("UnionOfNamedInvTypes.vdmsl");
String typeName = "CN";
NamedTypeInfo info = getInfo(typeName);
assertTotalNoOfNamedInvTypes(3);
assertNoOfLeafs(info, 2);
assertNotOptional(info);
assertNoInv(info);
typeName = "N";
info = getInfo(typeName);
assertNoOfLeafs(info, 1);
assertLeafType(info, ANatNumericBasicTypeIR.class, false);
assertNotOptional(info);
assertNoInv(info);
typeName = "C";
info = getInfo(typeName);
assertNoOfLeafs(info, 1);
assertLeafType(info, ACharBasicTypeIR.class, true);
assertNotOptional(info);
assertNoInv(info);
}
@Test
public void invariants()
{
// CN = C|N
// inv cn == is_char(cn) => cn = 'a';
// N = nat
// inv n == n = 1;
// C = [char];
load("Invariants.vdmsl");
assertInv(getInfo("CN"));
assertInv(getInfo("N"));
assertNoInv(getInfo("C"));
}
@Test
public void optionalUnion()
{
load("OptionalUnion.vdmsl");
// CN = [C|N];
// N = nat;
// C = char;
assertNotOptional(getInfo("CN"));
assertNotOptional(getInfo("N"));
assertNotOptional(getInfo("C"));
}
@Test
public void optionalNamed()
{
load("OptionalNamedType.vdmsl");
// CN = [C]|N;
// N = nat;
// C = char;
assertNotOptional(getInfo("CN"));
assertNotOptional(getInfo("C"));
assertNotOptional(getInfo("N"));
}
@Test
public void record()
{
load("Rec.vdmsl");
// R :: x : int
// inv r == r.x = 1;
//
// Rn = R | nat;
String typeName = "Rn";
NamedTypeInfo info = getInfo(typeName);
// We do not expect the record to be included
assertTotalNoOfNamedInvTypes(1);
// We expect to have the record type 'R' registered as a leaf type
assertNoOfLeafs(info, 2);
}
@Test
public void recursive()
{
load("Recursive.vdmsl");
// T = nat | T;
String typeName = "T";
NamedTypeInfo info = getInfo(typeName);
assertTotalNoOfNamedInvTypes(1);
assertNoOfLeafs(info, 1);
assertLeafType(info, ANatNumericBasicTypeIR.class, false);
}
@Test
public void unionWithoutNull()
{
load("UnionWithoutNull.vdmsl");
// CN = C|N;
// N = nat;
// C = char;
assertNotOptional(getInfo("CN"));
}
}