Add test_runner support for // [spec_parser] comments This CL adds support to the test runner for the test outcome expectation syntax that uses `// [...]` to indicate which diagnostic we should expect with the given tool. Currently, `...` is `analyzer` when testing the analyzer and `cfe` when testing the common front end. After landing this CL, it also supports `// [spec_parser]`. This change would allow us to migrate several tests from the multi-test format (like `code; //# 01: compile-time error`) to the new format, in particular tests with intentional syntax errors. Change-Id: I5dd2560a873eb7433d3e07aa8f393e83c51b28e7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501161 Reviewed-by: Bob Nystrom <rnystrom@google.com> Commit-Queue: Erik Ernst <eernst@google.com>
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart index 97f7ae5..7f16e86 100644 --- a/pkg/test_runner/lib/src/command_output.dart +++ b/pkg/test_runner/lib/src/command_output.dart
@@ -812,7 +812,7 @@ } } -class SpecParseCommandOutput extends CommandOutput { +class SpecParseCommandOutput extends CommandOutput with _StaticErrorOutput { SpecParseCommandOutput( Command command, int exitCode, @@ -840,10 +840,54 @@ if (hasTimedOut) return Expectation.timeout; if (hasNonUtf8) return Expectation.nonUtf8Error; if (truncatedOutput) return Expectation.truncatedOutput; - if (hasSyntaxError) return Expectation.syntaxError; - if (exitCode != 0) return Expectation.syntaxError; + if (testCase.testFile.isStaticErrorTest) { + return _validateExpectedErrors(testCase); + } + if (hasSyntaxError || exitCode != 0) return Expectation.syntaxError; return Expectation.pass; } + + /// Parses the ANTLR parser's diagnostic output. + /// + /// For example: `void main() {(}` in 'foo.dart' yields + /// Syntax error in foo.dart: + /// line 1:14 no viable alternative at input '(}' + /// Parsing failed + /// + /// The 'Syntax error' line is emitted once for each file with + /// a syntax error, and each error gets a 'line ...' message. + @override + void _parseErrors() { + var output = decodeUtf8(stderr); + var lines = output.split('\n'); + String? currentPath; + var processCommand = command as ProcessCommand; + var fallbackPath = processCommand.arguments.firstWhere( + (arg) => arg.endsWith('.dart'), + orElse: () => '', + ); + for (var line in lines) { + if (_pathRegExp.firstMatch(line) case var match?) { + currentPath = match[1]; + } else if (_errorRegExp.firstMatch(line) case var match?) { + var lineNum = int.parse(match[1]!); + var column = int.parse(match[2]!) + 1; // ANTLR is 0-based. + var message = match[3]!; + addError( + StaticError( + ErrorSource.specParser, + message, + path: currentPath ?? fallbackPath, + line: lineNum, + column: column, + ), + ); + } + } + } + + static final RegExp _pathRegExp = .new(r"^Syntax error in (.*):$"); + static final RegExp _errorRegExp = .new(r"^line (\d+):(\d+) (.*)$"); } class VMCommandOutput extends CommandOutput with _UnittestSuiteMessagesMixin { @@ -1537,6 +1581,7 @@ Compiler.dart2wasm: ErrorSource.web, Compiler.ddc: ErrorSource.web, Compiler.fasta: ErrorSource.cfe, + Compiler.specParser: ErrorSource.specParser, }[testCase.configuration.compiler]!; var expected = testCase.testFile.expectedErrors.where(
diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart index 9036295..a818aa9 100644 --- a/pkg/test_runner/lib/src/static_error.dart +++ b/pkg/test_runner/lib/src/static_error.dart
@@ -12,6 +12,7 @@ class ErrorSource { static const analyzer = ErrorSource._("analyzer"); static const cfe = ErrorSource._("CFE", marker: "cfe"); + static const specParser = ErrorSource._("spec_parser"); static const web = ErrorSource._("web"); /// Pseudo-front end for context messages. @@ -21,7 +22,7 @@ /// /// The order is significant here. In static error tests, error expectations /// must be in this order for consistency. - static const all = [analyzer, cfe, web]; + static const all = [analyzer, cfe, specParser, web]; /// Gets the source whose lowercase name is [name] or `null` if no source /// with that name could be found. @@ -453,6 +454,9 @@ // TODO(rnystrom): If the web compilers report warnings, encode that in // the message somehow and then look for it here. return false; + case ErrorSource.specParser: + // The spec parser does not report warnings. + return false; default: break; }