blob: 98ad357e033d858987d5a74666591f6cc8bc4c19 [file] [log] [blame]
// Copyright (c) 2019, 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:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'server_abstract.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ChangeWorkspaceFoldersTest);
});
}
@reflectiveTest
class ChangeWorkspaceFoldersTest extends AbstractLspAnalysisServerTest {
late String workspaceFolder1Path, workspaceFolder2Path, workspaceFolder3Path;
late Uri workspaceFolder1Uri, workspaceFolder2Uri, workspaceFolder3Uri;
@override
void setUp() {
super.setUp();
workspaceFolder1Path = convertPath('/workspace1');
workspaceFolder2Path = convertPath('/workspace2');
workspaceFolder3Path = convertPath('/workspace3');
newFolder(workspaceFolder1Path);
newFolder(workspaceFolder2Path);
newFolder(workspaceFolder3Path);
workspaceFolder1Uri = Uri.file(workspaceFolder1Path);
workspaceFolder2Uri = Uri.file(workspaceFolder2Path);
workspaceFolder3Uri = Uri.file(workspaceFolder3Path);
newFile(join(workspaceFolder1Path, 'pubspec.yaml'));
newFile(join(workspaceFolder2Path, 'pubspec.yaml'));
newFile(join(workspaceFolder3Path, 'pubspec.yaml'));
}
Future<void> test_changeWorkspaceFolders_add() async {
await initialize(rootUri: workspaceFolder1Uri);
await changeWorkspaceFolders(
add: [workspaceFolder2Uri, workspaceFolder3Uri]);
expect(
server.contextManager.includedPaths,
unorderedEquals([
workspaceFolder1Path,
workspaceFolder2Path,
workspaceFolder3Path,
]),
);
}
Future<void> test_changeWorkspaceFolders_addAndRemove() async {
await initialize(
workspaceFolders: [workspaceFolder1Uri, workspaceFolder2Uri],
);
await changeWorkspaceFolders(
add: [workspaceFolder3Uri],
remove: [workspaceFolder2Uri],
);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path, workspaceFolder3Path]),
);
}
Future<void>
test_changeWorkspaceFolders_addExplicitParentOfImplicit_closeFile() async {
final nestedFolderPath =
join(workspaceFolder1Path, 'nested', 'deeply', 'in', 'folders');
final nestedFilePath = join(nestedFolderPath, 'test.dart');
final nestedFileUri = Uri.file(nestedFilePath);
newFile(nestedFilePath);
await initialize(allowEmptyRootUri: true);
await openFile(nestedFileUri, '');
// Expect implicit root for the open file.
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
// Add the real project root to the workspace (which will become an
// explicit root but not change anything or rebuild contexts).
resetContextBuildCounter();
await changeWorkspaceFolders(add: [workspaceFolder1Uri]);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
// Closing the file should not change roots nor trigger a rebuild.
resetContextBuildCounter();
await closeFile(nestedFileUri);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
}
Future<void>
test_changeWorkspaceFolders_addExplicitParentOfImplicit_closeFolder() async {
final nestedFolderPath =
join(workspaceFolder1Path, 'nested', 'deeply', 'in', 'folders');
final nestedFilePath = join(nestedFolderPath, 'test.dart');
final nestedFileUri = Uri.file(nestedFilePath);
newFile(nestedFilePath);
await initialize(allowEmptyRootUri: true);
await openFile(nestedFileUri, '');
// Expect implicit root for the open file.
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
// Add the real project root to the workspace (which will become an
// explicit root but not change anything or rebuild contexts).
resetContextBuildCounter();
await changeWorkspaceFolders(add: [workspaceFolder1Uri]);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
// Removing the workspace folder should not change roots nor trigger a
// rebuild because the root is still the implicit root for the open file.
resetContextBuildCounter();
await closeFile(nestedFileUri);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
}
Future<void>
test_changeWorkspaceFolders_addImplicitChildOfExplicitParent_closeFile() async {
final nestedFolderPath =
join(workspaceFolder1Path, 'nested', 'deeply', 'in', 'folders');
final nestedFilePath = join(nestedFolderPath, 'test.dart');
final nestedFileUri = Uri.file(nestedFilePath);
newFile(nestedFilePath);
await initialize(workspaceFolders: [workspaceFolder1Uri]);
// Expect explicit root for the workspace folder.
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
// An open file should not trigger any changes or rebuilds.
resetContextBuildCounter();
await openFile(nestedFileUri, '');
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
// Closing the file should also not trigger any changes.
resetContextBuildCounter();
await closeFile(nestedFileUri);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
}
Future<void>
test_changeWorkspaceFolders_addImplicitChildOfExplicitParent_closeFolder() async {
final nestedFolderPath =
join(workspaceFolder1Path, 'nested', 'deeply', 'in', 'folders');
final nestedFilePath = join(nestedFolderPath, 'test.dart');
final nestedFileUri = Uri.file(nestedFilePath);
newFile(nestedFilePath);
await initialize(workspaceFolders: [workspaceFolder1Uri]);
// Expect explicit root for the workspace folder.
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
// Open a file, though no new root (or rebuild) is expected as it was mapped
// to the existing open project folder.
resetContextBuildCounter();
await openFile(nestedFileUri, '');
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
// Removing the workspace folder will retain the workspace folder, as that's
// the project root.
resetContextBuildCounter();
await changeWorkspaceFolders(remove: [workspaceFolder1Uri]);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
}
Future<void> test_changeWorkspaceFolders_implicitFile_noProject() async {
final nestedFolderPath =
join(workspaceFolder1Path, 'nested', 'deeply', 'in', 'folders');
final nestedFilePath = join(nestedFolderPath, 'test.dart');
final nestedFileUri = Uri.file(nestedFilePath);
newFile(nestedFilePath);
deleteFile(join(
workspaceFolder1Path, 'pubspec.yaml')); // Ensure no pubspecs in tree.
await initialize(allowEmptyRootUri: true);
await openFile(nestedFileUri, '');
// Because there is no pubspec in the tree and we don't locate a root, we
// expect the file to be analyzed solo.
expect(
server.contextManager.includedPaths,
unorderedEquals([nestedFilePath]),
);
// Adding the parent folder will switch to using that as the root and rebuild
// the root.
resetContextBuildCounter();
await changeWorkspaceFolders(add: [workspaceFolder1Uri]);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectContextBuilds();
}
Future<void> test_changeWorkspaceFolders_openFileOutsideRoot() async {
// When a file is opened that is outside of the analysis roots, the first
// analysis driver will be used (see [AbstractAnalysisServer.getAnalysisDriver])
// and no new root will be created.
final workspace1FilePath = join(workspaceFolder1Path, 'test.dart');
newFile(workspace1FilePath);
final workspace2FilePath = join(workspaceFolder2Path, 'test.dart');
final workspace2FileUri = Uri.file(workspace2FilePath);
newFile(workspace2FilePath);
await initialize(workspaceFolders: [workspaceFolder1Uri]);
// Expect explicit root for the workspace folder.
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
// Open a file in workspaceFolder2 which will reuse the existing driver for
// workspace1 so not change roots/trigger a rebuild.
resetContextBuildCounter();
await openFile(workspace2FileUri, '');
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
// Closing the file will also not trigger any changes.
resetContextBuildCounter();
await closeFile(workspace2FileUri);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
expectNoContextBuilds();
}
Future<void> test_changeWorkspaceFolders_remove() async {
await initialize(
workspaceFolders: [workspaceFolder1Uri, workspaceFolder2Uri],
);
await changeWorkspaceFolders(
remove: [workspaceFolder2Uri],
);
expect(
server.contextManager.includedPaths,
unorderedEquals([workspaceFolder1Path]),
);
}
Future<void> test_changeWorkspaceFolders_removeFlushesDiagnostics() async {
// Add our standard test project as well as a dummy project.
await initialize(workspaceFolders: [projectFolderUri, workspaceFolder1Uri]);
// Generate an error in the test project.
final firstDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
newFile(mainFilePath, content: 'String a = 1;');
final initialDiagnostics = await firstDiagnosticsUpdate;
expect(initialDiagnostics, hasLength(1));
// Ensure the error is removed if we removed the workspace folder.
final secondDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
await changeWorkspaceFolders(remove: [projectFolderUri]);
final updatedDiagnostics = await secondDiagnosticsUpdate;
expect(updatedDiagnostics, hasLength(0));
}
}