9297d718a1
This reverts commit b5294b9753.
Reason for revert: many failures on appjit, reload and fuchsia bots
Failure Link: <LINK TO FAILURE>
Original change's description:
> [test_runner] Invoke tests with relative paths.
>
> This makes tests more reproducible, and makes it easier to copy commands between workspaces, or between a failing bot and a local workspace.
>
> Change-Id: Ic8dd10a3540f314a406e5c5b0a23d97032e5d01d
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/508364
> Reviewed-by: Alexander Aprelev <aam@google.com>
> Commit-Queue: Ryan Macnak <rmacnak@google.com>
Change-Id: Id7aa668c0609df65a5f622ae73013a15e7f9200e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/511400
Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
663 lines
20 KiB
Dart
663 lines
20 KiB
Dart
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
import 'dart:io';
|
|
|
|
import 'package:shell_arg_splitter/shell_arg_splitter.dart';
|
|
|
|
import 'feature.dart';
|
|
import 'path.dart';
|
|
import 'static_error.dart';
|
|
import 'utils.dart';
|
|
|
|
final _multitestRegExp = RegExp(r"//# \w+:");
|
|
|
|
final _vmOptionsRegExp = RegExp(r"^[ \t]*// VMOptions=(.*)", multiLine: true);
|
|
final _environmentRegExp = RegExp(
|
|
r"^[ \t]*// Environment=(.*)",
|
|
multiLine: true,
|
|
);
|
|
final _packagesRegExp = RegExp(r"^[ \t]*// Packages=(.*)", multiLine: true);
|
|
final _experimentRegExp = RegExp(r"^--enable-experiment=([a-z0-9,-]+)$");
|
|
final _localFileRegExp = RegExp(
|
|
r"""^[ \t]*(?:import|part)\s*"""
|
|
r"""['"](?!package:|dart:)(.*?)['"]\s*"""
|
|
r"""(?:(?:deferred\s+)?as\s+\w+\s*)?"""
|
|
r"""(?:(?:show|hide)\s+\w+\s*(?:,\s*\w+\s*))*;""",
|
|
multiLine: true,
|
|
);
|
|
|
|
List<T> _parseOption<T>(
|
|
String filePath,
|
|
String contents,
|
|
String name,
|
|
T Function(String) convert, {
|
|
bool allowMultiple = false,
|
|
}) {
|
|
var matches = RegExp(
|
|
'^[ \t]*// $name=(.*)',
|
|
multiLine: true,
|
|
).allMatches(contents).toList();
|
|
if (!allowMultiple && matches.length > 1) {
|
|
throw FormatException('More than one "// $name=" line in test $filePath');
|
|
}
|
|
|
|
var options = <T>[];
|
|
for (var match in matches) {
|
|
for (var option in splitLine(match[1]!)) {
|
|
options.add(convert(option));
|
|
}
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
List<String> _parseStringOption(
|
|
String filePath,
|
|
String contents,
|
|
String name, {
|
|
bool allowMultiple = false,
|
|
}) => _parseOption<String>(
|
|
filePath,
|
|
contents,
|
|
name,
|
|
(string) => string,
|
|
allowMultiple: allowMultiple,
|
|
);
|
|
|
|
abstract class _TestFileBase {
|
|
/// The test suite directory containing this test.
|
|
final Path? _suiteDirectory;
|
|
|
|
/// The full path to the test file.
|
|
final Path path;
|
|
|
|
/// The path to the original multitest file this test was generated from.
|
|
///
|
|
/// If this test was not generated from a multitest, just returns [path].
|
|
Path get originPath;
|
|
|
|
/// The parsed error expectation markers in this test, if it is a static
|
|
/// error test.
|
|
///
|
|
/// If empty, the test is not a static error test.
|
|
final List<StaticError> expectedErrors;
|
|
|
|
/// The name of the multitest section this file corresponds to if it was
|
|
/// generated from a multitest. Otherwise, returns an empty string.
|
|
String get multitestKey;
|
|
|
|
/// If the test contains static error expectations, it's a "static error
|
|
/// test".
|
|
///
|
|
/// These tests exist to validate that a front end reports the right static
|
|
/// errors. Unless the expected errors are all warnings, a static error test
|
|
/// is skipped on configurations that are not purely front end.
|
|
bool get isStaticErrorTest => expectedErrors.isNotEmpty;
|
|
|
|
/// If the test contains any web-specific (`[web]`) static error expectations,
|
|
/// then it's a "web static error test".
|
|
///
|
|
/// These tests exist to validate that a Dart web compiler reports the right
|
|
/// expected errors.
|
|
bool get isWebStaticErrorTest =>
|
|
expectedErrors.any((error) => error.source == ErrorSource.web);
|
|
|
|
/// If the tests has no static error expectations, or all of the expectations
|
|
/// are warnings, then the test tests runtime semantics.
|
|
///
|
|
/// Note that this is *not* the negation of [isStaticErrorTest]. A test that
|
|
/// contains only warning expectations is both a static "error" test and a
|
|
/// runtime test. The test runner will validate that the front ends produce
|
|
/// the expected warnings *and* that a runtime also correctly executes the
|
|
/// test.
|
|
bool get isRuntimeTest => expectedErrors.every((error) => error.isWarning);
|
|
|
|
/// A hash code used to spread tests across shards.
|
|
int get shardHash {
|
|
// The VM C++ unit tests have a special fake TestFile with no suite
|
|
// directory or path. Don't crash in that case.
|
|
if (_suiteDirectory == null) {
|
|
return path.toString().hashCode;
|
|
}
|
|
|
|
return originPath.relativeTo(_suiteDirectory).toString().hashCode;
|
|
}
|
|
|
|
_TestFileBase(this._suiteDirectory, this.path, this.expectedErrors);
|
|
|
|
/// The logical name of the test.
|
|
///
|
|
/// This is its path relative to the test suite directory containing it,
|
|
/// minus any file extension. If this test was split from a multitest,
|
|
/// it contains the multitest key.
|
|
String get name {
|
|
var testNamePath = originPath.relativeTo(_suiteDirectory!);
|
|
var directory = testNamePath.directoryPath;
|
|
var filenameWithoutExt = testNamePath.filenameWithoutExtension;
|
|
|
|
String join(String base, String part) {
|
|
if (base.isEmpty) return part;
|
|
if (part.isEmpty) return base;
|
|
return "$base/$part";
|
|
}
|
|
|
|
var result = "$directory";
|
|
result = join(result, filenameWithoutExt);
|
|
result = join(result, multitestKey);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// Represents a single ".dart" file used as a test and the parsed metadata it
|
|
/// contains.
|
|
///
|
|
/// Special options for individual tests are currently specified in various
|
|
/// ways: with comments directly in test files, by using certain imports, or
|
|
/// by creating additional files in the test directories.
|
|
///
|
|
/// Here is a list of options that are used by 'test.dart' today:
|
|
///
|
|
/// * Flags can be passed to the VM process that runs the test by adding a
|
|
/// comment to the test file:
|
|
///
|
|
/// // VMOptions=--flag1 --flag2
|
|
///
|
|
/// * Flags can be passed to dart2js, VM or dartdevc by adding a comment to
|
|
/// the test file:
|
|
///
|
|
/// // SharedOptions=--flag1 --flag2
|
|
///
|
|
/// * Flags can be passed to dart2js by adding a comment to the test file:
|
|
///
|
|
/// // dart2jsOptions=--flag1 --flag2
|
|
///
|
|
/// * Flags can be passed to dart2wasm by adding a comment to the test file:
|
|
///
|
|
/// // dart2wasmOptions=--flag1 --flag2
|
|
///
|
|
/// * Flags can be passed to the dart script that contains the test also
|
|
/// using comments, as follows:
|
|
///
|
|
/// // DartOptions=--flag1 --flag2
|
|
///
|
|
/// * Extra environment variables can be passed to the process that runs
|
|
/// the test by adding comment(s) to the test file:
|
|
///
|
|
/// // Environment=ENV_VAR1=foo bar
|
|
/// // Environment=ENV_VAR2=bazz
|
|
///
|
|
/// * Most tests are not web tests, but can (and will be) wrapped within an
|
|
/// HTML file and another script file to test them also on browser
|
|
/// environments (e.g. language and corelib tests are run this way). We
|
|
/// deduce that if a file with the same name as the test, but ending in
|
|
/// ".html" instead of ".dart" exists, the test was intended to be a web
|
|
/// test and no wrapping is necessary.
|
|
///
|
|
/// * This test requires libfoobar.so, libfoobar.dylib or foobar.dll to be in
|
|
/// the system linker path of the VM.
|
|
///
|
|
/// // SharedObjects=foobar
|
|
///
|
|
/// * 'test.dart' assumes tests fail if the process returns a non-zero exit
|
|
/// code (in the case of web tests, we check for PASS/FAIL indications in
|
|
/// the test output).
|
|
class TestFile extends _TestFileBase {
|
|
/// Read the test file from the given [filePath].
|
|
factory TestFile.read(Path suiteDirectory, String filePath) {
|
|
if (filePath.endsWith('.dill')) {
|
|
return TestFile._(
|
|
suiteDirectory,
|
|
Path(filePath),
|
|
[],
|
|
requirements: [],
|
|
vmOptions: [[]],
|
|
sharedOptions: [],
|
|
dart2jsOptions: [],
|
|
dart2wasmOptions: [],
|
|
ddcOptions: [],
|
|
dartOptions: [],
|
|
packages: null,
|
|
isMultitest: false,
|
|
sharedObjects: [],
|
|
otherResources: [],
|
|
environment: {},
|
|
experiments: [],
|
|
);
|
|
}
|
|
|
|
final contents = File(filePath).readAsStringSync();
|
|
|
|
// Required features.
|
|
var requirements = _parseOption<Feature>(
|
|
filePath,
|
|
contents,
|
|
'Requirements',
|
|
(name) {
|
|
for (var feature in Feature.all) {
|
|
if (feature.name == name) return feature;
|
|
}
|
|
|
|
throw FormatException('Unknown feature "$name" in test $filePath');
|
|
},
|
|
);
|
|
|
|
final isVmIntermediateLanguageTest = filePath.endsWith('_il_test.dart');
|
|
|
|
// VM options.
|
|
var vmOptions = <List<String>>[];
|
|
var matches = _vmOptionsRegExp.allMatches(contents);
|
|
for (var match in matches) {
|
|
vmOptions.add(splitLine(match[1]!));
|
|
}
|
|
if (vmOptions.isEmpty) vmOptions.add(<String>[]);
|
|
|
|
// Other options.
|
|
var dartOptions = _parseStringOption(filePath, contents, 'DartOptions');
|
|
var sharedOptions = _parseStringOption(filePath, contents, 'SharedOptions');
|
|
var dart2jsOptions = _parseStringOption(
|
|
filePath,
|
|
contents,
|
|
'dart2jsOptions',
|
|
);
|
|
var dart2wasmOptions = _parseStringOption(
|
|
filePath,
|
|
contents,
|
|
'dart2wasmOptions',
|
|
);
|
|
var ddcOptions = _parseStringOption(filePath, contents, 'ddcOptions');
|
|
var otherResources = _parseStringOption(
|
|
filePath,
|
|
contents,
|
|
'OtherResources',
|
|
allowMultiple: true,
|
|
);
|
|
var sharedObjects = _parseStringOption(
|
|
filePath,
|
|
contents,
|
|
'SharedObjects',
|
|
allowMultiple: true,
|
|
);
|
|
|
|
// Extract the experiments from the shared options.
|
|
// TODO(rnystrom): Either tests should stop specifying experiment flags
|
|
// entirely and use "// Requirements=", or we should come up with a better
|
|
// syntax. Parsing from "// SharedOptions=" for now since that's where they
|
|
// are currently specified.
|
|
var experiments = <String>[];
|
|
for (var i = 0; i < sharedOptions.length; i++) {
|
|
var sharedOption = sharedOptions[i];
|
|
if (sharedOption.contains("--enable-experiment")) {
|
|
var match = _experimentRegExp.firstMatch(sharedOption);
|
|
if (match == null) {
|
|
throw Exception(
|
|
"SharedOptions marker cannot mix experiment flags with other "
|
|
"flags. Was:\n$sharedOption",
|
|
);
|
|
}
|
|
|
|
experiments.addAll(match[1]!.split(","));
|
|
sharedOptions.removeAt(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
// Environment.
|
|
var environment = <String, String>{};
|
|
matches = _environmentRegExp.allMatches(contents);
|
|
for (var match in matches) {
|
|
var envDef = match[1]!;
|
|
var name = envDef;
|
|
var value = '';
|
|
var pos = envDef.indexOf('=');
|
|
if (pos >= 0) {
|
|
name = envDef.substring(0, pos);
|
|
value = envDef.substring(pos + 1);
|
|
}
|
|
environment[name] = value;
|
|
}
|
|
|
|
// Packages.
|
|
String? packages;
|
|
|
|
matches = _packagesRegExp.allMatches(contents);
|
|
for (var match in matches) {
|
|
if (packages != null) {
|
|
throw FormatException(
|
|
'More than one "// Package..." line in test $filePath',
|
|
);
|
|
}
|
|
packages = match[1]!;
|
|
if (packages != 'none') {
|
|
// Packages=none means that no packages option should be given. Any
|
|
// other value overrides packages.
|
|
packages = Uri.file(
|
|
filePath,
|
|
).resolveUri(Uri.file(packages)).toFilePath();
|
|
}
|
|
}
|
|
|
|
var isMultitest = _multitestRegExp.hasMatch(contents);
|
|
if (isMultitest) {
|
|
DebugLogger.warning(
|
|
"${Path(filePath).toNativePath()} is a legacy multi-test file.",
|
|
);
|
|
}
|
|
|
|
var errorExpectations = <StaticError>[];
|
|
|
|
// The analyzer package also uses a similar syntax for expectations, but
|
|
// we don't want the test_runner to inadvertently think files containing
|
|
// those are static error tests.
|
|
if (!filePath.replaceAll('\\', '/').contains('/pkg/analyzer/')) {
|
|
try {
|
|
errorExpectations.addAll(_parseExpectations(filePath));
|
|
} on FormatException catch (error) {
|
|
throw FormatException(
|
|
"Invalid error expectation syntax in $filePath:\n$error",
|
|
);
|
|
}
|
|
}
|
|
|
|
return TestFile._(
|
|
suiteDirectory,
|
|
Path(filePath),
|
|
errorExpectations,
|
|
packages: packages,
|
|
environment: environment,
|
|
isMultitest: isMultitest,
|
|
requirements: requirements,
|
|
sharedOptions: sharedOptions,
|
|
dartOptions: dartOptions,
|
|
dart2jsOptions: dart2jsOptions,
|
|
dart2wasmOptions: dart2wasmOptions,
|
|
ddcOptions: ddcOptions,
|
|
vmOptions: vmOptions,
|
|
sharedObjects: sharedObjects,
|
|
otherResources: otherResources,
|
|
experiments: experiments,
|
|
isVmIntermediateLanguageTest: isVmIntermediateLanguageTest,
|
|
);
|
|
}
|
|
|
|
/// Parse expectations from the file with [path].
|
|
///
|
|
/// Recurses to follow local (not `dart:` or `package:`) imports.
|
|
static List<StaticError> _parseExpectations(String path) {
|
|
var parsed = <ParsedStaticErrorExpectations>[];
|
|
_parseExpectationFiles(path, parsed: parsed);
|
|
return StaticError.attachContextExpectations(parsed, rootPath: path);
|
|
}
|
|
|
|
/// Recursively parses expectation files starting from [path].
|
|
///
|
|
/// This follows local imports and explicit context paths in errors to find
|
|
/// all files that might contain expectations for the test.
|
|
///
|
|
/// [parsed] accumulates the results. [alreadyParsed] is used to prevent
|
|
/// infinite recursion in case of circular references.
|
|
static void _parseExpectationFiles(
|
|
String path, {
|
|
required List<ParsedStaticErrorExpectations> parsed,
|
|
Set<String>? alreadyParsed,
|
|
}) {
|
|
alreadyParsed ??= {};
|
|
var file = File(path);
|
|
var pathUri = Uri.parse(path);
|
|
// Missing files set no expectations.
|
|
if (!file.existsSync()) return;
|
|
|
|
// Catch import loops.
|
|
if (!alreadyParsed.add(StaticError.normalizePath(path))) return;
|
|
|
|
// Parse one file.
|
|
var contents = File(path).readAsStringSync();
|
|
var result = StaticError.parseExpectationsUnattached(
|
|
path: path,
|
|
source: contents,
|
|
);
|
|
parsed.add(result);
|
|
|
|
// Parse imports and recurse.
|
|
var matches = _localFileRegExp.allMatches(contents);
|
|
for (var match in matches) {
|
|
var localPath = Uri.tryParse(match[1]!);
|
|
// Broken import paths set no expectations.
|
|
if (localPath == null) continue;
|
|
var uriString = pathUri.resolve(localPath.path).toString();
|
|
_parseExpectationFiles(
|
|
uriString,
|
|
parsed: parsed,
|
|
alreadyParsed: alreadyParsed,
|
|
);
|
|
}
|
|
|
|
for (var error in result.errors) {
|
|
for (var contextPath in error.contextPaths) {
|
|
_parseExpectationFiles(
|
|
contextPath,
|
|
parsed: parsed,
|
|
alreadyParsed: alreadyParsed,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A special fake test file for representing a VM unit test written in C++.
|
|
TestFile.vmUnitTest(
|
|
String name, {
|
|
required this.hasCompileError,
|
|
required this.hasRuntimeError,
|
|
required this.hasCrash,
|
|
}) : packages = null,
|
|
environment = {},
|
|
isMultitest = false,
|
|
hasSyntaxError = false,
|
|
hasStaticWarning = false,
|
|
requirements = [],
|
|
sharedOptions = [],
|
|
dartOptions = [],
|
|
dart2jsOptions = [],
|
|
dart2wasmOptions = [],
|
|
ddcOptions = [],
|
|
vmOptions = [],
|
|
sharedObjects = [],
|
|
otherResources = [],
|
|
experiments = [],
|
|
isVmIntermediateLanguageTest = false,
|
|
super(null, Path("/fake/vm/cc/$name"), []);
|
|
|
|
TestFile._(
|
|
Path super.suiteDirectory,
|
|
super.path,
|
|
super.expectedErrors, {
|
|
this.packages,
|
|
required this.environment,
|
|
required this.isMultitest,
|
|
required this.requirements,
|
|
required this.sharedOptions,
|
|
required this.dartOptions,
|
|
required this.dart2jsOptions,
|
|
required this.dart2wasmOptions,
|
|
required this.ddcOptions,
|
|
required this.vmOptions,
|
|
required this.sharedObjects,
|
|
required this.otherResources,
|
|
required this.experiments,
|
|
this.isVmIntermediateLanguageTest = false,
|
|
}) : hasSyntaxError = false,
|
|
hasCompileError = false,
|
|
hasRuntimeError = false,
|
|
hasStaticWarning = false,
|
|
hasCrash = false {
|
|
assert(!isMultitest || dartOptions.isEmpty);
|
|
}
|
|
|
|
@override
|
|
Path get originPath => path;
|
|
|
|
@override
|
|
String get multitestKey => "";
|
|
|
|
final String? packages;
|
|
|
|
final Map<String, String> environment;
|
|
|
|
final bool isMultitest;
|
|
final bool hasSyntaxError;
|
|
final bool hasCompileError;
|
|
final bool hasRuntimeError;
|
|
final bool hasStaticWarning;
|
|
final bool hasCrash;
|
|
final bool isVmIntermediateLanguageTest;
|
|
|
|
/// The features that a test configuration must support in order to run this
|
|
/// test.
|
|
///
|
|
/// If the current configuration does not support one or more of these
|
|
/// requirements, the test is implicitly skipped.
|
|
final List<Feature> requirements;
|
|
|
|
final List<String> sharedOptions;
|
|
final List<String> dartOptions;
|
|
final List<String> dart2jsOptions;
|
|
final List<String> dart2wasmOptions;
|
|
final List<String> ddcOptions;
|
|
final List<List<String>> vmOptions;
|
|
final List<String> sharedObjects;
|
|
final List<String> otherResources;
|
|
|
|
/// The experiments this test enables.
|
|
///
|
|
/// Parsed from a shared options line like:
|
|
///
|
|
/// // SharedOptions=--enable-experiment=flubber,gloop
|
|
final List<String> experiments;
|
|
|
|
/// Derive a multitest test section file from this multitest file with the
|
|
/// given [multitestKey] and expectations.
|
|
TestFile split(
|
|
Path path,
|
|
String multitestKey,
|
|
String contents, {
|
|
bool hasCompileError = false,
|
|
bool hasRuntimeError = false,
|
|
bool hasStaticWarning = false,
|
|
bool hasSyntaxError = false,
|
|
}) => _MultitestFile(
|
|
this,
|
|
path,
|
|
multitestKey,
|
|
StaticError.parseExpectations(path: path.toString(), source: contents),
|
|
hasCompileError: hasCompileError,
|
|
hasRuntimeError: hasRuntimeError,
|
|
hasStaticWarning: hasStaticWarning,
|
|
hasSyntaxError: hasSyntaxError,
|
|
);
|
|
|
|
@override
|
|
String toString() =>
|
|
"""TestFile(
|
|
packages: $packages
|
|
environment: $environment
|
|
isMultitest: $isMultitest
|
|
hasSyntaxError: $hasSyntaxError
|
|
hasCompileError: $hasCompileError
|
|
hasRuntimeError: $hasRuntimeError
|
|
hasStaticWarning: $hasStaticWarning
|
|
hasCrash: $hasCrash
|
|
requirements: $requirements
|
|
sharedOptions: $sharedOptions
|
|
dartOptions: $dartOptions
|
|
dart2jsOptions: $dart2jsOptions
|
|
dart2wasmOptions: $dart2wasmOptions
|
|
ddcOptions: $ddcOptions
|
|
vmOptions: $vmOptions
|
|
sharedObjects: $sharedObjects
|
|
otherResources: $otherResources
|
|
experiments: $experiments
|
|
)""";
|
|
}
|
|
|
|
/// A [TestFile] for a single section file derived from a multitest.
|
|
///
|
|
/// This inherits most properties from the original test file, but overrides
|
|
/// the error flags based on the multitest section's expectation.
|
|
class _MultitestFile extends _TestFileBase implements TestFile {
|
|
/// The authored test file that was split to generate this multitest.
|
|
final TestFile _origin;
|
|
|
|
@override
|
|
final String multitestKey;
|
|
|
|
@override
|
|
final bool hasCompileError;
|
|
@override
|
|
final bool hasRuntimeError;
|
|
@override
|
|
final bool hasStaticWarning;
|
|
@override
|
|
final bool hasSyntaxError;
|
|
@override
|
|
bool get hasCrash => _origin.hasCrash;
|
|
@override
|
|
bool get isVmIntermediateLanguageTest => _origin.isVmIntermediateLanguageTest;
|
|
|
|
_MultitestFile(
|
|
this._origin,
|
|
Path path,
|
|
this.multitestKey,
|
|
List<StaticError> expectedErrors, {
|
|
required this.hasCompileError,
|
|
required this.hasRuntimeError,
|
|
required this.hasStaticWarning,
|
|
required this.hasSyntaxError,
|
|
}) : super(_origin._suiteDirectory, path, expectedErrors);
|
|
|
|
@override
|
|
Path get originPath => _origin.path;
|
|
|
|
@override
|
|
String? get packages => _origin.packages;
|
|
|
|
@override
|
|
List<Feature> get requirements => _origin.requirements;
|
|
@override
|
|
List<String> get dart2jsOptions => _origin.dart2jsOptions;
|
|
@override
|
|
List<String> get dart2wasmOptions => _origin.dart2wasmOptions;
|
|
@override
|
|
List<String> get dartOptions => _origin.dartOptions;
|
|
@override
|
|
List<String> get ddcOptions => _origin.ddcOptions;
|
|
@override
|
|
Map<String, String> get environment => _origin.environment;
|
|
|
|
@override
|
|
bool get isMultitest => _origin.isMultitest;
|
|
|
|
@override
|
|
List<String> get otherResources => _origin.otherResources;
|
|
@override
|
|
List<String> get sharedObjects => _origin.sharedObjects;
|
|
@override
|
|
List<String> get experiments => _origin.experiments;
|
|
@override
|
|
List<String> get sharedOptions => _origin.sharedOptions;
|
|
@override
|
|
List<List<String>> get vmOptions => _origin.vmOptions;
|
|
|
|
@override
|
|
TestFile split(
|
|
Path path,
|
|
String multitestKey,
|
|
String contents, {
|
|
bool hasCompileError = false,
|
|
bool hasRuntimeError = false,
|
|
bool hasStaticWarning = false,
|
|
bool hasSyntaxError = false,
|
|
}) => throw UnsupportedError(
|
|
"Can't derive a test from one already derived from a multitest.",
|
|
);
|
|
}
|