Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Unified Diff: tools/testing/dart/test_runner.dart

Issue 9559007: Update test.dart for detection output of machine formatted errors (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Added diagnostic for @static-clean conflicts Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/testing/dart/test_runner.dart
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 650cdcf6507e41a0bcd0b08a8e3eacba8974f488..2edd34c5968084275425b648f305ac527f75055e 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -32,6 +32,8 @@ class Command {
Command(this.executable, this.arguments) {
commandLine = "$executable ${Strings.join(arguments, ' ')}";
}
+
+ String toString() => commandLine;
}
/**
@@ -65,13 +67,15 @@ class TestCase {
bool isNegative;
Set<String> expectedOutcomes;
Function completedHandler;
+ TestInformation info;
TestCase(this.displayName,
this.commands,
this.configuration,
this.completedHandler,
this.expectedOutcomes,
- [this.isNegative = false]) {
+ [this.isNegative = false,
+ this.info = null]) {
if (!isNegative) {
this.isNegative = displayName.contains("NegativeTest");
}
@@ -165,7 +169,24 @@ class BrowserTestCase extends TestCase {
* the time the process took to run. It also contains a pointer to the
* [TestCase] this is the output of.
*/
-class TestOutput {
+interface TestOutput default TestOutputImpl {
+ TestOutput.fromCase(TestCase testCase, int exitCode, bool timedOut,
+ List<String> stdout, List<String> stderr, Duration time);
+
+ String get result();
+
+ bool get unexpectedOutput();
+
+ bool get hasCrashed();
+
+ bool get hasTimedOut();
+
+ bool get didFail();
+
+ List<String> get diagnostics();
+}
+
+class TestOutputImpl implements TestOutput {
TestCase testCase;
int exitCode;
bool timedOut;
@@ -173,18 +194,35 @@ class TestOutput {
List<String> stdout;
List<String> stderr;
Duration time;
+ List<String> diagnostics;
+
/**
* Set to true if we encounter a condition in the output that indicates we
* need to rerun this test.
*/
- bool requestRetry;
+ bool requestRetry = false;
- TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout,
+ // Don't call this constructor, call TestOutput.fromCase() to
+ // get anew TestOutput instance.
+ TestOutputImpl(this.testCase, this.exitCode, this.timedOut, this.stdout,
this.stderr, this.time) {
testCase.output = this;
- requestRetry = false;
+ diagnostics = [];
}
+ factory TestOutputImpl.fromCase (testCase, exitCode, timedOut, stdout, stderr,
+ time) {
+ if (testCase is BrowserTestCase) {
+ return new BrowserTestOutputImpl(testCase, exitCode, timedOut,
+ stdout, stderr, time);
+ } else if (testCase.configuration['component'] == 'dartc') {
+ return new AnalysisTestOutputImpl(testCase, exitCode, timedOut,
+ stdout, stderr, time);
+ }
+ return new TestOutputImpl(testCase, exitCode, timedOut,
+ stdout, stderr, time);
+ }
+
String get result() =>
hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS));
@@ -207,8 +245,19 @@ class TestOutput {
bool get hasTimedOut() => timedOut;
bool get didFail() {
- if (testCase is !BrowserTestCase) return (exitCode != 0 && !hasCrashed);
+ return (exitCode != 0 && !hasCrashed);
+ }
+
+ // Reverse result of a negative test.
+ bool get hasFailed() => (testCase.isNegative ? !didFail : didFail);
+
+}
+class BrowserTestOutputImpl extends TestOutputImpl {
+ BrowserTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) :
+ super(testCase, exitCode, timedOut, stdout, stderr, time);
+
+ bool get didFail() {
// Browser case:
// If the browser test failed, it may have been because DumpRenderTree
// and the virtual framebuffer X server didn't hook up, or DRT crashed with
@@ -235,12 +284,157 @@ class TestOutput {
}
previous_line = line;
}
-
return true;
}
+}
- // Reverse result of a negative test.
- bool get hasFailed() => (testCase.isNegative ? !didFail : didFail);
+// The static analyzer does not actaully execute code, so
+// the criteria for success now depend on the text sent
+// to stderr.
+class AnalysisTestOutputImpl extends TestOutputImpl {
+ boolean alreadyComputed = false;
+ boolean failResult;
+ AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) :
+ super(testCase, exitCode, timedOut, stdout, stderr, time) {
+ }
+
+ bool get didFail() {
+ if (!alreadyComputed) {
+ failResult = _didFail();
+ alreadyComputed = true;
+ }
+ return failResult;
+ }
+
+ bool _didFail() {
+ if (hasCrashed) return false;
+
+ List<String> errors = [];
+ List<String> staticWarnings = [];
+
+ // Read the returned list of errors and stuff them away.
+ for (String line in stderr) {
+ if (line.length == 0) continue;
+ List<String> fields = splitMachineError(line);
+ if (fields[0] == 'ERROR') {
+ errors.add(fields);
+ } else if (fields[0] == 'WARNING') {
+ // We only care about testing Static type warnings
+ // ignore all others
+ if (fields[1] == 'STATIC_TYPE') {
+ staticWarnings.add(fields);
+ }
+ }
+ // OK to Skip error output that doesn't match the machine format
+ }
+ if (testCase.info != null
+ && testCase.info.optionsFromFile['isMultitest']) {
+ return _didMultitestFail(errors, staticWarnings);
+ }
+ return _didStandardTestFail(errors, staticWarnings);
+ }
+
+ bool _didMultitestFail(List errors, List staticWarnings) {
+ String outcome = testCase.info.multitestOutcome;
+ if ((outcome == '' || outcome == 'compile-time error') && errors.length > 0) {
+ return true;
+ } else if (outcome == 'static type error' && staticWarnings.length > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ bool _didStandardTestFail(List errors, List staticWarnings) {
+ bool hasFatalTypeErrors = false;
+ int numStaticTypeAnnotations = 0;
+ int numCompileTimeAnnotations = 0;
+ var isStaticClean = false;
+ if (testCase.info != null) {
+ var optionsFromFile = testCase.info.optionsFromFile;
+ hasFatalTypeErrors = optionsFromFile['hasFatalTypeErrors'];
+ for (Command c in testCase.commands) {
+ for (String arg in c.arguments) {
+ if (arg == '--fatal-type-errors') {
+ hasFatalTypeErrors = true;
+ break;
+ }
+ }
+ }
+ numStaticTypeAnnotations = optionsFromFile['numStaticTypeAnnotations'];
+ numCompileTimeAnnotations = optionsFromFile['numCompileTimeAnnotations'];
+ isStaticClean = optionsFromFile['isStaticClean'];
+ }
+
+ if (errors.length == 0) {
+ if (!hasFatalTypeErrors && exitCode != 0) {
+ diagnostics.add("EXIT CODE MISMATCH: Expected error message:");
+ diagnostics.add(" command[0]:${testCase.commands[0]}");
+ diagnostics.add(" exitCode:${exitCode}");
+ return true;
+ }
+ } else if (exitCode == 0) {
+ diagnostics.add("EXIT CODE MISMATCH: Unexpected error message:");
+ diagnostics.add(" errors[0]:${errors[0]}");
+ diagnostics.add(" command[0]:${testCase.commands[0]}");
+ diagnostics.add(" exitCode:${exitCode}");
+ return true;
+ }
+ if (numStaticTypeAnnotations > 0 && isStaticClean) {
+ diagnostics.add("Cannot have both @static-clean and /// static type warning annotations.");
+ return true;
+ }
+
+ if (isStaticClean && staticWarnings.length > 0) {
+ diagnostics.add("@static-clean annotation found but analyzer returned warnings.");
+ return true;
+ }
+
+ if (numCompileTimeAnnotations > 0
+ && numCompileTimeAnnotations < errors.length) {
+
+ // Expected compile-time errors were not returned. The test did not 'fail' in the way
+ // intended so don't return failed.
+ diagnostics.add("Fewer compile time errors than annotated: ${numCompileTimeAnnotations}");
+ return false;
+ }
+
+ if (numStaticTypeAnnotations > 0 || hasFatalTypeErrors) {
+ // TODO(zundel): match up the annotation line numbers
+ // with the reported error line numbers
+ if (staticWarnings.length < numStaticTypeAnnotations) {
+ diagnostics.add("Fewer static type warnings than annotated: ${numStaticTypeAnnotations}");
+ return true;
+ }
+ return false;
+ } else if (errors.length != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ // Parse a line delimited by the | character using \ as an escape charager
+ // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ
+ List<String> splitMachineError(String line) {
+ StringBuffer field = new StringBuffer();
+ List<String> result = [];
+ bool escaped = false;
+ for (var i = 0 ; i < line.length; i++) {
+ var c = line[i];
+ if (!escaped && c == '\\') {
+ escaped = true;
+ continue;
+ }
+ escaped = false;
+ if (c == '|') {
+ result.add(field.toString());
+ field.clear();
+ continue;
+ }
+ field.add(c);
+ }
+ result.add(field.toString());
+ return result;
+ }
}
/**
@@ -277,8 +471,8 @@ class RunningProcess {
* command.
*/
void testComplete(int exitCode) {
- new TestOutput(testCase, exitCode, timedOut, stdout,
- stderr, new Date.now().difference(startTime));
+ new TestOutput.fromCase(testCase, exitCode, timedOut, stdout,
+ stderr, new Date.now().difference(startTime));
timeoutTimer.cancel();
if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
print(testCase.displayName);
@@ -295,8 +489,7 @@ class RunningProcess {
testCase.output.requestRetry = false;
this.timedOut = false;
testCase.dynamic.numRetries--;
- print("Potential flake. " +
- "Re-running ${testCase.displayName} " +
+ print("Potential flake. Re-running ${testCase.displayName} " +
"(${testCase.dynamic.numRetries} attempt(s) remains)");
this.start();
} else {
@@ -454,8 +647,8 @@ class BatchRunnerProcess {
void doStartTest(TestCase testCase) {
_startTime = new Date.now();
- _testStdout = new List<String>();
- _testStderr = new List<String>();
+ _testStdout = [];
+ _testStderr = [];
_stdoutDrained = false;
_stderrDrained = false;
_stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout);
@@ -482,8 +675,8 @@ class BatchRunnerProcess {
var exitCode = 0;
if (outcome == "CRASH") exitCode = -10;
if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
- new TestOutput(_currentTest, exitCode, outcome == "TIMEOUT", _testStdout,
- _testStderr, new Date.now().difference(_startTime));
+ new TestOutput.fromCase(_currentTest, exitCode, outcome == "TIMEOUT",
+ _testStdout, _testStderr, new Date.now().difference(_startTime));
// Move on when both stdout and stderr has been drained.
if (_stderrDrained) _testCompleted();
}

Powered by Google App Engine
This is Rietveld 408576698