Index: tools/testing/dart/lib/test_case.dart |
diff --git a/tools/testing/dart/lib/test_case.dart b/tools/testing/dart/lib/test_case.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..abdb0a1ba41fe8f7c97bd0c69858aa53b6dec855 |
--- /dev/null |
+++ b/tools/testing/dart/lib/test_case.dart |
@@ -0,0 +1,177 @@ |
+library test_case; |
+ |
+import 'command.dart'; |
+import 'status_file_parser.dart'; |
+import 'test_information.dart'; |
+import 'test_utils.dart'; |
+import 'utils.dart'; |
+ |
+const int SLOW_TIMEOUT_MULTIPLIER = 4; |
+ |
+typedef void TestCaseEvent(TestCase testCase); |
+ |
+/** |
+ * TestCase contains all the information needed to run a test and evaluate |
+ * its output. Running a test involves starting a separate process, with |
+ * the executable and arguments given by the TestCase, and recording its |
+ * stdout and stderr output streams, and its exit code. TestCase only |
+ * contains static information about the test; actually running the test is |
+ * performed by [ProcessQueue] using a [RunningProcess] object. |
+ * |
+ * The output information is stored in a [CommandOutput] instance contained |
+ * in TestCase.commandOutputs. The last CommandOutput instance is responsible |
+ * for evaluating if the test has passed, failed, crashed, or timed out, and the |
+ * TestCase has information about what the expected result of the test should |
+ * be. |
+ * |
+ * The TestCase has a callback function, [completedHandler], that is run when |
+ * the test is completed. |
+ */ |
+class TestCase extends UniqueObject { |
+ // Flags set in _expectations from the optional argument info. |
+ static final int IS_NEGATIVE = 1 << 0; |
+ static final int HAS_RUNTIME_ERROR = 1 << 1; |
+ static final int HAS_STATIC_WARNING = 1 << 2; |
+ static final int IS_NEGATIVE_IF_CHECKED = 1 << 3; |
+ static final int HAS_COMPILE_ERROR = 1 << 4; |
+ static final int HAS_COMPILE_ERROR_IF_CHECKED = 1 << 5; |
+ static final int EXPECT_COMPILE_ERROR = 1 << 6; |
+ /** |
+ * A list of commands to execute. Most test cases have a single command. |
+ * Dart2js tests have two commands, one to compile the source and another |
+ * to execute it. Some isolate tests might even have three, if they require |
+ * compiling multiple sources that are run in isolation. |
+ */ |
+ List<Command> commands; |
+ Map<Command, CommandOutput> commandOutputs = new Map<Command,CommandOutput>(); |
+ |
+ Map configuration; |
+ String displayName; |
+ int _expectations = 0; |
+ int hash = 0; |
+ Set<Expectation> expectedOutcomes; |
+ |
+ TestCase(this.displayName, |
+ this.commands, |
+ this.configuration, |
+ this.expectedOutcomes, |
+ {isNegative: false, |
+ TestInformation info: null}) { |
+ if (isNegative || displayName.contains("negative_test")) { |
+ _expectations |= IS_NEGATIVE; |
+ } |
+ if (info != null) { |
+ _setExpectations(info); |
+ hash = info.originTestPath.relativeTo(TestUtils.dartDir) |
+ .toString().hashCode; |
+ } |
+ } |
+ |
+ void _setExpectations(TestInformation info) { |
+ // We don't want to keep the entire (large) TestInformation structure, |
+ // so we copy the needed bools into flags set in a single integer. |
+ if (info.hasRuntimeError) _expectations |= HAS_RUNTIME_ERROR; |
+ if (info.hasStaticWarning) _expectations |= HAS_STATIC_WARNING; |
+ if (info.isNegativeIfChecked) _expectations |= IS_NEGATIVE_IF_CHECKED; |
+ if (info.hasCompileError) _expectations |= HAS_COMPILE_ERROR; |
+ if (info.hasCompileErrorIfChecked) { |
+ _expectations |= HAS_COMPILE_ERROR_IF_CHECKED; |
+ } |
+ if (info.hasCompileError || |
+ (configuration['checked'] && info.hasCompileErrorIfChecked)) { |
+ _expectations |= EXPECT_COMPILE_ERROR; |
+ } |
+ } |
+ |
+ bool get isNegative => _expectations & IS_NEGATIVE != 0; |
+ bool get hasRuntimeError => _expectations & HAS_RUNTIME_ERROR != 0; |
+ bool get hasStaticWarning => _expectations & HAS_STATIC_WARNING != 0; |
+ bool get isNegativeIfChecked => _expectations & IS_NEGATIVE_IF_CHECKED != 0; |
+ bool get hasCompileError => _expectations & HAS_COMPILE_ERROR != 0; |
+ bool get hasCompileErrorIfChecked => |
+ _expectations & HAS_COMPILE_ERROR_IF_CHECKED != 0; |
+ bool get expectCompileError => _expectations & EXPECT_COMPILE_ERROR != 0; |
+ |
+ bool get unexpectedOutput { |
+ var outcome = lastCommandOutput.result(this); |
+ return !expectedOutcomes.any((expectation) { |
+ return outcome.canBeOutcomeOf(expectation); |
+ }); |
+ } |
+ |
+ Expectation get result => lastCommandOutput.result(this); |
+ |
+ CommandOutput get lastCommandOutput { |
+ if (commandOutputs.length == 0) { |
+ throw new Exception("CommandOutputs is empty, maybe no command was run? (" |
+ "displayName: '$displayName', " |
+ "configurationString: '$configurationString')"); |
+ } |
+ return commandOutputs[commands[commandOutputs.length - 1]]; |
+ } |
+ |
+ Command get lastCommandExecuted { |
+ if (commandOutputs.length == 0) { |
+ throw new Exception("CommandOutputs is empty, maybe no command was run? (" |
+ "displayName: '$displayName', " |
+ "configurationString: '$configurationString')"); |
+ } |
+ return commands[commandOutputs.length - 1]; |
+ } |
+ |
+ int get timeout { |
+ if (expectedOutcomes.contains(Expectation.SLOW)) { |
+ return configuration['timeout'] * SLOW_TIMEOUT_MULTIPLIER; |
+ } else { |
+ return configuration['timeout']; |
+ } |
+ } |
+ |
+ String get configurationString { |
+ final compiler = configuration['compiler']; |
+ final runtime = configuration['runtime']; |
+ final mode = configuration['mode']; |
+ final arch = configuration['arch']; |
+ final checked = configuration['checked'] ? '-checked' : ''; |
+ return "$compiler-$runtime$checked ${mode}_$arch"; |
+ } |
+ |
+ List<String> get batchTestArguments { |
+ assert(commands.last is ProcessCommand); |
+ return (commands.last as ProcessCommand).arguments; |
+ } |
+ |
+ bool get isFlaky { |
+ if (expectedOutcomes.contains(Expectation.SKIP) || |
+ expectedOutcomes.contains(Expectation.SKIP_BY_DESIGN)) { |
+ return false; |
+ } |
+ |
+ return expectedOutcomes |
+ .where((expectation) => !expectation.isMetaExpectation).length > 1; |
+ } |
+ |
+ bool get isFinished { |
+ return commandOutputs.length > 0 && |
+ (!lastCommandOutput.successful || |
+ commands.length == commandOutputs.length); |
+ } |
+} |
+ |
+ |
+/** |
+ * BrowserTestCase has an extra compilation command that is run in a separate |
+ * process, before the regular test is run as in the base class [TestCase]. |
+ * If the compilation command fails, then the rest of the test is not run. |
+ */ |
+class BrowserTestCase extends TestCase { |
+ |
+ BrowserTestCase(displayName, commands, configuration, |
+ expectedOutcomes, info, isNegative, this._testingUrl) |
+ : super(displayName, commands, configuration, |
+ expectedOutcomes, isNegative: isNegative, info: info); |
+ |
+ String _testingUrl; |
+ |
+ String get testingUrl => _testingUrl; |
+} |