diff --git a/drift_dev/test/analysis/test_utils.dart b/drift_dev/test/analysis/test_utils.dart index a54a47f7..230e615e 100644 --- a/drift_dev/test/analysis/test_utils.dart +++ b/drift_dev/test/analysis/test_utils.dart @@ -1,5 +1,13 @@ +import 'dart:io'; +import 'dart:isolate'; + +import 'package:analyzer/dart/analysis/analysis_context.dart'; +import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; +import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/overlay_file_system.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:build/build.dart'; import 'package:drift_dev/src/analysis/backend.dart'; import 'package:drift_dev/src/analysis/driver/driver.dart'; @@ -7,18 +15,27 @@ import 'package:drift_dev/src/analysis/driver/error.dart'; import 'package:drift_dev/src/analysis/driver/state.dart'; import 'package:drift_dev/src/analyzer/options.dart'; import 'package:logging/logging.dart'; +import 'package:package_config/package_config.dart'; +import 'package:path/path.dart' as p; import 'package:test/expect.dart'; import 'package:test/scaffolding.dart'; +/// A [DriftBackend] implementation used for testing. +/// +/// This backend has limited support for Dart analysis: [sourceContents] forming +/// the package `a` are available for analysis. In addition, `drift` and +/// `drift_dev` imports can be analyzed as well. class TestBackend extends DriftBackend { - final Map sourceContents; + final Map sourceContents; late final DriftAnalysisDriver driver; + AnalysisContext? _dartContext; + TestBackend(Map sourceContents, DriftOptions options) : sourceContents = { for (final entry in sourceContents.entries) - AssetId.parse(entry.key).uri.toString(): entry.value, + AssetId.parse(entry.key).uri: entry.value, } { driver = DriftAnalysisDriver(this, options); } @@ -31,6 +48,50 @@ class TestBackend extends DriftBackend { return backend; } + Future _setupDartAnalyzer() async { + final provider = OverlayResourceProvider(PhysicalResourceProvider.INSTANCE); + + // Analyze example sources against the drift sources from the current + // drift_dev test runner. + final uri = await Isolate.packageConfig; + final hostConfig = + PackageConfig.parseBytes(await File.fromUri(uri!).readAsBytes(), uri); + final testConfig = PackageConfig([ + ...hostConfig.packages, + Package('a', Uri.directory('/a/'), packageUriRoot: Uri.parse('lib/')), + ]); + + // Write package config used to analyze dummy sources + final configBuffer = StringBuffer(); + PackageConfig.writeString(testConfig, configBuffer); + provider.setOverlay('/a/.dart_tool/package_config.json', + content: configBuffer.toString(), modificationStamp: 1); + + // Also put sources into the overlay: + sourceContents.forEach((key, value) { + if (key.scheme == 'package') { + final package = uri.pathSegments.first; + final path = + p.url.joinAll(['/$package/lib', ...uri.pathSegments.skip(1)]); + + provider.setOverlay(path, content: value, modificationStamp: 1); + } + }); + + final collection = AnalysisContextCollection( + includedPaths: ['/a/'], + resourceProvider: provider, + ); + + _dartContext = collection.contexts.single; + } + + Future ensureHasDartAnalyzer() async { + if (_dartContext == null) { + await _setupDartAnalyzer(); + } + } + @override Logger get log => Logger.root; @@ -46,9 +107,12 @@ class TestBackend extends DriftBackend { } @override - Future readDart(Uri uri) { - // TODO: implement readDart - throw UnimplementedError(); + Future readDart(Uri uri) async { + await ensureHasDartAnalyzer(); + final result = + await _dartContext!.currentSession.getLibraryByUri(uri.toString()); + + return (result as LibraryElementResult).element; } @override