mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:31:50 +00:00
[modular_test]: migrate modular_test to null safety
Change-Id: I516d05469dd2c2bf57e4ec079fc1007ccf4b4783 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240653 Reviewed-by: Nicholas Shahan <nshahan@google.com> Commit-Queue: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
parent
73935c1d83
commit
02cf9ea69c
|
@ -60,7 +60,7 @@ Future<void> writePackageConfig(
|
|||
}
|
||||
|
||||
String _packageConfigEntry(String name, Uri root,
|
||||
{Uri packageRoot, LanguageVersion version}) {
|
||||
{Uri? packageRoot, LanguageVersion? version}) {
|
||||
var fields = [
|
||||
'"name": "${name}"',
|
||||
'"rootUri": "$root"',
|
||||
|
|
|
@ -15,9 +15,8 @@ Future<Uri> findRoot() async {
|
|||
var segments = current.pathSegments;
|
||||
var index = segments.lastIndexOf('sdk');
|
||||
if (index == -1) {
|
||||
print("error: cannot find the root of the Dart SDK");
|
||||
exitCode = 1;
|
||||
return null;
|
||||
throw "error: cannot find the root of the Dart SDK";
|
||||
}
|
||||
current = current.resolve("../" * (segments.length - index - 1));
|
||||
if (await File.fromUri(current.resolve("sdk/DEPS")).exists()) {
|
||||
|
|
|
@ -24,29 +24,29 @@ abstract class Test {
|
|||
|
||||
class RunnerOptions {
|
||||
/// Name of the test suite being run.
|
||||
String suiteName;
|
||||
final String suiteName;
|
||||
|
||||
/// Configuration name to use when writing result logs.
|
||||
String configurationName;
|
||||
final String? configurationName;
|
||||
|
||||
/// Filter used to only run tests that match the filter name.
|
||||
String filter;
|
||||
final String? filter;
|
||||
|
||||
/// Where log files are emitted.
|
||||
///
|
||||
/// Note that all shards currently emit the same filenames, so two shards
|
||||
/// shouldn't be given the same [logDir] otherwise they will overwrite each
|
||||
/// other's log files.
|
||||
Uri logDir;
|
||||
final Uri? logDir;
|
||||
|
||||
/// Of [shards], which shard is currently being executed.
|
||||
int shard;
|
||||
final int shard;
|
||||
|
||||
/// How many shards will be used to run a suite.
|
||||
int shards;
|
||||
final int shards;
|
||||
|
||||
/// Whether to print verbose information.
|
||||
bool verbose;
|
||||
final bool verbose;
|
||||
|
||||
/// Template used to help developers reproduce the issue.
|
||||
///
|
||||
|
@ -54,23 +54,34 @@ class RunnerOptions {
|
|||
/// * %executable is replaced with `Platform.executable`
|
||||
/// * %script is replaced with the current `Platform.script`
|
||||
/// * %name is replaced with the test name.
|
||||
String reproTemplate;
|
||||
final String reproTemplate;
|
||||
|
||||
RunnerOptions(
|
||||
{required this.suiteName,
|
||||
this.configurationName,
|
||||
this.filter,
|
||||
this.logDir,
|
||||
required this.shard,
|
||||
required this.shards,
|
||||
required this.verbose,
|
||||
required this.reproTemplate});
|
||||
}
|
||||
|
||||
class _TestOutcome {
|
||||
/// Unique test name.
|
||||
String name;
|
||||
final String name;
|
||||
|
||||
/// Whether, after running the test, the test matches its expectations. Null
|
||||
/// before the test is executed.
|
||||
bool matchedExpectations;
|
||||
/// Whether, after running the test, the test matches its expectations.
|
||||
late bool matchedExpectations;
|
||||
|
||||
/// Additional output emitted by the test, only used when expectations don't
|
||||
/// match and more details need to be provided.
|
||||
String output;
|
||||
String? output;
|
||||
|
||||
/// Time used to run the test.
|
||||
Duration elapsedTime;
|
||||
late Duration elapsedTime;
|
||||
|
||||
_TestOutcome(this.name);
|
||||
}
|
||||
|
||||
Future<void> runSuite<T>(List<Test> tests, RunnerOptions options) async {
|
||||
|
@ -91,13 +102,13 @@ Future<void> runSuite<T>(List<Test> tests, RunnerOptions options) async {
|
|||
var test = sortedTests[i];
|
||||
var name = test.name;
|
||||
if (options.verbose) stdout.write('$name: ');
|
||||
if (options.filter != null && !name.contains(options.filter)) {
|
||||
if (options.filter != null && !name.contains(options.filter!)) {
|
||||
if (options.verbose) stdout.write('skipped\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
var watch = new Stopwatch()..start();
|
||||
var outcome = new _TestOutcome()..name = test.name;
|
||||
var outcome = new _TestOutcome(test.name);
|
||||
try {
|
||||
await test.run();
|
||||
if (options.verbose) stdout.write('pass\n');
|
||||
|
@ -153,7 +164,7 @@ Future<void> runSuite<T>(List<Test> tests, RunnerOptions options) async {
|
|||
}
|
||||
|
||||
// Ensure the directory URI ends with a path separator.
|
||||
var logDir = Directory.fromUri(options.logDir).uri;
|
||||
var logDir = Directory.fromUri(options.logDir!).uri;
|
||||
var resultJsonUri = logDir.resolve('results.json');
|
||||
var logsJsonUri = logDir.resolve('logs.json');
|
||||
File.fromUri(resultJsonUri)
|
||||
|
|
|
@ -41,17 +41,17 @@ class IOPipeline extends Pipeline<IOModularStep> {
|
|||
/// libraries), and not modules that are test specific. File names will be
|
||||
/// specific enough so that we can keep separate the artifacts created from
|
||||
/// running tools under different configurations (with different flags).
|
||||
Uri _resultsFolderUri;
|
||||
Uri get resultFolderUriForTesting => _resultsFolderUri;
|
||||
Uri? _resultsFolderUri;
|
||||
Uri? get resultFolderUriForTesting => _resultsFolderUri;
|
||||
|
||||
/// A unique number to denote the current modular test configuration.
|
||||
///
|
||||
/// When using [cacheSharedModules], a test can resuse the output of a
|
||||
/// previous run of this pipeline if that output was generated with the same
|
||||
/// configuration.
|
||||
int _currentConfiguration;
|
||||
int? _currentConfiguration;
|
||||
|
||||
final ConfigurationRegistry _registry;
|
||||
final ConfigurationRegistry? _registry;
|
||||
|
||||
/// Whether to keep alive the temporary folder used to store intermediate
|
||||
/// results in order to inspect it later in test.
|
||||
|
@ -65,13 +65,13 @@ class IOPipeline extends Pipeline<IOModularStep> {
|
|||
|
||||
@override
|
||||
Future<void> run(ModularTest test) async {
|
||||
var resultsDir = null;
|
||||
Directory? resultsDir;
|
||||
if (_resultsFolderUri == null) {
|
||||
resultsDir = await Directory.systemTemp.createTemp('modular_test_res-');
|
||||
_resultsFolderUri = resultsDir.uri;
|
||||
}
|
||||
if (cacheSharedModules) {
|
||||
_currentConfiguration = _registry.computeConfigurationId(test);
|
||||
_currentConfiguration = _registry!.computeConfigurationId(test);
|
||||
}
|
||||
await super.run(test);
|
||||
if (resultsDir != null &&
|
||||
|
@ -90,7 +90,7 @@ class IOPipeline extends Pipeline<IOModularStep> {
|
|||
Future<void> cleanup() async {
|
||||
if (_resultsFolderUri == null) return;
|
||||
if (saveIntermediateResultsForTesting || cacheSharedModules) {
|
||||
await Directory.fromUri(_resultsFolderUri).delete(recursive: true);
|
||||
await Directory.fromUri(_resultsFolderUri!).delete(recursive: true);
|
||||
_resultsFolderUri = null;
|
||||
}
|
||||
}
|
||||
|
@ -98,11 +98,12 @@ class IOPipeline extends Pipeline<IOModularStep> {
|
|||
@override
|
||||
Future<void> runStep(IOModularStep step, Module module,
|
||||
Map<Module, Set<DataId>> visibleData, List<String> flags) async {
|
||||
final resultsFolderUri = _resultsFolderUri!;
|
||||
if (cacheSharedModules && module.isShared) {
|
||||
// If all expected outputs are already available, skip the step.
|
||||
bool allCachedResultsFound = true;
|
||||
for (var dataId in step.resultData) {
|
||||
var cachedFile = File.fromUri(_resultsFolderUri
|
||||
var cachedFile = File.fromUri(resultsFolderUri
|
||||
.resolve(_toFileName(module, dataId, configSpecific: true)));
|
||||
if (!await cachedFile.exists()) {
|
||||
allCachedResultsFound = false;
|
||||
|
@ -121,8 +122,8 @@ class IOPipeline extends Pipeline<IOModularStep> {
|
|||
var stepFolder =
|
||||
await Directory.systemTemp.createTemp('modular_test_${stepId}-');
|
||||
for (var module in visibleData.keys) {
|
||||
for (var dataId in visibleData[module]) {
|
||||
var assetUri = _resultsFolderUri
|
||||
for (var dataId in visibleData[module]!) {
|
||||
var assetUri = resultsFolderUri
|
||||
.resolve(_toFileName(module, dataId, configSpecific: true));
|
||||
await File.fromUri(assetUri).copy(
|
||||
stepFolder.uri.resolve(_toFileName(module, dataId)).toFilePath());
|
||||
|
@ -147,7 +148,7 @@ class IOPipeline extends Pipeline<IOModularStep> {
|
|||
throw StateError(
|
||||
"Step '${step.runtimeType}' didn't produce an output file");
|
||||
}
|
||||
await outputFile.copy(_resultsFolderUri
|
||||
await outputFile.copy(resultsFolderUri
|
||||
.resolve(_toFileName(module, dataId, configSpecific: true))
|
||||
.toFilePath());
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ Future<ModularTest> loadTest(Uri uri) async {
|
|||
Set<String> defaultPackages = defaultTestSpecification.packages.keys.toSet();
|
||||
Module sdkModule = await _createSdkModule(root);
|
||||
Map<String, Module> modules = {'sdk': sdkModule};
|
||||
String specString;
|
||||
Module mainModule;
|
||||
String? specString;
|
||||
Module? mainModule;
|
||||
var entries = folder.listSync(recursive: false).toList()
|
||||
// Sort to avoid dependency on file system order.
|
||||
..sort(_compareFileSystemEntity);
|
||||
|
@ -54,7 +54,7 @@ Future<ModularTest> loadTest(Uri uri) async {
|
|||
"that is provided by default.");
|
||||
}
|
||||
if (modules.containsKey(moduleName)) {
|
||||
return _moduleConflict(fileName, modules[moduleName], testUri);
|
||||
return _moduleConflict(fileName, modules[moduleName]!, testUri);
|
||||
}
|
||||
var relativeUri = Uri.parse(fileName);
|
||||
var isMain = moduleName == 'main';
|
||||
|
@ -82,7 +82,7 @@ Future<ModularTest> loadTest(Uri uri) async {
|
|||
"that is provided by default.");
|
||||
}
|
||||
if (modules.containsKey(moduleName)) {
|
||||
return _moduleConflict(moduleName, modules[moduleName], testUri);
|
||||
return _moduleConflict(moduleName, modules[moduleName]!, testUri);
|
||||
}
|
||||
var sources = await _listModuleSources(entryUri);
|
||||
modules[moduleName] = Module(moduleName, [], testUri, sources,
|
||||
|
@ -133,7 +133,7 @@ Future<List<Uri>> _listModuleSources(Uri root) async {
|
|||
void _attachDependencies(
|
||||
Map<String, List<String>> dependencies, Map<String, Module> modules) {
|
||||
dependencies.forEach((name, moduleDependencies) {
|
||||
var module = modules[name];
|
||||
final module = modules[name];
|
||||
if (module == null) {
|
||||
_invalidTest(
|
||||
"declared dependencies for a non existing module named '$name'");
|
||||
|
@ -142,7 +142,7 @@ void _attachDependencies(
|
|||
_invalidTest("Module dependencies have already been declared on $name.");
|
||||
}
|
||||
moduleDependencies.forEach((dependencyName) {
|
||||
var moduleDependency = modules[dependencyName];
|
||||
final moduleDependency = modules[dependencyName];
|
||||
if (moduleDependency == null) {
|
||||
_invalidTest("'$name' declares a dependency on a non existing module "
|
||||
"named '$dependencyName'");
|
||||
|
@ -169,7 +169,7 @@ Future<void> _addModulePerPackage(Map<String, String> packages, Uri configRoot,
|
|||
if (module != null) {
|
||||
module.isPackage = true;
|
||||
} else {
|
||||
var packageLibUri = configRoot.resolve(packages[packageName]);
|
||||
var packageLibUri = configRoot.resolve(packages[packageName]!);
|
||||
var packageRootUri = Directory.fromUri(packageLibUri).parent.uri;
|
||||
var sources = await _listModuleSources(packageLibUri);
|
||||
// TODO(sigmund): validate that we don't use a different alias for a
|
||||
|
@ -254,7 +254,7 @@ _moduleConflict(String name, Module existing, Uri root) {
|
|||
var entryType = isFile ? 'file' : 'folder';
|
||||
|
||||
var existingIsFile =
|
||||
existing.packageBase.path == './' && existing.sources.length == 1;
|
||||
existing.packageBase!.path == './' && existing.sources.length == 1;
|
||||
var existingEntryType = existingIsFile ? 'file' : 'folder';
|
||||
|
||||
var existingName = existingIsFile
|
||||
|
@ -266,7 +266,7 @@ _moduleConflict(String name, Module existing, Uri root) {
|
|||
"'$existingName'.");
|
||||
}
|
||||
|
||||
_invalidTest(String message) {
|
||||
Never _invalidTest(String message) {
|
||||
throw new InvalidTestError(message);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ import 'pipeline.dart';
|
|||
import 'suite.dart';
|
||||
|
||||
/// A hook to fetch data previously computed for a dependency.
|
||||
typedef ModuleDataProvider = Object Function(Module, DataId);
|
||||
typedef SourceProvider = String Function(Uri);
|
||||
typedef ModuleDataProvider = Object? Function(Module, DataId);
|
||||
typedef SourceProvider = String? Function(Uri);
|
||||
|
||||
abstract class MemoryModularStep extends ModularStep {
|
||||
Future<Map<DataId, Object>> execute(
|
||||
|
@ -25,12 +25,12 @@ class MemoryPipeline extends Pipeline<MemoryModularStep> {
|
|||
|
||||
/// Internal state to hold the current results as they are computed by the
|
||||
/// pipeline. Expected to be null before and after the pipeline runs.
|
||||
Map<Module, Map<DataId, Object>> _results;
|
||||
Map<Module, Map<DataId, Object>>? _results;
|
||||
|
||||
/// A copy of [_result] at the time the pipeline last finished running.
|
||||
Map<Module, Map<DataId, Object>> resultsForTesting;
|
||||
Map<Module, Map<DataId, Object>>? resultsForTesting;
|
||||
|
||||
final ConfigurationRegistry _registry;
|
||||
final ConfigurationRegistry? _registry;
|
||||
|
||||
/// Cache of results when [cacheSharedModules] is true
|
||||
final List<Map<Module, Map<DataId, Object>>> _resultCache;
|
||||
|
@ -38,29 +38,29 @@ class MemoryPipeline extends Pipeline<MemoryModularStep> {
|
|||
MemoryPipeline(this._sources, List<MemoryModularStep> steps,
|
||||
{bool cacheSharedModules: false})
|
||||
: _registry = cacheSharedModules ? new ConfigurationRegistry() : null,
|
||||
_resultCache = cacheSharedModules ? [] : null,
|
||||
_resultCache = cacheSharedModules ? [] : const [],
|
||||
super(steps, cacheSharedModules);
|
||||
|
||||
@override
|
||||
Future<void> run(ModularTest test) async {
|
||||
_results = {};
|
||||
Map<Module, Map<DataId, Object>> cache = null;
|
||||
var results = _results = {};
|
||||
Map<Module, Map<DataId, Object>>? cache = null;
|
||||
if (cacheSharedModules) {
|
||||
int id = _registry.computeConfigurationId(test);
|
||||
int id = _registry!.computeConfigurationId(test);
|
||||
if (id < _resultCache.length) {
|
||||
cache = _resultCache[id];
|
||||
} else {
|
||||
assert(id == _resultCache.length);
|
||||
_resultCache.add(cache = {});
|
||||
}
|
||||
_results.addAll(cache);
|
||||
results.addAll(cache);
|
||||
}
|
||||
await super.run(test);
|
||||
resultsForTesting = _results;
|
||||
resultsForTesting = results;
|
||||
if (cacheSharedModules) {
|
||||
for (var module in _results.keys) {
|
||||
for (var module in results.keys) {
|
||||
if (module.isShared) {
|
||||
cache[module] = _results[module];
|
||||
cache![module] = results[module]!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,10 +70,11 @@ class MemoryPipeline extends Pipeline<MemoryModularStep> {
|
|||
@override
|
||||
Future<void> runStep(MemoryModularStep step, Module module,
|
||||
Map<Module, Set<DataId>> visibleData, List<String> flags) async {
|
||||
final results = _results!;
|
||||
if (cacheSharedModules && module.isShared) {
|
||||
bool allCachedResultsFound = true;
|
||||
for (var dataId in step.resultData) {
|
||||
if (_results[module] == null || _results[module][dataId] == null) {
|
||||
if (results[module] == null || results[module]![dataId] == null) {
|
||||
allCachedResultsFound = false;
|
||||
break;
|
||||
}
|
||||
|
@ -88,23 +89,23 @@ class MemoryPipeline extends Pipeline<MemoryModularStep> {
|
|||
visibleData.forEach((module, dataIdSet) {
|
||||
inputData[module] = {};
|
||||
for (var dataId in dataIdSet) {
|
||||
inputData[module][dataId] = _results[module][dataId];
|
||||
inputData[module]![dataId] = results[module]![dataId]!;
|
||||
}
|
||||
});
|
||||
Map<Uri, String> inputSources = {};
|
||||
if (step.needsSources) {
|
||||
module.sources.forEach((relativeUri) {
|
||||
var uri = module.rootUri.resolveUri(relativeUri);
|
||||
inputSources[uri] = _sources[uri];
|
||||
inputSources[uri] = _sources[uri]!;
|
||||
});
|
||||
}
|
||||
Map<DataId, Object> result = await step.execute(
|
||||
module,
|
||||
(Uri uri) => inputSources[uri],
|
||||
(Module m, DataId id) => inputData[m][id],
|
||||
(Module m, DataId id) => inputData[m]![id],
|
||||
flags);
|
||||
for (var dataId in step.resultData) {
|
||||
(_results[module] ??= {})[dataId] = result[dataId];
|
||||
(results[module] ??= {})[dataId] = result[dataId]!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class ModularStep {
|
|||
{this.needsSources: true,
|
||||
this.dependencyDataNeeded: const [],
|
||||
this.moduleDataNeeded: const [],
|
||||
this.resultData,
|
||||
this.resultData: const [],
|
||||
this.onlyOnMain: false,
|
||||
this.onlyOnSdk: false,
|
||||
this.notOnSdk: false});
|
||||
|
@ -94,13 +94,13 @@ abstract class Pipeline<S extends ModularStep> {
|
|||
// or by the same step on a dependency.
|
||||
Map<DataId, S> previousKinds = {};
|
||||
for (var step in steps) {
|
||||
if (step.resultData == null || step.resultData.isEmpty) {
|
||||
if (step.resultData.isEmpty) {
|
||||
_validationError(
|
||||
"'${step.runtimeType}' needs to declare what data it produces.");
|
||||
}
|
||||
for (var resultKind in step.resultData) {
|
||||
if (previousKinds.containsKey(resultKind) &&
|
||||
!areMutuallyExclusive(step, previousKinds[resultKind])) {
|
||||
!areMutuallyExclusive(step, previousKinds[resultKind]!)) {
|
||||
_validationError("Cannot produce the same data on two modular steps."
|
||||
" '$resultKind' was previously produced by "
|
||||
"'${previousKinds[resultKind].runtimeType}' but "
|
||||
|
@ -151,7 +151,7 @@ abstract class Pipeline<S extends ModularStep> {
|
|||
await _recursiveRun(
|
||||
step, dependency, computedData, transitiveDependencies, flags);
|
||||
deps.add(dependency);
|
||||
deps.addAll(transitiveDependencies[dependency]);
|
||||
deps.addAll(transitiveDependencies[dependency]!);
|
||||
}
|
||||
|
||||
if ((step.onlyOnMain && !module.isMain) ||
|
||||
|
@ -163,15 +163,15 @@ abstract class Pipeline<S extends ModularStep> {
|
|||
deps.forEach((dep) {
|
||||
visibleData[dep] = {};
|
||||
for (var dataId in step.dependencyDataNeeded) {
|
||||
if (computedData[dep].contains(dataId)) {
|
||||
visibleData[dep].add(dataId);
|
||||
if (computedData[dep]!.contains(dataId)) {
|
||||
visibleData[dep]!.add(dataId);
|
||||
}
|
||||
}
|
||||
});
|
||||
visibleData[module] = {};
|
||||
for (var dataId in step.moduleDataNeeded) {
|
||||
if (computedData[module].contains(dataId)) {
|
||||
visibleData[module].add(dataId);
|
||||
if (computedData[module]!.contains(dataId)) {
|
||||
visibleData[module]!.add(dataId);
|
||||
}
|
||||
}
|
||||
await runStep(step, module, visibleData, flags);
|
||||
|
|
|
@ -26,15 +26,15 @@ Future<void> runSuite(Uri suiteFolder, String suiteName, Options options,
|
|||
|
||||
await generic.runSuite(
|
||||
entries,
|
||||
new generic.RunnerOptions()
|
||||
..suiteName = suiteName
|
||||
..configurationName = options.configurationName
|
||||
..filter = options.filter
|
||||
..logDir = options.outputDirectory
|
||||
..shard = options.shard
|
||||
..shards = options.shards
|
||||
..verbose = options.verbose
|
||||
..reproTemplate = '%executable %script --verbose --filter %name');
|
||||
new generic.RunnerOptions(
|
||||
suiteName: suiteName,
|
||||
configurationName: options.configurationName,
|
||||
filter: options.filter,
|
||||
logDir: options.outputDirectory,
|
||||
shard: options.shard,
|
||||
shards: options.shards,
|
||||
verbose: options.verbose,
|
||||
reproTemplate: '%executable %script --verbose --filter %name'));
|
||||
await pipeline.cleanup();
|
||||
}
|
||||
|
||||
|
@ -59,11 +59,11 @@ class _PipelineTest implements generic.Test {
|
|||
class Options {
|
||||
bool showSkipped = false;
|
||||
bool verbose = false;
|
||||
String filter = null;
|
||||
String? filter;
|
||||
int shards = 1;
|
||||
int shard = 1;
|
||||
String configurationName;
|
||||
Uri outputDirectory;
|
||||
String? configurationName;
|
||||
Uri? outputDirectory;
|
||||
bool useSdk = false;
|
||||
|
||||
static Options parse(List<String> args) {
|
||||
|
@ -92,7 +92,7 @@ class Options {
|
|||
help: 'configuration name to use for emitting jsonl result files.');
|
||||
ArgResults argResults = parser.parse(args);
|
||||
int shards = int.tryParse(argResults['shards']) ?? 1;
|
||||
int shard;
|
||||
int shard = 1;
|
||||
if (shards > 1) {
|
||||
shard = int.tryParse(argResults['shard']) ?? 1;
|
||||
if (shard <= 0 || shard >= shards) {
|
||||
|
@ -101,7 +101,7 @@ class Options {
|
|||
exit(1);
|
||||
}
|
||||
}
|
||||
Uri toUri(s) => s == null ? null : Uri.base.resolveUri(Uri.file(s));
|
||||
Uri? toUri(s) => s == null ? null : Uri.base.resolveUri(Uri.file(s));
|
||||
return Options()
|
||||
..showSkipped = argResults['show-skipped']
|
||||
..verbose = argResults['verbose']
|
||||
|
|
|
@ -17,15 +17,7 @@ class ModularTest {
|
|||
final List<String> flags;
|
||||
|
||||
ModularTest(this.modules, this.mainModule, this.flags) {
|
||||
if (mainModule == null) {
|
||||
throw ArgumentError("main module was null");
|
||||
}
|
||||
if (flags == null) {
|
||||
throw ArgumentError("flags was null");
|
||||
}
|
||||
if (modules == null || modules.length == 0) {
|
||||
throw ArgumentError("modules cannot be null or empty");
|
||||
}
|
||||
if (modules.isEmpty) throw ArgumentError("modules cannot be empty");
|
||||
for (var module in modules) {
|
||||
module._validate();
|
||||
}
|
||||
|
@ -52,7 +44,7 @@ class Module {
|
|||
|
||||
/// The file containing the main entry method, if any. Stored as a relative
|
||||
/// [Uri] from [rootUri].
|
||||
final Uri mainSource;
|
||||
final Uri? mainSource;
|
||||
|
||||
/// Whether this module is also available as a package import, where the
|
||||
/// package name matches the module name.
|
||||
|
@ -63,7 +55,7 @@ class Module {
|
|||
|
||||
/// When [isPackage], the base where all package URIs are resolved against.
|
||||
/// Stored as a relative [Uri] from [rootUri].
|
||||
final Uri packageBase;
|
||||
final Uri? packageBase;
|
||||
|
||||
/// Whether this is the main entry module of a test.
|
||||
bool isMain;
|
||||
|
|
|
@ -72,15 +72,15 @@ TestSpecification parseTestSpecification(String contents) {
|
|||
if (key is! String) {
|
||||
_invalidSpecification("key: '$key' is not a string");
|
||||
}
|
||||
normalizedMap[key] = [];
|
||||
final values = normalizedMap[key] = [];
|
||||
if (value is String) {
|
||||
normalizedMap[key].add(value);
|
||||
values.add(value);
|
||||
} else if (value is List) {
|
||||
value.forEach((entry) {
|
||||
if (entry is! String) {
|
||||
_invalidSpecification("entry: '$entry' is not a string");
|
||||
}
|
||||
normalizedMap[key].add(entry);
|
||||
values.add(entry);
|
||||
});
|
||||
} else {
|
||||
_invalidSpecification(
|
||||
|
|
|
@ -6,7 +6,7 @@ description: >
|
|||
This is used within the Dart SDK to define and validate modular tests, and to
|
||||
execute them using the modular pipeline of different SDK tools.
|
||||
environment:
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
sdk: '>=2.16.0 <3.0.0'
|
||||
|
||||
dependencies:
|
||||
args: any
|
||||
|
|
|
@ -35,7 +35,7 @@ class IOPipelineTestStrategy implements PipelineTestStrategy<IOModularStep> {
|
|||
for (var uri in sources.keys) {
|
||||
var file = new File.fromUri(uri);
|
||||
await file.create(recursive: true);
|
||||
await file.writeAsStringSync(sources[uri]);
|
||||
file.writeAsStringSync(sources[uri]!);
|
||||
}
|
||||
return new IOPipeline(steps,
|
||||
saveIntermediateResultsForTesting: true,
|
||||
|
@ -44,49 +44,49 @@ class IOPipelineTestStrategy implements PipelineTestStrategy<IOModularStep> {
|
|||
|
||||
@override
|
||||
IOModularStep createSourceOnlyStep(
|
||||
{String Function(Map<Uri, String>) action,
|
||||
DataId resultId,
|
||||
{required String Function(Map<Uri, String?>) action,
|
||||
required DataId resultId,
|
||||
bool requestSources: true}) =>
|
||||
SourceOnlyStep(action, resultId, requestSources);
|
||||
|
||||
@override
|
||||
IOModularStep createModuleDataStep(
|
||||
{String Function(String) action,
|
||||
DataId inputId,
|
||||
DataId resultId,
|
||||
{required String Function(String) action,
|
||||
required DataId inputId,
|
||||
required DataId resultId,
|
||||
bool requestModuleData: true}) =>
|
||||
ModuleDataStep(action, inputId, resultId, requestModuleData);
|
||||
|
||||
@override
|
||||
IOModularStep createLinkStep(
|
||||
{String Function(String, List<String>) action,
|
||||
DataId inputId,
|
||||
DataId depId,
|
||||
DataId resultId,
|
||||
{required String Function(String, List<String?>) action,
|
||||
required DataId inputId,
|
||||
required DataId depId,
|
||||
required DataId resultId,
|
||||
bool requestDependenciesData: true}) =>
|
||||
LinkStep(action, inputId, depId, resultId, requestDependenciesData);
|
||||
|
||||
@override
|
||||
IOModularStep createMainOnlyStep(
|
||||
{String Function(String, List<String>) action,
|
||||
DataId inputId,
|
||||
DataId depId,
|
||||
DataId resultId,
|
||||
{required String Function(String, List<String?>) action,
|
||||
required DataId inputId,
|
||||
required DataId depId,
|
||||
required DataId resultId,
|
||||
bool requestDependenciesData: true}) =>
|
||||
MainOnlyStep(action, inputId, depId, resultId, requestDependenciesData);
|
||||
|
||||
@override
|
||||
IOModularStep createTwoOutputStep(
|
||||
{String Function(String) action1,
|
||||
String Function(String) action2,
|
||||
DataId inputId,
|
||||
DataId result1Id,
|
||||
DataId result2Id}) =>
|
||||
{required String Function(String) action1,
|
||||
required String Function(String) action2,
|
||||
required DataId inputId,
|
||||
required DataId result1Id,
|
||||
required DataId result2Id}) =>
|
||||
TwoOutputStep(action1, action2, inputId, result1Id, result2Id);
|
||||
|
||||
@override
|
||||
String getResult(covariant IOPipeline pipeline, Module m, DataId dataId) {
|
||||
var folderUri = pipeline.resultFolderUriForTesting;
|
||||
String? getResult(covariant IOPipeline pipeline, Module m, DataId dataId) {
|
||||
var folderUri = pipeline.resultFolderUriForTesting!;
|
||||
var file = File.fromUri(folderUri
|
||||
.resolve(pipeline.configSpecificResultFileNameForTesting(m, dataId)));
|
||||
return file.existsSync() ? file.readAsStringSync() : null;
|
||||
|
@ -100,7 +100,7 @@ class IOPipelineTestStrategy implements PipelineTestStrategy<IOModularStep> {
|
|||
}
|
||||
|
||||
class SourceOnlyStep implements IOModularStep {
|
||||
final String Function(Map<Uri, String>) action;
|
||||
final String Function(Map<Uri, String?>) action;
|
||||
final DataId resultId;
|
||||
final bool needsSources;
|
||||
List<DataId> get dependencyDataNeeded => const [];
|
||||
|
@ -115,12 +115,11 @@ class SourceOnlyStep implements IOModularStep {
|
|||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
Map<Uri, String> sources = {};
|
||||
Map<Uri, String?> sources = {};
|
||||
|
||||
for (var uri in module.sources) {
|
||||
var file = File.fromUri(root.resolveUri(uri));
|
||||
String data = await file.exists() ? await file.readAsString() : null;
|
||||
sources[uri] = data;
|
||||
sources[uri] = await file.exists() ? await file.readAsString() : null;
|
||||
}
|
||||
await File.fromUri(root.resolveUri(toUri(module, resultId)))
|
||||
.writeAsString(action(sources));
|
||||
|
@ -199,7 +198,7 @@ class LinkStep implements IOModularStep {
|
|||
final List<DataId> dependencyDataNeeded;
|
||||
List<DataId> get moduleDataNeeded => [inputId];
|
||||
List<DataId> get resultData => [resultId];
|
||||
final String Function(String, List<String>) action;
|
||||
final String Function(String, List<String?>) action;
|
||||
final DataId inputId;
|
||||
final DataId depId;
|
||||
final DataId resultId;
|
||||
|
@ -214,14 +213,14 @@ class LinkStep implements IOModularStep {
|
|||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
List<String> depsData = [];
|
||||
List<String?> depsData = [];
|
||||
for (var dependency in module.dependencies) {
|
||||
var depData = await _readHelper(dependency, root, depId, toUri);
|
||||
depsData.add(depData);
|
||||
}
|
||||
var inputData = await _readHelper(module, root, inputId, toUri);
|
||||
await File.fromUri(root.resolveUri(toUri(module, resultId)))
|
||||
.writeAsString(action(inputData, depsData));
|
||||
.writeAsString(action(inputData!, depsData));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -233,7 +232,7 @@ class MainOnlyStep implements IOModularStep {
|
|||
final List<DataId> dependencyDataNeeded;
|
||||
List<DataId> get moduleDataNeeded => [inputId];
|
||||
List<DataId> get resultData => [resultId];
|
||||
final String Function(String, List<String>) action;
|
||||
final String Function(String, List<String?>) action;
|
||||
final DataId inputId;
|
||||
final DataId depId;
|
||||
final DataId resultId;
|
||||
|
@ -248,21 +247,21 @@ class MainOnlyStep implements IOModularStep {
|
|||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
List<String> depsData = [];
|
||||
List<String?> depsData = [];
|
||||
for (var dependency in computeTransitiveDependencies(module)) {
|
||||
var depData = await _readHelper(dependency, root, depId, toUri);
|
||||
depsData.add(depData);
|
||||
}
|
||||
var inputData = await _readHelper(module, root, inputId, toUri);
|
||||
await File.fromUri(root.resolveUri(toUri(module, resultId)))
|
||||
.writeAsString(action(inputData, depsData));
|
||||
.writeAsString(action(inputData!, depsData));
|
||||
}
|
||||
|
||||
@override
|
||||
void notifyCached(Module module) {}
|
||||
}
|
||||
|
||||
Future<String> _readHelper(Module module, Uri root, DataId dataId,
|
||||
Future<String?> _readHelper(Module module, Uri root, DataId dataId,
|
||||
ModuleDataToRelativeUri toUri) async {
|
||||
var file = File.fromUri(root.resolveUri(toUri(module, dataId)));
|
||||
if (await file.exists()) {
|
||||
|
|
|
@ -19,7 +19,7 @@ main(List<String> args) async {
|
|||
if (entry is Directory) {
|
||||
var dirName = entry.uri.path.substring(baseDir.path.length);
|
||||
test(dirName, () => _runTest(entry.uri, dirName, options),
|
||||
skip: options.filter != null && !dirName.contains(options.filter));
|
||||
skip: options.filter != null && !dirName.contains(options.filter!));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ Future<void> _runTest(Uri uri, String dirName, _Options options) async {
|
|||
" ${Platform.executable} ${Platform.script} "
|
||||
"--update --show-update --filter $dirName");
|
||||
}
|
||||
expect(expectation, result);
|
||||
expect(result, expectation);
|
||||
} else if (await file.exists() && (await file.readAsString() == result)) {
|
||||
print(" expectation matches result and was up to date.");
|
||||
} else {
|
||||
|
@ -100,7 +100,7 @@ String _dumpAsText(ModularTest test) {
|
|||
class _Options {
|
||||
bool updateExpectations = false;
|
||||
bool showResultOnUpdate = false;
|
||||
String filter = null;
|
||||
String? filter;
|
||||
|
||||
static _Options parse(List<String> args) {
|
||||
var parser = new ArgParser()
|
||||
|
|
|
@ -30,56 +30,57 @@ class MemoryPipelineTestStrategy
|
|||
|
||||
@override
|
||||
MemoryModularStep createSourceOnlyStep(
|
||||
{String Function(Map<Uri, String>) action,
|
||||
DataId resultId,
|
||||
{required String Function(Map<Uri, String?>) action,
|
||||
required DataId resultId,
|
||||
bool requestSources: true}) =>
|
||||
SourceOnlyStep(action, resultId, requestSources);
|
||||
|
||||
@override
|
||||
MemoryModularStep createModuleDataStep(
|
||||
{String Function(String) action,
|
||||
DataId inputId,
|
||||
DataId resultId,
|
||||
{required String Function(String) action,
|
||||
required DataId inputId,
|
||||
required DataId resultId,
|
||||
bool requestModuleData: true}) =>
|
||||
ModuleDataStep(action, inputId, resultId, requestModuleData);
|
||||
|
||||
@override
|
||||
MemoryModularStep createLinkStep(
|
||||
{String Function(String, List<String>) action,
|
||||
DataId inputId,
|
||||
DataId depId,
|
||||
DataId resultId,
|
||||
{required String Function(String, List<String?>) action,
|
||||
required DataId inputId,
|
||||
required DataId depId,
|
||||
required DataId resultId,
|
||||
bool requestDependenciesData: true}) =>
|
||||
LinkStep(action, inputId, depId, resultId, requestDependenciesData);
|
||||
|
||||
@override
|
||||
MemoryModularStep createMainOnlyStep(
|
||||
{String Function(String, List<String>) action,
|
||||
DataId inputId,
|
||||
DataId depId,
|
||||
DataId resultId,
|
||||
{required String Function(String, List<String?>) action,
|
||||
required DataId inputId,
|
||||
required DataId depId,
|
||||
required DataId resultId,
|
||||
bool requestDependenciesData: true}) =>
|
||||
MainOnlyStep(action, inputId, depId, resultId, requestDependenciesData);
|
||||
|
||||
@override
|
||||
MemoryModularStep createTwoOutputStep(
|
||||
{String Function(String) action1,
|
||||
String Function(String) action2,
|
||||
DataId inputId,
|
||||
DataId result1Id,
|
||||
DataId result2Id}) =>
|
||||
{required String Function(String) action1,
|
||||
required String Function(String) action2,
|
||||
required DataId inputId,
|
||||
required DataId result1Id,
|
||||
required DataId result2Id}) =>
|
||||
TwoOutputStep(action1, action2, inputId, result1Id, result2Id);
|
||||
|
||||
@override
|
||||
String getResult(covariant MemoryPipeline pipeline, Module m, DataId dataId) {
|
||||
return pipeline.resultsForTesting[m][dataId];
|
||||
String? getResult(
|
||||
covariant MemoryPipeline pipeline, Module m, DataId dataId) {
|
||||
return pipeline.resultsForTesting![m]![dataId] as String?;
|
||||
}
|
||||
|
||||
FutureOr<void> cleanup(Pipeline<MemoryModularStep> pipeline) => null;
|
||||
}
|
||||
|
||||
class SourceOnlyStep implements MemoryModularStep {
|
||||
final String Function(Map<Uri, String>) action;
|
||||
final String Function(Map<Uri, String?>) action;
|
||||
final DataId resultId;
|
||||
final bool needsSources;
|
||||
List<DataId> get dependencyDataNeeded => const [];
|
||||
|
@ -96,7 +97,7 @@ class SourceOnlyStep implements MemoryModularStep {
|
|||
SourceProvider sourceProvider,
|
||||
ModuleDataProvider dataProvider,
|
||||
List<String> flags) {
|
||||
Map<Uri, String> sources = {};
|
||||
Map<Uri, String?> sources = {};
|
||||
for (var uri in module.sources) {
|
||||
sources[uri] = sourceProvider(module.rootUri.resolveUri(uri));
|
||||
}
|
||||
|
@ -127,9 +128,10 @@ class ModuleDataStep implements MemoryModularStep {
|
|||
SourceProvider sourceProvider,
|
||||
ModuleDataProvider dataProvider,
|
||||
List<String> flags) {
|
||||
var inputData = dataProvider(module, inputId) as String;
|
||||
if (inputData == null)
|
||||
var inputData = dataProvider(module, inputId) as String?;
|
||||
if (inputData == null) {
|
||||
return Future.value({resultId: "data for $module was null"});
|
||||
}
|
||||
return Future.value({resultId: action(inputData)});
|
||||
}
|
||||
|
||||
|
@ -159,12 +161,13 @@ class TwoOutputStep implements MemoryModularStep {
|
|||
SourceProvider sourceProvider,
|
||||
ModuleDataProvider dataProvider,
|
||||
List<String> flags) {
|
||||
var inputData = dataProvider(module, inputId) as String;
|
||||
if (inputData == null)
|
||||
var inputData = dataProvider(module, inputId) as String?;
|
||||
if (inputData == null) {
|
||||
return Future.value({
|
||||
result1Id: "data for $module was null",
|
||||
result2Id: "data for $module was null",
|
||||
result1Id: "result for $module was null",
|
||||
result2Id: "result for $module was null",
|
||||
});
|
||||
}
|
||||
return Future.value(
|
||||
{result1Id: action1(inputData), result2Id: action2(inputData)});
|
||||
}
|
||||
|
@ -177,7 +180,7 @@ class LinkStep implements MemoryModularStep {
|
|||
bool get needsSources => false;
|
||||
final List<DataId> dependencyDataNeeded;
|
||||
List<DataId> get moduleDataNeeded => [inputId];
|
||||
final String Function(String, List<String>) action;
|
||||
final String Function(String, List<String?>) action;
|
||||
final DataId inputId;
|
||||
final DataId depId;
|
||||
final DataId resultId;
|
||||
|
@ -196,9 +199,9 @@ class LinkStep implements MemoryModularStep {
|
|||
ModuleDataProvider dataProvider,
|
||||
List<String> flags) {
|
||||
List<String> depsData = module.dependencies
|
||||
.map((d) => dataProvider(d, depId) as String)
|
||||
.map((d) => dataProvider(d, depId).toString())
|
||||
.toList();
|
||||
var inputData = dataProvider(module, inputId) as String;
|
||||
var inputData = dataProvider(module, inputId).toString();
|
||||
return Future.value({resultId: action(inputData, depsData)});
|
||||
}
|
||||
|
||||
|
@ -210,7 +213,7 @@ class MainOnlyStep implements MemoryModularStep {
|
|||
bool get needsSources => false;
|
||||
final List<DataId> dependencyDataNeeded;
|
||||
List<DataId> get moduleDataNeeded => [inputId];
|
||||
final String Function(String, List<String>) action;
|
||||
final String Function(String, List<String?>) action;
|
||||
final DataId inputId;
|
||||
final DataId depId;
|
||||
final DataId resultId;
|
||||
|
@ -228,11 +231,11 @@ class MainOnlyStep implements MemoryModularStep {
|
|||
SourceProvider sourceProvider,
|
||||
ModuleDataProvider dataProvider,
|
||||
List<String> flags) {
|
||||
List<String> depsData = computeTransitiveDependencies(module)
|
||||
.map((d) => dataProvider(d, depId) as String)
|
||||
List<String?> depsData = computeTransitiveDependencies(module)
|
||||
.map((d) => dataProvider(d, depId) as String?)
|
||||
.toList();
|
||||
var inputData = dataProvider(module, inputId) as String;
|
||||
return Future.value({resultId: action(inputData, depsData)});
|
||||
var inputData = dataProvider(module, inputId) as String?;
|
||||
return Future.value({resultId: action(inputData!, depsData)});
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -34,16 +34,16 @@ abstract class PipelineTestStrategy<S extends ModularStep> {
|
|||
/// Create a step that applies [action] on all input files of the module, and
|
||||
/// emits a result with the given [id]
|
||||
S createSourceOnlyStep(
|
||||
{String Function(Map<Uri, String>) action,
|
||||
DataId resultId,
|
||||
{required String Function(Map<Uri, String?>) action,
|
||||
required DataId resultId,
|
||||
bool requestSources: true});
|
||||
|
||||
/// Create a step that applies [action] on the module [inputId] data, and
|
||||
/// emits a result with the given [resultId].
|
||||
S createModuleDataStep(
|
||||
{String Function(String) action,
|
||||
DataId inputId,
|
||||
DataId resultId,
|
||||
{required String Function(String) action,
|
||||
required DataId inputId,
|
||||
required DataId resultId,
|
||||
bool requestModuleData: true});
|
||||
|
||||
/// Create a step that applies [action] on the module [inputId] data and the
|
||||
|
@ -52,10 +52,10 @@ abstract class PipelineTestStrategy<S extends ModularStep> {
|
|||
///
|
||||
/// [depId] may be the same as [resultId] or [inputId].
|
||||
S createLinkStep(
|
||||
{String Function(String, List<String>) action,
|
||||
DataId inputId,
|
||||
DataId depId,
|
||||
DataId resultId,
|
||||
{required String Function(String, List<String?>) action,
|
||||
required DataId inputId,
|
||||
required DataId depId,
|
||||
required DataId resultId,
|
||||
bool requestDependenciesData: true});
|
||||
|
||||
/// Create a step that applies [action] only on the main module [inputId] data
|
||||
|
@ -65,23 +65,23 @@ abstract class PipelineTestStrategy<S extends ModularStep> {
|
|||
/// [depId] may be the same as [inputId] but not [resultId] since this action
|
||||
/// is only applied on the main module.
|
||||
S createMainOnlyStep(
|
||||
{String Function(String, List<String>) action,
|
||||
DataId inputId,
|
||||
DataId depId,
|
||||
DataId resultId,
|
||||
{required String Function(String, List<String?>) action,
|
||||
required DataId inputId,
|
||||
required DataId depId,
|
||||
required DataId resultId,
|
||||
bool requestDependenciesData: true});
|
||||
|
||||
/// Create a step that applies [action1] and [action2] on the module [inputId]
|
||||
/// data, and emits two results with the given [result1Id] and [result2Id].
|
||||
S createTwoOutputStep(
|
||||
{String Function(String) action1,
|
||||
String Function(String) action2,
|
||||
DataId inputId,
|
||||
DataId result1Id,
|
||||
DataId result2Id});
|
||||
{required String Function(String) action1,
|
||||
required String Function(String) action2,
|
||||
required DataId inputId,
|
||||
required DataId result1Id,
|
||||
required DataId result2Id});
|
||||
|
||||
/// Return the result data produced by a modular step.
|
||||
String getResult(Pipeline<S> pipeline, Module m, DataId dataId);
|
||||
String? getResult(Pipeline<S> pipeline, Module m, DataId dataId);
|
||||
|
||||
/// Do any cleanup work needed after pipeline is completed. Needed because
|
||||
/// some implementations retain data around to be able to answer [getResult]
|
||||
|
@ -322,7 +322,7 @@ runPipelineTest<S extends ModularStep>(PipelineTestStrategy<S> testStrategy) {
|
|||
var counterStep = testStrategy.createSourceOnlyStep(
|
||||
action: (_) => '${i++}', resultId: counterId);
|
||||
var linkStep = testStrategy.createLinkStep(
|
||||
action: (String m, List<String> deps) => "${deps.join(',')},$m",
|
||||
action: (String m, List<String?> deps) => "${deps.join(',')},$m",
|
||||
inputId: counterId,
|
||||
depId: counterId,
|
||||
resultId: linkId,
|
||||
|
@ -352,7 +352,7 @@ runPipelineTest<S extends ModularStep>(PipelineTestStrategy<S> testStrategy) {
|
|||
var counterStep = testStrategy.createSourceOnlyStep(
|
||||
action: (_) => '${i++}', resultId: counterId);
|
||||
var linkStep = testStrategy.createLinkStep(
|
||||
action: (String m, List<String> deps) => "${deps.join(',')},$m",
|
||||
action: (String m, List<String?> deps) => "${deps.join(',')},$m",
|
||||
inputId: counterId,
|
||||
depId: counterId,
|
||||
resultId: linkId,
|
||||
|
@ -384,7 +384,7 @@ runPipelineTest<S extends ModularStep>(PipelineTestStrategy<S> testStrategy) {
|
|||
var counterStep = testStrategy.createSourceOnlyStep(
|
||||
action: (_) => '${i++}', resultId: counterId);
|
||||
var linkStep = testStrategy.createLinkStep(
|
||||
action: (String m, List<String> deps) => "${deps.join(',')},$m",
|
||||
action: (String m, List<String?> deps) => "${deps.join(',')},$m",
|
||||
inputId: counterId,
|
||||
depId: counterId,
|
||||
resultId: linkId,
|
||||
|
@ -419,7 +419,7 @@ DataId _lowercaseId = const DataId("lowercase");
|
|||
DataId _uppercaseId = const DataId("uppercase");
|
||||
DataId _joinId = const DataId("join");
|
||||
|
||||
String _concat(Map<Uri, String> sources) {
|
||||
String _concat(Map<Uri, String?> sources) {
|
||||
var buffer = new StringBuffer();
|
||||
sources.forEach((uri, contents) {
|
||||
buffer.write("$uri: $contents\n");
|
||||
|
@ -430,7 +430,7 @@ String _concat(Map<Uri, String> sources) {
|
|||
String _lowercase(String contents) => contents.toLowerCase();
|
||||
String _uppercase(String contents) => contents.toUpperCase();
|
||||
|
||||
String _replaceAndJoin(String moduleData, List<String> depContents) {
|
||||
String _replaceAndJoin(String moduleData, List<String?> depContents) {
|
||||
var buffer = new StringBuffer();
|
||||
depContents.forEach(buffer.writeln);
|
||||
buffer.write(moduleData.replaceAll(".dart:", ""));
|
||||
|
|
|
@ -83,5 +83,5 @@ class _NoopPipeline extends Pipeline {
|
|||
@override
|
||||
Future<void> runStep(ModularStep step, Module module,
|
||||
Map<Module, Set<DataId>> visibleData, List<String> flags) =>
|
||||
null;
|
||||
Future.value(null);
|
||||
}
|
||||
|
|
|
@ -8,19 +8,10 @@ import 'package:modular_test/src/suite.dart';
|
|||
|
||||
main() {
|
||||
test('module test is not empty', () {
|
||||
expect(
|
||||
() => ModularTest([], null, []), throwsA(TypeMatcher<ArgumentError>()));
|
||||
|
||||
var m = Module("a", [], Uri.parse("app:/"), []);
|
||||
expect(() => ModularTest([], m, []), throwsA(TypeMatcher<ArgumentError>()));
|
||||
});
|
||||
|
||||
test('module test must have a main module', () {
|
||||
var m = Module("a", [], Uri.parse("app:/"), []);
|
||||
expect(() => ModularTest([m], null, []),
|
||||
throwsA(TypeMatcher<ArgumentError>()));
|
||||
});
|
||||
|
||||
test('package must depend on package', () {
|
||||
var m1a = Module("a", const [], Uri.parse("app:/"),
|
||||
[Uri.parse("a1.dart"), Uri.parse("a2.dart")],
|
||||
|
|
Loading…
Reference in a new issue