blob: 2c60efcd1dadefdea4b4fe04af95f148ac3a0bcd [file]
// 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.
/// Unit test for in-memory pipelines.
library;
import 'dart:io';
import 'package:modular_test/src/io_pipeline.dart';
import 'pipeline_common.dart';
void main() async {
var uri = Directory.systemTemp.uri.resolve("io_modular_test_root/");
int i = 0;
while (await Directory.fromUri(uri).exists()) {
uri = Directory.systemTemp.uri.resolve("io_modular_test_root$i/");
i++;
}
runPipelineTest(IOPipelineTestStrategy(uri));
}
/// The strategy implementation to exercise the pipeline test on a
/// [IOPipeline].
class IOPipelineTestStrategy implements PipelineTestStrategy<IOModularStep> {
@override
final Uri testRootUri;
IOPipelineTestStrategy(this.testRootUri);
@override
Future<Pipeline<IOModularStep>> createPipeline(
Map<Uri, String> sources,
List<IOModularStep> steps, {
bool cacheSharedModules = false,
}) async {
await Directory.fromUri(testRootUri).create();
for (var uri in sources.keys) {
var file = File.fromUri(uri);
await file.create(recursive: true);
file.writeAsStringSync(sources[uri]!);
}
return IOPipeline(
steps,
saveIntermediateResultsForTesting: true,
cacheSharedModules: cacheSharedModules,
);
}
@override
IOModularStep createSourceOnlyStep({
required String Function(Map<Uri, String?>) action,
required DataId resultId,
bool requestSources = true,
}) => SourceOnlyStep(action, resultId, requestSources);
@override
IOModularStep createModuleDataStep({
required String Function(String) action,
required DataId inputId,
required DataId resultId,
bool requestModuleData = true,
}) => ModuleDataStep(action, inputId, resultId, requestModuleData);
@override
IOModularStep createLinkStep({
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({
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({
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!;
var file = File.fromUri(
folderUri.resolve(
pipeline.configSpecificResultFileNameForTesting(m, dataId),
),
);
return file.existsSync() ? file.readAsStringSync() : null;
}
@override
Future<void> cleanup(covariant IOPipeline pipeline) async {
pipeline.cleanup();
await Directory.fromUri(testRootUri).delete(recursive: true);
}
}
class SourceOnlyStep implements IOModularStep {
final String Function(Map<Uri, String?>) action;
final DataId resultId;
@override
final bool needsSources;
@override
List<DataId> get dependencyDataNeeded => const [];
@override
List<DataId> get moduleDataNeeded => const [];
@override
List<DataId> get resultData => [resultId];
@override
bool get onlyOnMain => false;
@override
bool get onlyOnSdk => false;
@override
bool get notOnSdk => false;
SourceOnlyStep(this.action, this.resultId, this.needsSources);
@override
Future<void> execute(
Module module,
Uri root,
ModuleDataToRelativeUri toUri,
List<String> flags,
) async {
Map<Uri, String?> sources = {};
for (var uri in module.sources) {
var file = File.fromUri(root.resolveUri(uri));
sources[uri] = await file.exists() ? await file.readAsString() : null;
}
await File.fromUri(
root.resolveUri(toUri(module, resultId)),
).writeAsString(action(sources));
}
@override
void notifyCached(Module module) {}
}
class ModuleDataStep implements IOModularStep {
final String Function(String) action;
@override
bool get needsSources => false;
@override
List<DataId> get dependencyDataNeeded => const [];
@override
final List<DataId> moduleDataNeeded;
@override
List<DataId> get resultData => [resultId];
final DataId resultId;
final DataId inputId;
@override
bool get onlyOnMain => false;
@override
bool get onlyOnSdk => false;
@override
bool get notOnSdk => false;
ModuleDataStep(this.action, this.inputId, this.resultId, bool requestInput)
: moduleDataNeeded = requestInput ? [inputId] : [];
@override
Future<void> execute(
Module module,
Uri root,
ModuleDataToRelativeUri toUri,
List<String> flags,
) async {
var inputData = await _readHelper(module, root, inputId, toUri);
var result = inputData == null
? "data for $module was null"
: action(inputData);
await File.fromUri(
root.resolveUri(toUri(module, resultId)),
).writeAsString(result);
}
@override
void notifyCached(Module module) {}
}
class TwoOutputStep implements IOModularStep {
final String Function(String) action1;
final String Function(String) action2;
@override
bool get needsSources => false;
@override
List<DataId> get dependencyDataNeeded => const [];
@override
List<DataId> get moduleDataNeeded => [inputId];
@override
List<DataId> get resultData => [result1Id, result2Id];
final DataId result1Id;
final DataId result2Id;
final DataId inputId;
@override
bool get onlyOnMain => false;
@override
bool get onlyOnSdk => false;
@override
bool get notOnSdk => false;
TwoOutputStep(
this.action1,
this.action2,
this.inputId,
this.result1Id,
this.result2Id,
);
@override
Future<void> execute(
Module module,
Uri root,
ModuleDataToRelativeUri toUri,
List<String> flags,
) async {
var inputData = await _readHelper(module, root, inputId, toUri);
var result1 = inputData == null
? "data for $module was null"
: action1(inputData);
var result2 = inputData == null
? "data for $module was null"
: action2(inputData);
await File.fromUri(
root.resolveUri(toUri(module, result1Id)),
).writeAsString(result1);
await File.fromUri(
root.resolveUri(toUri(module, result2Id)),
).writeAsString(result2);
}
@override
void notifyCached(Module module) {}
}
class LinkStep implements IOModularStep {
@override
bool get needsSources => false;
@override
final List<DataId> dependencyDataNeeded;
@override
List<DataId> get moduleDataNeeded => [inputId];
@override
List<DataId> get resultData => [resultId];
final String Function(String, List<String?>) action;
final DataId inputId;
final DataId depId;
final DataId resultId;
@override
bool get onlyOnMain => false;
@override
bool get onlyOnSdk => false;
@override
bool get notOnSdk => false;
LinkStep(
this.action,
this.inputId,
this.depId,
this.resultId,
bool requestDependencies,
) : dependencyDataNeeded = requestDependencies ? [depId] : [];
@override
Future<void> execute(
Module module,
Uri root,
ModuleDataToRelativeUri toUri,
List<String> flags,
) async {
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));
}
@override
void notifyCached(Module module) {}
}
class MainOnlyStep implements IOModularStep {
@override
bool get needsSources => false;
@override
final List<DataId> dependencyDataNeeded;
@override
List<DataId> get moduleDataNeeded => [inputId];
@override
List<DataId> get resultData => [resultId];
final String Function(String, List<String?>) action;
final DataId inputId;
final DataId depId;
final DataId resultId;
@override
bool get onlyOnMain => true;
@override
bool get onlyOnSdk => false;
@override
bool get notOnSdk => false;
MainOnlyStep(
this.action,
this.inputId,
this.depId,
this.resultId,
bool requestDependencies,
) : dependencyDataNeeded = requestDependencies ? [depId] : [];
@override
Future<void> execute(
Module module,
Uri root,
ModuleDataToRelativeUri toUri,
List<String> flags,
) async {
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));
}
@override
void notifyCached(Module module) {}
}
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()) {
return await file.readAsString();
}
return null;
}