Allow empty test source when parsing metadata (#2583)
Some use cases with precompiled tests pass an empty test source file and
skip any of the behavior of configuration metadata annotations. This
isn't the golden path design for the runner, but we can avoid breaking
it easily. In this scenario the specific problem of a missing `main`
will have already been handled by other infrastructure, so whether the
error is clear is out of our control. This change does restore the less
direct error about missing main in the case where a typical test runner
user tries to run a completely empty test suite, but this is unlikely in
practice.
diff --git a/pkgs/test/test/runner/parse_metadata_test.dart b/pkgs/test/test/runner/parse_metadata_test.dart
index 403f394..97c6cc6 100644
--- a/pkgs/test/test/runner/parse_metadata_test.dart
+++ b/pkgs/test/test/runner/parse_metadata_test.dart
@@ -54,6 +54,10 @@
);
});
+ test('allows completely empty files', () {
+ expect(() => parseMetadata(_path, '', {}), returnsNormally);
+ });
+
group('@TestOn:', () {
test('parses a valid annotation', () {
var metadata = parseMetadata(
diff --git a/pkgs/test_core/lib/src/runner/parse_metadata.dart b/pkgs/test_core/lib/src/runner/parse_metadata.dart
index f5e54c1..e58571b 100644
--- a/pkgs/test_core/lib/src/runner/parse_metadata.dart
+++ b/pkgs/test_core/lib/src/runner/parse_metadata.dart
@@ -52,7 +52,12 @@
///
/// When main is missing a call to [parse] will throw a [FormatException] with
/// a descriptive message.
- late final bool _hasMain;
+ ///
+ /// An empty file may indicate an atypical use of the test runner in
+ /// precompiled mode without the test source available. In these cases the
+ /// definition is not required and it is assumed it is checked by whatever
+ /// compilation approach is used.
+ late final bool _hasMainOrEmpty;
_Parser(this._path, this._contents, this._platformVariables) {
var result = parseString(
@@ -63,9 +68,11 @@
var directives = result.unit.directives;
_annotations = directives.isEmpty ? [] : directives.first.metadata;
_languageVersionComment = result.unit.languageVersionToken?.value();
- _hasMain = result.unit.declarations.any(
- (d) => d is FunctionDeclaration && d.name.lexeme == 'main',
- );
+ _hasMainOrEmpty =
+ _contents.isEmpty ||
+ result.unit.declarations.any(
+ (d) => d is FunctionDeclaration && d.name.lexeme == 'main',
+ );
// We explicitly *don't* just look for "package:test" imports here,
// because it could be re-exported from another library.
@@ -84,7 +91,7 @@
/// Parses the metadata.
Metadata parse() {
- if (!_hasMain) {
+ if (!_hasMainOrEmpty) {
throw const FormatException('Missing definition of `main` method.');
}
Timeout? timeout;