blob: fea3b437da27387ce93325b83f4548229109a85c [file] [log] [blame]
// 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 '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/exception/exception.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/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
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/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/package_config_file_builder.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';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(AbstractContextManagerTest);
defineReflectiveTests(ContextManagerWithOptionsTest);
});
}
/// 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() {
var subProjPath = join(projPath, 'subproj');
var subProjFolder = newFolder(subProjPath);
newFile(join(subProjPath, 'pubspec.yaml'), content: 'contents');
var subProjFilePath = join(subProjPath, 'file.dart');
newFile(subProjFilePath, content: 'contents');
manager.setRoots(<String>[projPath], <String>[]);
// Make sure that there really are contexts for both the main project and
// the subproject.
var projectFolder = getFolder(projPath);
var projContextInfo = manager.getContextInfoFor(projectFolder);
expect(projContextInfo, isNotNull);
expect(projContextInfo.folder, projectFolder);
var subProjContextInfo = manager.getContextInfoFor(subProjFolder);
expect(subProjContextInfo, isNotNull);
expect(subProjContextInfo.folder, subProjFolder);
expect(projContextInfo.analysisDriver,
isNot(equals(subProjContextInfo.analysisDriver)));
// Check that getDriversInAnalysisRoot() works.
var drivers = manager.getDriversInAnalysisRoot(projectFolder);
expect(drivers, isNotNull);
expect(drivers, hasLength(2));
expect(drivers, contains(projContextInfo.analysisDriver));
expect(drivers, contains(subProjContextInfo.analysisDriver));
}
@failingTest
Future<void> 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.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
newFile('$libPath/nope.dart');
var embedderPath = '$projPath/embedder';
newFile('$embedderPath/entry.dart');
var 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"
''');
var projectFolder = newFolder(projPath);
// NOTE that this is Not in our package path yet.
// Setup context.
manager.setRoots(<String>[projPath], <String>[]);
await pumpEventQueue();
// Confirm that one driver / context was created.
var 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);
}
Future<void> test_embedder_packagespec() async {
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
newFile('$libPath/nope.dart');
var sdkExtPath = '$projPath/sdk_ext';
newFile('$sdkExtPath/entry.dart');
var 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'''
sky_engine:lib/''');
// Setup context.
manager.setRoots(<String>[projPath], <String>[]);
await pumpEventQueue();
// Confirm that one context was created.
var count = manager.numberOfContextsInAnalysisRoot(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
var project = convertPath('/project');
var excludedFolder = convertPath('$project/excluded');
// set roots
newFolder(project);
newFolder(excludedFolder);
manager.setRoots(<String>[project], <String>[excludedFolder]);
// verify
expect(manager.isInAnalysisRoot(convertPath('$excludedFolder/test.dart')),
isFalse);
}
void test_isInAnalysisRoot_inNestedContext() {
var subProjPath = join(projPath, 'subproj');
var subProjFolder = newFolder(subProjPath);
newFile(join(subProjPath, 'pubspec.yaml'), content: 'contents');
var subProjFilePath = join(subProjPath, 'file.dart');
newFile(subProjFilePath, content: 'contents');
manager.setRoots(<String>[projPath], <String>[]);
// Make sure that there really is a context for the subproject.
var 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(<String>[projPath], <String>[]);
expect(manager.isInAnalysisRoot('$projPath/test.dart'), isTrue);
}
void test_isInAnalysisRoot_notInRoot() {
manager.setRoots(<String>[projPath], <String>[]);
expect(manager.isInAnalysisRoot('/test.dart'), isFalse);
}
Future<void> test_packagesFolder_areAnalyzed() {
// create a context with a pubspec.yaml file
var pubspecPath = join(projPath, 'pubspec.yaml');
newFile(pubspecPath, content: 'pubspec');
// create a file in the "packages" folder
var filePath1 = join(projPath, 'packages', 'file1.dart');
var file1 = newFile(filePath1, content: 'contents');
manager.setRoots(<String>[projPath], <String>[]);
expect(callbacks.currentFilePaths, unorderedEquals([file1.path]));
var filePath2 = join(projPath, 'packages', 'file2.dart');
var file2 = newFile(filePath2, content: 'contents');
return pumpEventQueue().then((_) {
expect(callbacks.currentFilePaths,
unorderedEquals([file1.path, file2.path]));
});
}
Future<void> test_refresh_folder_with_packagespec() {
// create a context with a .packages file
var packagespecFile = join(projPath, '.packages');
newFile(packagespecFile, content: '');
manager.setRoots(<String>[projPath], <String>[]);
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.
Future<void> test_refresh_folder_with_packagespec_subfolders() {
// Create a folder with no .packages file, containing two subfolders with
// .packages files.
var subdir1Path = join(projPath, 'subdir1');
var subdir2Path = join(projPath, 'subdir2');
var packagespec1Path = join(subdir1Path, '.packages');
var packagespec2Path = join(subdir2Path, '.packages');
newFile(packagespec1Path, content: '');
newFile(packagespec2Path, content: '');
manager.setRoots(<String>[projPath], <String>[]);
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);
});
});
}
Future<void> test_refresh_folder_with_pubspec() {
// create a context with a pubspec.yaml file
var pubspecPath = join(projPath, 'pubspec.yaml');
newFile(pubspecPath, content: 'pubspec');
manager.setRoots(<String>[projPath], <String>[]);
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);
});
});
}
Future<void> test_refresh_folder_with_pubspec_subfolders() {
// Create a folder with no pubspec.yaml, containing two subfolders with
// pubspec.yaml files.
var subdir1Path = join(projPath, 'subdir1');
var subdir2Path = join(projPath, 'subdir2');
var pubspec1Path = join(subdir1Path, 'pubspec.yaml');
var pubspec2Path = join(subdir2Path, 'pubspec.yaml');
newFile(pubspec1Path, content: 'pubspec');
newFile(pubspec2Path, content: 'pubspec');
manager.setRoots(<String>[projPath], <String>[]);
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);
});
});
}
Future<void> test_refresh_oneContext() {
// create two contexts with pubspec.yaml files
var pubspecPath = join(projPath, 'pubspec.yaml');
newFile(pubspecPath, content: 'pubspec1');
var proj2Path = convertPath('/my/proj2');
newFolder(proj2Path);
var pubspec2Path = join(proj2Path, 'pubspec.yaml');
newFile(pubspec2Path, content: 'pubspec2');
var roots = <String>[projPath, proj2Path];
manager.setRoots(roots, <String>[]);
return pumpEventQueue().then((_) {
expect(callbacks.currentContextRoots, unorderedEquals(roots));
var then = callbacks.now;
callbacks.now++;
manager.refresh([getFolder(proj2Path)]);
return pumpEventQueue().then((_) {
expect(callbacks.currentContextRoots, unorderedEquals(roots));
expect(callbacks.currentContextTimestamps[projPath], then);
expect(callbacks.currentContextTimestamps[proj2Path], callbacks.now);
});
});
}
void test_setRoots_addFolderWithDartFile() {
var filePath = join(projPath, 'foo.dart');
newFile(filePath, content: 'contents');
manager.setRoots(<String>[projPath], <String>[]);
// verify
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
var drivers = manager.getDriversInAnalysisRoot(newFolder(projPath));
expect(drivers, hasLength(1));
expect(drivers[0], isNotNull);
var result = sourceFactory.forUri('dart:async');
expect(result, isNotNull);
}
void test_setRoots_addFolderWithDartFileInSubfolder() {
var filePath = join(projPath, 'foo', 'bar.dart');
newFile(filePath, content: 'contents');
manager.setRoots(<String>[projPath], <String>[]);
// verify
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
}
void test_setRoots_addFolderWithDummyLink() {
var filePath = join(projPath, 'foo.dart');
resourceProvider.newDummyLink(filePath);
manager.setRoots(<String>[projPath], <String>[]);
// verify
expect(callbacks.currentFilePaths, isEmpty);
}
void test_setRoots_addFolderWithNestedPackageSpec() {
var examplePath =
convertPath('$projPath/${ContextManagerTest.EXAMPLE_NAME}');
var 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(<String>[projPath], <String>[]);
expect(callbacks.currentContextRoots, hasLength(2));
expect(callbacks.currentContextRoots, contains(projPath));
var projSources = callbacks.currentFileSources(projPath);
expect(projSources, hasLength(1));
expect(projSources.first.uri, toUri('$libPath/main.dart'));
expect(callbacks.currentContextRoots, contains(examplePath));
var exampleSources = callbacks.currentFileSources(examplePath);
expect(exampleSources, hasLength(1));
expect(exampleSources.first.uri, toUri('$examplePath/example.dart'));
}
void test_setRoots_addFolderWithNestedPubspec() {
var examplePath =
convertPath('$projPath/${ContextManagerTest.EXAMPLE_NAME}');
var 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(<String>[projPath], <String>[]);
expect(callbacks.currentContextRoots, hasLength(2));
expect(callbacks.currentContextRoots, contains(projPath));
var projSources = callbacks.currentFileSources(projPath);
expect(projSources, hasLength(1));
expect(projSources.first.uri.toString(), 'package:proj/main.dart');
expect(callbacks.currentContextRoots, contains(examplePath));
var exampleSources = callbacks.currentFileSources(examplePath);
expect(exampleSources, hasLength(1));
expect(exampleSources.first.uri, toUri('$examplePath/example.dart'));
}
void test_setRoots_addFolderWithoutPubspec() {
manager.setRoots(<String>[projPath], <String>[]);
// verify
expect(callbacks.currentContextRoots, unorderedEquals([projPath]));
expect(callbacks.currentFilePaths, hasLength(0));
}
void test_setRoots_addFolderWithPackagespec() {
var packagespecPath = join(projPath, '.packages');
var testLib = convertPath('/home/somebody/.pub/cache/unittest-0.9.9/lib');
newFile(packagespecPath, content: 'unittest:${toUriStr(testLib)}');
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
var mainFile = newFile('$libPath/main.dart');
var source = mainFile.createSource();
manager.setRoots(<String>[projPath], <String>[]);
// verify
expect(callbacks.currentContextRoots, unorderedEquals([projPath]));
expect(callbacks.currentFilePaths, hasLength(1));
// smoketest resolution
var resolvedSource =
sourceFactory.resolveUri(source, 'package:unittest/unittest.dart');
expect(resolvedSource, isNotNull);
expect(resolvedSource.fullName, convertPath('$testLib/unittest.dart'));
}
void test_setRoots_addFolderWithPubspec() {
var pubspecPath = join(projPath, 'pubspec.yaml');
newFile(pubspecPath, content: 'pubspec');
manager.setRoots(<String>[projPath], <String>[]);
// verify
expect(callbacks.currentContextRoots, unorderedEquals([projPath]));
expect(callbacks.currentFilePaths, hasLength(0));
}
void test_setRoots_addFolderWithPubspec_andPackagespec() {
var pubspecPath = join(projPath, 'pubspec.yaml');
var packagespecPath = join(projPath, '.packages');
newFile(pubspecPath, content: 'pubspec');
newFile(packagespecPath, content: '');
manager.setRoots(<String>[projPath], <String>[]);
// verify
callbacks.assertContextPaths([projPath]);
}
void test_setRoots_addFolderWithPubspecAndLib() {
var binPath = '$projPath/${ContextManagerTest.BIN_NAME}';
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
var srcPath = '$libPath/${ContextManagerTest.SRC_NAME}';
var testPath = '$projPath/${ContextManagerTest.TEST_NAME}';
newFile('$projPath/${ContextManagerImpl.PUBSPEC_NAME}');
newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}',
content: 'proj:lib/');
var appPath = newFile('$binPath/app.dart').path;
newFile('$libPath/main.dart');
newFile('$srcPath/internal.dart');
var testFilePath = newFile('$testPath/main_test.dart').path;
manager.setRoots(<String>[projPath], <String>[]);
var sources = callbacks.currentFileSources(projPath);
expect(callbacks.currentContextRoots, unorderedEquals([projPath]));
expect(sources, hasLength(4));
var uris = sources.map((Source source) => source.uri.toString()).toList();
expect(uris, contains(toUriStr(appPath)));
expect(uris, contains('package:proj/main.dart'));
expect(uris, contains('package:proj/src/internal.dart'));
expect(uris, contains(toUriStr(testFilePath)));
}
void test_setRoots_addFolderWithPubspecAndPackagespecFolders() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProjectA = convertPath('$root/sub/aaa');
var subProjectB = convertPath('$root/sub/sub2/bbb');
var subProjectA_file = convertPath('$subProjectA/bin/a.dart');
var 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(<String>[root], <String>[]);
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
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var projectA = convertPath('$root/sub/aaa');
var projectALib = convertPath('$root/sub/aaa/lib');
var subProjectA_file = convertPath('$projectA/bin/a.dart');
var projectB = convertPath('$root/sub/sub2/bbb');
var projectBLib = convertPath('$root/sub/sub2/bbb/lib');
var 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/');
newFile(rootFile, content: 'library root;');
newFile(subProjectA_file, content: 'library a;');
newFile(subProjectB_file, content: 'library b;');
// set roots
manager.setRoots(<String>[root], <String>[]);
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': [getFolder(projectALib)]
}));
expect(
_packageMap(projectB),
equals({
'bar': [getFolder(projectBLib)]
}));
}
void test_setRoots_exclude_newRoot_withExcludedFile() {
// prepare paths
var project = convertPath('/project');
var file1 = convertPath('$project/file1.dart');
var file2 = convertPath('$project/file2.dart');
// create files
newFile(file1, content: '// 1');
newFile(file2, content: '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file1]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file2]);
}
void test_setRoots_exclude_newRoot_withExcludedFolder() {
// prepare paths
var project = convertPath('/project');
var folderA = convertPath('$project/aaa');
var folderB = convertPath('$project/bbb');
var fileA = convertPath('$folderA/a.dart');
var fileB = convertPath('$folderB/b.dart');
// create files
newFile(fileA, content: 'library a;');
newFile(fileB, content: 'library b;');
// set roots
manager.setRoots(<String>[project], <String>[folderB]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
void test_setRoots_exclude_sameRoot_addExcludedFile() {
// prepare paths
var project = convertPath('/project');
var file1 = convertPath('$project/file1.dart');
var file2 = convertPath('$project/file2.dart');
// create files
newFile(file1, content: '// 1');
newFile(file2, content: '// 2');
// set roots
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1, file2]);
// exclude "2"
manager.setRoots(<String>[project], <String>[file2]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
}
void test_setRoots_exclude_sameRoot_addExcludedFolder() {
// prepare paths
var project = convertPath('/project');
var folderA = convertPath('$project/aaa');
var folderB = convertPath('$project/bbb');
var fileA = convertPath('$folderA/a.dart');
var fileB = convertPath('$folderB/b.dart');
// create files
newFile(fileA, content: 'library a;');
newFile(fileB, content: 'library b;');
// initially both "aaa/a" and "bbb/b" are included
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA, fileB]);
// exclude "bbb/"
manager.setRoots(<String>[project], <String>[folderB]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFile() {
// prepare paths
var project = convertPath('/project');
var file1 = convertPath('$project/file1.dart');
var file2 = convertPath('$project/file2.dart');
// create files
newFile(file1, content: '// 1');
newFile(file2, content: '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file2]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
// stop excluding "2"
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1, file2]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFile_inFolder() {
// prepare paths
var project = convertPath('/project');
var file1 = convertPath('$project/bin/file1.dart');
var file2 = convertPath('$project/bin/file2.dart');
// create files
newFile(file1, content: '// 1');
newFile(file2, content: '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file2]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
// stop excluding "2"
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1, file2]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFolder() {
// prepare paths
var project = convertPath('/project');
var folderA = convertPath('$project/aaa');
var folderB = convertPath('$project/bbb');
var fileA = convertPath('$folderA/a.dart');
var fileB = convertPath('$folderB/b.dart');
// create files
newFile(fileA, content: 'library a;');
newFile(fileB, content: 'library b;');
// exclude "bbb/"
manager.setRoots(<String>[project], <String>[folderB]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
// stop excluding "bbb/"
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA, fileB]);
}
void test_setRoots_ignoreDocFolder() {
var project = convertPath('/project');
var fileA = convertPath('$project/foo.dart');
var fileB = convertPath('$project/lib/doc/bar.dart');
var fileC = convertPath('$project/doc/bar.dart');
newFile(fileA, content: '');
newFile(fileB, content: '');
newFile(fileC, content: '');
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA, fileB]);
}
void test_setRoots_nested_includedByOuter_innerFirst() {
var project = convertPath('/project');
var projectPubspec = convertPath('$project/pubspec.yaml');
var example = convertPath('$project/example');
var examplePubspec = convertPath('$example/pubspec.yaml');
// create files
newFile(projectPubspec, content: 'name: project');
newFile(examplePubspec, content: 'name: example');
manager.setRoots(<String>[example, project], <String>[]);
// verify
{
var rootInfo = manager.rootInfo;
expect(rootInfo.children, hasLength(1));
{
var projectInfo = rootInfo.children[0];
expect(projectInfo.folder.path, project);
expect(projectInfo.children, hasLength(1));
{
var 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() {
var project = convertPath('/project');
var projectPubspec = convertPath('$project/pubspec.yaml');
var example = convertPath('$project/example');
// create files
newFile(projectPubspec, content: 'name: project');
newFolder(example);
manager.setRoots(<String>[project, example], <String>[]);
// verify
{
var rootInfo = manager.rootInfo;
expect(rootInfo.children, hasLength(1));
{
var projectInfo = rootInfo.children[0];
expect(projectInfo.folder.path, project);
expect(projectInfo.children, isEmpty);
}
}
expect(callbacks.currentContextRoots, unorderedEquals([project]));
}
void test_setRoots_nested_includedByOuter_twoPubspecs() {
var project = convertPath('/project');
var projectPubspec = convertPath('$project/pubspec.yaml');
var example = convertPath('$project/example');
var examplePubspec = convertPath('$example/pubspec.yaml');
// create files
newFile(projectPubspec, content: 'name: project');
newFile(examplePubspec, content: 'name: example');
manager.setRoots(<String>[project, example], <String>[]);
// verify
{
var rootInfo = manager.rootInfo;
expect(rootInfo.children, hasLength(1));
{
var projectInfo = rootInfo.children[0];
expect(projectInfo.folder.path, project);
expect(projectInfo.children, hasLength(1));
{
var exampleInfo = projectInfo.children[0];
expect(exampleInfo.folder.path, example);
expect(exampleInfo.children, isEmpty);
}
}
}
expect(callbacks.currentContextRoots, unorderedEquals([project, example]));
}
void test_setRoots_newlyAddedFoldersGetProperPackageMap() {
var packagePath = convertPath('/package/foo');
newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}',
content: 'foo:${toUriStr('/package/foo')}');
var packageFolder = newFolder(packagePath);
manager.setRoots(<String>[projPath], <String>[]);
expect(
_currentPackageMap,
equals({
'foo': [packageFolder]
}));
}
void test_setRoots_noContext_excludedFolder() {
// prepare paths
var project = convertPath('/project');
var excludedFolder = convertPath('$project/excluded');
var excludedPubspec = convertPath('$excludedFolder/pubspec.yaml');
// create files
newFile(excludedPubspec, content: 'name: ignore-me');
// set "/project", and exclude "/project/excluded"
manager.setRoots(<String>[project], <String>[excludedFolder]);
callbacks.assertContextPaths([project]);
}
void test_setRoots_noContext_inDotFolder() {
var pubspecPath = join(projPath, '.pub', 'pubspec.yaml');
newFile(pubspecPath, content: 'name: test');
manager.setRoots(<String>[projPath], <String>[]);
// verify
expect(callbacks.currentContextRoots, hasLength(1));
expect(callbacks.currentContextRoots, contains(projPath));
expect(callbacks.currentFilePaths, hasLength(0));
}
void test_setRoots_packageResolver() {
var filePath = join(projPath, 'lib', 'foo.dart');
newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}',
content: 'foo:lib/');
newFile(filePath, content: 'contents');
manager.setRoots(<String>[projPath], <String>[]);
var drivers = manager.getDriversInAnalysisRoot(newFolder(projPath));
expect(drivers, hasLength(1));
expect(drivers[0], isNotNull);
var result = sourceFactory.forUri('package:foo/foo.dart');
expect(result.fullName, filePath);
}
void test_setRoots_packagesFolder_hasContext() {
var pubspecPath = join(projPath, 'packages', 'pubspec.yaml');
newFile(pubspecPath, content: 'name: test');
manager.setRoots(<String>[projPath], <String>[]);
// 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.
var project = convertPath('/project');
var fileA = convertPath('$project/foo.dart');
var fileB = convertPath('$project/.pub/bar.dart');
newFile(fileA, content: '');
newFile(fileB, content: '');
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
void test_setRoots_removeFolderWithoutPubspec() {
// add one root - there is a context
manager.setRoots(<String>[projPath], <String>[]);
expect(callbacks.currentContextRoots, hasLength(1));
// set empty roots - no contexts
manager.setRoots(<String>[], <String>[]);
expect(callbacks.currentContextRoots, hasLength(0));
expect(callbacks.currentFilePaths, hasLength(0));
}
void test_setRoots_removeFolderWithPackagespec() {
// create a pubspec
var pubspecPath = join(projPath, '.packages');
newFile(pubspecPath, content: '');
// add one root - there is a context
manager.setRoots(<String>[projPath], <String>[]);
expect(manager.changeSubscriptions, hasLength(1));
expect(callbacks.currentContextRoots, hasLength(1));
// set empty roots - no contexts
manager.setRoots(<String>[], <String>[]);
expect(manager.changeSubscriptions, hasLength(0));
expect(callbacks.currentContextRoots, hasLength(0));
expect(callbacks.currentFilePaths, hasLength(0));
}
void test_setRoots_removeFolderWithPackagespecFolder() {
// prepare paths
var projectA = convertPath('/projectA');
var projectB = convertPath('/projectB');
var subProjectA = convertPath('$projectA/sub');
var subProjectB = convertPath('$projectB/sub');
var projectA_file = convertPath('$projectA/a.dart');
var projectB_file = convertPath('$projectB/a.dart');
var subProjectA_pubspec = convertPath('$subProjectA/.packages');
var subProjectB_pubspec = convertPath('$subProjectB/.packages');
var subProjectA_file = convertPath('$subProjectA/bin/sub_a.dart');
var subProjectB_file = convertPath('$subProjectB/bin/sub_b.dart');
// create files
newFile(projectA_file, content: '// a');
newFile(projectB_file, content: '// b');
newFile(subProjectA_pubspec, content: '');
newFile(subProjectB_pubspec, content: '');
newFile(subProjectA_file, content: '// sub-a');
newFile(subProjectB_file, content: '// sub-b');
// set roots
manager.setRoots(<String>[projectA, projectB], <String>[]);
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(<String>[projectA], <String>[]);
callbacks.assertContextPaths([projectA, subProjectA]);
callbacks.assertContextFiles(projectA, [projectA_file]);
callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
}
void test_setRoots_removeFolderWithPubspec() {
// create a pubspec
var pubspecPath = join(projPath, 'pubspec.yaml');
newFile(pubspecPath, content: 'pubspec');
// add one root - there is a context
manager.setRoots(<String>[projPath], <String>[]);
expect(callbacks.currentContextRoots, hasLength(1));
// set empty roots - no contexts
manager.setRoots(<String>[], <String>[]);
expect(callbacks.currentContextRoots, hasLength(0));
expect(callbacks.currentFilePaths, hasLength(0));
}
void test_setRoots_removeFolderWithPubspecFolder() {
// prepare paths
var projectA = convertPath('/projectA');
var projectB = convertPath('/projectB');
var subProjectA = convertPath('$projectA/sub');
var subProjectB = convertPath('$projectB/sub');
var projectA_file = convertPath('$projectA/a.dart');
var projectB_file = convertPath('$projectB/a.dart');
var subProjectA_pubspec = convertPath('$subProjectA/pubspec.yaml');
var subProjectB_pubspec = convertPath('$subProjectB/pubspec.yaml');
var subProjectA_file = convertPath('$subProjectA/bin/sub_a.dart');
var subProjectB_file = convertPath('$subProjectB/bin/sub_b.dart');
// create files
newFile(projectA_file, content: '// a');
newFile(projectB_file, content: '// b');
newFile(subProjectA_pubspec, content: 'pubspec');
newFile(subProjectB_pubspec, content: 'pubspec');
newFile(subProjectA_file, content: '// sub-a');
newFile(subProjectB_file, content: '// sub-b');
// set roots
manager.setRoots(<String>[projectA, projectB], <String>[]);
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(<String>[projectA], <String>[]);
callbacks.assertContextPaths([projectA, subProjectA]);
callbacks.assertContextFiles(projectA, [projectA_file]);
callbacks.assertContextFiles(subProjectA, [subProjectA_file]);
}
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.
var project = convertPath('/.pub/project');
var fileA = convertPath('$project/foo.dart');
newFile(fileA, content: '');
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
Future<void> test_watch_addDummyLink() {
manager.setRoots(<String>[projPath], <String>[]);
// empty folder initially
expect(callbacks.currentFilePaths, isEmpty);
// add link
var filePath = join(projPath, 'foo.dart');
resourceProvider.newDummyLink(filePath);
// the link was ignored
return pumpEventQueue().then((_) {
expect(callbacks.currentFilePaths, isEmpty);
});
}
Future<void> test_watch_addFile() {
manager.setRoots(<String>[projPath], <String>[]);
// empty folder initially
expect(callbacks.currentFilePaths, hasLength(0));
// add file
var filePath = join(projPath, 'foo.dart');
newFile(filePath, content: 'contents');
// the file was added
return pumpEventQueue().then((_) {
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
});
}
Future<void> test_watch_addFile_excluded() {
// prepare paths
var project = convertPath('/project');
var folderA = convertPath('$project/aaa');
var folderB = convertPath('$project/bbb');
var fileA = convertPath('$folderA/a.dart');
var fileB = convertPath('$folderB/b.dart');
// create files
newFile(fileA, content: 'library a;');
// set roots
manager.setRoots(<String>[project], <String>[folderB]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
// add a file, ignored as excluded
newFile(fileB, content: 'library b;');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
});
}
Future<void> test_watch_addFile_inDocFolder_inner() {
// prepare paths
var project = convertPath('/project');
var fileA = convertPath('$project/a.dart');
var fileB = convertPath('$project/lib/doc/b.dart');
// create files
newFile(fileA, content: '');
// set roots
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
// add a "lib/doc" file, it is not ignored
newFile(fileB, content: '');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA, fileB]);
});
}
Future<void> test_watch_addFile_inDocFolder_topLevel() {
// prepare paths
var project = convertPath('/project');
var fileA = convertPath('$project/a.dart');
var fileB = convertPath('$project/doc/b.dart');
// create files
newFile(fileA, content: '');
// set roots
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
// add a "doc" file, it is ignored
newFile(fileB, content: '');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
});
}
Future<void> 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.
var project = convertPath('/project');
var fileA = convertPath('$project/foo.dart');
var fileB = convertPath('$project/.pub/bar.dart');
newFile(fileA, content: '');
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
newFile(fileB, content: '');
await pumpEventQueue();
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
Future<void> 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.
var project = convertPath('/.pub/project');
var fileA = convertPath('$project/foo.dart');
var fileB = convertPath('$project/bar/baz.dart');
newFile(fileA, content: '');
manager.setRoots(<String>[project], <String>[]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
newFile(fileB, content: '');
await pumpEventQueue();
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA, fileB]);
}
Future<void> test_watch_addFileInSubfolder() {
manager.setRoots(<String>[projPath], <String>[]);
// empty folder initially
expect(callbacks.currentFilePaths, hasLength(0));
// add file in subfolder
var filePath = join(projPath, 'foo', 'bar.dart');
newFile(filePath, content: 'contents');
// the file was added
return pumpEventQueue().then((_) {
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
});
}
Future<void> test_watch_addPackagespec_toRoot() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var rootPackagespec = convertPath('$root/.packages');
// create files
newFile(rootFile, content: 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root]);
// verify files
callbacks.assertContextFiles(root, [rootFile]);
// add packagespec - still just one root
newFile(rootPackagespec, content: '');
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.
});
}
Future<void> test_watch_addPackagespec_toSubFolder() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub/aaa');
var subPubspec = convertPath('$subProject/.packages');
var subFile = convertPath('$subProject/bin/a.dart');
// create files
newFile(rootFile, content: 'library root;');
newFile(subFile, content: 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root]);
// verify files
callbacks.assertContextFiles(root, [rootFile, subFile]);
// add .packages
newFile(subPubspec, content: '');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
});
}
Future<void> test_watch_addPackagespec_toSubFolder_ofSubFolder() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub');
var subPubspec = convertPath('$subProject/.packages');
var subFile = convertPath('$subProject/bin/sub.dart');
var subSubPubspec = convertPath('$subProject/subsub/.packages');
// create files
newFile(rootFile, content: 'library root;');
newFile(subPubspec, content: '');
newFile(subFile, content: 'library sub;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
// add pubspec - ignore, because is already in a packagespec-based context
newFile(subSubPubspec, content: '');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
});
}
Future<void> test_watch_addPackagespec_toSubFolder_withPubspec() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub/aaa');
var subPackagespec = convertPath('$subProject/.packages');
var subPubspec = convertPath('$subProject/pubspec.yaml');
var subFile = convertPath('$subProject/bin/a.dart');
// create files
newFile(subPubspec, content: 'pubspec');
newFile(rootFile, content: 'library root;');
newFile(subFile, content: 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root, subProject]);
// verify files
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
// add .packages
newFile(subPackagespec, content: '');
return pumpEventQueue().then((_) {
// Should NOT create another context.
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
});
}
Future<void> test_watch_addPubspec_toRoot() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var rootPubspec = convertPath('$root/pubspec.yaml');
// create files
newFile(rootFile, content: 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root]);
// verify files
callbacks.assertContextFiles(root, [rootFile]);
// add pubspec - still just one root
newFile(rootPubspec, content: 'pubspec');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root]);
callbacks.assertContextFiles(root, [rootFile]);
});
}
Future<void> test_watch_addPubspec_toSubFolder() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub/aaa');
var subPubspec = convertPath('$subProject/pubspec.yaml');
var subFile = convertPath('$subProject/bin/a.dart');
// create files
newFile(rootFile, content: 'library root;');
newFile(subFile, content: 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root]);
// verify files
callbacks.assertContextFiles(root, [rootFile, subFile]);
// add pubspec
newFile(subPubspec, content: 'pubspec');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
});
}
Future<void> test_watch_addPubspec_toSubFolder_ofSubFolder() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub');
var subPubspec = convertPath('$subProject/pubspec.yaml');
var subFile = convertPath('$subProject/bin/sub.dart');
var subSubPubspec = convertPath('$subProject/subsub/pubspec.yaml');
// create files
newFile(rootFile, content: 'library root;');
newFile(subPubspec, content: 'pubspec');
newFile(subFile, content: 'library sub;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
// add pubspec - ignore, because is already in a pubspec-based context
newFile(subSubPubspec, content: 'pubspec');
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
});
}
Future<void> test_watch_deleteFile() {
var filePath = join(projPath, 'foo.dart');
// add root with a file
var file = newFile(filePath, content: 'contents');
var projFolder = file.parent;
manager.setRoots(<String>[projPath], <String>[]);
// the file was added
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
expect(file.exists, isTrue);
expect(projFolder.exists, isTrue);
// delete the file
deleteFile(filePath);
return pumpEventQueue().then((_) {
expect(file.exists, isFalse);
expect(projFolder.exists, isTrue);
expect(callbacks.currentFilePaths, hasLength(0));
});
}
Future<void> test_watch_deleteFolder() {
var filePath = join(projPath, 'foo.dart');
// add root with a file
var file = newFile(filePath, content: 'contents');
var projFolder = file.parent;
manager.setRoots(<String>[projPath], <String>[]);
// the file was added
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
expect(file.exists, isTrue);
expect(projFolder.exists, isTrue);
// delete the folder
deleteFolder(projPath);
return pumpEventQueue().then((_) {
expect(file.exists, isFalse);
expect(projFolder.exists, isFalse);
expect(callbacks.currentFilePaths, hasLength(0));
});
}
Future<void> test_watch_deletePackagespec_fromRoot() {
// prepare paths
var root = convertPath('/root');
var rootPubspec = convertPath('$root/.packages');
var rootFile = convertPath('$root/root.dart');
// create files
newFile(rootPubspec, content: '');
newFile(rootFile, content: 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root]);
callbacks.assertContextFiles(root, [rootFile]);
// delete the pubspec
deleteFile(rootPubspec);
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root]);
callbacks.assertContextFiles(root, [rootFile]);
});
}
Future<void> test_watch_deletePackagespec_fromSubFolder() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub/aaa');
var subPubspec = convertPath('$subProject/.packages');
var subFile = convertPath('$subProject/bin/a.dart');
// create files
newFile(subPubspec, content: '');
newFile(rootFile, content: 'library root;');
newFile(subFile, content: 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root, subProject]);
// verify files
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
// delete the pubspec
deleteFile(subPubspec);
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root]);
callbacks.assertContextFiles(root, [rootFile, subFile]);
});
}
Future<void> test_watch_deletePackagespec_fromSubFolder_withPubspec() {
// prepare paths:
//
// root
// root.dart
// sub
// aaa
// .packages
// pubspec.yaml
// bin
// a.dart
//
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub/aaa');
var subPackagespec = convertPath('$subProject/.packages');
var subPubspec = convertPath('$subProject/pubspec.yaml');
var subFile = convertPath('$subProject/bin/a.dart');
// create files
newFile(subPackagespec, content: '');
newFile(subPubspec, content: 'pubspec');
newFile(rootFile, content: 'library root;');
newFile(subFile, content: 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root, subProject]);
// verify files
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
// delete the packagespec
deleteFile(subPackagespec);
return pumpEventQueue().then((_) {
// Should NOT merge
callbacks.assertContextPaths([root, subProject]);
callbacks.assertContextFiles(subProject, [subFile]);
});
}
Future<void> test_watch_deletePubspec_fromRoot() {
// prepare paths
var root = convertPath('/root');
var rootPubspec = convertPath('$root/pubspec.yaml');
var rootFile = convertPath('$root/root.dart');
// create files
newFile(rootPubspec, content: 'pubspec');
newFile(rootFile, content: 'library root;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root]);
callbacks.assertContextFiles(root, [rootFile]);
// delete the pubspec
deleteFile(rootPubspec);
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root]);
callbacks.assertContextFiles(root, [rootFile]);
});
}
Future<void> test_watch_deletePubspec_fromSubFolder() {
// prepare paths
var root = convertPath('/root');
var rootFile = convertPath('$root/root.dart');
var subProject = convertPath('$root/sub/aaa');
var subPubspec = convertPath('$subProject/pubspec.yaml');
var subFile = convertPath('$subProject/bin/a.dart');
// create files
newFile(subPubspec, content: 'pubspec');
newFile(rootFile, content: 'library root;');
newFile(subFile, content: 'library a;');
// set roots
manager.setRoots(<String>[root], <String>[]);
callbacks.assertContextPaths([root, subProject]);
// verify files
callbacks.assertContextFiles(root, [rootFile]);
callbacks.assertContextFiles(subProject, [subFile]);
// delete the pubspec
deleteFile(subPubspec);
return pumpEventQueue().then((_) {
callbacks.assertContextPaths([root]);
callbacks.assertContextFiles(root, [rootFile, subFile]);
});
}
Future<void> test_watch_modifyFile() {
var filePath = join(projPath, 'foo.dart');
// add root with a file
newFile(filePath, content: 'contents');
manager.setRoots(<String>[projPath], <String>[]);
// the file was added
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
// TODO(brianwilkerson) Test when the file was modified
// update the file
callbacks.now++;
modifyFile(filePath, 'new contents');
return pumpEventQueue().then((_) {
// TODO(brianwilkerson) Test when the file was modified
});
}
Future<void> test_watch_modifyPackageConfigJson() {
var packageConfigPath = '$projPath/.dart_tool/package_config.json';
var filePath = convertPath('$projPath/bin/main.dart');
newFile(packageConfigPath, content: '');
newFile(filePath, content: 'library main;');
manager.setRoots(<String>[projPath], <String>[]);
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
expect(_currentPackageMap, isEmpty);
// update .dart_tool/package_config.json
callbacks.now++;
modifyFile(
packageConfigPath,
(PackageConfigFileBuilder()..add(name: 'my', rootPath: '../'))
.toContent(toUriStr: toUriStr),
);
return pumpEventQueue().then((_) {
// verify new package info
expect(_currentPackageMap.keys, unorderedEquals(['my']));
});
}
Future<void> test_watch_modifyPackagespec() {
var packagesPath = convertPath('$projPath/.packages');
var filePath = convertPath('$projPath/bin/main.dart');
newFile(packagesPath, content: '');
newFile(filePath, content: 'library main;');
manager.setRoots(<String>[projPath], <String>[]);
var filePaths = callbacks.currentFilePaths;
expect(filePaths, hasLength(1));
expect(filePaths, contains(filePath));
expect(_currentPackageMap, isEmpty);
// update .packages
callbacks.now++;
modifyFile(packagesPath, 'main:./lib/');
return pumpEventQueue().then((_) {
// verify new package info
expect(_currentPackageMap.keys, unorderedEquals(['main']));
});
}
}
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;
String projPath;
AnalysisError missing_return =
AnalysisError(null, 0, 1, HintCode.MISSING_RETURN, [
['x']
]);
AnalysisError invalid_assignment_error =
AnalysisError(null, 0, 1, CompileTimeErrorCode.INVALID_ASSIGNMENT, [
['x'],
['y']
]);
AnalysisError unused_local_variable =
AnalysisError(null, 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
['x']
]);
List<Glob> get analysisFilesGlobs {
var patterns = <String>[
'**/*.${AnalysisEngine.SUFFIX_DART}',
'**/*.${AnalysisEngine.SUFFIX_HTML}',
'**/*.${AnalysisEngine.SUFFIX_HTM}',
'**/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}'
];
return patterns
.map((pattern) => Glob(path.posix.separator, pattern))
.toList();
}
AnalysisOptions get analysisOptions => callbacks.analysisOptions;
List<ErrorProcessor> get errorProcessors => analysisOptions.errorProcessors;
List<Linter> get lints => analysisOptions.lintRules;
SourceFactory get sourceFactory => callbacks.sourceFactory;
Map<String, List<Folder>> 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();
}
void setUp() {
processRequiredPlugins();
projPath = convertPath('/my/proj');
newFolder(projPath);
// Create an SDK in the mock file system.
MockSdk(resourceProvider: resourceProvider);
var sdkManager = DartSdkManager(convertPath(sdkRoot));
manager = ContextManagerImpl(
resourceProvider,
sdkManager,
analysisFilesGlobs,
InstrumentationService.NULL_SERVICE,
);
var logger = PerformanceLog(NullStringSink());
var scheduler = AnalysisDriverScheduler(logger);
callbacks = TestContextManagerCallbacks(
resourceProvider, sdkManager, logger, scheduler);
manager.callbacks = callbacks;
}
Map<String, List<Folder>> _packageMap(String contextPath) {
var folder = getFolder(contextPath);
var info = manager.getContextInfoFor(folder);
return info.analysisDriver.sourceFactory?.packageMap;
}
}
@reflectiveTest
class ContextManagerWithOptionsTest extends ContextManagerTest {
String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
void deleteOptionsFile() {
deleteFile('$projPath/$optionsFileName');
}
Future<void> 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(<String>[projPath], <String>[]);
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
Future<void> 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.
var 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(<String>[projPath], <String>[]);
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<AvoidAs>());
expect(errorProcessors, hasLength(1));
expect(getProcessor(missing_return).severity, isNull);
}
Future<void> test_analysis_options_include() async {
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
var sdkExtPath = '$projPath/sdk_ext';
newFile('$sdkExtPath/entry.dart');
var 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(<String>[projPath], <String>[]);
await pumpEventQueue();
// Verify options were set.
expect(errorProcessors, hasLength(1));
expect(lints, hasLength(1));
expect(lints[0].name, 'camel_case_types');
}
Future<void> test_analysis_options_include_package() async {
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
var sdkExtPath = '$projPath/sdk_ext';
newFile('$sdkExtPath/entry.dart');
var sdkExtSrcPath = '$projPath/sdk_ext/src';
newFile('$sdkExtSrcPath/part.dart');
// Setup package
var 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:${toUriStr(booLibPosixPath)}\n');
newFile('$projPath/$optionsFileName', content: r'''
include: package:boo/other_options.yaml
''');
// Setup context.
manager.setRoots(<String>[projPath], <String>[]);
await pumpEventQueue();
// Verify options were set.
expect(errorProcessors, hasLength(1));
expect(lints, hasLength(1));
expect(lints[0].name, 'camel_case_types');
}
@failingTest
Future<void> test_analysis_options_parse_failure() async {
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
var sdkExtPath = '$projPath/sdk_ext';
newFile('$sdkExtPath/entry.dart');
var sdkExtSrcPath = '$projPath/sdk_ext/src';
newFile('$sdkExtSrcPath/part.dart');
// Setup analysis options file with ignore list.
var optionsFilePath = newFile('$projPath/$optionsFileName', content: r'''
;
''').path;
// Setup context.
manager.setRoots(<String>[projPath], <String>[]);
// 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));
}
Future<void> test_deleteRoot_hasAnalysisOptions() async {
newFile('$projPath/$optionsFileName');
// Add the root.
manager.setRoots(<String>[projPath], <String>[]);
await pumpEventQueue();
// Remove the root, with the analysis options file.
// No exceptions.
deleteFolder(projPath);
await pumpEventQueue();
}
@failingTest
Future<void> test_embedder_options() async {
// This fails because the ContextBuilder doesn't pick up the strongMode
// flag from the embedder.yaml file.
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
var sdkExtPath = '$projPath/sdk_ext';
newFile('$projPath/test', content: 'test.dart');
newFile('$sdkExtPath/entry.dart');
// 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(<String>[projPath], <String>[]);
await pumpEventQueue();
// Confirm that one context was created.
var count = manager.numberOfContextsInAnalysisRoot(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');
}
Future<void> test_error_filter_analysis_option() async {
// Create files.
newFile('$projPath/$optionsFileName', content: r'''
analyzer:
errors:
unused_local_variable: ignore
''');
// Setup context.
manager.setRoots(<String>[projPath], <String>[]);
// Verify filter setup.
expect(errorProcessors, hasLength(1));
expect(getProcessor(unused_local_variable).severity, isNull);
}
Future<void> 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(<String>[projPath], <String>[]);
// Verify filter setup.
expect(errorProcessors, hasLength(2));
expect(getProcessor(invalid_assignment_error).severity, isNull);
expect(getProcessor(unused_local_variable).severity, ErrorSeverity.ERROR);
}
Future<void> 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(<String>[projPath], <String>[]);
// Verify filter setup.
expect(errorProcessors, isNotNull);
expect(errorProcessors, hasLength(2));
}
Future<void> test_error_filter_analysis_option_unpsecified() async {
// Create files.
newFile('$projPath/$optionsFileName', content: r'''
analyzer:
# errors:
# unused_local_variable: ignore
''');
// Setup context.
manager.setRoots(<String>[projPath], <String>[]);
// Verify filter setup.
expect(errorProcessors, isEmpty);
}
Future<void> test_non_analyzable_files_not_considered() async {
// Set up project and get a reference to the driver.
manager.setRoots(<String>[projPath], <String>[]);
var projectFolder = 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
Future<void> 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 = newFile('$projPath/bin/test.dart', content: r'''
main() {
var paths = <int>[];
var names = <String>[];
paths.addAll(names.map((s) => s.length));
}
''');
newFile('$projPath/$optionsFileName', content: r'''
analyzer:
strong-mode: false
''');
// Create the context.
manager.setRoots(<String>[projPath], <String>[]);
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'.
modifyFile('$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
Future<void> test_path_filter_analysis_option() async {
// This fails because we're not analyzing the analysis options file.
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
newFile('$libPath/nope.dart');
var sdkExtPath = '$projPath/sdk_ext';
newFile('$sdkExtPath/entry.dart');
var 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(<String>[projPath], <String>[]);
// Verify that analysis options was parsed and the ignore patterns applied.
var projectFolder = newFolder(projPath);
var drivers = manager.getDriversInAnalysisRoot(projectFolder);
expect(drivers, hasLength(1));
var driver = drivers[0];
expect(
driver.addedFiles,
unorderedEquals(
['/my/proj/lib/main.dart', '/my/proj/$optionsFileName']));
}
Future<void> test_path_filter_child_contexts_option() async {
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
newFile('$libPath/pubspec.yaml', content: r'''
name: foobar
''');
var 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(<String>[projPath], <String>[]);
// Verify that the context in other_lib wasn't created and that the
// context in lib was created.
var projectFolder = 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')));
}
Future<void>
test_path_filter_recursive_wildcard_child_contexts_option() async {
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
newFile('$libPath/pubspec.yaml', content: r'''
name: foobar
''');
var 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(<String>[projPath], <String>[]);
// Verify that the context in other_lib wasn't created and that the
// context in lib was created.
var projectFolder = 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')));
}
Future<void> test_path_filter_wildcard_child_contexts_option() async {
// Create files.
var libPath = '$projPath/${ContextManagerTest.LIB_NAME}';
newFile('$libPath/main.dart');
newFile('$libPath/pubspec.yaml', content: r'''
name: foobar
''');
var 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(<String>[projPath], <String>[]);
var projectFolder = 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() {
var project = convertPath('/project');
var projectPubspec = convertPath('$project/pubspec.yaml');
var example = convertPath('$project/example');
var examplePubspec = convertPath('$example/pubspec.yaml');
// create files
newFile(projectPubspec, content: 'name: project');
newFile(examplePubspec, content: 'name: example');
newFile('$project/$optionsFileName', content: r'''
analyzer:
exclude:
- 'example'
''');
manager.setRoots(<String>[project, example], <String>[]);
// verify
{
var rootInfo = manager.rootInfo;
expect(rootInfo.children, hasLength(1));
{
var projectInfo = rootInfo.children[0];
expect(projectInfo.folder.path, project);
expect(projectInfo.children, hasLength(1));
{
var 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() {
var a = convertPath('/a');
var c = convertPath('$a/b/c');
var aPubspec = convertPath('$a/pubspec.yaml');
var cPubspec = convertPath('$c/pubspec.yaml');
// create files
newFile(aPubspec, content: 'name: aaa');
newFile(cPubspec, content: 'name: ccc');
newFile('$a/$optionsFileName', content: r'''
analyzer:
exclude:
- 'b**'
''');
manager.setRoots(<String>[a, c], <String>[]);
// verify
{
var rootInfo = manager.rootInfo;
expect(rootInfo.children, hasLength(1));
{
var aInfo = rootInfo.children[0];
expect(aInfo.folder.path, a);
expect(aInfo.children, hasLength(1));
{
var cInfo = aInfo.children[0];
expect(cInfo.folder.path, c);
expect(cInfo.children, isEmpty);
}
}
}
expect(callbacks.currentContextRoots, hasLength(2));
expect(callbacks.currentContextRoots, unorderedEquals([a, c]));
}
Future<void> test_watchEvents() async {
var libPath = newFolder('$projPath/${ContextManagerTest.LIB_NAME}').path;
manager.setRoots(<String>[projPath], <String>[]);
newFile('$libPath/main.dart');
await Future.delayed(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<String, AnalysisDriver> driverMap = <String, AnalysisDriver>{};
/// Map from context to the timestamp when the context was created.
Map<String, int> currentContextTimestamps = <String, int>{};
/// Map from context to (map from file path to timestamp of last event).
final Map<String, Map<String, int>> currentContextFilePaths =
<String, Map<String, int>>{};
/// A map from the paths of contexts to a set of the sources that should be
/// explicitly analyzed in those contexts.
final Map<String, Set<Source>> currentContextSources =
<String, Set<Source>>{};
/// 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<String> lastFlushedFiles;
/// The watch events that have been broadcast.
List<WatchEvent> watchEvents = <WatchEvent>[];
@override
AbstractNotificationManager notificationManager = 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<String> get currentContextRoots {
return currentContextTimestamps.keys;
}
/// Return the paths to the files being analyzed in the current context root.
Iterable<String> get currentFilePaths {
if (currentDriver == null) {
return <String>[];
}
return currentDriver.addedFiles;
}
/// Return the current source factory.
SourceFactory get sourceFactory => currentDriver?.sourceFactory;
@override
AnalysisDriver addAnalysisDriver(Folder folder, ContextRoot contextRoot) {
var path = folder.path;
expect(currentContextRoots, isNot(contains(path)));
expect(contextRoot, isNotNull);
expect(contextRoot.root, path);
currentContextTimestamps[path] = now;
var builder = createContextBuilder(folder);
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.instrumentationService.logException(
CaughtException.withMessage('Analysis failed: ${result.filePath}',
result.exception.exception, result.exception.stackTrace));
});
return currentDriver;
}
@override
void afterContextRefresh() {}
@override
void afterWatchEvent(WatchEvent event) {}
@override
void analysisOptionsUpdated(AnalysisDriver driver) {}
@override
void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
var driver = driverMap[contextFolder.path];
if (driver != null) {
changeSet.addedFiles.forEach((source) {
driver.addFile(source);
});
changeSet.changedFiles.forEach((source) {
driver.changeFile(source);
});
changeSet.removedFiles.forEach((source) {
driver.removeFile(source);
});
}
}
@override
void applyFileRemoved(AnalysisDriver driver, String file) {
driver.removeFile(file);
}
void assertContextFiles(String contextPath, List<String> expectedFiles) {
expect(getCurrentFilePaths(contextPath), unorderedEquals(expectedFiles));
}
void assertContextPaths(List<String> expected) {
expect(currentContextRoots, unorderedEquals(expected));
}
@override
void broadcastWatchEvent(WatchEvent event) {
watchEvents.add(event);
}
@override
ContextBuilder createContextBuilder(Folder folder) {
var builderOptions = ContextBuilderOptions();
var builder = ContextBuilder(resourceProvider, sdkManager, null,
options: builderOptions);
return builder;
}
/// Return the paths to the files being analyzed in the current context root.
Iterable<Source> currentFileSources(String contextPath) {
if (currentDriver == null) {
return <Source>[];
}
var driver = driverMap[contextPath];
var sourceFactory = driver.sourceFactory;
return driver.addedFiles.map((String path) {
var file = resourceProvider.getFile(path);
var source = file.createSource();
var uri = sourceFactory.restoreUri(source);
return file.createSource(uri);
});
}
/// Return the paths to the files being analyzed in the current context root.
Iterable<String> getCurrentFilePaths(String contextPath) {
if (currentDriver == null) {
return <String>[];
}
return driverMap[contextPath].addedFiles;
}
@override
void removeContext(Folder folder, List<String> flushedFiles) {
var path = folder.path;
expect(currentContextRoots, contains(path));
currentContextTimestamps.remove(path);
currentContextFilePaths.remove(path);
currentContextSources.remove(path);
lastFlushedFiles = flushedFiles;
}
}