| // Copyright (c) 2024, 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 'package:analyzer/dart/analysis/results.dart'; | |
| import 'package:analyzer/dart/analysis/session.dart'; | |
| import 'package:analyzer/file_system/file_system.dart'; | |
| import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart'; | |
| import 'package:analyzer/src/dart/analysis/byte_store.dart'; | |
| import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart'; | |
| import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag; | |
| import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine; | |
| import 'package:analyzer/src/test_utilities/find_node.dart'; | |
| import 'package:analyzer/src/test_utilities/mock_sdk.dart'; | |
| import 'package:analyzer/src/util/file_paths.dart' as file_paths; | |
| import 'package:analyzer_testing/resource_provider_mixin.dart'; | |
| import 'package:meta/meta.dart'; | |
| import 'package:test/test.dart'; | |
| /// A base test framework for writing tests that resolve a String as Dart source | |
| /// code. | |
| // TODO(srawlins): This is all copied from the `AbstractSingleUnitTest` and | |
| // `AbstractContextTest` classes in the analysis_server package. It is pared | |
| // down as the minimum amount of code needed to run the tests in this package. | |
| class SingleUnitTest with ResourceProviderMixin { | |
| static final ByteStore _byteStore = MemoryByteStore(); | |
| late String testCode; | |
| late ParsedUnitResult testParsedResult; | |
| late ResolvedUnitResult testAnalysisResult; | |
| late FindNode findNode; | |
| final Map<String, String> _declaredVariables = {}; | |
| AnalysisContextCollectionImpl? _analysisContextCollection; | |
| File get testFile => getFile(_testFilePath); | |
| List<String> get _collectionIncludedPaths => [_workspaceRootPath]; | |
| Folder get _sdkRoot => newFolder('/sdk'); | |
| String get _testFilePath => '$_testPackageLibPath/test.dart'; | |
| String get _testPackageLibPath => '$_testPackageRootPath/lib'; | |
| String get _testPackageRootPath => '$_workspaceRootPath/test'; | |
| String get _workspaceRootPath => '/home'; | |
| void addTestSource(String code) { | |
| testCode = code; | |
| newFile(testFile.path, code); | |
| } | |
| void changeFile(File file) { | |
| _contextFor(file).driver.changeFile(file.path); | |
| } | |
| Future<ParsedUnitResult> getParsedUnit(File file) async { | |
| var path = file.path; | |
| var session = await _sessionFor(file); | |
| var result = session.getParsedUnit(path) as ParsedUnitResult; | |
| testParsedResult = result; | |
| testCode = result.content; | |
| var testUnit = result.unit; | |
| findNode = FindNode(testCode, testUnit); | |
| return result; | |
| } | |
| Future<ResolvedUnitResult> getResolvedUnit(File file) async { | |
| var path = file.path; | |
| var session = await _sessionFor(file); | |
| var result = await session.getResolvedUnit(path) as ResolvedUnitResult; | |
| testAnalysisResult = result; | |
| testCode = result.content; | |
| var testUnit = result.unit; | |
| expect( | |
| result.diagnostics.where((d) { | |
| return d.diagnosticCode != diag.deadCode && | |
| d.diagnosticCode != diag.unusedCatchClause && | |
| d.diagnosticCode != diag.unusedCatchStack && | |
| d.diagnosticCode != diag.unusedElement && | |
| d.diagnosticCode != diag.unusedField && | |
| d.diagnosticCode != diag.unusedImport && | |
| d.diagnosticCode != diag.unusedLocalVariable; | |
| }), | |
| isEmpty, | |
| ); | |
| findNode = FindNode(testCode, testUnit); | |
| return result; | |
| } | |
| @override | |
| File newFile(String path, String content) { | |
| if (_analysisContextCollection != null && !path.endsWith('.dart')) { | |
| throw StateError('Only dart files can be changed after analysis.'); | |
| } | |
| var file = super.newFile(path, content); | |
| _addAnalyzedFileToDrivers(file); | |
| return file; | |
| } | |
| Future<void> parseTestCode(String code) async { | |
| addTestSource(code); | |
| await getParsedUnit(testFile); | |
| } | |
| Future<void> resolveTestCode(String code) async { | |
| addTestSource(code); | |
| await getResolvedUnit(testFile); | |
| } | |
| @mustCallSuper | |
| void setUp() { | |
| createMockSdk(resourceProvider: resourceProvider, root: _sdkRoot); | |
| } | |
| @mustCallSuper | |
| Future<void> tearDown() async { | |
| AnalysisEngine.instance.clearCaches(); | |
| await _analysisContextCollection?.dispose(); | |
| } | |
| void _addAnalyzedFilesToDrivers() { | |
| for (var analysisContext in _analysisContextCollection!.contexts) { | |
| for (var path in analysisContext.contextRoot.analyzedFiles()) { | |
| if (file_paths.isDart(resourceProvider.pathContext, path)) { | |
| analysisContext.driver.addFile(path); | |
| } | |
| } | |
| } | |
| } | |
| void _addAnalyzedFileToDrivers(File file) { | |
| var collection = _analysisContextCollection; | |
| if (collection != null) { | |
| for (var analysisContext in collection.contexts) { | |
| if (analysisContext.contextRoot.isAnalyzed(file.path)) { | |
| analysisContext.driver.addFile(file.path); | |
| } | |
| } | |
| } | |
| } | |
| DriverBasedAnalysisContext _contextFor(File file) { | |
| _createAnalysisContexts(); | |
| return _analysisContextCollection!.contextFor(file.path); | |
| } | |
| /// Creates all analysis contexts in [_collectionIncludedPaths]. | |
| void _createAnalysisContexts() { | |
| if (_analysisContextCollection != null) { | |
| return; | |
| } | |
| _analysisContextCollection = AnalysisContextCollectionImpl( | |
| byteStore: _byteStore, | |
| declaredVariables: _declaredVariables, | |
| enableIndex: true, | |
| includedPaths: _collectionIncludedPaths.map(convertPath).toList(), | |
| resourceProvider: resourceProvider, | |
| sdkPath: _sdkRoot.path, | |
| withFineDependencies: true, | |
| ); | |
| _addAnalyzedFilesToDrivers(); | |
| } | |
| Future<AnalysisSession> _sessionFor(File file) async { | |
| var analysisContext = _contextFor(file); | |
| await analysisContext.applyPendingFileChanges(); | |
| return analysisContext.currentSession; | |
| } | |
| } |