package net.sf.orcc.tests.ui; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import net.sf.orcc.OrccProjectNature; import net.sf.orcc.cal.CalInjectorProvider; import net.sf.orcc.cal.CalStandaloneSetup; import net.sf.orcc.cal.cal.AstEntity; import net.sf.orcc.cal.cal.Variable; import net.sf.orcc.cal.services.Evaluator; import net.sf.orcc.cal.services.Typer; import net.sf.orcc.df.Actor; import net.sf.orcc.frontend.ActorTransformer; import net.sf.orcc.frontend.UnitTransformer; import net.sf.orcc.ir.ExprList; import net.sf.orcc.ir.Expression; import net.sf.orcc.ir.IrFactory; import net.sf.orcc.ir.Type; import net.sf.orcc.ir.util.ExpressionPrinter; import net.sf.orcc.tests.util.TestInterpreter; import org.eclipse.core.resources.ICommand; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jdt.core.JavaCore; import org.eclipse.xtext.diagnostics.Severity; import org.eclipse.xtext.junit4.AbstractXtextTests; import org.eclipse.xtext.junit4.InjectWith; import org.eclipse.xtext.junit4.XtextRunner; import org.eclipse.xtext.junit4.util.ParseHelper; import org.eclipse.xtext.resource.IResourceServiceProvider; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.resource.XtextResourceSet; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.validation.CheckMode; import org.eclipse.xtext.validation.IResourceValidator; import org.eclipse.xtext.validation.Issue; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import com.google.inject.Inject; import com.google.inject.Provider; @RunWith(XtextRunner.class) @InjectWith(CalInjectorProvider.class) public class AllTests extends AbstractXtextTests { private static final String prefix = "test/"; private static final String projectName = "Tests"; private static final String projectPrefix = "/Tests/src/"; @Inject private ParseHelper<AstEntity> parser; @Inject private Provider<XtextResourceSet> provider; @Inject private IResourceServiceProvider serviceProvider; @Override @Before public void setUp() { try { super.setUp(); with(CalStandaloneSetup.class); } catch (Exception e) { e.printStackTrace(); } IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IProject project = root.getProject(projectName); if (!project.exists()) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); try { IProjectDescription description = workspace .newProjectDescription(projectName); String[] natures = description.getNatureIds(); String[] newNatures = new String[natures.length + 2]; // add new natures System.arraycopy(natures, 0, newNatures, 2, natures.length); newNatures[0] = OrccProjectNature.NATURE_ID; newNatures[1] = JavaCore.NATURE_ID; description.setNatureIds(newNatures); project.create(description, null); // retrieves the up-to-date description project.open(null); description = project.getDescription(); // filters out the Java builder ICommand[] commands = description.getBuildSpec(); List<ICommand> buildSpec = new ArrayList<ICommand>( commands.length); for (ICommand command : commands) { if (!JavaCore.BUILDER_ID.equals(command.getBuilderName())) { buildSpec.add(command); } } // updates the description and replaces the existing description description.setBuildSpec(buildSpec.toArray(new ICommand[0])); project.setDescription(description, null); } catch (CoreException e) { e.printStackTrace(); } } } /** * Parses, validates, compiles, and interprets the actor defined in the file * whose name is given. Then matches the output of the interpreter with the * <code>expected</code> string. * * @param expected * expected output * @param name * name of a .cal file that contains an entity */ private void assertExecution(String expected, String name) { EObject entity = generateCode(name); Assert.assertNotNull("expected parsing, validation, and code " + "generation to be correct for " + name, entity); TestInterpreter interpreter = new TestInterpreter((Actor) entity); interpreter.initialize(); interpreter.schedule(); String output = interpreter.getOutput(); Assert.assertEquals("expected " + expected + ", got " + output, expected, output); } /** * Parses, validates, and generates code for the entity defined in the file * whose name is given. * * @param name * name of a .cal file that contains an entity * @return an IR entity if the file could be parsed, validated, and * translated to IR, otherwise <code>null</code> */ private EObject generateCode(String name) { AstEntity entity = parseAndValidate(name); if (entity == null) { return null; } if (entity.getActor() != null) { return new ActorTransformer().doSwitch(entity.getActor()); } else if (entity.getUnit() != null) { return new UnitTransformer().doSwitch(entity.getActor()); } return null; } /** * Parses and validates the entity defined in the file whose name is given. * * @param name * name of a .cal file that contains an entity * @return an AST entity if the file could be parsed and validated, * otherwise <code>null</code> */ private AstEntity parseAndValidate(String name) { XtextResourceSet resourceSet = provider.get(); resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); InputStream in = Thread.currentThread().getContextClassLoader() .getResourceAsStream(name); URI uri = URI.createPlatformResourceURI(projectPrefix + name, true); AstEntity entity = parser.parse(in, uri, null, resourceSet); // validates resources IResourceValidator v = serviceProvider.getResourceValidator(); Resource resource = entity.eResource(); List<Issue> issues = v.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl); boolean isValid = true; for (Issue issue : issues) { if (issue.getSeverity() == Severity.ERROR) { System.err.println(issue.toString()); isValid = false; } else { System.out.println(issue.toString()); } } return isValid ? entity : null; } @Test public void passCheckGenerator() throws Exception { AstEntity entity = parseAndValidate(prefix + "pass/Generator.cal"); List<Variable> stateVars = entity.getActor().getStateVariables(); Variable var = stateVars.get(0); Expression expr = Evaluator.getValue(var); ExprList l11 = IrFactory.eINSTANCE.createExprList(); l11.getValue().add(IrFactory.eINSTANCE.createExprInt(1)); l11.getValue().add(IrFactory.eINSTANCE.createExprInt(2)); l11.getValue().add(IrFactory.eINSTANCE.createExprInt(3)); ExprList l12 = IrFactory.eINSTANCE.createExprList(); l12.getValue().add(IrFactory.eINSTANCE.createExprInt(2)); l12.getValue().add(IrFactory.eINSTANCE.createExprInt(4)); l12.getValue().add(IrFactory.eINSTANCE.createExprInt(6)); ExprList l1 = IrFactory.eINSTANCE.createExprList(); l1.getValue().add(l11); l1.getValue().add(l12); ExprList expected = IrFactory.eINSTANCE.createExprList(); expected.getValue().add(l1); String strExpected = new ExpressionPrinter().doSwitch(expected); Assert.assertTrue("value of stateVar should be " + strExpected, EcoreUtil.equals(expr, expected)); } @Test public void passCheckInitialize() throws Exception { Assert.assertNotNull("expected correct actor with initialize action", parseAndValidate(prefix + "pass/InitializePattern.cal")); } @Test public void passCheckTypeInt() throws Exception { AstEntity entity = parseAndValidate(prefix + "pass/TypeInt.cal"); List<Variable> stateVars = entity.getActor().getStateVariables(); Variable x = stateVars.get(0); Variable y = stateVars.get(1); Type type = Typer.getType(x); Assert.assertTrue("type of x should be uint(size=3)", EcoreUtil.equals(type, IrFactory.eINSTANCE.createTypeUint(3))); type = Typer.getType(x.getValue()); Assert.assertTrue("type of value of x should be uint(size=3)", EcoreUtil.equals(type, IrFactory.eINSTANCE.createTypeUint(3))); // type of "x + 1" is type of "8", i.e. uint(size=4) // but because the expression is assigned to y whose type is int(...) // it becomes int(size=5) type = Typer.getType(y.getValue()); Assert.assertTrue("type of value of y should be uint(size=4)", EcoreUtil.equals(type, IrFactory.eINSTANCE.createTypeUint(4))); } @Test public void passExecElsif() throws Exception { assertExecution("okok", prefix + "pass/Elsif.cal"); } @Test public void passExecElsifExpr() throws Exception { assertExecution("result = 0", prefix + "pass/ElsifExpr.cal"); } @Test public void passExecElsifStateVar() throws Exception { assertExecution("ok", prefix + "pass/ElsifStateVar.cal"); } @Test public void passExecInitStateVar() throws Exception { assertExecution("pp = 8", prefix + "pass/InitStateVarFunction.cal"); } @Test public void passExecShadow() throws Exception { assertExecution("x = 0", prefix + "pass/Shadowing.cal"); } @Test public void passExecWhile() throws Exception { assertExecution("idx is 60", prefix + "pass/CodegenWhile.cal"); } @Test public void xfailCheckBadFsm() throws Exception { Assert.assertNull( "there cannot be two transitions from a source state with the same action", parseAndValidate(prefix + "xfail/BadFsm.cal")); } @Test public void xfailCheckParam() throws Exception { Assert.assertNull( "assignment to an actor parameter must not be allowed", parseAndValidate(prefix + "xfail/Param.cal")); } @Test public void xfailCheckPattern1() throws Exception { Assert.assertNull( "reference to an output port in an input pattern must not be allowed", parseAndValidate(prefix + "xfail/Pattern1.cal")); } @Test public void xfailCheckPattern2() throws Exception { Assert.assertNull("an input pattern cannot contain expressions", parseAndValidate(prefix + "xfail/Pattern2.cal")); } @Test public void xfailCheckPattern3() throws Exception { Assert.assertNull( "combining Pattern1 and Pattern2 must be invalid code", parseAndValidate(prefix + "xfail/Pattern3.cal")); } @Test public void xfailCheckPattern4() throws Exception { Assert.assertNull( "more than one reference per output port must not be allowed", parseAndValidate(prefix + "xfail/Pattern4.cal")); } @Test public void xfailCheckPattern5() throws Exception { Assert.assertNull( "more than one reference per input port must not be allowed", parseAndValidate(prefix + "xfail/Pattern5.cal")); } @Test public void xfailCheckTypeError1() throws Exception { Assert.assertNull( "passing a list in lieu of a scalar must raise a type error", parseAndValidate(prefix + "xfail/TypeError1.cal")); } @Test public void xfailCheckTypeError2() throws Exception { Assert.assertNull( "passing a scalar in lieu of a list must raise a type error", parseAndValidate(prefix + "xfail/TypeError2.cal")); } @Test public void xfailCheckTypeError3() throws Exception { Assert.assertNull( "the size of a type must be a compile-time constant > 0", parseAndValidate(prefix + "xfail/TypeError3.cal")); } }