// 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:convert'; import 'package:analyzer/dart/analysis/analysis_context.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/analysis/session.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/file_system/overlay_file_system.dart'; import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/src/dart/analysis/driver.dart'; import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart'; import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine; import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/test_utilities/mock_sdk.dart'; import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; /// TODO(paulberry): this logic is duplicated from other packages. Find a way /// share it, or avoid relying on it. class AbstractContextTest with ResourceProviderMixin { OverlayResourceProvider overlayResourceProvider; AnalysisContextCollectionImpl _analysisContextCollection; AnalysisDriver _driver; final Set knownPackages = {}; /// Whether the test should perform analysis with NNBD enabled. /// /// `false` by default. May be overridden in derived test classes. bool get analyzeWithNnbd => false; AnalysisDriver get driver { if (_driver == null) { _createAnalysisContexts(); } return _driver; } String get homePath => '/home'; AnalysisSession get session => driver.currentSession; String get testsPath => '$homePath/tests'; void addMetaPackage() { addPackageFile('meta', 'meta.dart', r''' library meta; const Required required = const Required(); class Required { final String reason; const Required([this.reason]); } '''); } /// Add a new file with the given [pathInLib] to the package with the given /// [packageName]. Then ensure that the package under test depends on the /// package. File addPackageFile(String packageName, String pathInLib, String content) { var packagePath = '/.pub-cache/$packageName'; knownPackages.add(packageName); return newFile('$packagePath/lib/$pathInLib', content: content); } /// Add the quiver package and a library with URI, /// "package:quiver/check.dart". /// /// Then ensure that the package under test depends on the package. void addQuiverPackage() { addPackageFile('quiver', 'check.dart', r''' library quiver.check; T checkNotNull(T reference, {dynamic message}) => T; '''); } Source addSource(String path, String content, [Uri uri]) { File file = newFile(path, content: content); Source source = file.createSource(uri); driver.addFile(file.path); driver.changeFile(file.path); return source; } /// Add the test_core package and a library with URI, /// "package:test_core/test_core.dart". /// /// Then ensure that the package under test depends on the package. void addTestCorePackage() { addPackageFile('test_core', 'test_core.dart', r''' library test_core; void setUp(dynamic callback()) {} void group(dynamic description, dynamic body()) {} void test(dynamic description, dynamic body()) {} '''); addPackageFile('test', 'test.dart', r''' library test; export 'package:test_core/test_core.dart'; '''); } /// Return the existing analysis context that should be used to analyze the /// given [path], or throw [StateError] if the [path] is not analyzed in any /// of the created analysis contexts. AnalysisContext getContext(String path) { return _getContext(path); } /// Return the existing analysis driver that should be used to analyze the /// given [path], or throw [StateError] if the [path] is not analyzed in any /// of the created analysis contexts. AnalysisDriver getDriver(String path) { return _getContext(path).driver; } LineInfo getLineInfo(String path) => (session.getFile2(path) as FileResult).lineInfo; void setUp() { setupResourceProvider(); overlayResourceProvider = OverlayResourceProvider(resourceProvider); MockSdk(resourceProvider: resourceProvider); newFolder(testsPath); newFile('$testsPath/.packages', content: ''' tests:file://$testsPath/lib '''); var pubspecPath = '$testsPath/pubspec.yaml'; // Subclasses may write out a different file first. if (!getFile(pubspecPath).exists) { newFile(pubspecPath, content: ''' name: tests version: 1.0.0 environment: sdk: '>=2.9.0 <3.0.0' '''); } } void setupResourceProvider() {} void tearDown() { AnalysisEngine.instance.clearCaches(); } /// Create all analysis contexts in [_homePath]. void _createAnalysisContexts() { var packageConfigJson = { 'configVersion': 2, 'packages': [ for (var packageName in knownPackages) { 'name': packageName, 'rootUri': toUriStr('/.pub-cache/$packageName'), 'packageUri': 'lib/', 'languageVersion': '2.12' }, { 'name': 'tests', 'rootUri': '../', 'packageUri': 'lib/', 'languageVersion': analyzeWithNnbd ? '2.12' : '2.9' } ], 'generated': '2020-10-21T21:13:05.186004Z', 'generator': 'pub', 'generatorVersion': '2.10.0' }; newFile('$testsPath/.dart_tool/package_config.json', content: JsonEncoder.withIndent(' ').convert(packageConfigJson)); _analysisContextCollection = AnalysisContextCollectionImpl( includedPaths: [convertPath(homePath)], enableIndex: true, resourceProvider: overlayResourceProvider, sdkPath: convertPath('/sdk'), ); _driver = getDriver(convertPath(testsPath)); } /// Return the existing analysis context that should be used to analyze the /// given [path], or throw [StateError] if the [path] is not analyzed in any /// of the created analysis contexts. DriverBasedAnalysisContext _getContext(String path) { if (_analysisContextCollection == null) { _createAnalysisContexts(); } path = convertPath(path); return _analysisContextCollection.contextFor(path); } }