| // Copyright (c) 2016, 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:typed_data'; |
| |
| import 'package:analyzer/dart/analysis/declared_variables.dart'; |
| import 'package:analyzer/dart/analysis/features.dart'; |
| import 'package:analyzer/dart/sdk/build_sdk_summary.dart'; |
| import 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/src/context/packages.dart'; |
| import 'package:analyzer/src/dart/analysis/byte_store.dart'; |
| import 'package:analyzer/src/dart/analysis/experiments.dart'; |
| import 'package:analyzer/src/dart/analysis/feature_set_provider.dart'; |
| import 'package:analyzer/src/dart/analysis/file_content_cache.dart'; |
| import 'package:analyzer/src/dart/analysis/file_state.dart'; |
| import 'package:analyzer/src/dart/analysis/library_graph.dart'; |
| import 'package:analyzer/src/dart/analysis/performance_logger.dart'; |
| import 'package:analyzer/src/dart/sdk/sdk.dart'; |
| import 'package:analyzer/src/generated/engine.dart' |
| show AnalysisOptions, AnalysisOptionsImpl; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/source/package_map_resolver.dart'; |
| import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| import 'package:analyzer/src/test_utilities/mock_sdk.dart'; |
| import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; |
| import 'package:analyzer/src/util/either.dart'; |
| import 'package:analyzer/src/workspace/basic.dart'; |
| import 'package:analyzer_utilities/check/check.dart'; |
| import 'package:meta/meta.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../resolution/context_collection_resolution.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(FileSystemStateTest); |
| defineReflectiveTests(FileSystemState_BazelWorkspaceTest); |
| defineReflectiveTests(FileSystemState_PubPackageTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class FileSystemState_BazelWorkspaceTest extends BazelWorkspaceResolutionTest { |
| void test_getFileForUri_hasGenerated_askGeneratedFirst() async { |
| var relPath = 'dart/my/test/a.dart'; |
| var writablePath = convertPath('$workspaceRootPath/$relPath'); |
| var generatedPath = convertPath('$workspaceRootPath/bazel-bin/$relPath'); |
| |
| // This generated file should be used instead of the writable. |
| newFile(generatedPath, ''); |
| |
| var analysisDriver = driverFor(convertPath(testFilePath)); |
| |
| var fsState = analysisDriver.fsState; |
| |
| // Prepare URI(s). |
| var generatedUri = toUri(generatedPath); |
| var writableUri = toUri(writablePath); |
| |
| // The file is the generated file. |
| var generatedFile = fsState.getFileForUri(generatedUri).t1!; |
| expect(generatedFile.uri, writableUri); |
| expect(generatedFile.path, generatedPath); |
| |
| // The file is cached under the requested URI. |
| var writableFile1 = fsState.getFileForUri(writableUri).t1!; |
| var writableFile2 = fsState.getFileForUri(writableUri).t1!; |
| expect(writableFile1, same(generatedFile)); |
| expect(writableFile2, same(generatedFile)); |
| } |
| |
| void test_getFileForUri_hasGenerated_askWritableFirst() async { |
| var relPath = 'dart/my/test/a.dart'; |
| var writablePath = convertPath('$workspaceRootPath/$relPath'); |
| var generatedPath = convertPath('$workspaceRootPath/bazel-bin/$relPath'); |
| |
| // This generated file should be used instead of the writable. |
| newFile(generatedPath, ''); |
| |
| var analysisDriver = driverFor(convertPath(testFilePath)); |
| |
| var fsState = analysisDriver.fsState; |
| |
| // Prepare URI(s). |
| var generatedUri = toUri(generatedPath); |
| var writableUri = toUri(writablePath); |
| |
| // The file is cached under the requested URI. |
| var writableFile1 = fsState.getFileForUri(writableUri).t1!; |
| var writableFile2 = fsState.getFileForUri(writableUri).t1!; |
| expect(writableFile2, same(writableFile1)); |
| |
| // The file is the generated file. |
| var generatedFile = fsState.getFileForUri(generatedUri).t1!; |
| expect(generatedFile.uri, writableUri); |
| expect(generatedFile.path, generatedPath); |
| expect(writableFile2, same(generatedFile)); |
| } |
| |
| void test_getFileForUri_nestedLib_notCanonicalUri() async { |
| var outerPath = convertPath('$workspaceRootPath/my/outer/lib/a.dart'); |
| var outerUri = Uri.parse('package:my.outer/a.dart'); |
| |
| var innerPath = convertPath('/workspace/my/outer/lib/inner/lib/b.dart'); |
| var innerUri = Uri.parse('package:my.outer.lib.inner/b.dart'); |
| |
| var analysisDriver = driverFor(outerPath); |
| var fsState = analysisDriver.fsState; |
| |
| // User code might use such relative URI. |
| var innerUri2 = outerUri.resolve('inner/lib/b.dart'); |
| expect(innerUri2, Uri.parse('package:my.outer/inner/lib/b.dart')); |
| |
| // However the returned file must use the canonical URI. |
| var innerFile = fsState.getFileForUri(innerUri2).t1!; |
| expect(innerFile.path, innerPath); |
| expect(innerFile.uri, innerUri); |
| } |
| } |
| |
| @reflectiveTest |
| class FileSystemState_PubPackageTest extends PubPackageResolutionTest { |
| @override |
| bool get retainDataForTesting => true; |
| |
| FileState get _dartAsyncState { |
| return fileStateForUriStr('dart:async'); |
| } |
| |
| FileState get _dartCoreState { |
| return fileStateForUriStr('dart:core'); |
| } |
| |
| FileState get _dartMathState { |
| return fileStateForUriStr('dart:math'); |
| } |
| |
| FileState fileStateFor(File file) { |
| return fsStateFor(file).getFileForPath(file.path); |
| } |
| |
| FileState fileStateForUri(Uri uri) { |
| return fsStateFor(testFile).getFileForUri(uri).t1!; |
| } |
| |
| FileState fileStateForUriStr(String uriStr) { |
| final uri = Uri.parse(uriStr); |
| return fileStateForUri(uri); |
| } |
| |
| FileSystemState fsStateFor(File file) { |
| return driverFor(file.path).fsState; |
| } |
| |
| test_newFile_augmentation_augmentationExists_hasImport() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| import augment 'c.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library augment 'b.dart'; |
| '''); |
| |
| final cState = fileStateFor(c); |
| // We have not asked for `b.dart` yet, but it was found using URI. |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile.path, b.path); |
| expect(kind.augmented?.file.path, b.path); |
| }); |
| |
| final bState = fileStateFor(b); |
| _assertAugmentationFiles(bState, [c]); |
| // We have not asked for `a.dart` yet, but it was found using URI. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile.path, a.path); |
| expect(kind.augmented?.file.path, a.path); |
| }); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| |
| // Check `c.dart` again, now using the `b.dart` state. |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(bState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Check `b.dart` again, now using the `a.dart` state. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_augmentation_augmentationExists_hasImport_disconnected() async { |
| final a = getFile('$testPackageLibPath/a.dart'); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| import augment 'c.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library augment 'b.dart'; |
| '''); |
| |
| final cState = fileStateFor(c); |
| // We have not asked for `b.dart` yet, but it was found using URI. |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile.path, b.path); |
| expect(kind.augmented?.file.path, b.path); |
| }); |
| |
| final bState = fileStateFor(b); |
| _assertAugmentationFiles(bState, [c]); |
| // We have not asked for `a.dart` yet, but it was found using URI. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile.path, a.path); |
| // The file `a.dart` does not exist, so no import, so `null`. |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| // Check `c.dart` again, now using the `b.dart` state. |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(bState); |
| expect(kind.library, isNull); |
| }); |
| |
| // The file `a.dart` does not exist. |
| final aState = fileStateFor(a); |
| expect(aState.exists, isFalse); |
| _assertAugmentationFiles(aState, []); |
| // Check `b.dart` again, now using the `a.dart` state. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| // The URI can be resolved, it points at `a.dart` file. |
| expect(kind.uriFile, same(aState)); |
| // The file `a.dart` does not exist, so no import, so `null`. |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_newFile_augmentation_augmentationExists_noImport() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library augment 'b.dart'; |
| '''); |
| |
| // We found `b.dart` from the augmentation file `c.dart`. |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile.path, b.path); |
| // `b.dart` does not import `c.dart` as an augmentation. |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| |
| // Reading `a.dart` does not change anything. |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| |
| // `b.dart` does not import `c.dart` as an augmentation. |
| final bState = fileStateFor(b); |
| _assertAugmentationFiles(bState, []); |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Check `c.dart` again, now using the `b.dart` state. |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile, same(bState)); |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_newFile_augmentation_cycle1_augmentSelf() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'b.dart'; |
| import augment 'b.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| |
| // We can construct a cycle using augmentations. |
| final bState = fileStateFor(b); |
| _assertAugmentationFiles(bState, [b]); |
| bState.assertKind((bKind) { |
| bKind as AugmentationKnownFileStateKind; |
| bKind.assertAugmented(bState); |
| expect(bKind.library, isNull); |
| }); |
| |
| // The cycle does not prevent building of the library cycle. |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| // TODO(scheglov) ask for the cycle signature |
| }); |
| } |
| |
| test_newFile_augmentation_cycle2() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| import augment 'c.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library augment 'b.dart'; |
| import augment 'b.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| |
| final bState = fileStateFor(b); |
| _assertAugmentationFiles(bState, [c]); |
| |
| final cState = fileStateFor(c); |
| _assertAugmentationFiles(cState, [b]); |
| |
| // We can construct a cycle using augmentations. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(bState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // The cycle does not prevent building of the library cycle. |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| // TODO(scheglov) ask for the cycle signature |
| }); |
| } |
| |
| test_newFile_augmentation_invalid() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| library augment 'da:'; |
| '''); |
| |
| // The URI is invalid, so there is no way to discover the target. |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as AugmentationUnknownFileStateKind; |
| expect(kind.directive.uri, 'da:'); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_newFile_augmentation_libraryExists_hasImport() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| // We have not asked for `a.dart` yet, but it was found using URI. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile.path, a.path); |
| expect(kind.augmented?.file.path, a.path); |
| }); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| // Check `b.dart` again, now using the `a.dart` state. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_augmentation_libraryExists_noImport() async { |
| final a = newFile('$testPackageLibPath/a.dart', ''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, []); |
| |
| final bState = fileStateFor(b); |
| // We can find `a.dart` using the URI. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| // But `a.dart` does not import `b.dart`. |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| |
| // Refreshing `a.dart` does not change anything. |
| aState.refresh(); |
| _assertAugmentationFiles(aState, []); |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_newFile_augmentation_targetNotExists() async { |
| final a = getFile('$testPackageLibPath/a.dart'); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| // We can find `a.dart` from `b.dart` using the URI. |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile.path, a.path); |
| // The file `a.dart` does not exist, so no import. |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| |
| // We can get `a.dart`, but it does not exist. |
| final aState = fileStateFor(a); |
| expect(aState.exists, isFalse); |
| _assertAugmentationFiles(aState, []); |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| // The file `a.dart` does not exist, so no import. |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_newFile_augmentation_twoLibraries() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'c.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| import augment 'c.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [c]); |
| |
| // We use the URI from `library augment` to find the augmentation target. |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Reading `b.dart` does not update the augmentation. |
| final bState = fileStateFor(b); |
| _assertAugmentationFiles(bState, [c]); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing `a.dart` does not update the augmentation. |
| aState.refresh(); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing `b.dart` does not update the augmentation. |
| bState.refresh(); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Exclude from `a.dart`, the URI still points at `a.dart`. |
| // But `c.dart` is not a valid augmentation anymore. |
| newFile(a.path, ''); |
| aState.refresh(); |
| _assertAugmentationFiles(aState, []); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| |
| // Exclude from `b.dart`, still point at `a.dart`, still not valid. |
| newFile(b.path, ''); |
| bState.refresh(); |
| _assertAugmentationFiles(bState, []); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| |
| // Include into `b.dart`, still point at `a.dart`, still not valid. |
| newFile(b.path, r''' |
| import augment 'c.dart'; |
| '''); |
| bState.refresh(); |
| _assertAugmentationFiles(bState, [c]); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.augmented, isNull); |
| expect(kind.library, isNull); |
| }); |
| |
| // Include into `a.dart`, restore to `a.dart` as the target. |
| newFile(a.path, r''' |
| import augment 'c.dart'; |
| '''); |
| aState.refresh(); |
| _assertAugmentationFiles(aState, [c]); |
| cState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_doesNotExist() { |
| final a = getFile('$testPackageLibPath/a.dart'); |
| |
| final file = fileStateFor(a); |
| expect(file.path, a.path); |
| expect(file.uri, Uri.parse('package:test/a.dart')); |
| expect(file.content, ''); |
| expect(file.exists, isFalse); |
| |
| file.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| kind.assertLibrary(file); |
| check(kind.imports).matches([ |
| (import) => import |
| ..isLibrary(_dartCoreState) |
| ..isSyntheticDartCoreImport.isTrue, |
| ]); |
| check(kind.exports).isEmpty; |
| }); |
| |
| expect(file.exportedFiles, isEmpty); |
| expect(file.partedFiles, isEmpty); |
| expect(file.libraryFiles, [file]); |
| expect(file.isPart, isFalse); |
| } |
| |
| test_newFile_library_exports_dart() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| export 'dart:async'; |
| export 'dart:math'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.exports).matches([ |
| (export) => export.isLibrary(_dartAsyncState), |
| (export) => export.isLibrary(_dartMathState), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_exports_inSummary_library() async { |
| // Prepare a bundle where `package:foo/foo.dart` is a library. |
| final librarySummaryFiles = <File>[]; |
| { |
| final fooRoot = getFolder('$workspaceRootPath/foo'); |
| |
| newFile('${fooRoot.path}/lib/foo.dart', 'class F {}'); |
| |
| final fooPackageConfigFile = getFile( |
| '${fooRoot.path}/.dart_tool/package_config.json', |
| ); |
| |
| writePackageConfig( |
| fooPackageConfigFile.path, |
| PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), |
| ); |
| |
| final analysisDriver = driverFor(fooRoot.path); |
| final bundleBytes = await analysisDriver.buildPackageBundle( |
| uriList: [ |
| Uri.parse('package:foo/foo.dart'), |
| ], |
| ); |
| |
| final bundleFile = getFile('/home/summaries/packages.sum'); |
| bundleFile.writeAsBytesSync(bundleBytes); |
| |
| librarySummaryFiles.add(bundleFile); |
| |
| // Delete, so it is not available as a file. |
| // We don't have a package config for it anyway, but just to be sure. |
| fooRoot.delete(); |
| } |
| |
| // Prepare for recreating the collection, with summaries. |
| sdkSummaryFile = await _writeSdkSummary(); |
| this.librarySummaryFiles = librarySummaryFiles; |
| |
| disposeAnalysisContextCollection(); |
| |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| export 'dart:async'; |
| export 'package:foo/foo.dart'; |
| export 'b.dart'; |
| '''); |
| |
| final b = getFile('$testPackageLibPath/b.dart'); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.exports).matches([ |
| (import) { |
| final expected = Uri.parse('dart:async'); |
| import.withInSummaryLibrary(expected); |
| }, |
| (import) { |
| final expected = Uri.parse('package:foo/foo.dart'); |
| import.withInSummaryLibrary(expected); |
| }, |
| (import) => import.isLibrary(bState), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_exports_inSummary_part() async { |
| // Prepare a bundle where `package:foo/foo2.dart` is a part. |
| final librarySummaryFiles = <File>[]; |
| { |
| final fooRoot = getFolder('$workspaceRootPath/foo'); |
| |
| newFile('${fooRoot.path}/lib/foo.dart', r''' |
| part 'foo2.dart'; |
| '''); |
| |
| newFile('${fooRoot.path}/lib/foo2.dart', r''' |
| part of 'foo.dart'; |
| '''); |
| |
| final fooPackageConfigFile = getFile( |
| '${fooRoot.path}/.dart_tool/package_config.json', |
| ); |
| |
| writePackageConfig( |
| fooPackageConfigFile.path, |
| PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), |
| ); |
| |
| final analysisDriver = driverFor(fooRoot.path); |
| final bundleBytes = await analysisDriver.buildPackageBundle( |
| uriList: [ |
| Uri.parse('package:foo/foo.dart'), |
| ], |
| ); |
| |
| final bundleFile = getFile('/home/summaries/packages.sum'); |
| bundleFile.writeAsBytesSync(bundleBytes); |
| |
| librarySummaryFiles.add(bundleFile); |
| |
| // Delete, so it is not available as a file. |
| // We don't have a package config for it anyway, but just to be sure. |
| fooRoot.delete(); |
| } |
| |
| // Prepare for recreating the collection, with summaries. |
| sdkSummaryFile = await _writeSdkSummary(); |
| this.librarySummaryFiles = librarySummaryFiles; |
| |
| disposeAnalysisContextCollection(); |
| |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| export 'package:foo/foo2.dart'; |
| export 'b.dart'; |
| '''); |
| |
| final b = getFile('$testPackageLibPath/b.dart'); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.exports).matches([ |
| (export) { |
| final expected = Uri.parse('package:foo/foo2.dart'); |
| export.withInSummaryNotLibrary(expected); |
| }, |
| (export) => export.isLibrary(bState), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_exports_invalidRelativeUri() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| export '::net'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.exports).matches([ |
| (export) => export.isNotFile(), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_exports_package() async { |
| final a = newFile('$testPackageLibPath/a.dart', ''); |
| final b = newFile('$testPackageLibPath/b.dart', ''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| export 'a.dart'; |
| export 'package:test/b.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| final cState = fileStateFor(c); |
| |
| cState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.exports).matches([ |
| (export) => export.isLibrary(aState), |
| (export) => export.isLibrary(bState), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_exports_part() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part of my.lib; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| export 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.exports).matches([ |
| (export) => export.isFile(aState), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_augmentation() async { |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| import 'b.dart'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| final cState = fileStateFor(c); |
| |
| cState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (import) => import.isFile(bState), |
| (import) => import |
| ..isLibrary(_dartCoreState) |
| ..isSyntheticDartCoreImport.isTrue, |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_dart() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import 'dart:async'; |
| import 'dart:math'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (import) => import.isLibrary(_dartAsyncState), |
| (import) => import.isLibrary(_dartMathState), |
| (import) => import |
| ..isLibrary(_dartCoreState) |
| ..isSyntheticDartCoreImport.isTrue, |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_dart_explicitDartCore() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import 'dart:core'; |
| import 'dart:math'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (import) => import |
| ..isLibrary(_dartCoreState) |
| ..isSyntheticDartCoreImport.isFalse, |
| (import) => import.isLibrary(_dartMathState), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_inSummary_library() async { |
| // Prepare a bundle where `package:foo/foo.dart` is a library. |
| final librarySummaryFiles = <File>[]; |
| { |
| final fooRoot = getFolder('$workspaceRootPath/foo'); |
| |
| newFile('${fooRoot.path}/lib/foo.dart', 'class F {}'); |
| |
| final fooPackageConfigFile = getFile( |
| '${fooRoot.path}/.dart_tool/package_config.json', |
| ); |
| |
| writePackageConfig( |
| fooPackageConfigFile.path, |
| PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), |
| ); |
| |
| final analysisDriver = driverFor(fooRoot.path); |
| final bundleBytes = await analysisDriver.buildPackageBundle( |
| uriList: [ |
| Uri.parse('package:foo/foo.dart'), |
| ], |
| ); |
| |
| final bundleFile = getFile('/home/summaries/packages.sum'); |
| bundleFile.writeAsBytesSync(bundleBytes); |
| |
| librarySummaryFiles.add(bundleFile); |
| |
| // Delete, so it is not available as a file. |
| // We don't have a package config for it anyway, but just to be sure. |
| fooRoot.delete(); |
| } |
| |
| // Prepare for recreating the collection, with summaries. |
| sdkSummaryFile = await _writeSdkSummary(); |
| this.librarySummaryFiles = librarySummaryFiles; |
| |
| disposeAnalysisContextCollection(); |
| |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import 'dart:async'; |
| import 'package:foo/foo.dart'; |
| import 'b.dart'; |
| '''); |
| |
| final b = getFile('$testPackageLibPath/b.dart'); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (import) { |
| final expected = Uri.parse('dart:async'); |
| import.withInSummaryLibrary(expected); |
| }, |
| (import) { |
| final expected = Uri.parse('package:foo/foo.dart'); |
| import.withInSummaryLibrary(expected); |
| }, |
| (import) => import.isLibrary(bState), |
| (import) { |
| final expected = Uri.parse('dart:core'); |
| import |
| ..withInSummaryLibrary(expected) |
| ..isSyntheticDartCoreImport.isTrue; |
| }, |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_inSummary_part() async { |
| // Prepare a bundle where `package:foo/foo2.dart` is a part. |
| final librarySummaryFiles = <File>[]; |
| { |
| final fooRoot = getFolder('$workspaceRootPath/foo'); |
| |
| newFile('${fooRoot.path}/lib/foo.dart', r''' |
| part 'foo2.dart'; |
| '''); |
| |
| newFile('${fooRoot.path}/lib/foo2.dart', r''' |
| part of 'foo.dart'; |
| '''); |
| |
| final fooPackageConfigFile = getFile( |
| '${fooRoot.path}/.dart_tool/package_config.json', |
| ); |
| |
| writePackageConfig( |
| fooPackageConfigFile.path, |
| PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), |
| ); |
| |
| final analysisDriver = driverFor(fooRoot.path); |
| final bundleBytes = await analysisDriver.buildPackageBundle( |
| uriList: [ |
| Uri.parse('package:foo/foo.dart'), |
| ], |
| ); |
| |
| final bundleFile = getFile('/home/summaries/packages.sum'); |
| bundleFile.writeAsBytesSync(bundleBytes); |
| |
| librarySummaryFiles.add(bundleFile); |
| |
| // Delete, so it is not available as a file. |
| // We don't have a package config for it anyway, but just to be sure. |
| fooRoot.delete(); |
| } |
| |
| // Prepare for recreating the collection, with summaries. |
| sdkSummaryFile = await _writeSdkSummary(); |
| this.librarySummaryFiles = librarySummaryFiles; |
| |
| disposeAnalysisContextCollection(); |
| |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import 'package:foo/foo2.dart'; |
| import 'b.dart'; |
| '''); |
| |
| final b = getFile('$testPackageLibPath/b.dart'); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (export) { |
| final expected = Uri.parse('package:foo/foo2.dart'); |
| export.withInSummaryNotLibrary(expected); |
| }, |
| (export) => export.isLibrary(bState), |
| (export) { |
| final expected = Uri.parse('dart:core'); |
| export |
| ..withInSummaryLibrary(expected) |
| ..isSyntheticDartCoreImport.isTrue; |
| }, |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_invalidRelativeUri() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import '::net'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (import) => import.isNotFile(), |
| (import) => import.isLibrary(_dartCoreState), |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_package() async { |
| final a = newFile('$testPackageLibPath/a.dart', ''); |
| final b = newFile('$testPackageLibPath/b.dart', ''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| import 'a.dart'; |
| import 'package:test/b.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| final cState = fileStateFor(c); |
| |
| cState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (import) => import.isLibrary(aState), |
| (import) => import.isLibrary(bState), |
| (import) => import |
| ..isLibrary(_dartCoreState) |
| ..isSyntheticDartCoreImport.isTrue, |
| ]); |
| }); |
| } |
| |
| test_newFile_library_imports_library_part() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part of my.lib; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| import 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| check(kind.imports).matches([ |
| (import) => import.isFile(aState), |
| (import) => import |
| ..isLibrary(_dartCoreState) |
| ..isSyntheticDartCoreImport.isTrue, |
| ]); |
| }); |
| } |
| |
| test_newFile_library_includePart_withoutPartOf() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| // no part of |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| |
| // Library `a.dart` includes `b.dart` as a part. |
| _assertPartedFiles(aState, [b]); |
| |
| // But `b.dart` thinks that it is a library itself. |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| |
| // Refreshing the library does not change this. |
| aState.refresh(); |
| _assertPartedFiles(aState, [b]); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| } |
| |
| test_newFile_libraryDirective() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| library my; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my'); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_noDirectives() async { |
| final a = newFile('$testPackageLibPath/a.dart', ''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| } |
| |
| /// TODO(scheglov) Test discovery of a sibling library |
| test_newFile_partOfName() async { |
| final a = newFile('$testPackageLibPath/nested/a.dart', r''' |
| library my.lib; |
| part '../b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of my.lib; |
| '''); |
| |
| final bState = fileStateFor(b); |
| |
| // We don't know the library initially. |
| // Even though the library file exists, we have not seen it yet. |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| expect(kind.directive.name, 'my.lib'); |
| expect(kind.libraries, isEmpty); |
| expect(kind.library, isNull); |
| }); |
| |
| // Read the library file. |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my.lib'); |
| }); |
| _assertPartedFiles(aState, [b]); |
| |
| // Now the part knows its library. |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState]); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_partOfName_differentName() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| library my.lib; |
| part 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of other.lib; |
| '''); |
| |
| final bState = fileStateFor(b); |
| |
| // We don't know the library initially. |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| expect(kind.directive.name, 'other.lib'); |
| kind.assertLibraries([]); |
| expect(kind.library, isNull); |
| }); |
| |
| // Read the library file. |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my.lib'); |
| }); |
| _assertPartedFiles(aState, [b]); |
| |
| // We still don't know the library, because the part wants `other.lib`, |
| // but `a.dart` that includes `b.dart` has the name `my.lib`. |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([]); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_newFile_partOfName_twoLibraries() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| library my.lib; |
| part 'c.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library my.lib; |
| part 'c.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| part of my.lib; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my.lib'); |
| }); |
| _assertPartedFiles(aState, [c]); |
| |
| // We set the library while reading `a.dart` file. |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState]); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Reading `b.dart` does not update the part. |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my.lib'); |
| }); |
| _assertPartedFiles(bState, [c]); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState, bState]); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing `b.dart` does not update the part. |
| bState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState, bState]); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing `a.dart` does not update the part. |
| aState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState, bState]); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Exclude the part from `a.dart`, switch to `b.dart` instead. |
| newFile(a.path, ''); |
| aState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([bState]); |
| kind.assertLibrary(bState); |
| }); |
| |
| // Exclude the part from `b.dart`, no library. |
| newFile(b.path, ''); |
| bState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([]); |
| expect(kind.library, isNull); |
| }); |
| |
| // Include into `b.dart`, use it as the library. |
| newFile(b.path, r''' |
| library my.lib; |
| part 'c.dart'; |
| '''); |
| bState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([bState]); |
| kind.assertLibrary(bState); |
| }); |
| |
| // Include into `a.dart`, switch to `a.dart`. |
| newFile(a.path, r''' |
| library my.lib; |
| part 'c.dart'; |
| '''); |
| aState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState, bState]); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_partOfUri_doesNotExist() async { |
| final a = getFile('$testPackageLibPath/a.dart'); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of 'a.dart'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| |
| // The URI in `part of URI` tells us which library to use. |
| // However it does not exist, so it does not include the file, so the |
| // part file will not be analyzed during the library analysis. |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile.path, a.path); |
| expect(kind.library, isNull); |
| }); |
| |
| final aState = fileStateFor(a); |
| expect(aState.exists, isFalse); |
| _assertPartedFiles(aState, []); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| }); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.library, isNull); |
| }); |
| |
| // Create `a.dart` that includes the part file. |
| newFile(a.path, r''' |
| part 'b.dart'; |
| '''); |
| |
| // The library file has already been read because of `part of uri`. |
| // So, we explicitly refresh it. |
| aState.refresh(); |
| _assertPartedFiles(aState, [b]); |
| |
| // Now the part file knows its library. |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing the part file does not break the kind. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_partOfUri_exists_hasPart() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of 'a.dart'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| // We have not read the library file explicitly yet. |
| // But it was read because of the `part of` directive. |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile.path, a.path); |
| expect(kind.library?.file.path, a.path); |
| }); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| }); |
| _assertPartedFiles(aState, [b]); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing the part file does not break the kind. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_newFile_partOfUri_exists_noPart() async { |
| final a = newFile('$testPackageLibPath/a.dart', ''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| // The URI in `part of URI` tells us which library to use. |
| // However `a.dart` does not include `b.dart` as a part, so `b.dart` will |
| // not be analyzed during the library analysis. |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_newFile_partOfUri_invalid() async { |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of 'da:'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| |
| // The URI is invalid, so there is no way to discover the library. |
| bState.assertKind((kind) { |
| kind as PartOfUriUnknownFileStateKind; |
| expect(kind.directive.uri, 'da:'); |
| }); |
| |
| // Reading a library that includes this part does not change the fact |
| // that the URI in the `part of URI` in `b.dart` cannot be resolved. |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part 'b.dart'; |
| '''); |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| }); |
| _assertPartedFiles(aState, [b]); |
| |
| bState.assertKind((kind) { |
| kind as PartOfUriUnknownFileStateKind; |
| expect(kind.directive.uri, 'da:'); |
| }); |
| } |
| |
| test_newFile_partOfUri_twoLibraries() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part 'c.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part 'c.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| part of 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertPartedFiles(aState, [c]); |
| |
| // We set the library while reading `a.dart` file. |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| kind.assertLibrary(aState); |
| }); |
| |
| // Reading `b.dart` does not update the part. |
| final bState = fileStateFor(b); |
| _assertPartedFiles(bState, [c]); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing `b.dart` does not update the part. |
| bState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| kind.assertLibrary(aState); |
| }); |
| |
| // Refreshing `a.dart` does not update the part. |
| aState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| kind.assertLibrary(aState); |
| }); |
| |
| // Exclude the part from `a.dart`, but the URI in `part of` still resolves |
| // to `a.dart`, so no changes. |
| newFile(a.path, ''); |
| aState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.library, isNull); |
| }); |
| |
| // Exclude the part from `b.dart`, no changes. |
| newFile(b.path, ''); |
| bState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.library, isNull); |
| }); |
| |
| // Include into `b.dart`, no changes. |
| newFile(b.path, r''' |
| part 'c.dart'; |
| '''); |
| bState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.library, isNull); |
| }); |
| |
| // Include into `a.dart`, no changes. |
| newFile(a.path, r''' |
| part 'c.dart'; |
| '''); |
| aState.refresh(); |
| cState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_refresh_augmentation_to_library() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Make it a library. |
| newFile(b.path, ''); |
| |
| // Not an augmentation anymore, but a library. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| |
| // But `a.dart` still uses `b.dart` as an augmentation. |
| _assertAugmentationFiles(aState, [b]); |
| |
| // ...even if we attempt to refresh. |
| aState.refresh(); |
| _assertAugmentationFiles(aState, [b]); |
| } |
| |
| test_refresh_augmentation_to_partOfName() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| library my.lib; |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Make it a part. |
| newFile(b.path, r''' |
| part of my.lib; |
| '''); |
| |
| // Not an augmentation anymore, but a part. |
| // This part can find the referenced library by name `my.lib`. |
| // But the library does not include this part, so no library. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState]); |
| expect(kind.library, isNull); |
| }); |
| |
| // But `a.dart` still uses `b.dart` as an augmentation. |
| _assertAugmentationFiles(aState, [b]); |
| _assertPartedFiles(aState, []); |
| |
| // ...even if we attempt to refresh. |
| aState.refresh(); |
| _assertAugmentationFiles(aState, [b]); |
| _assertPartedFiles(aState, []); |
| |
| // Now include `b.dart` into `a.dart` as a part. |
| newFile(a.path, r''' |
| library my.lib; |
| part 'b.dart'; |
| '''); |
| aState.refresh(); |
| |
| // ...not an augmentation, but a known part. |
| _assertAugmentationFiles(aState, []); |
| _assertPartedFiles(aState, [b]); |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState]); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_refresh_augmentation_to_partOfUri() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library augment 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // Make it a part. |
| newFile(b.path, r''' |
| part of 'a.dart'; |
| '''); |
| |
| // Not an augmentation anymore, but a part. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| expect(kind.library, isNull); |
| }); |
| |
| // But `a.dart` still uses `b.dart` as an augmentation. |
| _assertAugmentationFiles(aState, [b]); |
| _assertPartedFiles(aState, []); |
| |
| // ...even if we attempt to refresh. |
| aState.refresh(); |
| _assertAugmentationFiles(aState, [b]); |
| _assertPartedFiles(aState, []); |
| |
| // Now include `b.dart` into `a.dart` as a part. |
| newFile(a.path, r''' |
| part 'b.dart'; |
| '''); |
| aState.refresh(); |
| |
| // ...not an augmentation, but a known part. |
| _assertAugmentationFiles(aState, []); |
| _assertPartedFiles(aState, [b]); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| } |
| |
| test_refresh_library_removePart_partOfName() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part of my; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of my; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library my; |
| part 'a.dart'; |
| part 'b.dart'; |
| '''); |
| |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my'); |
| }); |
| _assertPartedFiles(cState, [a, b]); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| // Both part files know the library. |
| aState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([cState]); |
| kind.assertLibrary(cState); |
| }); |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([cState]); |
| kind.assertLibrary(cState); |
| }); |
| |
| newFile(c.path, r''' |
| library my; |
| part 'b.dart'; |
| '''); |
| |
| // Stop referencing `a.dart` part file. |
| cState.refresh(); |
| _assertPartedFiles(cState, [b]); |
| |
| // The library does not include `a.dart` as a part anymore. |
| // The part `b.dart` is still connected. |
| aState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([cState]); |
| expect(kind.library, isNull); |
| }); |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([cState]); |
| kind.assertLibrary(cState); |
| }); |
| } |
| |
| test_refresh_library_removePart_partOfUri() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part of 'c.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of 'c.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library my; |
| part 'a.dart'; |
| part 'b.dart'; |
| '''); |
| |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my'); |
| }); |
| _assertPartedFiles(cState, [a, b]); |
| |
| final aState = fileStateFor(a); |
| final bState = fileStateFor(b); |
| |
| // Both part files know the library. |
| aState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, cState); |
| kind.assertLibrary(cState); |
| }); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, cState); |
| kind.assertLibrary(cState); |
| }); |
| |
| newFile(c.path, r''' |
| library my; |
| part 'b.dart'; |
| '''); |
| |
| // Stop referencing `a.dart` part file. |
| cState.refresh(); |
| _assertPartedFiles(cState, [b]); |
| |
| // But the URIs in the `part of URI` are still the same. |
| // So, both parts are still linked to the library. |
| aState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(cState)); |
| expect(kind.library, isNull); |
| }); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, cState); |
| kind.assertLibrary(cState); |
| }); |
| } |
| |
| test_refresh_library_to_augmentation() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| import augment 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library b; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertAugmentationFiles(aState, [b]); |
| |
| // TODO(scheglov) Restore. |
| // final aCycle_1 = aState.libraryCycle; |
| |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'b'); |
| }); |
| |
| newFile(b.path, r''' |
| library augment 'a.dart'; |
| '''); |
| |
| // We will discover the target by URI. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as AugmentationKnownFileStateKind; |
| kind.assertAugmented(aState); |
| kind.assertLibrary(aState); |
| }); |
| |
| // The file `b.dart` was something else, but now it is a known augmentation. |
| // This affects libraries that include it. |
| // TODO(scheglov) Restore. |
| // final aCycle_2 = aState.libraryCycle; |
| // expect(aCycle_2.apiSignature, isNot(aCycle_1.apiSignature)); |
| } |
| |
| test_refresh_library_to_partOfName() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| library my.lib; |
| part 'b.dart'; |
| '''); |
| |
| // No `part of`, so it is a library. |
| final b = newFile('$testPackageLibPath/b.dart', ''); |
| |
| final aState = fileStateFor(a); |
| _assertPartedFiles(aState, [b]); |
| |
| final aCycle_1 = aState.libraryCycle; |
| |
| // No `part of`, so it is a library. |
| // It does not matter, that `a.dart` tried to use it as part. |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| |
| // Make it a part. |
| newFile(b.path, r''' |
| part of my.lib; |
| '''); |
| |
| // We will discover the library by name. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| kind.assertLibraries([aState]); |
| kind.assertLibrary(aState); |
| }); |
| |
| // The file `b.dart` was something else, but now it is a known part. |
| // This affects libraries that include it. |
| final aCycle_2 = aState.libraryCycle; |
| expect(aCycle_2.apiSignature, isNot(aCycle_1.apiSignature)); |
| } |
| |
| test_refresh_library_to_partOfName_noLibrary() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| library my; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my'); |
| }); |
| |
| newFile(a.path, r''' |
| part of my; |
| '''); |
| |
| aState.refresh(); |
| |
| // No library that includes it, so it stays unknown. |
| aState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| expect(kind.directive.name, 'my'); |
| kind.assertLibraries([]); |
| expect(kind.library, isNull); |
| }); |
| } |
| |
| test_refresh_library_to_partOfUri() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library b; |
| '''); |
| |
| final aState = fileStateFor(a); |
| _assertPartedFiles(aState, [b]); |
| |
| final aCycle_1 = aState.libraryCycle; |
| |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'b'); |
| }); |
| |
| newFile(b.path, r''' |
| part of 'a.dart'; |
| '''); |
| |
| // We will discover the library using the URI. |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| |
| // The file `b.dart` was something else, but now it is a known part. |
| // This affects libraries that include it. |
| final aCycle_2 = aState.libraryCycle; |
| expect(aCycle_2.apiSignature, isNot(aCycle_1.apiSignature)); |
| } |
| |
| test_refresh_partOfName_twoLibraries() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part of my.lib; |
| class A1 {} |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| library my.lib; |
| part 'a.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| library my.lib; |
| part 'a.dart'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my.lib'); |
| }); |
| _assertPartedFiles(bState, [a]); |
| |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, 'my.lib'); |
| }); |
| _assertPartedFiles(cState, [a]); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| expect(kind.directive.name, 'my.lib'); |
| kind.assertLibraries([bState, cState]); |
| kind.assertLibrary(bState); |
| }); |
| |
| final bCycle_1 = bState.libraryCycle; |
| final cCycle_1 = cState.libraryCycle; |
| |
| // Update `a.dart` part. |
| newFile(a.path, r''' |
| part of my.lib; |
| class A2 {} |
| '''); |
| aState.refresh(); |
| // `a.dart` is still a part. |
| aState.assertKind((kind) { |
| kind as PartOfNameFileStateKind; |
| expect(kind.directive.name, 'my.lib'); |
| kind.assertLibraries([bState, cState]); |
| kind.assertLibrary(bState); |
| }); |
| |
| // ...but the unlinked signature of `a.dart` is different. |
| // We invalidate `b.dart` it references `a.dart`. |
| // We invalidate `c.dart` it references `a.dart`. |
| // Even though `a.dart` is not a valid part of `c.dart`. |
| final bCycle_2 = bState.libraryCycle; |
| final cCycle_2 = cState.libraryCycle; |
| expect(bCycle_2.apiSignature, isNot(bCycle_1.apiSignature)); |
| expect(cCycle_2.apiSignature, isNot(cCycle_1.apiSignature)); |
| } |
| |
| test_refresh_partOfUri_to_library() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part 'b.dart'; |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part of 'a.dart'; |
| '''); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| _assertPartedFiles(aState, [b]); |
| |
| final aCycle_1 = aState.libraryCycle; |
| |
| // There is `part of` in `b.dart`, so it is a part. |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(aState)); |
| kind.assertLibrary(aState); |
| }); |
| |
| // There are no directives in `b.dart`, so it is a library. |
| newFile(b.path, r''' |
| // no part of |
| '''); |
| bState.refresh(); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| |
| // Library `a.dart` still considers `b.dart` its part. |
| _assertPartedFiles(aState, [b]); |
| |
| // The library cycle for `a.dart` is different now. |
| final aCycle_2 = aState.libraryCycle; |
| expect(aCycle_2.apiSignature, isNot(aCycle_1.apiSignature)); |
| } |
| |
| test_refresh_partOfUri_twoLibraries() async { |
| final a = newFile('$testPackageLibPath/a.dart', r''' |
| part of 'b.dart'; |
| class A1 {} |
| '''); |
| |
| final b = newFile('$testPackageLibPath/b.dart', r''' |
| part 'a.dart'; |
| '''); |
| |
| final c = newFile('$testPackageLibPath/c.dart', r''' |
| part 'a.dart'; |
| '''); |
| |
| final bState = fileStateFor(b); |
| bState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| _assertPartedFiles(bState, [a]); |
| |
| final cState = fileStateFor(c); |
| cState.assertKind((kind) { |
| kind as LibraryFileStateKind; |
| expect(kind.name, isNull); |
| }); |
| _assertPartedFiles(cState, [a]); |
| |
| final aState = fileStateFor(a); |
| aState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(bState)); |
| kind.assertLibrary(bState); |
| }); |
| |
| final bCycle_1 = bState.libraryCycle; |
| final cCycle_1 = cState.libraryCycle; |
| |
| // Update `a.dart` part. |
| newFile(a.path, r''' |
| part of 'b.dart'; |
| class A2 {} |
| '''); |
| aState.refresh(); |
| // `a.dart` is still a part. |
| aState.assertKind((kind) { |
| kind as PartOfUriKnownFileStateKind; |
| expect(kind.uriFile, same(bState)); |
| kind.assertLibrary(bState); |
| }); |
| |
| // ...but the unlinked signature of `a.dart` is different. |
| // We invalidate `b.dart` it references `a.dart`. |
| // We invalidate `c.dart` it references `a.dart`. |
| // Even though `a.dart` is not a valid part of `c.dart`. |
| final bCycle_2 = bState.libraryCycle; |
| final cCycle_2 = cState.libraryCycle; |
| expect(bCycle_2.apiSignature, isNot(bCycle_1.apiSignature)); |
| expect(cCycle_2.apiSignature, isNot(cCycle_1.apiSignature)); |
| } |
| |
| void _assertAugmentationFiles(FileState fileState, List<File> expected) { |
| final actualFiles = fileState.augmentationFiles.map((part) { |
| if (part != null) { |
| return getFile(part.path); |
| } |
| }).toList(); |
| expect(actualFiles, expected); |
| } |
| |
| void _assertPartedFiles(FileState fileState, List<File> expected) { |
| final actualFiles = fileState.partedFiles.map((part) { |
| if (part != null) { |
| return getFile(part.path); |
| } |
| }).toList(); |
| expect(actualFiles, expected); |
| } |
| |
| Future<File> _writeSdkSummary() async { |
| final file = getFile('/home/summaries/sdk.sum'); |
| final bytes = await buildSdkSummary2( |
| resourceProvider: resourceProvider, |
| sdkPath: sdkRoot.path, |
| ); |
| file.writeAsBytesSync(bytes); |
| return file; |
| } |
| } |
| |
| @reflectiveTest |
| class FileSystemStateTest with ResourceProviderMixin { |
| final ByteStore byteStore = MemoryByteStore(); |
| final FileContentOverlay contentOverlay = FileContentOverlay(); |
| |
| final StringBuffer logBuffer = StringBuffer(); |
| final _GeneratedUriResolverMock generatedUriResolver = |
| _GeneratedUriResolverMock(); |
| late final SourceFactory sourceFactory; |
| late final PerformanceLog logger; |
| |
| late final FileSystemState fileSystemState; |
| |
| void setUp() { |
| logger = PerformanceLog(logBuffer); |
| |
| var sdkRoot = newFolder('/sdk'); |
| createMockSdk( |
| resourceProvider: resourceProvider, |
| root: sdkRoot, |
| ); |
| var sdk = FolderBasedDartSdk(resourceProvider, sdkRoot); |
| |
| var packageMap = <String, List<Folder>>{ |
| 'aaa': [getFolder('/aaa/lib')], |
| 'bbb': [getFolder('/bbb/lib')], |
| }; |
| |
| var packages = Packages({ |
| 'aaa': Package( |
| name: 'aaa', |
| rootFolder: newFolder('/packages/aaa'), |
| libFolder: newFolder('/packages/aaa/lib'), |
| languageVersion: null, |
| ), |
| 'bbb': Package( |
| name: 'bbb', |
| rootFolder: newFolder('/packages/bbb'), |
| libFolder: newFolder('/packages/bbb/lib'), |
| languageVersion: null, |
| ), |
| }); |
| |
| var workspace = BasicWorkspace.find( |
| resourceProvider, |
| packages, |
| convertPath('/test'), |
| ); |
| |
| sourceFactory = SourceFactory([ |
| DartUriResolver(sdk), |
| generatedUriResolver, |
| PackageMapUriResolver(resourceProvider, packageMap), |
| ResourceUriResolver(resourceProvider) |
| ]); |
| |
| AnalysisOptions analysisOptions = AnalysisOptionsImpl(); |
| var featureSetProvider = FeatureSetProvider.build( |
| sourceFactory: sourceFactory, |
| resourceProvider: resourceProvider, |
| packages: Packages.empty, |
| packageDefaultFeatureSet: FeatureSet.latestLanguageVersion(), |
| nonPackageDefaultLanguageVersion: ExperimentStatus.currentVersion, |
| nonPackageDefaultFeatureSet: FeatureSet.latestLanguageVersion(), |
| ); |
| fileSystemState = FileSystemState( |
| logger, |
| byteStore, |
| resourceProvider, |
| 'contextName', |
| sourceFactory, |
| workspace, |
| analysisOptions, |
| DeclaredVariables(), |
| Uint32List(0), |
| Uint32List(0), |
| featureSetProvider, |
| fileContentStrategy: StoredFileContentStrategy( |
| FileContentCache.ephemeral(resourceProvider), |
| ), |
| prefetchFiles: null, |
| isGenerated: (_) => false, |
| testData: null, |
| ); |
| } |
| |
| test_definedClassMemberNames() { |
| String path = convertPath('/aaa/lib/a.dart'); |
| newFile(path, r''' |
| class A { |
| int a, b; |
| A(); |
| A.c(); |
| d() {} |
| get e => null; |
| set f(_) {} |
| } |
| class B { |
| g() {} |
| } |
| '''); |
| FileState file = fileSystemState.getFileForPath(path); |
| expect(file.definedClassMemberNames, |
| unorderedEquals(['a', 'b', 'd', 'e', 'f', 'g'])); |
| } |
| |
| test_definedClassMemberNames_enum() { |
| String path = convertPath('/aaa/lib/a.dart'); |
| newFile(path, r''' |
| enum E1 { |
| v1; |
| int field1, field2; |
| const E1(); |
| const E1.namedConstructor(); |
| void method() {} |
| get getter => 0; |
| set setter(_) {} |
| } |
| |
| enum E2 { |
| v2; |
| get getter2 => 0; |
| } |
| '''); |
| FileState file = fileSystemState.getFileForPath(path); |
| expect( |
| file.definedClassMemberNames, |
| unorderedEquals([ |
| 'v1', |
| 'field1', |
| 'field2', |
| 'method', |
| 'getter', |
| 'setter', |
| 'v2', |
| 'getter2', |
| ]), |
| ); |
| } |
| |
| test_definedTopLevelNames() { |
| String path = convertPath('/aaa/lib/a.dart'); |
| newFile(path, r''' |
| class A {} |
| class B = Object with A; |
| typedef C(); |
| D() {} |
| get E => null; |
| set F(_) {} |
| var G, H; |
| '''); |
| FileState file = fileSystemState.getFileForPath(path); |
| expect(file.definedTopLevelNames, |
| unorderedEquals(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])); |
| } |
| |
| test_getFileForPath_emptyUri() { |
| String path = convertPath('/test.dart'); |
| newFile(path, r''' |
| import ''; |
| export ''; |
| part ''; |
| '''); |
| |
| FileState file = fileSystemState.getFileForPath(path); |
| _assertIsUnresolvedFile(file.importedFiles[0]); |
| _assertIsUnresolvedFile(file.exportedFiles[0]); |
| _assertIsUnresolvedFile(file.partedFiles[0]); |
| } |
| |
| test_getFileForPath_hasLibraryDirective_hasPartOfDirective() { |
| String a = convertPath('/test/lib/a.dart'); |
| newFile(a, r''' |
| library L; |
| part of L; |
| '''); |
| FileState file = fileSystemState.getFileForPath(a); |
| expect(file.isPart, isFalse); |
| } |
| |
| test_getFileForPath_invalidUri() { |
| String a = convertPath('/aaa/lib/a.dart'); |
| String a1 = convertPath('/aaa/lib/a1.dart'); |
| String a2 = convertPath('/aaa/lib/a2.dart'); |
| String a3 = convertPath('/aaa/lib/a3.dart'); |
| String content_a1 = r''' |
| import 'package:aaa/a1.dart'; |
| import ':[invalid uri]'; |
| |
| export 'package:aaa/a2.dart'; |
| export ':[invalid uri]'; |
| |
| part 'a3.dart'; |
| part ':[invalid uri]'; |
| '''; |
| newFile(a, content_a1); |
| |
| FileState file = fileSystemState.getFileForPath(a); |
| |
| expect(_excludeSdk(file.importedFiles), hasLength(2)); |
| expect(file.importedFiles[0]!.path, a1); |
| expect(file.importedFiles[0]!.uri, Uri.parse('package:aaa/a1.dart')); |
| expect(file.importedFiles[0]!.source, isNotNull); |
| _assertIsUnresolvedFile(file.importedFiles[1]); |
| |
| expect(_excludeSdk(file.exportedFiles), hasLength(2)); |
| expect(file.exportedFiles[0]!.path, a2); |
| expect(file.exportedFiles[0]!.uri, Uri.parse('package:aaa/a2.dart')); |
| expect(file.exportedFiles[0]!.source, isNotNull); |
| _assertIsUnresolvedFile(file.exportedFiles[1]); |
| |
| expect(_excludeSdk(file.partedFiles), hasLength(2)); |
| expect(file.partedFiles[0]!.path, a3); |
| expect(file.partedFiles[0]!.uri, Uri.parse('package:aaa/a3.dart')); |
| expect(file.partedFiles[0]!.source, isNotNull); |
| _assertIsUnresolvedFile(file.partedFiles[1]); |
| } |
| |
| test_getFileForPath_onlyDartFiles() { |
| String not_dart = convertPath('/test/lib/not_dart.txt'); |
| String a = convertPath('/test/lib/a.dart'); |
| String b = convertPath('/test/lib/b.dart'); |
| String c = convertPath('/test/lib/c.dart'); |
| String d = convertPath('/test/lib/d.dart'); |
| newFile(a, r''' |
| library lib; |
| import 'dart:math'; |
| import 'b.dart'; |
| import 'not_dart.txt'; |
| export 'c.dart'; |
| export 'not_dart.txt'; |
| part 'd.dart'; |
| part 'not_dart.txt'; |
| '''); |
| FileState file = fileSystemState.getFileForPath(a); |
| expect(_excludeSdk(file.importedFiles).map((f) => f!.path), [b, not_dart]); |
| expect(file.exportedFiles.map((f) => f!.path), [c, not_dart]); |
| expect(file.partedFiles.map((f) => f!.path), [d, not_dart]); |
| expect(_excludeSdk(fileSystemState.knownFilePaths), |
| unorderedEquals([a, b, c, d, not_dart])); |
| } |
| |
| test_getFileForPath_samePath() { |
| String path = convertPath('/aaa/lib/a.dart'); |
| FileState file1 = fileSystemState.getFileForPath(path); |
| FileState file2 = fileSystemState.getFileForPath(path); |
| expect(file2, same(file1)); |
| } |
| |
| test_getFileForUri_invalidUri() { |
| var uri = Uri.parse('package:x'); |
| fileSystemState.getFileForUri(uri).map( |
| (file) { |
| expect(file, isNull); |
| }, |
| (_) { |
| fail('Expected null.'); |
| }, |
| ); |
| } |
| |
| test_getFilesSubtypingName_class() { |
| String a = convertPath('/a.dart'); |
| String b = convertPath('/b.dart'); |
| |
| newFile(a, r''' |
| class A {} |
| class B extends A {} |
| '''); |
| newFile(b, r''' |
| class A {} |
| class D implements A {} |
| '''); |
| |
| FileState aFile = fileSystemState.getFileForPath(a); |
| FileState bFile = fileSystemState.getFileForPath(b); |
| |
| expect( |
| fileSystemState.getFilesSubtypingName('A'), |
| unorderedEquals([aFile, bFile]), |
| ); |
| |
| // Change b.dart so that it does not subtype A. |
| newFile(b, r''' |
| class C {} |
| class D implements C {} |
| '''); |
| bFile.refresh(); |
| expect( |
| fileSystemState.getFilesSubtypingName('A'), |
| unorderedEquals([aFile]), |
| ); |
| expect( |
| fileSystemState.getFilesSubtypingName('C'), |
| unorderedEquals([bFile]), |
| ); |
| } |
| |
| test_getFilesSubtypingName_enum_implements() { |
| String a = convertPath('/a.dart'); |
| String b = convertPath('/b.dart'); |
| |
| newFile(a, r''' |
| class A {} |
| enum E1 implements A { |
| v |
| } |
| '''); |
| newFile(b, r''' |
| class A {} |
| enum E2 implements A { |
| v |
| } |
| '''); |
| |
| FileState aFile = fileSystemState.getFileForPath(a); |
| FileState bFile = fileSystemState.getFileForPath(b); |
| |
| expect( |
| fileSystemState.getFilesSubtypingName('A'), |
| unorderedEquals([aFile, bFile]), |
| ); |
| |
| // Change b.dart so that it does not subtype A. |
| newFile(b, r''' |
| class C {} |
| enum E2 implements C { |
| v |
| } |
| '''); |
| bFile.refresh(); |
| expect( |
| fileSystemState.getFilesSubtypingName('A'), |
| unorderedEquals([aFile]), |
| ); |
| expect( |
| fileSystemState.getFilesSubtypingName('C'), |
| unorderedEquals([bFile]), |
| ); |
| } |
| |
| test_getFilesSubtypingName_enum_with() { |
| String a = convertPath('/a.dart'); |
| String b = convertPath('/b.dart'); |
| |
| newFile(a, r''' |
| mixin M {} |
| enum E1 with M { |
| v |
| } |
| '''); |
| newFile(b, r''' |
| mixin M {} |
| enum E2 with M { |
| v |
| } |
| '''); |
| |
| FileState aFile = fileSystemState.getFileForPath(a); |
| FileState bFile = fileSystemState.getFileForPath(b); |
| |
| expect( |
| fileSystemState.getFilesSubtypingName('M'), |
| unorderedEquals([aFile, bFile]), |
| ); |
| } |
| |
| test_hasUri() { |
| Uri uri = Uri.parse('package:aaa/foo.dart'); |
| String templatePath = convertPath('/aaa/lib/foo.dart'); |
| String generatedPath = convertPath('/generated/aaa/lib/foo.dart'); |
| |
| Source generatedSource = _SourceMock(generatedPath, uri); |
| |
| generatedUriResolver.resolveAbsoluteFunction = (uri) => generatedSource; |
| |
| expect(fileSystemState.hasUri(templatePath), isFalse); |
| expect(fileSystemState.hasUri(generatedPath), isTrue); |
| } |
| |
| test_libraryCycle() { |
| String pa = convertPath('/aaa/lib/a.dart'); |
| String pb = convertPath('/aaa/lib/b.dart'); |
| String pc = convertPath('/aaa/lib/c.dart'); |
| String pd = convertPath('/aaa/lib/d.dart'); |
| |
| FileState fa = fileSystemState.getFileForPath(pa); |
| FileState fb = fileSystemState.getFileForPath(pb); |
| FileState fc = fileSystemState.getFileForPath(pc); |
| FileState fd = fileSystemState.getFileForPath(pd); |
| |
| // Compute library cycles for all files. |
| fa.libraryCycle; |
| fb.libraryCycle; |
| fc.libraryCycle; |
| fd.libraryCycle; |
| _assertFilesWithoutLibraryCycle([]); |
| |
| // No imports, so just a single file. |
| newFile(pa, ''); |
| _assertLibraryCycle(fa, [fa], []); |
| |
| // Import b.dart into a.dart, two files now. |
| newFile(pa, "import 'b.dart';"); |
| fa.refresh(); |
| _assertFilesWithoutLibraryCycle([fa]); |
| _assertLibraryCycle(fa, [fa], [fb.libraryCycle]); |
| |
| // Update b.dart so that it imports c.dart now. |
| newFile(pb, "import 'c.dart';"); |
| fb.refresh(); |
| _assertFilesWithoutLibraryCycle([fa, fb]); |
| _assertLibraryCycle(fa, [fa], [fb.libraryCycle]); |
| _assertLibraryCycle(fb, [fb], [fc.libraryCycle]); |
| _assertFilesWithoutLibraryCycle([]); |
| |
| // Update b.dart so that it exports d.dart instead. |
| newFile(pb, "export 'd.dart';"); |
| fb.refresh(); |
| _assertFilesWithoutLibraryCycle([fa, fb]); |
| _assertLibraryCycle(fa, [fa], [fb.libraryCycle]); |
| _assertLibraryCycle(fb, [fb], [fd.libraryCycle]); |
| _assertFilesWithoutLibraryCycle([]); |
| |
| // Update a.dart so that it does not import b.dart anymore. |
| newFile(pa, ''); |
| fa.refresh(); |
| _assertFilesWithoutLibraryCycle([fa]); |
| _assertLibraryCycle(fa, [fa], []); |
| } |
| |
| test_libraryCycle_cycle() { |
| String pa = convertPath('/aaa/lib/a.dart'); |
| String pb = convertPath('/aaa/lib/b.dart'); |
| |
| newFile(pa, "import 'b.dart';"); |
| newFile(pb, "import 'a.dart';"); |
| |
| FileState fa = fileSystemState.getFileForPath(pa); |
| FileState fb = fileSystemState.getFileForPath(pb); |
| |
| // Compute library cycles for all files. |
| fa.libraryCycle; |
| fb.libraryCycle; |
| _assertFilesWithoutLibraryCycle([]); |
| |
| // It's a cycle. |
| _assertLibraryCycle(fa, [fa, fb], []); |
| _assertLibraryCycle(fb, [fa, fb], []); |
| expect(fa.libraryCycle, same(fb.libraryCycle)); |
| |
| // Update a.dart so that it does not import b.dart anymore. |
| newFile(pa, ''); |
| fa.refresh(); |
| _assertFilesWithoutLibraryCycle([fa, fb]); |
| _assertLibraryCycle(fa, [fa], []); |
| _assertLibraryCycle(fb, [fb], [fa.libraryCycle]); |
| } |
| |
| test_libraryCycle_invalidPart_withPart() { |
| var pa = convertPath('/aaa/lib/a.dart'); |
| |
| newFile(pa, r''' |
| part of lib; |
| part 'a.dart'; |
| '''); |
| |
| var fa = fileSystemState.getFileForPath(pa); |
| |
| _assertLibraryCycle(fa, [fa], []); |
| } |
| |
| test_libraryCycle_part() { |
| var a_path = convertPath('/aaa/lib/a.dart'); |
| var b_path = convertPath('/aaa/lib/b.dart'); |
| |
| newFile(a_path, r''' |
| part 'b.dart'; |
| '''); |
| newFile(b_path, r''' |
| part of 'a.dart'; |
| '''); |
| |
| var a_file = fileSystemState.getFileForPath(a_path); |
| var b_file = fileSystemState.getFileForPath(b_path); |
| _assertFilesWithoutLibraryCycle([a_file, b_file]); |
| |
| // Compute the library cycle for 'a.dart', the library. |
| var a_libraryCycle = a_file.libraryCycle; |
| _assertFilesWithoutLibraryCycle([b_file]); |
| |
| // The part 'b.dart' has its own library cycle. |
| // If the user chooses to import a part, it is a compile-time error. |
| // We could handle this in different ways: |
| // 1. Completely ignore an import of a file with a `part of` directive. |
| // 2. Treat such file as a library anyway. |
| // By giving a part its own library cycle we support (2). |
| var b_libraryCycle = b_file.libraryCycle; |
| expect(b_libraryCycle, isNot(same(a_libraryCycle))); |
| _assertFilesWithoutLibraryCycle([]); |
| } |
| |
| test_referencedNames() { |
| String path = convertPath('/aaa/lib/a.dart'); |
| newFile(path, r''' |
| A foo(B p) { |
| foo(null); |
| C c = new C(p); |
| return c; |
| } |
| '''); |
| FileState file = fileSystemState.getFileForPath(path); |
| expect(file.referencedNames, unorderedEquals(['A', 'B', 'C'])); |
| } |
| |
| test_refresh_differentApiSignature() { |
| String path = convertPath('/aaa/lib/a.dart'); |
| newFile(path, r''' |
| class A {} |
| '''); |
| FileState file = fileSystemState.getFileForPath(path); |
| expect(file.definedTopLevelNames, contains('A')); |
| List<int> signature = file.apiSignature; |
| |
| // Update the resource and refresh the file state. |
| newFile(path, r''' |
| class B {} |
| '''); |
| final changeKind = file.refresh(); |
| expect(changeKind, FileStateRefreshResult.apiChanged); |
| |
| expect(file.definedTopLevelNames, contains('B')); |
| expect(file.apiSignature, isNot(signature)); |
| } |
| |
| test_refresh_sameApiSignature() { |
| String path = convertPath('/aaa/lib/a.dart'); |
| newFile(path, r''' |
| class C { |
| foo() { |
| print(111); |
| } |
| } |
| '''); |
| FileState file = fileSystemState.getFileForPath(path); |
| List<int> signature = file.apiSignature; |
| |
| // Update the resource and refresh the file state. |
| newFile(path, r''' |
| class C { |
| foo() { |
| print(222); |
| } |
| } |
| '''); |
| final changeKind = file.refresh(); |
| expect(changeKind, FileStateRefreshResult.contentChanged); |
| |
| expect(file.apiSignature, signature); |
| } |
| |
| test_store_zeroLengthUnlinked() { |
| String path = convertPath('/test.dart'); |
| newFile(path, 'class A {}'); |
| |
| // Get the file, prepare unlinked. |
| FileState file = fileSystemState.getFileForPath(path); |
| expect(file.unlinked2, isNotNull); |
| |
| // Make the unlinked unit in the byte store zero-length, damaged. |
| byteStore.putGet(file.test.unlinkedKey, Uint8List(0)); |
| |
| // Refresh should not fail, zero bytes in the store are ignored. |
| file.refresh(); |
| expect(file.unlinked2, isNotNull); |
| } |
| |
| test_subtypedNames() { |
| String path = convertPath('/test.dart'); |
| newFile(path, r''' |
| class X extends A {} |
| class Y extends A with B {} |
| class Z implements C, D {} |
| '''); |
| FileState file = fileSystemState.getFileForPath(path); |
| expect(file.referencedNames, unorderedEquals(['A', 'B', 'C', 'D'])); |
| } |
| |
| test_transitiveSignature() { |
| String pa = convertPath('/aaa/lib/a.dart'); |
| String pb = convertPath('/aaa/lib/b.dart'); |
| String pc = convertPath('/aaa/lib/c.dart'); |
| String pd = convertPath('/aaa/lib/d.dart'); |
| |
| newFile(pa, "class A {}"); |
| newFile(pb, "import 'a.dart';"); |
| newFile(pc, "import 'b.dart';"); |
| newFile(pd, "class D {}"); |
| |
| FileState fa = fileSystemState.getFileForPath(pa); |
| FileState fb = fileSystemState.getFileForPath(pb); |
| FileState fc = fileSystemState.getFileForPath(pc); |
| FileState fd = fileSystemState.getFileForPath(pd); |
| |
| // Compute transitive closures for all files. |
| // This implicitly computes library cycles. |
| expect(fa.transitiveSignature, isNotNull); |
| expect(fb.transitiveSignature, isNotNull); |
| expect(fc.transitiveSignature, isNotNull); |
| expect(fd.transitiveSignature, isNotNull); |
| _assertFilesWithoutLibraryCycle([]); |
| |
| // Make an update to a.dart that does not change its API signature. |
| // All library cycles are still valid. |
| newFile(pa, "class A {} // the same API signature"); |
| fa.refresh(); |
| _assertFilesWithoutLibraryCycle([]); |
| |
| // Change a.dart API signature. |
| // This flushes signatures of b.dart and c.dart, but d.dart is still OK. |
| newFile(pa, "class A2 {}"); |
| fa.refresh(); |
| _assertFilesWithoutLibraryCycle([fa, fb, fc]); |
| } |
| |
| test_transitiveSignature_part() { |
| var aPath = convertPath('/test/lib/a.dart'); |
| var bPath = convertPath('/test/lib/b.dart'); |
| |
| newFile(aPath, r''' |
| part 'b.dart'; |
| '''); |
| newFile(bPath, ''' |
| part of 'a.dart'; |
| '''); |
| |
| var aFile = fileSystemState.getFileForPath(aPath); |
| var bFile = fileSystemState.getFileForPath(bPath); |
| |
| var aSignature = aFile.transitiveSignature; |
| var bSignature = bFile.transitiveSignature; |
| |
| // It is not valid to use a part as a library, and so ask its signature. |
| // But when this happens, we should compute the transitive signature anyway. |
| // And it should not be the signature of the containing library. |
| expect(bSignature, isNot(aSignature)); |
| } |
| |
| void _assertFilesWithoutLibraryCycle(List<FileState> expected) { |
| var actual = fileSystemState.test.filesWithoutLibraryCycle; |
| expect(_excludeSdk(actual), unorderedEquals(expected)); |
| } |
| |
| void _assertIsUnresolvedFile(FileState? file) { |
| expect(file, isNull); |
| } |
| |
| void _assertLibraryCycle( |
| FileState file, |
| List<FileState> expectedLibraries, |
| List<LibraryCycle> expectedDirectDependencies, |
| ) { |
| expect(file.libraryCycle.libraries, unorderedEquals(expectedLibraries)); |
| expect( |
| _excludeSdk(file.libraryCycle.directDependencies), |
| unorderedEquals(expectedDirectDependencies), |
| ); |
| } |
| |
| List<T> _excludeSdk<T>(Iterable<T> files) { |
| return files.where((file) { |
| if (file is LibraryCycle) { |
| return !file.libraries.any((file) => file.uri.isScheme('dart')); |
| } else if (file is FileState) { |
| return !file.uri.isScheme('dart'); |
| } else if (file == null) { |
| return true; |
| } else { |
| return !(file as String).startsWith(convertPath('/sdk')); |
| } |
| }).toList(); |
| } |
| } |
| |
| class _GeneratedUriResolverMock extends UriResolver { |
| Source? Function(Uri)? resolveAbsoluteFunction; |
| |
| Uri? Function(String)? pathToUriFunction; |
| |
| @override |
| noSuchMethod(Invocation invocation) { |
| throw StateError('Unexpected invocation of ${invocation.memberName}'); |
| } |
| |
| @override |
| Uri? pathToUri(String path) { |
| return pathToUriFunction?.call(path); |
| } |
| |
| @override |
| Source? resolveAbsolute(Uri uri) { |
| if (resolveAbsoluteFunction != null) { |
| return resolveAbsoluteFunction!(uri); |
| } |
| return null; |
| } |
| } |
| |
| class _SourceMock implements Source { |
| @override |
| final String fullName; |
| |
| @override |
| final Uri uri; |
| |
| _SourceMock(this.fullName, this.uri); |
| |
| @override |
| noSuchMethod(Invocation invocation) { |
| throw StateError('Unexpected invocation of ${invocation.memberName}'); |
| } |
| } |
| |
| extension on FileState { |
| void assertKind(void Function(FileStateKind kind) f) { |
| expect(kind.file, same(this)); |
| f(kind); |
| } |
| } |
| |
| extension on FileStateKind { |
| void assertLibrary(FileState expectedLibraryFile) { |
| final expectedKind = expectedLibraryFile.kind as LibraryFileStateKind; |
| expect(library, same(expectedKind)); |
| } |
| } |
| |
| extension on AugmentationKnownFileStateKind { |
| void assertAugmented(FileState expectedFile) { |
| // The expected file must be a valid augmentation target. |
| final expectedKind = expectedFile.kind as LibraryOrAugmentationFileKind; |
| |
| // Any valid augmentation target is always the URI target. |
| expect(uriFile, same(expectedFile)); |
| |
| // Check the augmentation target itself. |
| expect(augmented, same(expectedKind)); |
| } |
| } |
| |
| extension on PartOfNameFileStateKind { |
| void assertLibraries(Iterable<FileState> expectedFiles) { |
| final expectedKinds = expectedFiles.map((e) { |
| return e.kind as LibraryFileStateKind; |
| }).toList(); |
| expect(libraries, unorderedEquals(expectedKinds)); |
| } |
| } |
| |
| extension on CheckTarget<ImportDirectiveState> { |
| @useResult |
| CheckTarget<Source?> get importedLibrarySource { |
| return nest( |
| value.importedLibrarySource, |
| (selected) => 'importedLibrarySource ${valueStr(selected)}', |
| ); |
| } |
| |
| @useResult |
| CheckTarget<bool> get isSyntheticDartCoreImport { |
| return nest( |
| value.isSyntheticDartCoreImport, |
| (selected) => 'isSyntheticDartCoreImport ${valueStr(selected)}', |
| ); |
| } |
| |
| /// Is [ImportDirectiveWithFile], but not a library. |
| void isFile(FileState expected) { |
| this.isA<ImportDirectiveWithFile>() |
| ..importedFile.isIdenticalTo(expected) |
| ..importedSource.uri.isEqualTo(expected.uri) |
| ..importedLibrary.isNull |
| ..importedLibrarySource.isNull; |
| } |
| |
| /// Is [ImportDirectiveWithFile], and is a library. |
| void isLibrary(FileState expected) { |
| final expectedKind = expected.kind as LibraryFileStateKind; |
| this.isA<ImportDirectiveWithFile>() |
| ..importedFile.isIdenticalTo(expected) |
| ..importedSource.uri.isEqualTo(expected.uri) |
| ..importedLibrary.isNotNull.isIdenticalTo(expectedKind) |
| ..importedLibrarySource.isNotNull.uri.isEqualTo(expected.uri); |
| } |
| |
| /// Exactly [ImportDirectiveState], even the file is not known. |
| void isNotFile() { |
| hasExactType<ImportDirectiveState>(); |
| } |
| |
| void withInSummaryLibrary(Uri expected) { |
| this.isA<ImportDirectiveWithInSummarySource>() |
| ..importedSource.uri.isEqualTo(expected) |
| ..importedLibrarySource.isNotNull.uri.isEqualTo(expected); |
| } |
| |
| void withInSummaryNotLibrary(Uri expected) { |
| this.isA<ImportDirectiveWithInSummarySource>() |
| ..importedSource.uri.isEqualTo(expected) |
| ..importedLibrarySource.isNull; |
| } |
| } |
| |
| extension on CheckTarget<ExportDirectiveState> { |
| @useResult |
| CheckTarget<Source?> get exportedLibrarySource { |
| return nest( |
| value.exportedLibrarySource, |
| (selected) => 'exportedLibrarySource ${valueStr(selected)}', |
| ); |
| } |
| |
| /// Is [ExportDirectiveWithFile], but not a library. |
| void isFile(FileState expected) { |
| this.isA<ExportDirectiveWithFile>() |
| ..exportedFile.isIdenticalTo(expected) |
| ..exportedSource.uri.isEqualTo(expected.uri) |
| ..exportedLibrary.isNull |
| ..exportedLibrarySource.isNull; |
| } |
| |
| /// Is [ExportDirectiveWithFile], and is a library. |
| void isLibrary(FileState expected) { |
| final expectedKind = expected.kind as LibraryFileStateKind; |
| this.isA<ExportDirectiveWithFile>() |
| ..exportedFile.isIdenticalTo(expected) |
| ..exportedSource.uri.isEqualTo(expected.uri) |
| ..exportedLibrary.isIdenticalTo(expectedKind) |
| ..exportedLibrarySource.isNotNull.uri.isEqualTo(expected.uri); |
| } |
| |
| /// Exactly [ExportDirectiveState], even the file is not known. |
| void isNotFile() { |
| hasExactType<ExportDirectiveState>(); |
| } |
| |
| void withInSummaryLibrary(Uri expected) { |
| this.isA<ExportDirectiveWithInSummarySource>() |
| ..exportedSource.uri.isEqualTo(expected) |
| ..exportedLibrarySource.isNotNull.uri.isEqualTo(expected); |
| } |
| |
| void withInSummaryNotLibrary(Uri expected) { |
| this.isA<ExportDirectiveWithInSummarySource>() |
| ..exportedSource.uri.isEqualTo(expected) |
| ..exportedLibrarySource.isNull; |
| } |
| } |
| |
| extension on CheckTarget<ImportDirectiveWithFile> { |
| @useResult |
| CheckTarget<FileState> get importedFile { |
| return nest( |
| value.importedFile, |
| (selected) => 'importedFile ${valueStr(selected)}', |
| ); |
| } |
| |
| @useResult |
| CheckTarget<LibraryFileStateKind?> get importedLibrary { |
| return nest( |
| value.importedLibrary, |
| (selected) => 'importedLibrary ${valueStr(selected)}', |
| ); |
| } |
| |
| @useResult |
| CheckTarget<Source> get importedSource { |
| return nest( |
| value.importedSource, |
| (selected) => 'importedSource ${valueStr(selected)}', |
| ); |
| } |
| } |
| |
| extension on CheckTarget<ExportDirectiveWithFile> { |
| @useResult |
| CheckTarget<FileState> get exportedFile { |
| return nest( |
| value.exportedFile, |
| (selected) => 'exportedFile ${valueStr(selected)}', |
| ); |
| } |
| |
| @useResult |
| CheckTarget<LibraryFileStateKind?> get exportedLibrary { |
| return nest( |
| value.exportedLibrary, |
| (selected) => 'exportedLibrary ${valueStr(selected)}', |
| ); |
| } |
| |
| @useResult |
| CheckTarget<Source> get exportedSource { |
| return nest( |
| value.exportedSource, |
| (selected) => 'exportedSource ${valueStr(selected)}', |
| ); |
| } |
| } |
| |
| extension on CheckTarget<ImportDirectiveWithInSummarySource> { |
| @useResult |
| CheckTarget<InSummarySource> get importedSource { |
| return nest( |
| value.importedSource, |
| (selected) => 'importedSource ${valueStr(selected)}', |
| ); |
| } |
| } |
| |
| extension on CheckTarget<ExportDirectiveWithInSummarySource> { |
| @useResult |
| CheckTarget<InSummarySource> get exportedSource { |
| return nest( |
| value.exportedSource, |
| (selected) => 'exportedSource ${valueStr(selected)}', |
| ); |
| } |
| } |
| |
| extension on CheckTarget<Source> { |
| @useResult |
| CheckTarget<Uri> get uri { |
| return nest( |
| value.uri, |
| (selected) => 'uri ${valueStr(selected)}', |
| ); |
| } |
| } |
| |
| extension _Either2Extension<T1, T2> on Either2<T1, T2> { |
| T1 get t1 { |
| late T1 result; |
| map( |
| (t1) => result = t1, |
| (_) => throw 'Expected T1', |
| ); |
| return result; |
| } |
| } |