// Copyright (c) 2014, 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:async'; import 'package:analysis_server/src/context_manager.dart'; import 'package:analysis_server/src/plugin/notification_manager.dart'; import 'package:analysis_server/src/utilities/null_string_sink.dart'; import 'package:analyzer/error/error.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/instrumentation/instrumentation.dart'; import 'package:analyzer/source/error_processor.dart'; import 'package:analyzer/src/context/builder.dart'; import 'package:analyzer/src/context/context_root.dart'; import 'package:analyzer/src/dart/analysis/byte_store.dart'; import 'package:analyzer/src/dart/analysis/driver.dart'; import 'package:analyzer/src/dart/analysis/file_state.dart'; import 'package:analyzer/src/dart/analysis/performance_logger.dart'; import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart'; import 'package:analyzer/src/dart/analysis/session.dart'; import 'package:analyzer/src/error/codes.dart'; import 'package:analyzer/src/generated/engine.dart' hide AnalysisResult; import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/generated/source_io.dart'; import 'package:analyzer/src/services/lint.dart'; import 'package:analyzer/src/summary/summary_file_builder.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/glob.dart'; import 'package:linter/src/rules.dart'; import 'package:linter/src/rules/avoid_as.dart'; import 'package:path/path.dart' as path; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import 'package:watcher/watcher.dart'; import 'src/plugin/plugin_manager_test.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(AbstractContextManagerTest); defineReflectiveTests(ContextManagerWithNewOptionsTest); defineReflectiveTests(ContextManagerWithOldOptionsTest); }); } /// Wrapper around the test package's `fail` function. /// /// Unlike the test package's `fail` function, this function is not annotated /// with @alwaysThrows, so we can call it at the top of a test method without /// causing the rest of the method to be flagged as dead code. void _fail(String message) { fail(message); } @reflectiveTest class AbstractContextManagerTest extends ContextManagerTest { void test_contextsInAnalysisRoot_nestedContext() { String subProjPath = join(projPath, 'subproj'); Folder subProjFolder = resourceProvider.newFolder(subProjPath); resourceProvider.newFile(join(subProjPath, 'pubspec.yaml'), 'contents'); String subProjFilePath = join(subProjPath, 'file.dart'); resourceProvider.newFile(subProjFilePath, 'contents'); manager.setRoots([projPath], [], {}); // Make sure that there really are contexts for both the main project and // the subproject. Folder projectFolder = resourceProvider.getFolder(projPath); ContextInfo projContextInfo = manager.getContextInfoFor(projectFolder); expect(projContextInfo, isNotNull); expect(projContextInfo.folder, projectFolder); ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder); expect(subProjContextInfo, isNotNull); expect(subProjContextInfo.folder, subProjFolder); expect(projContextInfo.analysisDriver, isNot(equals(subProjContextInfo.analysisDriver))); // Check that getDriversInAnalysisRoot() works. List drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, isNotNull); expect(drivers, hasLength(2)); expect(drivers, contains(projContextInfo.analysisDriver)); expect(drivers, contains(subProjContextInfo.analysisDriver)); } @failingTest test_embedder_added() async { // NoSuchMethodError: The getter 'apiSignature' was called on null. // Receiver: null // Tried calling: apiSignature // dart:core Object.noSuchMethod // package:analyzer/src/dart/analysis/driver.dart 460:20 AnalysisDriver.configure // package:analysis_server/src/context_manager.dart 1043:16 ContextManagerImpl._checkForPackagespecUpdate // package:analysis_server/src/context_manager.dart 1553:5 ContextManagerImpl._handleWatchEvent //return super.test_embedder_added(); _fail('NoSuchMethodError'); // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/nope.dart'); String embedderPath = '$projPath/embedder'; newFile('$embedderPath/entry.dart'); String embedderSrcPath = '$projPath/embedder/src'; newFile('$embedderSrcPath/part.dart'); // Setup _embedder.yaml. newFile('$libPath/_embedder.yaml', content: r''' embedded_libs: "dart:foobar": "../embedder/entry.dart" "dart:typed_data": "../embedder/src/part" '''); Folder projectFolder = resourceProvider.newFolder(projPath); // NOTE that this is Not in our package path yet. // Setup context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Confirm that one driver / context was created. List drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, isNotNull); expect(drivers, hasLength(1)); // No embedded libs yet. expect(sourceFactory.forUri('dart:typed_data'), isNull); // Add .packages file that introduces a dependency with embedded libs. newFile('$projPath/.packages', content: r''' test_pack:lib/'''); await pumpEventQueue(); // Confirm that we still have just one driver / context. drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, isNotNull); expect(drivers, hasLength(1)); // Embedded lib should be defined now. expect(sourceFactory.forUri('dart:typed_data'), isNotNull); } test_embedder_packagespec() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/nope.dart'); String sdkExtPath = '$projPath/sdk_ext'; newFile('$sdkExtPath/entry.dart'); String sdkExtSrcPath = '$projPath/sdk_ext/src'; newFile('$sdkExtSrcPath/part.dart'); // Setup _embedder.yaml. newFile('$libPath/_embedder.yaml', content: r''' embedded_libs: "dart:foobar": "../sdk_ext/entry.dart" "dart:typed_data": "../sdk_ext/src/part" '''); // Setup .packages file newFile('$projPath/.packages', content: r''' test_pack:lib/'''); // Setup context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Confirm that one context was created. int count = manager .numberOfContextsInAnalysisRoot(resourceProvider.newFolder(projPath)); expect(count, equals(1)); var source = sourceFactory.forUri('dart:foobar'); expect(source, isNotNull); expect(source.fullName, convertPath('/my/proj/sdk_ext/entry.dart')); // We can't find dart:core because we didn't list it in our // embedded_libs map. expect(sourceFactory.forUri('dart:core'), isNull); // We can find dart:typed_data because we listed it in our // embedded_libs map. expect(sourceFactory.forUri('dart:typed_data'), isNotNull); } void test_isInAnalysisRoot_excluded() { // prepare paths String project = convertPath('/project'); String excludedFolder = convertPath('$project/excluded'); // set roots resourceProvider.newFolder(project); resourceProvider.newFolder(excludedFolder); manager.setRoots( [project], [excludedFolder], {}); // verify expect(manager.isInAnalysisRoot(convertPath('$excludedFolder/test.dart')), isFalse); } void test_isInAnalysisRoot_inNestedContext() { String subProjPath = join(projPath, 'subproj'); Folder subProjFolder = resourceProvider.newFolder(subProjPath); resourceProvider.newFile(join(subProjPath, 'pubspec.yaml'), 'contents'); String subProjFilePath = join(subProjPath, 'file.dart'); resourceProvider.newFile(subProjFilePath, 'contents'); manager.setRoots([projPath], [], {}); // Make sure that there really is a context for the subproject. ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder); expect(subProjContextInfo, isNotNull); expect(subProjContextInfo.folder, subProjFolder); // Check that isInAnalysisRoot() works. expect(manager.isInAnalysisRoot(subProjFilePath), isTrue); } void test_isInAnalysisRoot_inRoot() { manager.setRoots([projPath], [], {}); expect(manager.isInAnalysisRoot('$projPath/test.dart'), isTrue); } void test_isInAnalysisRoot_notInRoot() { manager.setRoots([projPath], [], {}); expect(manager.isInAnalysisRoot('/test.dart'), isFalse); } test_packagesFolder_areAnalyzed() { // create a context with a pubspec.yaml file String pubspecPath = join(projPath, 'pubspec.yaml'); resourceProvider.newFile(pubspecPath, 'pubspec'); // create a file in the "packages" folder String filePath1 = join(projPath, 'packages', 'file1.dart'); File file1 = resourceProvider.newFile(filePath1, 'contents'); manager.setRoots([projPath], [], {}); expect(callbacks.currentFilePaths, unorderedEquals([file1.path])); String filePath2 = join(projPath, 'packages', 'file2.dart'); File file2 = resourceProvider.newFile(filePath2, 'contents'); return pumpEventQueue().then((_) { expect(callbacks.currentFilePaths, unorderedEquals([file1.path, file2.path])); }); } test_path_filter() async { // Setup context. Folder root = resourceProvider.newFolder(projPath); manager.setRoots([projPath], [], {}); expect(callbacks.currentFilePaths, isEmpty); // Set ignore patterns for context. ContextInfo rootInfo = manager.getContextInfoFor(root); manager.setIgnorePatternsForContext( rootInfo, ['sdk_ext/**', 'lib/ignoreme.dart']); // Start creating files. newFile('$projPath/${ContextManagerImpl.PUBSPEC_NAME}'); String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/ignoreme.dart'); String sdkExtPath = '$projPath/sdk_ext'; newFile('$sdkExtPath/entry.dart'); String sdkExtSrcPath = '$projPath/sdk_ext/src'; newFile('$sdkExtSrcPath/part.dart'); // Pump event loop so new files are discovered and added to context. await pumpEventQueue(); // Verify that ignored files were ignored. Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(convertPath('/my/proj/lib/main.dart'))); } test_refresh_folder_with_packagespec() { // create a context with a .packages file String packagespecFile = join(projPath, '.packages'); resourceProvider.newFile(packagespecFile, ''); manager.setRoots([projPath], [], {}); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([projPath])); callbacks.now++; manager.refresh(null); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([projPath])); expect(callbacks.currentContextTimestamps[projPath], callbacks.now); }); }); } // TODO(paulberry): This test only tests PackagesFileDisposition. // Once http://dartbug.com/23909 is fixed, add a test for sdk extensions // and PackageMapDisposition. test_refresh_folder_with_packagespec_subfolders() { // Create a folder with no .packages file, containing two subfolders with // .packages files. String subdir1Path = join(projPath, 'subdir1'); String subdir2Path = join(projPath, 'subdir2'); String packagespec1Path = join(subdir1Path, '.packages'); String packagespec2Path = join(subdir2Path, '.packages'); resourceProvider.newFile(packagespec1Path, ''); resourceProvider.newFile(packagespec2Path, ''); manager.setRoots([projPath], [], {}); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([subdir1Path, subdir2Path, projPath])); callbacks.now++; manager.refresh(null); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([subdir1Path, subdir2Path, projPath])); expect(callbacks.currentContextTimestamps[projPath], callbacks.now); expect(callbacks.currentContextTimestamps[subdir1Path], callbacks.now); expect(callbacks.currentContextTimestamps[subdir2Path], callbacks.now); }); }); } test_refresh_folder_with_pubspec() { // create a context with a pubspec.yaml file String pubspecPath = join(projPath, 'pubspec.yaml'); resourceProvider.newFile(pubspecPath, 'pubspec'); manager.setRoots([projPath], [], {}); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([projPath])); callbacks.now++; manager.refresh(null); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([projPath])); expect(callbacks.currentContextTimestamps[projPath], callbacks.now); }); }); } test_refresh_folder_with_pubspec_subfolders() { // Create a folder with no pubspec.yaml, containing two subfolders with // pubspec.yaml files. String subdir1Path = join(projPath, 'subdir1'); String subdir2Path = join(projPath, 'subdir2'); String pubspec1Path = join(subdir1Path, 'pubspec.yaml'); String pubspec2Path = join(subdir2Path, 'pubspec.yaml'); resourceProvider.newFile(pubspec1Path, 'pubspec'); resourceProvider.newFile(pubspec2Path, 'pubspec'); manager.setRoots([projPath], [], {}); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([subdir1Path, subdir2Path, projPath])); callbacks.now++; manager.refresh(null); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals([subdir1Path, subdir2Path, projPath])); expect(callbacks.currentContextTimestamps[projPath], callbacks.now); expect(callbacks.currentContextTimestamps[subdir1Path], callbacks.now); expect(callbacks.currentContextTimestamps[subdir2Path], callbacks.now); }); }); } test_refresh_oneContext() { // create two contexts with pubspec.yaml files String pubspecPath = join(projPath, 'pubspec.yaml'); resourceProvider.newFile(pubspecPath, 'pubspec1'); String proj2Path = convertPath('/my/proj2'); resourceProvider.newFolder(proj2Path); String pubspec2Path = join(proj2Path, 'pubspec.yaml'); resourceProvider.newFile(pubspec2Path, 'pubspec2'); List roots = [projPath, proj2Path]; manager.setRoots(roots, [], {}); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals(roots)); int then = callbacks.now; callbacks.now++; manager.refresh([resourceProvider.getResource(proj2Path)]); return pumpEventQueue().then((_) { expect(callbacks.currentContextRoots, unorderedEquals(roots)); expect(callbacks.currentContextTimestamps[projPath], then); expect(callbacks.currentContextTimestamps[proj2Path], callbacks.now); }); }); } test_sdk_ext_packagespec() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/nope.dart'); String sdkExtPath = '$projPath/sdk_ext'; newFile('$sdkExtPath/entry.dart'); String sdkExtSrcPath = '$projPath/sdk_ext/src'; newFile('$sdkExtSrcPath/part.dart'); // Setup sdk extension mapping. newFile('$libPath/_sdkext', content: r''' { "dart:foobar": "../sdk_ext/entry.dart" } '''); // Setup .packages file newFile('$projPath/.packages', content: r''' test_pack:lib/'''); // Setup context. manager.setRoots([projPath], [], {}); // Confirm that one context was created. int count = manager .numberOfContextsInAnalysisRoot(resourceProvider.newFolder(projPath)); expect(count, equals(1)); var source = sourceFactory.forUri('dart:foobar'); expect(source.fullName, equals(convertPath('/my/proj/sdk_ext/entry.dart'))); } void test_setRoots_addFolderWithDartFile() { String filePath = resourceProvider.pathContext.join(projPath, 'foo.dart'); resourceProvider.newFile(filePath, 'contents'); manager.setRoots([projPath], [], {}); // verify Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); List drivers = manager.getDriversInAnalysisRoot(resourceProvider.newFolder(projPath)); expect(drivers, hasLength(1)); expect(drivers[0], isNotNull); Source result = sourceFactory.forUri('dart:async'); expect(result, isNotNull); } void test_setRoots_addFolderWithDartFileInSubfolder() { String filePath = join(projPath, 'foo', 'bar.dart'); resourceProvider.newFile(filePath, 'contents'); manager.setRoots([projPath], [], {}); // verify Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); } void test_setRoots_addFolderWithDummyLink() { String filePath = join(projPath, 'foo.dart'); resourceProvider.newDummyLink(filePath); manager.setRoots([projPath], [], {}); // verify expect(callbacks.currentFilePaths, isEmpty); } void test_setRoots_addFolderWithNestedPackageSpec() { String examplePath = convertPath('$projPath/${ContextManagerTest.EXAMPLE_NAME}'); String libPath = convertPath('$projPath/${ContextManagerTest.LIB_NAME}'); newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}'); newFile('$libPath/main.dart'); newFile('$examplePath/${ContextManagerImpl.PACKAGE_SPEC_NAME}'); newFile('$examplePath/example.dart'); manager.setRoots([projPath], [], {}); expect(callbacks.currentContextRoots, hasLength(2)); expect(callbacks.currentContextRoots, contains(projPath)); Iterable projSources = callbacks.currentFileSources(projPath); expect(projSources, hasLength(1)); expect(projSources.first.uri.toString(), (new Uri.file(join(libPath, 'main.dart')).toString())); expect(callbacks.currentContextRoots, contains(examplePath)); Iterable exampleSources = callbacks.currentFileSources(examplePath); expect(exampleSources, hasLength(1)); expect(exampleSources.first.uri.toString(), (new Uri.file(join(examplePath, 'example.dart')).toString())); } void test_setRoots_addFolderWithNestedPubspec() { String examplePath = convertPath('$projPath/${ContextManagerTest.EXAMPLE_NAME}'); String libPath = convertPath('$projPath/${ContextManagerTest.LIB_NAME}'); newFile('$projPath/${ContextManagerImpl.PUBSPEC_NAME}'); newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'proj:lib/'); newFile('$libPath/main.dart'); newFile('$examplePath/${ContextManagerImpl.PUBSPEC_NAME}'); newFile('$examplePath/example.dart'); manager.setRoots([projPath], [], {}); expect(callbacks.currentContextRoots, hasLength(2)); expect(callbacks.currentContextRoots, contains(projPath)); Iterable projSources = callbacks.currentFileSources(projPath); expect(projSources, hasLength(1)); expect(projSources.first.uri.toString(), 'package:proj/main.dart'); expect(callbacks.currentContextRoots, contains(examplePath)); Iterable exampleSources = callbacks.currentFileSources(examplePath); expect(exampleSources, hasLength(1)); expect(exampleSources.first.uri.toString(), (new Uri.file('$examplePath/example.dart').toString())); } void test_setRoots_addFolderWithoutPubspec() { manager.setRoots([projPath], [], {}); // verify expect(callbacks.currentContextRoots, unorderedEquals([projPath])); expect(callbacks.currentFilePaths, hasLength(0)); } void test_setRoots_addFolderWithPackagespec() { String packagespecPath = join(projPath, '.packages'); var testLib = convertPath('/home/somebody/.pub/cache/unittest-0.9.9/lib'); var testLibUri = resourceProvider.pathContext.toUri(testLib); resourceProvider.newFile(packagespecPath, 'unittest:$testLibUri'); String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; File mainFile = newFile('$libPath/main.dart'); Source source = mainFile.createSource(); manager.setRoots([projPath], [], {}); // verify expect(callbacks.currentContextRoots, unorderedEquals([projPath])); expect(callbacks.currentFilePaths, hasLength(1)); // smoketest resolution Source resolvedSource = sourceFactory.resolveUri(source, 'package:unittest/unittest.dart'); expect(resolvedSource, isNotNull); expect(resolvedSource.fullName, convertPath('$testLib/unittest.dart')); } void test_setRoots_addFolderWithPackagespecAndPackageRoot() { // The package root should take priority. String packagespecPath = join(projPath, '.packages'); var testLib = convertPath('/home/somebody/.pub/cache/unittest-0.9.9/lib'); var testLibUri = resourceProvider.pathContext.toUri(testLib); resourceProvider.newFile(packagespecPath, 'unittest:$testLibUri'); String packageRootPath = '/package/root/'; manager.setRoots([projPath], [], {projPath: packageRootPath}); expect(callbacks.currentContextRoots, unorderedEquals([projPath])); _checkPackageRoot(projPath, packageRootPath); } void test_setRoots_addFolderWithPubspec() { String pubspecPath = join(projPath, 'pubspec.yaml'); resourceProvider.newFile(pubspecPath, 'pubspec'); manager.setRoots([projPath], [], {}); // verify expect(callbacks.currentContextRoots, unorderedEquals([projPath])); expect(callbacks.currentFilePaths, hasLength(0)); } void test_setRoots_addFolderWithPubspec_andPackagespec() { String pubspecPath = join(projPath, 'pubspec.yaml'); String packagespecPath = join(projPath, '.packages'); resourceProvider.newFile(pubspecPath, 'pubspec'); resourceProvider.newFile(packagespecPath, ''); manager.setRoots([projPath], [], {}); // verify callbacks.assertContextPaths([projPath]); } void test_setRoots_addFolderWithPubspecAndLib() { String binPath = '$projPath/${ContextManagerTest.BIN_NAME}'; String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; String srcPath = '$libPath/${ContextManagerTest.SRC_NAME}'; String testPath = '$projPath/${ContextManagerTest.TEST_NAME}'; newFile('$projPath/${ContextManagerImpl.PUBSPEC_NAME}'); newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'proj:lib/'); String appPath = newFile('$binPath/app.dart').path; newFile('$libPath/main.dart'); newFile('$srcPath/internal.dart'); String testFilePath = newFile('$testPath/main_test.dart').path; manager.setRoots([projPath], [], {}); Iterable sources = callbacks.currentFileSources(projPath); expect(callbacks.currentContextRoots, unorderedEquals([projPath])); expect(sources, hasLength(4)); List uris = sources.map((Source source) => source.uri.toString()).toList(); expect(uris, contains((new Uri.file(appPath)).toString())); expect(uris, contains('package:proj/main.dart')); expect(uris, contains('package:proj/src/internal.dart')); expect(uris, contains((new Uri.file(testFilePath)).toString())); } void test_setRoots_addFolderWithPubspecAndPackagespecFolders() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProjectA = convertPath('$root/sub/aaa'); String subProjectB = convertPath('$root/sub/sub2/bbb'); String subProjectA_file = convertPath('$subProjectA/bin/a.dart'); String subProjectB_file = convertPath('$subProjectB/bin/b.dart'); // create files newFile('$subProjectA/pubspec.yaml', content: 'pubspec'); newFile('$subProjectB/pubspec.yaml', content: 'pubspec'); newFile('$subProjectA/.packages'); newFile('$subProjectB/.packages'); newFile(rootFile, content: 'library root;'); newFile(subProjectA_file, content: 'library a;'); newFile(subProjectB_file, content: 'library b;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, subProjectA, subProjectB]); // verify files callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProjectA, [subProjectA_file]); callbacks.assertContextFiles(subProjectB, [subProjectB_file]); } void test_setRoots_addFolderWithPubspecFolders() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String projectA = convertPath('$root/sub/aaa'); String projectALib = convertPath('$root/sub/aaa/lib'); String subProjectA_file = convertPath('$projectA/bin/a.dart'); String projectB = convertPath('$root/sub/sub2/bbb'); String projectBLib = convertPath('$root/sub/sub2/bbb/lib'); String subProjectB_file = convertPath('$projectB/bin/b.dart'); // create files newFile('$projectA/${ContextManagerImpl.PUBSPEC_NAME}'); newFile('$projectA/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'foo:lib/'); newFile('$projectB/${ContextManagerImpl.PUBSPEC_NAME}'); newFile('$projectB/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'bar:lib/'); resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subProjectA_file, 'library a;'); resourceProvider.newFile(subProjectB_file, 'library b;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, projectA, projectB]); // verify files callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(projectA, [subProjectA_file]); callbacks.assertContextFiles(projectB, [subProjectB_file]); // verify package maps expect(_packageMap(root), isEmpty); expect( _packageMap(projectA), equals({ 'foo': [resourceProvider.getFolder(projectALib)] })); expect( _packageMap(projectB), equals({ 'bar': [resourceProvider.getFolder(projectBLib)] })); } void test_setRoots_addPackageRoot() { String packagePathFoo = convertPath('/package1/foo'); String packageRootPath = convertPath('/package2/foo'); newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'foo:file:///package1/foo'); Folder packageFolder = resourceProvider.newFolder(packagePathFoo); List includedPaths = [projPath]; List excludedPaths = []; manager.setRoots(includedPaths, excludedPaths, {}); expect( _currentPackageMap, equals({ 'foo': [packageFolder] })); manager.setRoots(includedPaths, excludedPaths, {projPath: packageRootPath}); _checkPackageRoot(projPath, equals(packageRootPath)); } void test_setRoots_changePackageRoot() { String packageRootPath1 = '/package1'; String packageRootPath2 = '/package2'; List includedPaths = [projPath]; List excludedPaths = []; manager.setRoots(includedPaths, excludedPaths, {projPath: packageRootPath1}); _checkPackageRoot(projPath, equals(packageRootPath1)); manager.setRoots(includedPaths, excludedPaths, {projPath: packageRootPath2}); _checkPackageRoot(projPath, equals(packageRootPath2)); } void test_setRoots_exclude_newRoot_withExcludedFile() { // prepare paths String project = convertPath('/project'); String file1 = convertPath('$project/file1.dart'); String file2 = convertPath('$project/file2.dart'); // create files resourceProvider.newFile(file1, '// 1'); resourceProvider.newFile(file2, '// 2'); // set roots manager.setRoots([project], [file1], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [file2]); } void test_setRoots_exclude_newRoot_withExcludedFolder() { // prepare paths String project = convertPath('/project'); String folderA = convertPath('$project/aaa'); String folderB = convertPath('$project/bbb'); String fileA = convertPath('$folderA/a.dart'); String fileB = convertPath('$folderB/b.dart'); // create files resourceProvider.newFile(fileA, 'library a;'); resourceProvider.newFile(fileB, 'library b;'); // set roots manager.setRoots([project], [folderB], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); } void test_setRoots_exclude_sameRoot_addExcludedFile() { // prepare paths String project = convertPath('/project'); String file1 = convertPath('$project/file1.dart'); String file2 = convertPath('$project/file2.dart'); // create files resourceProvider.newFile(file1, '// 1'); resourceProvider.newFile(file2, '// 2'); // set roots manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [file1, file2]); // exclude "2" manager.setRoots([project], [file2], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [file1]); } void test_setRoots_exclude_sameRoot_addExcludedFolder() { // prepare paths String project = convertPath('/project'); String folderA = convertPath('$project/aaa'); String folderB = convertPath('$project/bbb'); String fileA = convertPath('$folderA/a.dart'); String fileB = convertPath('$folderB/b.dart'); // create files resourceProvider.newFile(fileA, 'library a;'); resourceProvider.newFile(fileB, 'library b;'); // initially both "aaa/a" and "bbb/b" are included manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA, fileB]); // exclude "bbb/" manager.setRoots([project], [folderB], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); } void test_setRoots_exclude_sameRoot_removeExcludedFile() { // prepare paths String project = convertPath('/project'); String file1 = convertPath('$project/file1.dart'); String file2 = convertPath('$project/file2.dart'); // create files resourceProvider.newFile(file1, '// 1'); resourceProvider.newFile(file2, '// 2'); // set roots manager.setRoots([project], [file2], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [file1]); // stop excluding "2" manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [file1, file2]); } void test_setRoots_exclude_sameRoot_removeExcludedFile_inFolder() { // prepare paths String project = convertPath('/project'); String file1 = convertPath('$project/bin/file1.dart'); String file2 = convertPath('$project/bin/file2.dart'); // create files resourceProvider.newFile(file1, '// 1'); resourceProvider.newFile(file2, '// 2'); // set roots manager.setRoots([project], [file2], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [file1]); // stop excluding "2" manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [file1, file2]); } void test_setRoots_exclude_sameRoot_removeExcludedFolder() { // prepare paths String project = convertPath('/project'); String folderA = convertPath('$project/aaa'); String folderB = convertPath('$project/bbb'); String fileA = convertPath('$folderA/a.dart'); String fileB = convertPath('$folderB/b.dart'); // create files resourceProvider.newFile(fileA, 'library a;'); resourceProvider.newFile(fileB, 'library b;'); // exclude "bbb/" manager.setRoots([project], [folderB], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); // stop excluding "bbb/" manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA, fileB]); } void test_setRoots_ignoreDocFolder() { String project = convertPath('/project'); String fileA = convertPath('$project/foo.dart'); String fileB = convertPath('$project/lib/doc/bar.dart'); String fileC = convertPath('$project/doc/bar.dart'); resourceProvider.newFile(fileA, ''); resourceProvider.newFile(fileB, ''); resourceProvider.newFile(fileC, ''); manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA, fileB]); } void test_setRoots_nested_includedByOuter_innerFirst() { String project = convertPath('/project'); String projectPubspec = convertPath('$project/pubspec.yaml'); String example = convertPath('$project/example'); String examplePubspec = convertPath('$example/pubspec.yaml'); // create files resourceProvider.newFile(projectPubspec, 'name: project'); resourceProvider.newFile(examplePubspec, 'name: example'); manager .setRoots([example, project], [], {}); // verify { ContextInfo rootInfo = manager.rootInfo; expect(rootInfo.children, hasLength(1)); { ContextInfo projectInfo = rootInfo.children[0]; expect(projectInfo.folder.path, project); expect(projectInfo.children, hasLength(1)); { ContextInfo exampleInfo = projectInfo.children[0]; expect(exampleInfo.folder.path, example); expect(exampleInfo.children, isEmpty); } } } expect(callbacks.currentContextRoots, unorderedEquals([project, example])); } void test_setRoots_nested_includedByOuter_outerPubspec() { String project = convertPath('/project'); String projectPubspec = convertPath('$project/pubspec.yaml'); String example = convertPath('$project/example'); // create files resourceProvider.newFile(projectPubspec, 'name: project'); resourceProvider.newFolder(example); manager .setRoots([project, example], [], {}); // verify { ContextInfo rootInfo = manager.rootInfo; expect(rootInfo.children, hasLength(1)); { ContextInfo projectInfo = rootInfo.children[0]; expect(projectInfo.folder.path, project); expect(projectInfo.children, isEmpty); } } expect(callbacks.currentContextRoots, unorderedEquals([project])); } void test_setRoots_nested_includedByOuter_twoPubspecs() { String project = convertPath('/project'); String projectPubspec = convertPath('$project/pubspec.yaml'); String example = convertPath('$project/example'); String examplePubspec = convertPath('$example/pubspec.yaml'); // create files resourceProvider.newFile(projectPubspec, 'name: project'); resourceProvider.newFile(examplePubspec, 'name: example'); manager .setRoots([project, example], [], {}); // verify { ContextInfo rootInfo = manager.rootInfo; expect(rootInfo.children, hasLength(1)); { ContextInfo projectInfo = rootInfo.children[0]; expect(projectInfo.folder.path, project); expect(projectInfo.children, hasLength(1)); { ContextInfo exampleInfo = projectInfo.children[0]; expect(exampleInfo.folder.path, example); expect(exampleInfo.children, isEmpty); } } } expect(callbacks.currentContextRoots, unorderedEquals([project, example])); } void test_setRoots_newFolderWithPackageRoot() { String packageRootPath = '/package'; manager.setRoots([projPath], [], {projPath: packageRootPath}); _checkPackageRoot(projPath, equals(packageRootPath)); } void test_setRoots_newlyAddedFoldersGetProperPackageMap() { String packagePath = convertPath('/package/foo'); newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'foo:file:///package/foo'); Folder packageFolder = resourceProvider.newFolder(packagePath); manager.setRoots([projPath], [], {}); expect( _currentPackageMap, equals({ 'foo': [packageFolder] })); } void test_setRoots_noContext_excludedFolder() { // prepare paths String project = convertPath('/project'); String excludedFolder = convertPath('$project/excluded'); String excludedPubspec = convertPath('$excludedFolder/pubspec.yaml'); // create files resourceProvider.newFile(excludedPubspec, 'name: ignore-me'); // set "/project", and exclude "/project/excluded" manager.setRoots( [project], [excludedFolder], {}); callbacks.assertContextPaths([project]); } void test_setRoots_noContext_inDotFolder() { String pubspecPath = join(projPath, '.pub', 'pubspec.yaml'); resourceProvider.newFile(pubspecPath, 'name: test'); manager.setRoots([projPath], [], {}); // verify expect(callbacks.currentContextRoots, hasLength(1)); expect(callbacks.currentContextRoots, contains(projPath)); expect(callbacks.currentFilePaths, hasLength(0)); } void test_setRoots_packageResolver() { String filePath = join(projPath, 'lib', 'foo.dart'); newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'foo:lib/'); resourceProvider.newFile(filePath, 'contents'); manager.setRoots([projPath], [], {}); var drivers = manager.getDriversInAnalysisRoot(resourceProvider.newFolder(projPath)); expect(drivers, hasLength(1)); expect(drivers[0], isNotNull); Source result = sourceFactory.forUri('package:foo/foo.dart'); expect(result.fullName, filePath); } void test_setRoots_packagesFolder_hasContext() { String pubspecPath = join(projPath, 'packages', 'pubspec.yaml'); resourceProvider.newFile(pubspecPath, 'name: test'); manager.setRoots([projPath], [], {}); // verify expect(callbacks.currentContextRoots, hasLength(2)); expect(callbacks.currentContextRoots, contains(projPath)); expect(callbacks.currentFilePaths, hasLength(0)); } void test_setRoots_pathContainsDotFile() { // If the path to a file (relative to the context root) contains a folder // whose name begins with '.', then the file is ignored. String project = convertPath('/project'); String fileA = convertPath('$project/foo.dart'); String fileB = convertPath('$project/.pub/bar.dart'); resourceProvider.newFile(fileA, ''); resourceProvider.newFile(fileB, ''); manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); } void test_setRoots_removeFolderWithoutPubspec() { // add one root - there is a context manager.setRoots([projPath], [], {}); expect(callbacks.currentContextRoots, hasLength(1)); // set empty roots - no contexts manager.setRoots([], [], {}); expect(callbacks.currentContextRoots, hasLength(0)); expect(callbacks.currentFilePaths, hasLength(0)); } void test_setRoots_removeFolderWithPackagespec() { // create a pubspec String pubspecPath = join(projPath, '.packages'); resourceProvider.newFile(pubspecPath, ''); // add one root - there is a context manager.setRoots([projPath], [], {}); expect(manager.changeSubscriptions, hasLength(1)); expect(callbacks.currentContextRoots, hasLength(1)); // set empty roots - no contexts manager.setRoots([], [], {}); expect(manager.changeSubscriptions, hasLength(0)); expect(callbacks.currentContextRoots, hasLength(0)); expect(callbacks.currentFilePaths, hasLength(0)); } void test_setRoots_removeFolderWithPackagespecFolder() { // prepare paths String projectA = convertPath('/projectA'); String projectB = convertPath('/projectB'); String subProjectA = convertPath('$projectA/sub'); String subProjectB = convertPath('$projectB/sub'); String projectA_file = convertPath('$projectA/a.dart'); String projectB_file = convertPath('$projectB/a.dart'); String subProjectA_pubspec = convertPath('$subProjectA/.packages'); String subProjectB_pubspec = convertPath('$subProjectB/.packages'); String subProjectA_file = convertPath('$subProjectA/bin/sub_a.dart'); String subProjectB_file = convertPath('$subProjectB/bin/sub_b.dart'); // create files resourceProvider.newFile(projectA_file, '// a'); resourceProvider.newFile(projectB_file, '// b'); resourceProvider.newFile(subProjectA_pubspec, ''); resourceProvider.newFile(subProjectB_pubspec, ''); resourceProvider.newFile(subProjectA_file, '// sub-a'); resourceProvider.newFile(subProjectB_file, '// sub-b'); // set roots manager .setRoots([projectA, projectB], [], {}); callbacks .assertContextPaths([projectA, subProjectA, projectB, subProjectB]); callbacks.assertContextFiles(projectA, [projectA_file]); callbacks.assertContextFiles(projectB, [projectB_file]); callbacks.assertContextFiles(subProjectA, [subProjectA_file]); callbacks.assertContextFiles(subProjectB, [subProjectB_file]); // remove "projectB" manager.setRoots([projectA], [], {}); callbacks.assertContextPaths([projectA, subProjectA]); callbacks.assertContextFiles(projectA, [projectA_file]); callbacks.assertContextFiles(subProjectA, [subProjectA_file]); } void test_setRoots_removeFolderWithPubspec() { // create a pubspec String pubspecPath = join(projPath, 'pubspec.yaml'); resourceProvider.newFile(pubspecPath, 'pubspec'); // add one root - there is a context manager.setRoots([projPath], [], {}); expect(callbacks.currentContextRoots, hasLength(1)); // set empty roots - no contexts manager.setRoots([], [], {}); expect(callbacks.currentContextRoots, hasLength(0)); expect(callbacks.currentFilePaths, hasLength(0)); } void test_setRoots_removeFolderWithPubspecFolder() { // prepare paths String projectA = convertPath('/projectA'); String projectB = convertPath('/projectB'); String subProjectA = convertPath('$projectA/sub'); String subProjectB = convertPath('$projectB/sub'); String projectA_file = convertPath('$projectA/a.dart'); String projectB_file = convertPath('$projectB/a.dart'); String subProjectA_pubspec = convertPath('$subProjectA/pubspec.yaml'); String subProjectB_pubspec = convertPath('$subProjectB/pubspec.yaml'); String subProjectA_file = convertPath('$subProjectA/bin/sub_a.dart'); String subProjectB_file = convertPath('$subProjectB/bin/sub_b.dart'); // create files resourceProvider.newFile(projectA_file, '// a'); resourceProvider.newFile(projectB_file, '// b'); resourceProvider.newFile(subProjectA_pubspec, 'pubspec'); resourceProvider.newFile(subProjectB_pubspec, 'pubspec'); resourceProvider.newFile(subProjectA_file, '// sub-a'); resourceProvider.newFile(subProjectB_file, '// sub-b'); // set roots manager .setRoots([projectA, projectB], [], {}); callbacks .assertContextPaths([projectA, subProjectA, projectB, subProjectB]); callbacks.assertContextFiles(projectA, [projectA_file]); callbacks.assertContextFiles(projectB, [projectB_file]); callbacks.assertContextFiles(subProjectA, [subProjectA_file]); callbacks.assertContextFiles(subProjectB, [subProjectB_file]); // remove "projectB" manager.setRoots([projectA], [], {}); callbacks.assertContextPaths([projectA, subProjectA]); callbacks.assertContextFiles(projectA, [projectA_file]); callbacks.assertContextFiles(subProjectA, [subProjectA_file]); } void test_setRoots_removePackageRoot() { String packagePathFoo = convertPath('/package1/foo'); String packageRootPath = convertPath('/package2/foo'); Folder packageFolder = resourceProvider.newFolder(packagePathFoo); newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'foo:file:///package1/foo'); List includedPaths = [projPath]; List excludedPaths = []; manager.setRoots(includedPaths, excludedPaths, {projPath: packageRootPath}); _checkPackageRoot(projPath, equals(packageRootPath)); manager.setRoots(includedPaths, excludedPaths, {}); expect( _currentPackageMap, equals({ 'foo': [packageFolder] })); } void test_setRoots_rootPathContainsDotFile() { // If the path to the context root itself contains a folder whose name // begins with '.', then that is not sufficient to cause any files in the // context to be ignored. String project = convertPath('/.pub/project'); String fileA = convertPath('$project/foo.dart'); resourceProvider.newFile(fileA, ''); manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); } test_watch_addDummyLink() { manager.setRoots([projPath], [], {}); // empty folder initially expect(callbacks.currentFilePaths, isEmpty); // add link String filePath = join(projPath, 'foo.dart'); resourceProvider.newDummyLink(filePath); // the link was ignored return pumpEventQueue().then((_) { expect(callbacks.currentFilePaths, isEmpty); }); } test_watch_addFile() { manager.setRoots([projPath], [], {}); // empty folder initially expect(callbacks.currentFilePaths, hasLength(0)); // add file String filePath = join(projPath, 'foo.dart'); resourceProvider.newFile(filePath, 'contents'); // the file was added return pumpEventQueue().then((_) { Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); }); } test_watch_addFile_excluded() { // prepare paths String project = convertPath('/project'); String folderA = convertPath('$project/aaa'); String folderB = convertPath('$project/bbb'); String fileA = convertPath('$folderA/a.dart'); String fileB = convertPath('$folderB/b.dart'); // create files resourceProvider.newFile(fileA, 'library a;'); // set roots manager.setRoots([project], [folderB], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); // add a file, ignored as excluded resourceProvider.newFile(fileB, 'library b;'); return pumpEventQueue().then((_) { callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); }); } test_watch_addFile_inDocFolder_inner() { // prepare paths String project = convertPath('/project'); String fileA = convertPath('$project/a.dart'); String fileB = convertPath('$project/lib/doc/b.dart'); // create files resourceProvider.newFile(fileA, ''); // set roots manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); // add a "lib/doc" file, it is not ignored resourceProvider.newFile(fileB, ''); return pumpEventQueue().then((_) { callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA, fileB]); }); } test_watch_addFile_inDocFolder_topLevel() { // prepare paths String project = convertPath('/project'); String fileA = convertPath('$project/a.dart'); String fileB = convertPath('$project/doc/b.dart'); // create files resourceProvider.newFile(fileA, ''); // set roots manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); // add a "doc" file, it is ignored resourceProvider.newFile(fileB, ''); return pumpEventQueue().then((_) { callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); }); } test_watch_addFile_pathContainsDotFile() async { // If a file is added and the path to it (relative to the context root) // contains a folder whose name begins with '.', then the file is ignored. String project = convertPath('/project'); String fileA = convertPath('$project/foo.dart'); String fileB = convertPath('$project/.pub/bar.dart'); resourceProvider.newFile(fileA, ''); manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); resourceProvider.newFile(fileB, ''); await pumpEventQueue(); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); } test_watch_addFile_rootPathContainsDotFile() async { // If a file is added and the path to the context contains a folder whose // name begins with '.', then the file is not ignored. String project = convertPath('/.pub/project'); String fileA = convertPath('$project/foo.dart'); String fileB = convertPath('$project/bar/baz.dart'); resourceProvider.newFile(fileA, ''); manager.setRoots([project], [], {}); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA]); resourceProvider.newFile(fileB, ''); await pumpEventQueue(); callbacks.assertContextPaths([project]); callbacks.assertContextFiles(project, [fileA, fileB]); } test_watch_addFileInSubfolder() { manager.setRoots([projPath], [], {}); // empty folder initially expect(callbacks.currentFilePaths, hasLength(0)); // add file in subfolder String filePath = join(projPath, 'foo', 'bar.dart'); resourceProvider.newFile(filePath, 'contents'); // the file was added return pumpEventQueue().then((_) { Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); }); } test_watch_addPackagespec_toRoot() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String rootPackagespec = convertPath('$root/.packages'); // create files resourceProvider.newFile(rootFile, 'library root;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root]); // verify files callbacks.assertContextFiles(root, [rootFile]); // add packagespec - still just one root resourceProvider.newFile(rootPackagespec, ''); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile]); // TODO(pquitslund): verify that a new source factory is created -- // likely this will need to happen in a corresponding ServerContextManagerTest. }); } test_watch_addPackagespec_toSubFolder() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub/aaa'); String subPubspec = convertPath('$subProject/.packages'); String subFile = convertPath('$subProject/bin/a.dart'); // create files resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subFile, 'library a;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root]); // verify files callbacks.assertContextFiles(root, [rootFile, subFile]); // add .packages resourceProvider.newFile(subPubspec, ''); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); }); } test_watch_addPackagespec_toSubFolder_ofSubFolder() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub'); String subPubspec = convertPath('$subProject/.packages'); String subFile = convertPath('$subProject/bin/sub.dart'); String subSubPubspec = convertPath('$subProject/subsub/.packages'); // create files resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subPubspec, ''); resourceProvider.newFile(subFile, 'library sub;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); // add pubspec - ignore, because is already in a packagespec-based context resourceProvider.newFile(subSubPubspec, ''); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); }); } test_watch_addPackagespec_toSubFolder_withPubspec() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub/aaa'); String subPackagespec = convertPath('$subProject/.packages'); String subPubspec = convertPath('$subProject/pubspec.yaml'); String subFile = convertPath('$subProject/bin/a.dart'); // create files resourceProvider.newFile(subPubspec, 'pubspec'); resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subFile, 'library a;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, subProject]); // verify files callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); // add .packages resourceProvider.newFile(subPackagespec, ''); return pumpEventQueue().then((_) { // Should NOT create another context. callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); }); } test_watch_addPubspec_toRoot() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String rootPubspec = convertPath('$root/pubspec.yaml'); // create files resourceProvider.newFile(rootFile, 'library root;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root]); // verify files callbacks.assertContextFiles(root, [rootFile]); // add pubspec - still just one root resourceProvider.newFile(rootPubspec, 'pubspec'); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile]); }); } test_watch_addPubspec_toSubFolder() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub/aaa'); String subPubspec = convertPath('$subProject/pubspec.yaml'); String subFile = convertPath('$subProject/bin/a.dart'); // create files resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subFile, 'library a;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root]); // verify files callbacks.assertContextFiles(root, [rootFile, subFile]); // add pubspec resourceProvider.newFile(subPubspec, 'pubspec'); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); }); } test_watch_addPubspec_toSubFolder_ofSubFolder() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub'); String subPubspec = convertPath('$subProject/pubspec.yaml'); String subFile = convertPath('$subProject/bin/sub.dart'); String subSubPubspec = convertPath('$subProject/subsub/pubspec.yaml'); // create files resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subPubspec, 'pubspec'); resourceProvider.newFile(subFile, 'library sub;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); // add pubspec - ignore, because is already in a pubspec-based context resourceProvider.newFile(subSubPubspec, 'pubspec'); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); }); } test_watch_deleteFile() { String filePath = join(projPath, 'foo.dart'); // add root with a file File file = resourceProvider.newFile(filePath, 'contents'); Folder projFolder = file.parent; manager.setRoots([projPath], [], {}); // the file was added Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); expect(file.exists, isTrue); expect(projFolder.exists, isTrue); // delete the file resourceProvider.deleteFile(filePath); return pumpEventQueue().then((_) { expect(file.exists, isFalse); expect(projFolder.exists, isTrue); expect(callbacks.currentFilePaths, hasLength(0)); }); } test_watch_deleteFolder() { String filePath = join(projPath, 'foo.dart'); // add root with a file File file = resourceProvider.newFile(filePath, 'contents'); Folder projFolder = file.parent; manager.setRoots([projPath], [], {}); // the file was added Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); expect(file.exists, isTrue); expect(projFolder.exists, isTrue); // delete the folder resourceProvider.deleteFolder(projPath); return pumpEventQueue().then((_) { expect(file.exists, isFalse); expect(projFolder.exists, isFalse); expect(callbacks.currentFilePaths, hasLength(0)); }); } test_watch_deletePackagespec_fromRoot() { // prepare paths String root = convertPath('/root'); String rootPubspec = convertPath('$root/.packages'); String rootFile = convertPath('$root/root.dart'); // create files resourceProvider.newFile(rootPubspec, ''); resourceProvider.newFile(rootFile, 'library root;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile]); // delete the pubspec resourceProvider.deleteFile(rootPubspec); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile]); }); } test_watch_deletePackagespec_fromSubFolder() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub/aaa'); String subPubspec = convertPath('$subProject/.packages'); String subFile = convertPath('$subProject/bin/a.dart'); // create files resourceProvider.newFile(subPubspec, ''); resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subFile, 'library a;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, subProject]); // verify files callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); // delete the pubspec resourceProvider.deleteFile(subPubspec); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile, subFile]); }); } test_watch_deletePackagespec_fromSubFolder_withPubspec() { // prepare paths: // // root // root.dart // sub // aaa // .packages // pubspec.yaml // bin // a.dart // String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub/aaa'); String subPackagespec = convertPath('$subProject/.packages'); String subPubspec = convertPath('$subProject/pubspec.yaml'); String subFile = convertPath('$subProject/bin/a.dart'); // create files resourceProvider.newFile(subPackagespec, ''); resourceProvider.newFile(subPubspec, 'pubspec'); resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subFile, 'library a;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, subProject]); // verify files callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); // delete the packagespec resourceProvider.deleteFile(subPackagespec); return pumpEventQueue().then((_) { // Should NOT merge callbacks.assertContextPaths([root, subProject]); callbacks.assertContextFiles(subProject, [subFile]); }); } test_watch_deletePubspec_fromRoot() { // prepare paths String root = convertPath('/root'); String rootPubspec = convertPath('$root/pubspec.yaml'); String rootFile = convertPath('$root/root.dart'); // create files resourceProvider.newFile(rootPubspec, 'pubspec'); resourceProvider.newFile(rootFile, 'library root;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile]); // delete the pubspec resourceProvider.deleteFile(rootPubspec); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile]); }); } test_watch_deletePubspec_fromSubFolder() { // prepare paths String root = convertPath('/root'); String rootFile = convertPath('$root/root.dart'); String subProject = convertPath('$root/sub/aaa'); String subPubspec = convertPath('$subProject/pubspec.yaml'); String subFile = convertPath('$subProject/bin/a.dart'); // create files resourceProvider.newFile(subPubspec, 'pubspec'); resourceProvider.newFile(rootFile, 'library root;'); resourceProvider.newFile(subFile, 'library a;'); // set roots manager.setRoots([root], [], {}); callbacks.assertContextPaths([root, subProject]); // verify files callbacks.assertContextFiles(root, [rootFile]); callbacks.assertContextFiles(subProject, [subFile]); // delete the pubspec resourceProvider.deleteFile(subPubspec); return pumpEventQueue().then((_) { callbacks.assertContextPaths([root]); callbacks.assertContextFiles(root, [rootFile, subFile]); }); } test_watch_modifyFile() { String filePath = join(projPath, 'foo.dart'); // add root with a file resourceProvider.newFile(filePath, 'contents'); manager.setRoots([projPath], [], {}); // the file was added Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); // TODO(brianwilkerson) Test when the file was modified // update the file callbacks.now++; resourceProvider.modifyFile(filePath, 'new contents'); return pumpEventQueue().then((_) { // TODO(brianwilkerson) Test when the file was modified }); } test_watch_modifyPackagespec() { String packagesPath = convertPath('$projPath/.packages'); String filePath = convertPath('$projPath/bin/main.dart'); resourceProvider.newFile(packagesPath, ''); resourceProvider.newFile(filePath, 'library main;'); manager.setRoots([projPath], [], {}); Iterable filePaths = callbacks.currentFilePaths; expect(filePaths, hasLength(1)); expect(filePaths, contains(filePath)); expect(_currentPackageMap, isEmpty); // update .packages callbacks.now++; resourceProvider.modifyFile(packagesPath, 'main:./lib/'); return pumpEventQueue().then((_) { // verify new package info expect(_currentPackageMap.keys, unorderedEquals(['main'])); }); } /** * Verify that package URI's for source files in [path] will be resolved * using a package root matching [expectation]. */ void _checkPackageRoot(String path, expectation) { // TODO(brianwilkerson) Figure out how to test this. Possibly by comparing // the contents of the package map (although that approach doesn't work at // the moment). // FolderDisposition disposition = callbacks.currentContextDispositions[path]; // expect(disposition.packageRoot, expectation); // TODO(paulberry): we should also verify that the package map itself is // correct. See dartbug.com/23909. } } abstract class ContextManagerTest with ResourceProviderMixin { /** * The name of the 'bin' directory. */ static const String BIN_NAME = 'bin'; /** * The name of the 'example' directory. */ static const String EXAMPLE_NAME = 'example'; /** * The name of the 'lib' directory. */ static const String LIB_NAME = 'lib'; /** * The name of the 'src' directory. */ static const String SRC_NAME = 'src'; /** * The name of the 'test' directory. */ static const String TEST_NAME = 'test'; ContextManagerImpl manager; TestContextManagerCallbacks callbacks; UriResolver packageResolver = null; String projPath = null; AnalysisError missing_return = new AnalysisError(null, 0, 1, HintCode.MISSING_RETURN, [ ['x'] ]); AnalysisError invalid_assignment_error = new AnalysisError(null, 0, 1, StaticTypeWarningCode.INVALID_ASSIGNMENT, [ ['x'], ['y'] ]); AnalysisError unused_local_variable = new AnalysisError(null, 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ ['x'] ]); List get analysisFilesGlobs { List patterns = [ '**/*.${AnalysisEngine.SUFFIX_DART}', '**/*.${AnalysisEngine.SUFFIX_HTML}', '**/*.${AnalysisEngine.SUFFIX_HTM}', '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}', '**/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}' ]; return patterns .map((pattern) => new Glob(path.posix.separator, pattern)) .toList(); } AnalysisOptions get analysisOptions => callbacks.analysisOptions; List get errorProcessors => analysisOptions.errorProcessors; List get lints => analysisOptions.lintRules; SourceFactory get sourceFactory => callbacks.sourceFactory; Map> get _currentPackageMap => _packageMap(projPath); /** * TODO(brianwilkerson) This doesn't add the strong mode processor when using * the new analysis driver. */ ErrorProcessor getProcessor(AnalysisError error) => errorProcessors .firstWhere((ErrorProcessor p) => p.appliesTo(error), orElse: () => null); void processRequiredPlugins() { registerLintRules(); } UriResolver providePackageResolver(Folder folder) => packageResolver; void setUp() { processRequiredPlugins(); projPath = convertPath('/my/proj'); resourceProvider.newFolder(projPath); // Create an SDK in the mock file system. new MockSdk(generateSummaryFiles: true, resourceProvider: resourceProvider); DartSdkManager sdkManager = new DartSdkManager(convertPath('/sdk'), true); manager = new ContextManagerImpl( resourceProvider, sdkManager, providePackageResolver, analysisFilesGlobs, InstrumentationService.NULL_SERVICE, new AnalysisOptionsImpl()); PerformanceLog logger = new PerformanceLog(new NullStringSink()); AnalysisDriverScheduler scheduler = new AnalysisDriverScheduler(logger); callbacks = new TestContextManagerCallbacks( resourceProvider, sdkManager, logger, scheduler); manager.callbacks = callbacks; } /** * Verify that package URI's for source files in [path] will be resolved * using a package root matching [expectation]. */ void _checkPackageRoot(String path, expectation) { // TODO(brianwilkerson) Figure out how to test this. Possibly by comparing // the contents of the package map (although that approach doesn't work at // the moment). // FolderDisposition disposition = callbacks.currentContextDispositions[path]; // expect(disposition.packageRoot, expectation); // TODO(paulberry): we should also verify that the package map itself is // correct. See dartbug.com/23909. } Map> _packageMap(String contextPath) { Folder folder = resourceProvider.getFolder(contextPath); ContextInfo info = manager.getContextInfoFor(folder); return info.analysisDriver.sourceFactory?.packageMap; } } @reflectiveTest class ContextManagerWithNewOptionsTest extends ContextManagerWithOptionsTest { String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; @failingTest test_analysis_options_parse_failure() async { // We have lost the ability to detect errors of this form. return super.test_analysis_options_parse_failure(); } } @reflectiveTest class ContextManagerWithOldOptionsTest extends ContextManagerWithOptionsTest { String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_FILE; } abstract class ContextManagerWithOptionsTest extends ContextManagerTest { String get optionsFileName; void deleteOptionsFile() { deleteFile('$projPath/$optionsFileName'); } test_analysis_options_file_delete() async { // Setup analysis options newFile('$projPath/$optionsFileName', content: r''' embedded_libs: "dart:foobar": "../sdk_ext/entry.dart" analyzer: errors: unused_local_variable: false linter: rules: - camel_case_types '''); // Setup context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Verify options were set. expect(errorProcessors, hasLength(1)); expect(lints, hasLength(1)); // Remove options. deleteOptionsFile(); await pumpEventQueue(); // Verify defaults restored. expect(errorProcessors, isEmpty); expect(lints, isEmpty); } @failingTest test_analysis_options_file_delete_with_embedder() async { // This fails because the ContextBuilder doesn't pick up the strongMode // flag from the embedder.yaml file. // Setup _embedder.yaml. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/_embedder.yaml', content: r''' analyzer: language: enablePreviewDart2: true errors: missing_return: false linter: rules: - avoid_as '''); // Setup .packages file newFile('$projPath/.packages', content: r''' test_pack:lib/'''); // Setup analysis options newFile('$projPath/$optionsFileName', content: r''' analyzer: errors: unused_local_variable: false linter: rules: - camel_case_types '''); // Setup context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Verify options were set. expect(errorProcessors, hasLength(2)); expect(lints, hasLength(2)); // Remove options. deleteOptionsFile(); await pumpEventQueue(); // Verify defaults restored. expect(lints, hasLength(1)); expect(lints.first, const TypeMatcher()); expect(errorProcessors, hasLength(1)); expect(getProcessor(missing_return).severity, isNull); } test_analysis_options_include() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); String sdkExtPath = '$projPath/sdk_ext'; newFile('$sdkExtPath/entry.dart'); String sdkExtSrcPath = '$projPath/sdk_ext/src'; newFile('$sdkExtSrcPath/part.dart'); // Setup analysis options file which includes another options file. newFile('$projPath/$optionsFileName', content: r''' include: other_options.yaml '''); newFile('$projPath/other_options.yaml', content: r''' analyzer: errors: unused_local_variable: false linter: rules: - camel_case_types '''); // Setup context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Verify options were set. expect(errorProcessors, hasLength(1)); expect(lints, hasLength(1)); expect(lints[0].name, 'camel_case_types'); } test_analysis_options_include_package() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); String sdkExtPath = '$projPath/sdk_ext'; newFile('$sdkExtPath/entry.dart'); String sdkExtSrcPath = '$projPath/sdk_ext/src'; newFile('$sdkExtSrcPath/part.dart'); // Setup package String booLibPosixPath = '/my/pkg/boo/lib'; newFile('$booLibPosixPath/other_options.yaml', content: r''' analyzer: errors: unused_local_variable: false linter: rules: - camel_case_types '''); // Setup analysis options file which includes another options file. newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}', content: 'boo:$booLibPosixPath\n'); newFile('$projPath/$optionsFileName', content: r''' include: package:boo/other_options.yaml '''); // Setup context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Verify options were set. expect(errorProcessors, hasLength(1)); expect(lints, hasLength(1)); expect(lints[0].name, 'camel_case_types'); } test_analysis_options_parse_failure() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); String sdkExtPath = '$projPath/sdk_ext'; newFile('$sdkExtPath/entry.dart'); String sdkExtSrcPath = '$projPath/sdk_ext/src'; newFile('$sdkExtSrcPath/part.dart'); // Setup analysis options file with ignore list. String optionsFilePath = newFile('$projPath/$optionsFileName', content: r''' ; ''').path; // Setup context. manager.setRoots([projPath], [], {}); // Check that an error was produced. TestNotificationManager notificationManager = callbacks.notificationManager; var errors = notificationManager.recordedErrors; expect(errors, hasLength(1)); expect(errors[errors.keys.first][optionsFilePath], hasLength(1)); } test_deleteRoot_hasAnalysisOptions() async { newFile('$projPath/$optionsFileName'); // Add the root. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Remove the root, with the analysis options file. // No exceptions. resourceProvider.deleteFolder(projPath); await pumpEventQueue(); } @failingTest test_embedder_options() async { // This fails because the ContextBuilder doesn't pick up the strongMode // flag from the embedder.yaml file. // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; String sdkExtPath = '$projPath/sdk_ext'; newFile('$projPath/test', content: 'test.dart'); newFile('$sdkExtPath/entry.dart'); var synchronousSession = SynchronousSession(analysisOptions, null); List bytes = new SummaryBuilder( [], RestrictedAnalysisContext(synchronousSession, null)) .build(); newFileWithBytes('$projPath/sdk.ds', bytes); // Setup _embedder.yaml. newFile('$libPath/_embedder.yaml', content: r''' embedded_libs: "dart:foobar": "../sdk_ext/entry.dart" analyzer: strong-mode: true errors: missing_return: false linter: rules: - avoid_as '''); // Setup .packages file newFile('$projPath/.packages', content: r''' test_pack:lib/'''); // Setup analysis options newFile('$projPath/$optionsFileName', content: r''' analyzer: exclude: - 'test/**' errors: unused_local_variable: false linter: rules: - camel_case_types '''); // Setup context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); // Confirm that one context was created. int count = manager .numberOfContextsInAnalysisRoot(resourceProvider.newFolder(projPath)); expect(count, equals(1)); // Verify options. // * from `_embedder.yaml`: // TODO(brianwilkerson) Figure out what to use in place of 'strongMode'. // expect(analysisOptions.strongMode, isTrue); // * verify tests are excluded expect( callbacks.currentContextFilePaths[projPath].keys, unorderedEquals( ['/my/proj/sdk_ext/entry.dart', '/my/proj/$optionsFileName'])); // Verify filter setup. expect(errorProcessors, hasLength(2)); // * (embedder.) expect(getProcessor(missing_return).severity, isNull); // * (options.) expect(getProcessor(unused_local_variable).severity, isNull); // Verify lints. var lintNames = lints.map((lint) => lint.name); expect( lintNames, unorderedEquals([ 'avoid_as' /* embedder */, 'camel_case_types' /* options */ ])); // Sanity check embedder libs. var source = sourceFactory.forUri('dart:foobar'); expect(source, isNotNull); expect(source.fullName, '/my/proj/sdk_ext/entry.dart'); } test_error_filter_analysis_option() async { // Create files. newFile('$projPath/$optionsFileName', content: r''' analyzer: errors: unused_local_variable: ignore '''); // Setup context. manager.setRoots([projPath], [], {}); // Verify filter setup. expect(errorProcessors, hasLength(1)); expect(getProcessor(unused_local_variable).severity, isNull); } test_error_filter_analysis_option_multiple_filters() async { // Create files. newFile('$projPath/$optionsFileName', content: r''' analyzer: errors: invalid_assignment: ignore unused_local_variable: error '''); // Setup context. manager.setRoots([projPath], [], {}); // Verify filter setup. expect(errorProcessors, hasLength(2)); expect(getProcessor(invalid_assignment_error).severity, isNull); expect(getProcessor(unused_local_variable).severity, ErrorSeverity.ERROR); } test_error_filter_analysis_option_synonyms() async { // Create files. newFile('$projPath/$optionsFileName', content: r''' analyzer: errors: unused_local_variable: ignore ambiguous_import: false '''); // Setup context. manager.setRoots([projPath], [], {}); // Verify filter setup. expect(errorProcessors, isNotNull); expect(errorProcessors, hasLength(2)); } test_error_filter_analysis_option_unpsecified() async { // Create files. newFile('$projPath/$optionsFileName', content: r''' analyzer: # errors: # unused_local_variable: ignore '''); // Setup context. manager.setRoots([projPath], [], {}); // Verify filter setup. expect(errorProcessors, isEmpty); } test_non_analyzable_files_not_considered() async { // Set up project and get a reference to the driver. manager.setRoots([projPath], [], {}); Folder projectFolder = resourceProvider.newFolder(projPath); var drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, hasLength(1)); // Add the driver to the manager so that it will receive the events. manager.driverMap[projectFolder] = drivers[0]; // Ensure adding a file that shouldn't be analyzed is not picked up. newFile('$projPath/test.txt'); await pumpEventQueue(); expect(drivers[0].hasFilesToAnalyze, false); // Ensure modifying a file that shouldn't be analyzed is not picked up. modifyFile('$projPath/test.txt', 'new content'); await pumpEventQueue(); expect(drivers[0].hasFilesToAnalyze, false); } @failingTest test_optionsFile_update_strongMode() async { // It appears that this fails because we are not correctly updating the // analysis options in the driver when the file is modified. //return super.test_optionsFile_update_strongMode(); // After a few other changes, the test now times out on my machine, so I'm // disabling it in order to prevent it from being flaky. _fail('Test times out'); var file = resourceProvider.newFile('$projPath/bin/test.dart', r''' main() { var paths = []; var names = []; paths.addAll(names.map((s) => s.length)); } '''); resourceProvider.newFile('$projPath/$optionsFileName', r''' analyzer: strong-mode: false '''); // Create the context. manager.setRoots([projPath], [], {}); await pumpEventQueue(); var result = await callbacks.currentDriver.getResult(file.path); // Not strong mode - both in the context and the SDK context. // AnalysisContext sdkContext = sourceFactory.dartSdk.context; // TODO(brianwilkerson) Figure out whether there is an option other than // 'strongMode' that will apply to the SDK context. // expect(analysisOptions.strongMode, isFalse); // expect(sdkContext.analysisOptions.strongMode, isFalse); expect(result.errors, isEmpty); // Update the options file - turn on 'strong-mode'. resourceProvider.updateFile('$projPath/$optionsFileName', r''' analyzer: strong-mode: true '''); await pumpEventQueue(); // Strong mode - both in the context and the SDK context. result = await callbacks.currentDriver.getResult(file.path); // Not strong mode - both in the context and the SDK context. // sdkContext = sourceFactory.dartSdk.context; // TODO(brianwilkerson) Figure out whether there is an option other than // 'strongMode' that will apply to the SDK context. // expect(analysisOptions.strongMode, isTrue); // expect(sdkContext.analysisOptions.strongMode, isTrue); // The code is strong-mode clean. // Verify that TypeSystem was reset. expect(result.errors, isEmpty); } @failingTest test_path_filter_analysis_option() async { // This fails because we're not analyzing the analysis options file. // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/nope.dart'); String sdkExtPath = '$projPath/sdk_ext'; newFile('$sdkExtPath/entry.dart'); String sdkExtSrcPath = '$projPath/sdk_ext/src'; newFile('$sdkExtSrcPath/part.dart'); // Setup analysis options file with ignore list. newFile('$projPath/$optionsFileName', content: r''' analyzer: exclude: - lib/nope.dart - 'sdk_ext/**' '''); // Setup context. manager.setRoots([projPath], [], {}); // Verify that analysis options was parsed and the ignore patterns applied. Folder projectFolder = resourceProvider.newFolder(projPath); var drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, hasLength(1)); AnalysisDriver driver = drivers[0]; expect( driver.addedFiles, unorderedEquals( ['/my/proj/lib/main.dart', '/my/proj/$optionsFileName'])); } test_path_filter_child_contexts_option() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/pubspec.yaml', content: r''' name: foobar '''); String otherLibPath = '$projPath/other_lib'; newFile('$otherLibPath/entry.dart'); newFile('$otherLibPath/pubspec.yaml', content: r''' name: other_lib '''); // Setup analysis options file with ignore list that ignores the 'other_lib' // directory by name. newFile('$projPath/$optionsFileName', content: r''' analyzer: exclude: - 'other_lib' '''); // Setup context. manager.setRoots([projPath], [], {}); // Verify that the context in other_lib wasn't created and that the // context in lib was created. Folder projectFolder = resourceProvider.newFolder(projPath); var drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, hasLength(2)); expect(drivers[0].name, equals(convertPath('/my/proj'))); expect(drivers[1].name, equals(convertPath('/my/proj/lib'))); } test_path_filter_recursive_wildcard_child_contexts_option() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/pubspec.yaml', content: r''' name: foobar '''); String otherLibPath = '$projPath/other_lib'; newFile('$otherLibPath/entry.dart'); newFile('$otherLibPath/pubspec.yaml', content: r''' name: other_lib '''); // Setup analysis options file with ignore list that ignores 'other_lib' // and all descendants. newFile('$projPath/$optionsFileName', content: r''' analyzer: exclude: - 'other_lib/**' '''); // Setup context. manager.setRoots([projPath], [], {}); // Verify that the context in other_lib wasn't created and that the // context in lib was created. Folder projectFolder = resourceProvider.newFolder(projPath); var drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, hasLength(2)); expect(drivers[0].name, equals(convertPath('/my/proj'))); expect(drivers[1].name, equals(convertPath('/my/proj/lib'))); } test_path_filter_wildcard_child_contexts_option() async { // Create files. String libPath = '$projPath/${ContextManagerTest.LIB_NAME}'; newFile('$libPath/main.dart'); newFile('$libPath/pubspec.yaml', content: r''' name: foobar '''); String otherLibPath = '$projPath/other_lib'; newFile('$otherLibPath/entry.dart'); newFile('$otherLibPath/pubspec.yaml', content: r''' name: other_lib '''); // Setup analysis options file with ignore list that ignores 'other_lib' // and all immediate children. newFile('$projPath/$optionsFileName', content: r''' analyzer: exclude: - 'other_lib/*' '''); // Setup context / driver. manager.setRoots([projPath], [], {}); Folder projectFolder = resourceProvider.newFolder(projPath); var drivers = manager.getDriversInAnalysisRoot(projectFolder); expect(drivers, hasLength(2)); expect(drivers[0].name, equals(convertPath('/my/proj'))); expect(drivers[1].name, equals(convertPath('/my/proj/lib'))); } void test_setRoots_nested_excludedByOuter() { String project = convertPath('/project'); String projectPubspec = convertPath('$project/pubspec.yaml'); String example = convertPath('$project/example'); String examplePubspec = convertPath('$example/pubspec.yaml'); // create files resourceProvider.newFile(projectPubspec, 'name: project'); resourceProvider.newFile(examplePubspec, 'name: example'); newFile('$project/$optionsFileName', content: r''' analyzer: exclude: - 'example' '''); manager .setRoots([project, example], [], {}); // verify { ContextInfo rootInfo = manager.rootInfo; expect(rootInfo.children, hasLength(1)); { ContextInfo projectInfo = rootInfo.children[0]; expect(projectInfo.folder.path, project); expect(projectInfo.children, hasLength(1)); { ContextInfo exampleInfo = projectInfo.children[0]; expect(exampleInfo.folder.path, example); expect(exampleInfo.children, isEmpty); } } } expect(callbacks.currentContextRoots, hasLength(2)); expect(callbacks.currentContextRoots, unorderedEquals([project, example])); } void test_setRoots_nested_excludedByOuter_deep() { String a = convertPath('/a'); String c = convertPath('$a/b/c'); String aPubspec = convertPath('$a/pubspec.yaml'); String cPubspec = convertPath('$c/pubspec.yaml'); // create files resourceProvider.newFile(aPubspec, 'name: aaa'); resourceProvider.newFile(cPubspec, 'name: ccc'); newFile('$a/$optionsFileName', content: r''' analyzer: exclude: - 'b**' '''); manager.setRoots([a, c], [], {}); // verify { ContextInfo rootInfo = manager.rootInfo; expect(rootInfo.children, hasLength(1)); { ContextInfo aInfo = rootInfo.children[0]; expect(aInfo.folder.path, a); expect(aInfo.children, hasLength(1)); { ContextInfo cInfo = aInfo.children[0]; expect(cInfo.folder.path, c); expect(cInfo.children, isEmpty); } } } expect(callbacks.currentContextRoots, hasLength(2)); expect(callbacks.currentContextRoots, unorderedEquals([a, c])); } test_watchEvents() async { String libPath = newFolder('$projPath/${ContextManagerTest.LIB_NAME}').path; manager.setRoots([projPath], [], {}); newFile('$libPath/main.dart'); await new Future.delayed(new Duration(milliseconds: 1)); expect(callbacks.watchEvents, hasLength(1)); } } class TestContextManagerCallbacks extends ContextManagerCallbacks { /** * Source of timestamps stored in [currentContextFilePaths]. */ int now = 0; /** * The analysis driver that was created. */ AnalysisDriver currentDriver; /** * A table mapping paths to the analysis driver associated with that path. */ Map driverMap = {}; /** * Map from context to the timestamp when the context was created. */ Map currentContextTimestamps = {}; /** * Map from context to (map from file path to timestamp of last event). */ final Map> currentContextFilePaths = >{}; /** * A map from the paths of contexts to a set of the sources that should be * explicitly analyzed in those contexts. */ final Map> currentContextSources = >{}; /** * Resource provider used for this test. */ final ResourceProvider resourceProvider; /** * The manager managing the SDKs. */ final DartSdkManager sdkManager; /** * The logger used by the scheduler and the driver. */ final PerformanceLog logger; /** * The scheduler used by the driver. */ final AnalysisDriverScheduler scheduler; /** * The list of `flushedFiles` in the last [removeContext] invocation. */ List lastFlushedFiles; /** * The watch events that have been broadcast. */ List watchEvents = []; @override NotificationManager notificationManager = new TestNotificationManager(); TestContextManagerCallbacks( this.resourceProvider, this.sdkManager, this.logger, this.scheduler); /** * Return the current set of analysis options. */ AnalysisOptions get analysisOptions => currentDriver?.analysisOptions; /** * Return the paths to the context roots that currently exist. */ Iterable get currentContextRoots { return currentContextTimestamps.keys; } /** * Return the paths to the files being analyzed in the current context root. */ Iterable get currentFilePaths { if (currentDriver == null) { return []; } return currentDriver.addedFiles; } /** * Return the current source factory. */ SourceFactory get sourceFactory => currentDriver?.sourceFactory; @override AnalysisDriver addAnalysisDriver( Folder folder, ContextRoot contextRoot, AnalysisOptions options) { String path = folder.path; expect(currentContextRoots, isNot(contains(path))); expect(contextRoot, isNotNull); expect(contextRoot.root, path); currentContextTimestamps[path] = now; ContextBuilder builder = createContextBuilder(folder, options, useSummaries: true); builder.analysisDriverScheduler = scheduler; builder.byteStore = MemoryByteStore(); builder.performanceLog = logger; builder.fileContentOverlay = FileContentOverlay(); currentDriver = builder.buildDriver(contextRoot); driverMap[path] = currentDriver; currentDriver.exceptions.listen((ExceptionResult result) { AnalysisEngine.instance.logger .logError('Analysis failed: ${result.path}', result.exception); }); return currentDriver; } @override void afterWatchEvent(WatchEvent event) {} @override void analysisOptionsUpdated(AnalysisDriver driver) {} @override void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { AnalysisDriver driver = driverMap[contextFolder.path]; if (driver != null) { changeSet.addedSources.forEach((source) { driver.addFile(source.fullName); }); changeSet.changedSources.forEach((source) { driver.changeFile(source.fullName); }); changeSet.removedSources.forEach((source) { driver.removeFile(source.fullName); }); } } @override void applyFileRemoved(AnalysisDriver driver, String file) { driver.removeFile(file); } void assertContextFiles(String contextPath, List expectedFiles) { expect(getCurrentFilePaths(contextPath), unorderedEquals(expectedFiles)); } void assertContextPaths(List expected) { expect(currentContextRoots, unorderedEquals(expected)); } @override void broadcastWatchEvent(WatchEvent event) { watchEvents.add(event); } @override ContextBuilder createContextBuilder(Folder folder, AnalysisOptions options, {bool useSummaries = false}) { ContextBuilderOptions builderOptions = new ContextBuilderOptions(); builderOptions.defaultOptions = options; ContextBuilder builder = new ContextBuilder( resourceProvider, sdkManager, null, options: builderOptions); return builder; } /** * Return the paths to the files being analyzed in the current context root. */ Iterable currentFileSources(String contextPath) { if (currentDriver == null) { return []; } AnalysisDriver driver = driverMap[contextPath]; SourceFactory sourceFactory = driver.sourceFactory; return driver.addedFiles.map((String path) { File file = resourceProvider.getFile(path); Source source = file.createSource(); Uri uri = sourceFactory.restoreUri(source); return file.createSource(uri); }); } /** * Return the paths to the files being analyzed in the current context root. */ Iterable getCurrentFilePaths(String contextPath) { if (currentDriver == null) { return []; } return driverMap[contextPath].addedFiles; } @override void removeContext(Folder folder, List flushedFiles) { String path = folder.path; expect(currentContextRoots, contains(path)); currentContextTimestamps.remove(path); currentContextFilePaths.remove(path); currentContextSources.remove(path); lastFlushedFiles = flushedFiles; } }