blob: d85214a9a326d9f356f60f544b47836972511e83 [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library test.analysis_server.src.single_context_manager;
import 'dart:core' hide Resource;
import 'package:analysis_server/src/single_context_manager.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.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/util/glob.dart';
import 'package:linter/src/plugin/linter_plugin.dart';
import 'package:path/path.dart';
import 'package:plugin/manager.dart';
import 'package:plugin/plugin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
import 'context_manager_test.dart' show TestContextManagerCallbacks;
import 'mock_sdk.dart';
import 'mocks.dart';
import 'utils.dart';
main() {
initializeTestEnvironment();
defineReflectiveTests(SingleContextManagerTest);
}
@reflectiveTest
class SingleContextManagerTest {
MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
TestUriResolver packageResolver;
TestContextManagerCallbacks callbacks;
SingleContextManager manager;
List<Glob> get analysisFilesGlobs {
List<String> patterns = <String>[
'**/*.${AnalysisEngine.SUFFIX_DART}',
'**/*.${AnalysisEngine.SUFFIX_HTML}',
];
return patterns
.map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
.toList();
}
String newFile(List<String> pathComponents, [String content = '']) {
String filePath = posix.joinAll(pathComponents);
resourceProvider.newFile(filePath, content);
return filePath;
}
String newFolder(List<String> pathComponents) {
String folderPath = posix.joinAll(pathComponents);
resourceProvider.newFolder(folderPath);
return folderPath;
}
void setUp() {
packageResolver = new TestUriResolver();
_processRequiredPlugins();
DartSdkManager sdkManager =
new DartSdkManager('', false, (_) => new MockSdk());
manager = new SingleContextManager(resourceProvider, sdkManager,
(_) => packageResolver, analysisFilesGlobs, new AnalysisOptionsImpl());
callbacks = new TestContextManagerCallbacks(resourceProvider);
manager.callbacks = callbacks;
}
void test_isIgnored_false() {
String project = '/project';
manager.setRoots(<String>[project], <String>[], <String, String>{});
expect(manager.isIgnored('$project/file.dart'), isFalse);
}
void test_isIgnored_true_inDotFolder() {
String project = '/project';
manager.setRoots(<String>[project], <String>[], <String, String>{});
expect(manager.isIgnored('$project/foo/.bar/file.dart'), isTrue);
}
void test_isIgnored_true_inExcludedPath() {
String project = '/project';
String excludedPath = '/project/excluded';
manager.setRoots(
<String>[project], <String>[excludedPath], <String, String>{});
expect(manager.isIgnored('$excludedPath/file.dart'), isTrue);
}
void test_isIgnored_true_notInRoot() {
String root1 = '/context/root1';
String root2 = '/context/root2';
manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
expect(manager.isIgnored('$context/root3/file.dart'), isTrue);
}
void test_isInAnalysisRoot_false_inExcludedPath() {
String project = '/project';
String excludedPath = '/project/excluded';
manager.setRoots(
<String>[project], <String>[excludedPath], <String, String>{});
expect(manager.isInAnalysisRoot('$excludedPath/file.dart'), isFalse);
}
void test_isInAnalysisRoot_false_notInRoot() {
String root1 = '/context/root1';
String root2 = '/context/root2';
manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
expect(manager.isInAnalysisRoot('$context/root3/file.dart'), isFalse);
}
void test_isInAnalysisRoot_true() {
String project = '/project';
manager.setRoots(<String>[project], <String>[], <String, String>{});
expect(manager.isInAnalysisRoot('$project/file.dart'), isTrue);
}
void test_refresh() {
String project = '/project';
String file1 = '$project/file1.dart';
String file2 = '$project/file2.dart';
// create files
resourceProvider.newFile(file1, '');
resourceProvider.newFile(file2, '');
// set roots
manager.setRoots(<String>[project], <String>[file2], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
// refresh
manager.refresh([]);
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
}
void test_setRoots_addFolderWithDartFile() {
String project = '/project';
String file = '$project/lib/foo.dart';
resourceProvider.newFile(file, '');
manager.setRoots(<String>[project], <String>[], <String, String>{});
// verify
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file]);
}
void test_setRoots_addFolderWithDartFileInSubfolder() {
String project = '/project';
String file = '$project/foo/bar.dart';
resourceProvider.newFile(file, '');
manager.setRoots(<String>[project], <String>[], <String, String>{});
// verify
callbacks.assertContextFiles(project, [file]);
}
void test_setRoots_addFolderWithDummyLink() {
String project = '/project';
String file = '$project/foo.dart';
resourceProvider.newDummyLink(file);
manager.setRoots(<String>[project], <String>[], <String, String>{});
// verify
callbacks.assertContextFiles(project, []);
}
void test_setRoots_exclude_newRoot_withExcludedFile() {
String project = '/project';
String file1 = '$project/file1.dart';
String file2 = '$project/file2.dart';
// create files
resourceProvider.newFile(file1, '');
resourceProvider.newFile(file2, '');
// set roots
manager.setRoots(<String>[project], <String>[file1], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file2]);
}
void test_setRoots_exclude_newRoot_withExcludedFolder() {
String project = '/project';
String folderA = '$project/aaa';
String folderB = '$project/bbb';
String fileA = '$folderA/a.dart';
String fileB = '$folderB/b.dart';
// create files
resourceProvider.newFile(fileA, '');
resourceProvider.newFile(fileB, '');
// set roots
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
void test_setRoots_exclude_sameRoot_addExcludedFile() {
String project = '/project';
String file1 = '$project/file1.dart';
String file2 = '$project/file2.dart';
// create files
resourceProvider.newFile(file1, '');
resourceProvider.newFile(file2, '');
// set roots
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1, file2]);
// exclude "2"
manager.setRoots(<String>[project], <String>[file2], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
}
void test_setRoots_exclude_sameRoot_addExcludedFolder() {
String project = '/project';
String folderA = '$project/aaa';
String folderB = '$project/bbb';
String fileA = '$folderA/a.dart';
String fileB = '$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(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA, fileB]);
// exclude "bbb/"
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFile() {
String project = '/project';
String file1 = '$project/file1.dart';
String file2 = '$project/file2.dart';
// create files
resourceProvider.newFile(file1, '// 1');
resourceProvider.newFile(file2, '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file2], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
// stop excluding "2"
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1, file2]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFile_inFolder() {
String project = '/project';
String file1 = '$project/bin/file1.dart';
String file2 = '$project/bin/file2.dart';
// create files
resourceProvider.newFile(file1, '// 1');
resourceProvider.newFile(file2, '// 2');
// set roots
manager.setRoots(<String>[project], <String>[file2], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
// stop excluding "2"
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1, file2]);
}
void test_setRoots_exclude_sameRoot_removeExcludedFolder() {
String project = '/project';
String folderA = '$project/aaa';
String folderB = '$project/bbb';
String fileA = '$folderA/a.dart';
String fileB = '$folderB/b.dart';
// create files
resourceProvider.newFile(fileA, 'library a;');
resourceProvider.newFile(fileB, 'library b;');
// exclude "bbb/"
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
// stop excluding "bbb/"
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA, fileB]);
}
void test_setRoots_ignoreGlobs() {
String project = '/project';
String file1 = '$project/file.dart';
String file2 = '$project/file.foo';
// create files
resourceProvider.newFile(file1, '');
resourceProvider.newFile(file2, '');
// set roots
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [file1]);
}
void test_setRoots_newContextFolder_coverNewRoot() {
String contextPath = '/context';
String root1 = '$contextPath/root1';
String file1 = '$root1/file1.dart';
String root2 = '$contextPath/root2';
String file2 = '$root2/file1.dart';
// create files
resourceProvider.newFile(file1, '');
resourceProvider.newFile(file2, '');
// cover single root '/context/root1'
manager.setRoots(<String>[root1], <String>[], <String, String>{});
callbacks.assertContextPaths([root1]);
callbacks.assertContextFiles(root1, [file1]);
// cover two roots
manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
callbacks.assertContextPaths([contextPath]);
callbacks.assertContextFiles(contextPath, [file1, file2]);
// cover single root '/context/root2'
manager.setRoots(<String>[root2], <String>[], <String, String>{});
callbacks.assertContextPaths([root2]);
callbacks.assertContextFiles(root2, [file2]);
}
void test_setRoots_newContextFolder_replace() {
String contextPath1 = '/context1';
String root11 = '$contextPath1/root1';
String root12 = '$contextPath1/root2';
String file11 = '$root11/file1.dart';
String file12 = '$root12/file2.dart';
String contextPath2 = '/context2';
String root21 = '$contextPath2/root1';
String root22 = '$contextPath2/root2';
String file21 = '$root21/file1.dart';
String file22 = '$root22/file2.dart';
// create files
resourceProvider.newFile(file11, '');
resourceProvider.newFile(file12, '');
resourceProvider.newFile(file21, '');
resourceProvider.newFile(file22, '');
// set roots in '/context1'
manager.setRoots(<String>[root11, root12], <String>[], <String, String>{});
callbacks.assertContextPaths([contextPath1]);
callbacks.assertContextFiles(contextPath1, [file11, file12]);
// set roots in '/context2'
manager.setRoots(<String>[root21, root22], <String>[], <String, String>{});
callbacks.assertContextPaths([contextPath2]);
callbacks.assertContextFiles(contextPath2, [file21, file22]);
}
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 = '/project';
String fileA = '$project/foo.dart';
String fileB = '$project/.pub/bar.dart';
resourceProvider.newFile(fileA, '');
resourceProvider.newFile(fileB, '');
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
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 = '/.pub/project';
String fileA = '$project/foo.dart';
resourceProvider.newFile(fileA, '');
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
test_watch_addFile() async {
String project = '/project';
manager.setRoots(<String>[project], <String>[], <String, String>{});
// empty folder initially
callbacks.assertContextFiles(project, []);
// add file
String file = '$project/foo.dart';
resourceProvider.newFile(file, 'contents');
// the file was added
await pumpEventQueue();
callbacks.assertContextFiles(project, [file]);
}
test_watch_addFile_afterChangingRoots() async {
String contextPath = '/context';
String root1 = '$contextPath/root1';
String root2 = '$contextPath/root2';
String file1 = '$root1/file1.dart';
String file2 = '$root2/file2.dart';
manager.setRoots(<String>[root1], <String>[], <String, String>{});
manager.setRoots(<String>[root2], <String>[], <String, String>{});
manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
manager.setRoots(<String>[root2], <String>[], <String, String>{});
// empty folder initially
callbacks.assertContextFiles(root2, []);
// add files
resourceProvider.newFile(file1, '');
resourceProvider.newFile(file2, '');
// the file was added
await pumpEventQueue();
callbacks.assertContextFiles(root2, [file2]);
}
test_watch_addFile_excluded() async {
String project = '/project';
String folderA = '$project/aaa';
String folderB = '$project/bbb';
String fileA = '$folderA/a.dart';
String fileB = '$folderB/b.dart';
// create files
resourceProvider.newFile(fileA, 'library a;');
// set roots
manager.setRoots(<String>[project], <String>[folderB], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
// add a file, ignored as excluded
resourceProvider.newFile(fileB, 'library b;');
await pumpEventQueue();
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
test_watch_addFile_notInRoot() async {
String contextPath = '/roots';
String root1 = '$contextPath/root1';
String root2 = '$contextPath/root2';
String root3 = '$contextPath/root3';
String file1 = '$root1/file1.dart';
String file2 = '$root2/file2.dart';
String file3 = '$root3/file3.dart';
// create files
resourceProvider.newFile(file1, '');
resourceProvider.newFile(file2, '');
// set roots
manager.setRoots(<String>[root1, root2], <String>[], <String, String>{});
callbacks.assertContextPaths([contextPath]);
callbacks.assertContextFiles(contextPath, [file1, file2]);
// add a file, not in a root - ignored
resourceProvider.newFile(file3, '');
await pumpEventQueue();
callbacks.assertContextPaths([contextPath]);
callbacks.assertContextFiles(contextPath, [file1, file2]);
}
test_watch_addFile_pathContainsDotFile() async {
// If a file is added and the absolute path to it contains a folder whose
// name begins with '.', then the file is ignored.
String project = '/project';
String fileA = '$project/foo.dart';
String fileB = '$project/.pub/bar.dart';
resourceProvider.newFile(fileA, '');
manager.setRoots(<String>[project], <String>[], <String, String>{});
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
resourceProvider.newFile(fileB, '');
await pumpEventQueue();
callbacks.assertContextPaths([project]);
callbacks.assertContextFiles(project, [fileA]);
}
test_watch_addFileInSubfolder() async {
String project = '/project';
manager.setRoots(<String>[project], <String>[], <String, String>{});
// empty folder initially
callbacks.assertContextFiles(project, []);
// add file in subfolder
String file = '$project/foo/bar.dart';
resourceProvider.newFile(file, 'contents');
// the file was added
await pumpEventQueue();
callbacks.assertContextFiles(project, [file]);
}
test_watch_deleteFile() async {
String project = '/project';
String file = '$project/foo.dart';
// add root with a file
resourceProvider.newFile(file, 'contents');
manager.setRoots(<String>[project], <String>[], <String, String>{});
// the file was added
callbacks.assertContextFiles(project, [file]);
// delete the file
resourceProvider.deleteFile(file);
await pumpEventQueue();
callbacks.assertContextFiles(project, []);
}
test_watch_deleteFolder() async {
String project = '/project';
String file = '$project/foo.dart';
// add root with a file
resourceProvider.newFile(file, 'contents');
manager.setRoots(<String>[project], <String>[], <String, String>{});
// the file was added
callbacks.assertContextFiles(project, [file]);
// delete the folder
resourceProvider.deleteFolder(project);
await pumpEventQueue();
callbacks.assertContextFiles(project, []);
}
test_watch_modifyFile() async {
String project = '/project';
String file = '$project/foo.dart';
// add root with a file
resourceProvider.newFile(file, 'contents');
manager.setRoots(<String>[project], <String>[], <String, String>{});
// the file was added
Map<String, int> filePaths = callbacks.currentContextFilePaths[project];
expect(filePaths, hasLength(1));
expect(filePaths, contains(file));
expect(filePaths[file], equals(callbacks.now));
// update the file
callbacks.now++;
resourceProvider.modifyFile(file, 'new contents');
await pumpEventQueue();
return expect(filePaths[file], equals(callbacks.now));
}
void _processRequiredPlugins() {
List<Plugin> plugins = <Plugin>[];
plugins.addAll(AnalysisEngine.instance.requiredPlugins);
plugins.add(AnalysisEngine.instance.commandLinePlugin);
plugins.add(AnalysisEngine.instance.optionsPlugin);
plugins.add(linterPlugin);
ExtensionManager manager = new ExtensionManager();
manager.processPlugins(plugins);
}
}
class TestUriResolver extends UriResolver {
@override
Source resolveAbsolute(Uri uri, [Uri actualUri]) {
return null;
}
}