Permalink
Browse files

CheckerTests and some cleanup

The Checker tests now have their own (more flexible and lightweight) type
of tests.
  • Loading branch information...
jakhog committed Aug 2, 2017
1 parent b5d6161 commit 17cea510f65d8433bb23ae09591f22a9e690ed4a
Showing with 342 additions and 103 deletions.
  1. +33 −35 language/thingml/src/org/thingml/xtext/formatting2/ThingMLFormatter.xtend
  2. +39 −0 testing/framework/src/main/java/org/thingml/testing/errors/ThingMLCheckerError.java
  3. +17 −5 testing/framework/src/main/java/org/thingml/testing/framework/ThingMLTest.java
  4. +1 −0 testing/framework/src/main/java/org/thingml/testing/framework/ThingMLTestCase.java
  5. +115 −0 testing/framework/src/main/java/org/thingml/testing/tests/CheckerTest.java
  6. +0 −18 testing/framework/src/main/java/org/thingml/testing/tests/general/GeneralTest.java
  7. +0 −9 testing/framework/src/main/java/org/thingml/testing/tests/general/GeneralTestHelper.java
  8. +64 −0 testing/src/test/java/org/thingml/testing/providers/CheckerTests.java
  9. +1 −6 testing/src/test/resources/tests/{General → }/Checker/testCheckAbstractFunction.thingml
  10. +1 −6 testing/src/test/resources/tests/{General → }/Checker/testCheckAbstractFunction1.thingml
  11. +3 −8 testing/src/test/resources/tests/{General → }/Checker/testCheckFunctionCalls.thingml
  12. +3 −8 testing/src/test/resources/tests/{General → }/Checker/testCheckFunctionCalls2.thingml
  13. +1 −8 testing/src/test/resources/tests/{General → }/Checker/testCheckStateMachine.thingml
  14. +16 −0 utilities/src/main/java/org/thingml/utilities/logging/BufferedLogger.java
  15. +16 −0 utilities/src/main/java/org/thingml/utilities/logging/Logger.java
  16. +16 −0 utilities/src/main/java/org/thingml/utilities/logging/NullLogger.java
  17. +16 −0 utilities/src/main/java/org/thingml/utilities/logging/SystemLogger.java
@@ -5,57 +5,55 @@ package org.thingml.xtext.formatting2
import com.google.inject.Inject
import org.eclipse.xtext.formatting2.AbstractFormatter2
import org.eclipse.xtext.formatting2.FormatterRequest
import org.eclipse.xtext.formatting2.IFormattableDocument
import org.eclipse.xtext.util.ExceptionAcceptor
import org.thingml.xtext.constraints.ThingMLHelpers
import org.thingml.xtext.services.ThingMLGrammarAccess
import org.thingml.xtext.thingML.AbstractConnector
import org.thingml.xtext.thingML.Action
import org.thingml.xtext.thingML.ActionBlock
import org.thingml.xtext.thingML.ArrayIndex
import org.thingml.xtext.thingML.CompositeState
import org.thingml.xtext.thingML.ConditionalAction
import org.thingml.xtext.thingML.Configuration
import org.thingml.xtext.thingML.Enumeration
import org.thingml.xtext.thingML.EnumerationLiteral
import org.thingml.xtext.thingML.Event
import org.thingml.xtext.thingML.EventReference
import org.thingml.xtext.thingML.Expression
import org.thingml.xtext.thingML.ExpressionGroup
import org.thingml.xtext.thingML.Function
import org.thingml.xtext.thingML.FunctionCallExpression
import org.thingml.xtext.thingML.FunctionCallStatement
import org.thingml.xtext.thingML.Handler
import org.thingml.xtext.thingML.Instance
import org.thingml.xtext.thingML.InternalPort
import org.thingml.xtext.thingML.InternalTransition
import org.thingml.xtext.thingML.LoopAction
import org.thingml.xtext.thingML.Message
import org.thingml.xtext.thingML.ObjectType
import org.thingml.xtext.thingML.Parameter
import org.thingml.xtext.thingML.PlatformAnnotation
import org.thingml.xtext.thingML.Port
import org.thingml.xtext.thingML.PrimitiveType
import org.thingml.xtext.thingML.Property
import org.thingml.xtext.thingML.PropertyReference
import org.thingml.xtext.thingML.Protocol
import org.thingml.xtext.thingML.ProvidedPort
import org.thingml.xtext.thingML.Region
import org.thingml.xtext.thingML.RequiredPort
import org.thingml.xtext.thingML.SendAction
import org.thingml.xtext.thingML.Session
import org.thingml.xtext.thingML.State
import org.thingml.xtext.thingML.StateContainer
import org.thingml.xtext.thingML.Thing
import org.thingml.xtext.thingML.ThingMLModel
import org.thingml.xtext.thingML.Transition
import org.thingml.xtext.thingML.Type
import org.thingml.xtext.thingML.State
import org.thingml.xtext.thingML.StateContainer
import org.thingml.xtext.thingML.Region
import org.thingml.xtext.thingML.Session
import org.thingml.xtext.thingML.Action
import org.thingml.xtext.thingML.ActionBlock
import org.thingml.xtext.thingML.ConditionalAction
import org.thingml.xtext.thingML.LoopAction
import org.thingml.xtext.thingML.Message
import org.thingml.xtext.thingML.UnaryMinus
import org.thingml.xtext.thingML.Variable
import org.thingml.xtext.thingML.Parameter
import org.thingml.xtext.thingML.FunctionCallStatement
import org.thingml.xtext.thingML.Expression
import org.thingml.xtext.thingML.Transition
import org.thingml.xtext.thingML.InternalTransition
import org.thingml.xtext.thingML.Handler
import org.thingml.xtext.thingML.Event
import org.thingml.xtext.thingML.Instance
import org.thingml.xtext.thingML.AbstractConnector
import org.thingml.xtext.thingML.Enumeration
import org.thingml.xtext.thingML.EnumerationLiteral
import org.thingml.xtext.thingML.SendAction
import org.thingml.xtext.thingML.PropertyReference
import org.thingml.xtext.thingML.EventReference
import org.thingml.xtext.constraints.ThingMLHelpers
import org.thingml.xtext.helpers.ActionHelper
import org.thingml.xtext.thingML.ExpressionGroup
import org.thingml.xtext.thingML.FunctionCallExpression
import org.thingml.xtext.thingML.ArrayIndex
import org.thingml.xtext.thingML.VariableAssignment
import org.thingml.xtext.thingML.UnaryMinus
import org.thingml.xtext.thingML.ThingMLPackage
import org.eclipse.xtext.Keyword
import org.eclipse.xtext.formatting2.FormatterRequest
import org.eclipse.xtext.util.ExceptionAcceptor
class ThingMLFormatter extends AbstractFormatter2 {
@@ -137,7 +135,7 @@ class ThingMLFormatter extends AbstractFormatter2 {
def dispatch void format(Thing thing, extension IFormattableDocument document) {
//TODO add a blank line in-between each bloack of features
thing.interior[indent]
for(org.thingml.xtext.thingML.Property p : thing.properties) {
for(Property p : thing.properties) {
p.format
}
for(Port p : thing.ports) {
@@ -346,7 +344,7 @@ class ThingMLFormatter extends AbstractFormatter2 {
def void formatState(State state, extension IFormattableDocument document) {
state.surround[newLine]
state.interior[indent]
for(org.thingml.xtext.thingML.Property p : state.properties) {
for(Property p : state.properties) {
p.format
}
state.regionFor.keyword("{").append[newLine]
@@ -0,0 +1,39 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*/
package org.thingml.testing.errors;
public class ThingMLCheckerError extends AssertionError {
private static final long serialVersionUID = 1L;
public ThingMLCheckerError(boolean shouldSucceed, boolean compilerChecker) {
super(checkerType(compilerChecker)+failType(shouldSucceed));
}
private static String checkerType(boolean compilerChecker) {
if (compilerChecker)
return "Compiler checker ";
else
return "Generic checker ";
}
private static String failType(boolean shouldSucceed) {
if (shouldSucceed)
return "should succeed but contains errors";
else
return "should fail but contains no errors";
}
}
@@ -45,7 +45,7 @@
private UUID uuid;
private transient Description description;
private transient ThingMLTestCase[] cases;
protected transient ThingMLTestCase[] cases;
private transient RunNotifier notifier;
@@ -96,15 +96,23 @@ private final void generateDescription() {
}
// Return the cases so they can be run, or ignore them
boolean should = shouldRun();
boolean shouldRun = shouldRun();
boolean shouldIgnore = shouldIgnoreCases();
Collection<Runnable> caseRunners = new ArrayList<Runnable>();
for (ThingMLTestCase cse : cases) {
if (prepared && should) {
if (!prepared) {
// Something failed in the preparation
this.notifier.fireTestIgnored(cse.getDescription());
} else if (!shouldRun) {
// The preparation was fine - but we should not run the cases
if (shouldIgnore)
this.notifier.fireTestIgnored(cse.getDescription());
} else {
// Preparation was fine - and we should run the cases
cse.setNotifier(this.notifier);
caseRunners.add(cse);
}
else
this.notifier.fireTestIgnored(cse.getDescription());
}
return caseRunners;
}
@@ -157,6 +165,10 @@ public boolean shouldRun() {
return true;
}
public boolean shouldIgnoreCases() {
return true;
}
public void prepareDirectory(String compiler, Configuration configuration, File directory) throws AssertionError {
// Allows modification of the directory where the target platform code will be run, e.g. to add files or other dependencies
// This is called after the platform code is generated, but before the platform code is compiled/executed
@@ -69,6 +69,7 @@ protected ThingMLTestCase(ThingMLTest parent, ThingMLCompiler compiler) {
}
public String getCompilerId() { return this.id; }
public ThingMLCompiler getCompiler() { return this.compiler; }
@Override
public Description getDescription() {
@@ -0,0 +1,115 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*/
package org.thingml.testing.tests;
import java.io.File;
import java.util.Collection;
import org.junit.internal.runners.model.EachTestNotifier;
import org.junit.runner.notification.RunNotifier;
import org.thingml.compilers.checker.Checker;
import org.thingml.testing.errors.ThingMLCheckerError;
import org.thingml.testing.framework.ThingMLTestCase;
import org.thingml.utilities.logging.Logger;
import org.thingml.xtext.constraints.ThingMLHelpers;
import org.thingml.xtext.helpers.AnnotatedElementHelper;
import org.thingml.xtext.thingML.Configuration;
import org.thingml.xtext.thingML.Thing;
public class CheckerTest extends ThingMLFileTest {
private static final long serialVersionUID = 1L;
public CheckerTest(File thingmlFile, String[] compilers) {
super(thingmlFile, compilers);
}
@Override
public boolean prepare(RunNotifier notifier) throws InterruptedException {
// Load model from file and run generic preparation
if (!super.prepare(notifier)) return false;
// Figure out if the checker should fail, and if it is the generic one or the compiler one that should fail
boolean shouldSucceed = findAnnotation("checker_should_fail", "false");
boolean compilerChecker = findAnnotation("checker", "compiler");
if (!compilerChecker) {
// We should try the generic checker
Checker checker = new Checker("ThingMLTesting", null);
checker.do_generic_check(this.model, Logger.NULL);
EachTestNotifier not = new EachTestNotifier(notifier, getDescription());
if (shouldSucceed == checker.containsErrors())
not.addFailure(new ThingMLCheckerError(shouldSucceed, compilerChecker));
for (ThingMLTestCase cse : this.cases)
notifier.fireTestIgnored(cse.getDescription());
} else {
// We should try the individual compiler checkers
for (ThingMLTestCase cse : this.cases) {
EachTestNotifier not = new EachTestNotifier(notifier, cse.getDescription());
not.fireTestStarted();
Checker checker = cse.getCompiler().checker;
Collection<Configuration> configurations = ThingMLHelpers.allConfigurations(this.model);
boolean foundError = false;
if (configurations.isEmpty()) {
// If no configurations is present - we do the generic checks
checker.do_generic_check(this.model, Logger.NULL);
foundError = checker.containsErrors();
} else {
// Or we try the checker for all configurations
for (Configuration configuration : configurations) {
checker.do_check(configuration, Logger.NULL);
foundError = foundError || checker.containsErrors();
}
}
if (shouldSucceed == foundError)
not.addFailure(new ThingMLCheckerError(shouldSucceed, compilerChecker));
not.fireTestFinished();
}
}
return true;
}
@Override
public boolean shouldRun() {
// These tests should never be compiled and executed - but maybe the super needs to do something
return super.shouldRun() && false;
}
@Override
public boolean shouldIgnoreCases() {
// The cases should not be ignored even though they are not run - we will set the result ourself
return super.shouldIgnoreCases() && false;
}
private boolean findAnnotation(String name, String value) {
for (Thing thing : ThingMLHelpers.allThings(this.model))
if (AnnotatedElementHelper.isDefined(thing, name, value))
return true;
for (Configuration configuration : ThingMLHelpers.allConfigurations(this.model))
if (AnnotatedElementHelper.isDefined(configuration, name, value))
return true;
return false;
}
}
@@ -26,24 +26,20 @@
import org.junit.internal.runners.model.EachTestNotifier;
import org.junit.runner.notification.RunNotifier;
import org.thingml.compilers.checker.Checker;
import org.thingml.testing.errors.ThingMLOutputError;
import org.thingml.testing.tests.ThingMLFileTest;
import org.thingml.testing.utilities.CommandRunner.Output;
import org.thingml.utilities.logging.Logger;
import org.thingml.xtext.thingML.Configuration;
public class GeneralTest extends ThingMLFileTest {
private static final long serialVersionUID = 1L;
protected ArrayList<GeneralTestInputOutput> inputoutputs;
protected boolean checkerShouldFail;
public GeneralTest(File thingmlFile, String[] compilers) {
super(thingmlFile, compilers);
inputoutputs = new ArrayList<GeneralTestInputOutput>();
checkerShouldFail = false;
}
@Override
@@ -55,15 +51,6 @@ public boolean prepare(RunNotifier notifier) throws InterruptedException {
// The helper is used temporarily to keep track of a lot of references within the model while it is being modified
GeneralTestHelper helper = new GeneralTestHelper(this.model);
// If the the test is supposed to verify the checker - it will have a @test_checker "false" annotation
checkerShouldFail = helper.checkerShouldFail();
if (checkerShouldFail) {
// If so - try to run it
Checker checker = new Checker("ThingMLTesting", null);
checker.do_generic_check(this.model, Logger.NULL);
if (!checker.containsErrors()) throw new AssertionError("Checker should fail but contains no errors");
}
// Populate list of @test inputs and outputs
inputoutputs.addAll(helper.getAllInputOutputs());
@@ -87,11 +74,6 @@ public boolean prepare(RunNotifier notifier) throws InterruptedException {
return true;
}
@Override
public boolean shouldRun() {
return super.shouldRun() && !checkerShouldFail;
}
@Override
public void prepareDirectory(String compiler, Configuration configuration, File directory) throws AssertionError {
super.prepareDirectory(compiler, configuration, directory);
@@ -389,15 +389,6 @@ public boolean isTestThing(Thing thing) {
return instancesof;
}
public boolean checkerShouldFail() {
for (Thing thing : allTestThings())
if (AnnotatedElementHelper.isDefined(thing, "test_checker", "false"))
return true;
if (AnnotatedElementHelper.isDefined(config, "test_checker", "false"))
return true;
return false;
}
/* --- Reference finding helpers --- */
public Thing findThing(String name) throws AssertionError {
for (Thing thing : ThingMLHelpers.allThings(model))
Oops, something went wrong.

0 comments on commit 17cea51

Please sign in to comment.