mirror of
https://github.com/immich-app/drift.git
synced 2026-09-30 13:22:57 +08:00
175 lines
4.8 KiB
Dart
175 lines
4.8 KiB
Dart
import 'package:analyzer/dart/analysis/features.dart';
|
|
import 'package:analyzer/dart/analysis/utilities.dart';
|
|
import 'package:analyzer/file_system/memory_file_system.dart';
|
|
import 'package:build/build.dart';
|
|
import 'package:build_test/build_test.dart';
|
|
import 'package:drift_dev/integrations/build.dart';
|
|
import 'package:glob/glob.dart';
|
|
import 'package:logging/logging.dart';
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
import 'package:test/test.dart';
|
|
import 'package:yaml/yaml.dart';
|
|
|
|
BuilderOptions builderOptionsFromYaml(String yaml) {
|
|
final map = loadYaml(yaml);
|
|
return BuilderOptions((map as YamlMap).cast());
|
|
}
|
|
|
|
Logger loggerThat(dynamic expectedLogs) {
|
|
final logger = Logger.detached('drift_dev_test');
|
|
|
|
expect(logger.onRecord, expectedLogs);
|
|
return logger;
|
|
}
|
|
|
|
TypeMatcher<LogRecord> record(dynamic message) {
|
|
return isA<LogRecord>().having((e) => e.message, 'message', message);
|
|
}
|
|
|
|
Future<TestReaderWriter> driftTestEnvironment(
|
|
{String rootPackage = 'a'}) async {
|
|
final rw = TestReaderWriter(rootPackage: rootPackage);
|
|
final reader = await PackageAssetReader.currentIsolate();
|
|
for (final package in [
|
|
'async',
|
|
'convert',
|
|
'collection',
|
|
'drift',
|
|
'meta',
|
|
'stream_channel',
|
|
'sqlite3',
|
|
'path',
|
|
'stack_trace',
|
|
'typed_data',
|
|
]) {
|
|
await for (final asset
|
|
in reader.findAssets(Glob('lib/**'), package: package)) {
|
|
rw.testing.writeBytes(asset, await reader.readAsBytes(asset));
|
|
}
|
|
}
|
|
|
|
return rw;
|
|
}
|
|
|
|
Future<DriftBuildResult> emulateDriftBuild({
|
|
required Map<String, String> inputs,
|
|
BuilderOptions options = const BuilderOptions({}),
|
|
Logger? logger,
|
|
bool modularBuild = false,
|
|
}) async {
|
|
logger ??= Logger.detached('emulateDriftBuild');
|
|
final logLines = <LogRecord>[];
|
|
|
|
final env = await driftTestEnvironment();
|
|
final prepare = preparingBuilder(options);
|
|
final result = await testBuilders(
|
|
[
|
|
prepare,
|
|
discover(options),
|
|
analyzer(options),
|
|
modularBuild ? modular(options) : driftBuilderNotShared(options),
|
|
],
|
|
postProcessBuilders: [
|
|
driftCleanup(options),
|
|
],
|
|
appliesBuilders: {
|
|
prepare: ['FileDeletingBuilder']
|
|
},
|
|
inputs,
|
|
rootPackage: 'a',
|
|
onLog: (record) {
|
|
logLines.add(record);
|
|
if (record.level >= Level.WARNING) {
|
|
// We sometimes want to assert that no warnings are printed, but
|
|
// everything below that is noise.
|
|
logger?.log(
|
|
record.level, record.message, record.error, record.stackTrace);
|
|
}
|
|
},
|
|
readerWriter: env,
|
|
// Assets from other packages are visible, but we're not running
|
|
// builders on them.
|
|
generateFor:
|
|
inputs.keys.where((e) => makeAssetId(e).package == 'a').toSet(),
|
|
);
|
|
if (result.buildResult.failureType != null) {
|
|
throw Exception('testBuilders failed');
|
|
}
|
|
|
|
logger.clearListeners();
|
|
return DriftBuildResult(env);
|
|
}
|
|
|
|
class DriftBuildResult {
|
|
final TestReaderWriter writer;
|
|
|
|
DriftBuildResult(this.writer);
|
|
|
|
Iterable<AssetId> get dartOutputs {
|
|
return writer.testing.assetsWritten.where((e) {
|
|
return e.extension == '.dart' &&
|
|
// TODO: Replace with a better check for deleted assets,
|
|
// https://github.com/dart-lang/build/discussions/4186#discussioncomment-14848165
|
|
!e.path.endsWith('.temp.dart');
|
|
});
|
|
}
|
|
|
|
void checkDartOutputs(Map<String, Object> outputs) {
|
|
checkOutputs(outputs, dartOutputs, writer);
|
|
}
|
|
}
|
|
|
|
extension ReaderWriterUtils on TestReaderWriter {
|
|
String readGenerated(String assetId) {
|
|
var id = AssetId.parse(assetId);
|
|
if (!testing.exists(id)) {
|
|
id = AssetId(
|
|
id.package,
|
|
'.dart_tool/build/generated/${id.package}/${id.path}',
|
|
);
|
|
|
|
// If neither succeeded then the asset was output but written somewhere
|
|
// unexpected.
|
|
if (!testing.exists(id)) {
|
|
throw StateError(
|
|
'Internal error: "$assetId" was recorded as output, but the file '
|
|
'could not be found. All assets: ${testing.assets}',
|
|
);
|
|
}
|
|
}
|
|
|
|
return testing.readString(id);
|
|
}
|
|
}
|
|
|
|
class IsValidDartFile extends CustomMatcher {
|
|
IsValidDartFile(dynamic valueOrMatcher)
|
|
: super(
|
|
'A syntactically-valid Dart source file',
|
|
'parsed unit',
|
|
valueOrMatcher,
|
|
);
|
|
|
|
@override
|
|
Object? featureValueOf(actual) {
|
|
final resourceProvider = MemoryResourceProvider();
|
|
if (actual is List<int>) {
|
|
resourceProvider.newFileWithBytes('/foo.dart', actual);
|
|
} else if (actual is String) {
|
|
resourceProvider.newFile('/foo.dart', actual);
|
|
} else {
|
|
throw 'Not a String or a List<int>';
|
|
}
|
|
|
|
return parseFile(
|
|
path: '/foo.dart',
|
|
featureSet: FeatureSet.fromEnableFlags2(
|
|
sdkLanguageVersion: Version(3, 0, 0),
|
|
flags: const [],
|
|
),
|
|
resourceProvider: resourceProvider,
|
|
throwIfDiagnostics: true,
|
|
).unit;
|
|
}
|
|
}
|