blob: 6ce04bc6dbb8cb13daba3ccb75a600096a98cb41 [file]
// Copyright (c) 2015, 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/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart'
hide AnalysisOptions;
import 'package:analysis_server/src/utilities/mocks.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:linter/src/rules.dart';
import 'package:path/path.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../analysis_server_base.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(AnalysisOptionsFileNotificationTest);
defineReflectiveTests(PluginConflictsNotificationTest);
});
}
@reflectiveTest
class AnalysisOptionsFileNotificationTest extends PubPackageAnalysisServerTest {
late File optionsFile;
Map<File, List<AnalysisError>> filesErrors = {};
final testSource = '''
void f() {
var x = '';
int y = x; // Not assignable.
print(y);
}''';
List<AnalysisError> get testFileErrors => filesErrors[testFile]!;
void addOptionsFile(String contents) {
optionsFile = newAnalysisOptionsYamlFile(testPackageRootPath, contents);
}
@override
void processNotification(Notification notification) {
if (notification.event == analysisNotificationErrors) {
var decoded = AnalysisErrorsParams.fromNotification(
notification,
clientUriConverter: server.uriConverter,
);
filesErrors[getFile(decoded.file)] = decoded.errors;
}
}
@override
Future<void> setUp() async {
registerLintRules();
super.setUp();
await setRoots(included: [workspaceRootPath], excluded: []);
}
Future<void> test_error_filter() async {
addOptionsFile('''
analyzer:
errors:
unused_local_variable: ignore
''');
addTestFile('''
void f() {
String unused = "";
}
''');
await waitForTasksFinished();
// Verify options file.
// TODO(brianwilkerson): Implement options file analysis in the new driver.
// expect(optionsFileErrors, isNotNull);
// expect(optionsFileErrors, isEmpty);
// Verify test file.
expect(testFileErrors, isNotNull);
expect(testFileErrors, isEmpty);
}
Future<void> test_error_filter_removed() async {
addOptionsFile('''
analyzer:
errors:
unused_local_variable: ignore
''');
addTestFile('''
void f() {
String unused = "";
}
''');
await waitForTasksFinished();
// Verify options file.
// TODO(brianwilkerson): Implement options file analysis in the new driver.
// expect(optionsFileErrors, isNotNull);
// expect(optionsFileErrors, isEmpty);
// Verify test file.
expect(testFileErrors, isNotNull);
expect(testFileErrors, isEmpty);
addOptionsFile('''
analyzer:
errors:
# unused_local_variable: ignore
''');
await pumpEventQueue();
await waitForTasksFinished();
// Verify options file.
// TODO(brianwilkerson): Implement options file analysis in the new driver.
// expect(optionsFileErrors, isEmpty);
// Verify test file.
expect(testFileErrors, hasLength(1));
}
Future<void> test_lint_options_changes() async {
addOptionsFile('''
linter:
rules:
- camel_case_types
- constant_identifier_names
''');
addTestFile(testSource);
await waitForTasksFinished();
verifyLintsEnabled(['camel_case_types', 'constant_identifier_names']);
addOptionsFile('''
linter:
rules:
- camel_case_types
''');
await pumpEventQueue();
await waitForTasksFinished();
verifyLintsEnabled(['camel_case_types']);
}
Future<void> test_lint_options_unsupported() async {
addOptionsFile('''
linter:
rules:
- unsupported
''');
addTestFile(testSource);
await waitForTasksFinished();
// TODO(brianwilkerson): Implement options file analysis in the new driver.
// expect(optionsFileErrors, hasLength(1));
// expect(optionsFileErrors.first.severity, AnalysisErrorSeverity.WARNING);
// expect(optionsFileErrors.first.type, AnalysisErrorType.STATIC_WARNING);
}
Future<void> test_options_file_added() async {
addTestFile(testSource);
await waitForTasksFinished();
// Verify that lints are disabled.
expect(testFileAnalysisOptions.lint, false);
// Add options file with a lint enabled.
addOptionsFile('''
linter:
rules:
- camel_case_types
''');
await pumpEventQueue();
await waitForTasksFinished();
verifyLintsEnabled(['camel_case_types']);
}
Future<void> test_options_file_parse_error() async {
addOptionsFile('''
; #bang
''');
await waitForTasksFinished();
// TODO(brianwilkerson): Implement options file analysis in the new driver.
// expect(optionsFileErrors, hasLength(1));
// expect(optionsFileErrors.first.severity, AnalysisErrorSeverity.ERROR);
// expect(optionsFileErrors.first.type, AnalysisErrorType.COMPILE_TIME_ERROR);
}
Future<void> test_options_file_removed() async {
addOptionsFile('''
linter:
rules:
- camel_case_types
''');
addTestFile(testSource);
await waitForTasksFinished();
verifyLintsEnabled(['camel_case_types']);
deleteFile(optionsFile.path);
await pumpEventQueue();
await waitForTasksFinished();
expect(testFileAnalysisOptions.lint, false);
}
void verifyLintsEnabled(List<String> lints) {
var options = testFileAnalysisOptions;
expect(options.lint, true);
var rules = options.lintRules.map((rule) => rule.name);
expect(rules, unorderedEquals(lints));
}
}
@reflectiveTest
class PluginConflictsNotificationTest extends PubPackageAnalysisServerTest {
@override
late final TestPluginManager pluginManager = TestPluginManager(
resourceProvider,
);
Map<File, List<AnalysisError>?> filesErrors = {};
@override
void processNotification(Notification notification) {
if (notification.event == analysisNotificationErrors) {
var decoded = AnalysisErrorsParams.fromNotification(
notification,
clientUriConverter: server.uriConverter,
);
filesErrors[getFile(decoded.file)] = decoded.errors;
}
}
@override
void setUp() {
registerLintRules();
super.setUp();
}
Future<void> test_plugin_conflict_different_sources() async {
var optionsFile = newAnalysisOptionsYamlFile(testPackageRootPath, '''
plugins:
foo: ^1.0.0
''');
var nestedOptionsFile = newAnalysisOptionsYamlFile(
join(testPackageRootPath, 'sub'),
'''
plugins:
foo:
path: ../foo
''',
);
await setRoots(included: [workspaceRootPath], excluded: []);
await waitForTasksFinished();
await pumpEventQueue();
var rootErrors = filesErrors[optionsFile]!;
expect(rootErrors, hasLength(1));
expect(rootErrors[0].code, 'incompatible_plugin_source');
// We only report one file in the conflict, not the second.
var nestedErrors = filesErrors[nestedOptionsFile]!;
// TODO(srawlins): This is temporary. By the end of this arc of work, we
// won't be reporting this. https://github.com/dart-lang/sdk/issues/63627
expect(nestedErrors, hasLength(1));
expect(nestedErrors[0].code, 'plugins_in_inner_options');
}
Future<void> test_plugin_conflict_different_versions() async {
var optionsFile = newAnalysisOptionsYamlFile(testPackageRootPath, '''
plugins:
foo: ^1.0.0
''');
var nestedOptionsFile = newAnalysisOptionsYamlFile(
join(testPackageRootPath, 'sub'),
'''
plugins:
foo: ^2.0.0
''',
);
await setRoots(included: [workspaceRootPath], excluded: []);
await waitForTasksFinished();
await pumpEventQueue();
var rootErrors = filesErrors[optionsFile]!;
expect(rootErrors, hasLength(1));
expect(rootErrors[0].code, 'incompatible_plugin_source');
// We only report one file in the conflict, not the second.
var nestedErrors = filesErrors[nestedOptionsFile]!;
// TODO(srawlins): This is temporary. By the end of this arc of work, we
// won't be reporting this. https://github.com/dart-lang/sdk/issues/63627
expect(nestedErrors, hasLength(1));
expect(nestedErrors[0].code, 'plugins_in_inner_options');
}
Future<void> test_plugin_conflict_resolved_on_update() async {
var optionsFile = newAnalysisOptionsYamlFile(testPackageRootPath, '''
plugins:
foo: ^1.0.0
''');
var nestedOptionsFile = newAnalysisOptionsYamlFile(
join(testPackageRootPath, 'sub'),
'''
plugins:
foo: ^2.0.0
''',
);
await setRoots(included: [workspaceRootPath], excluded: []);
await waitForTasksFinished();
await pumpEventQueue();
expect(filesErrors[optionsFile]!, hasLength(1));
// TODO(srawlins): This is temporary. By the end of this arc of work, we
// won't be reporting this. https://github.com/dart-lang/sdk/issues/63627
expect(filesErrors[nestedOptionsFile]!, hasLength(1));
expect(filesErrors[nestedOptionsFile]![0].code, 'plugins_in_inner_options');
newAnalysisOptionsYamlFile(join(testPackageRootPath, 'sub'), '''
plugins:
foo: ^1.0.0
''');
await pumpEventQueue();
await waitForTasksFinished();
expect(filesErrors[optionsFile]!, isEmpty);
// TODO(srawlins): This is temporary. By the end of this arc of work, we
// won't be reporting this. https://github.com/dart-lang/sdk/issues/63627
expect(filesErrors[nestedOptionsFile]!, hasLength(1));
expect(filesErrors[nestedOptionsFile]![0].code, 'plugins_in_inner_options');
}
Future<void> test_plugin_no_conflict_different_plugins() async {
var optionsFile = newAnalysisOptionsYamlFile(testPackageRootPath, '''
plugins:
foo: ^1.0.0
''');
var nestedOptionsFile = newAnalysisOptionsYamlFile(
join(testPackageRootPath, 'sub'),
'''
plugins:
bar: ^1.0.0
''',
);
await setRoots(included: [workspaceRootPath], excluded: []);
await waitForTasksFinished();
await pumpEventQueue();
var rootErrors = filesErrors[optionsFile]!;
expect(rootErrors, isEmpty);
var nestedErrors = filesErrors[nestedOptionsFile]!;
// TODO(srawlins): This is temporary. By the end of this arc of work, we
// won't be reporting this. https://github.com/dart-lang/sdk/issues/63627
expect(nestedErrors, hasLength(1));
expect(nestedErrors[0].code, 'plugins_in_inner_options');
}
Future<void> test_plugin_no_conflict_identical_sources() async {
var optionsFile = newAnalysisOptionsYamlFile(testPackageRootPath, '''
plugins:
foo: ^1.0.0
''');
var nestedOptionsFile = newAnalysisOptionsYamlFile(
join(testPackageRootPath, 'sub'),
'''
plugins:
foo: ^1.0.0
''',
);
await setRoots(included: [workspaceRootPath], excluded: []);
await waitForTasksFinished();
await pumpEventQueue();
var rootErrors = filesErrors[optionsFile]!;
expect(rootErrors, isEmpty);
var nestedErrors = filesErrors[nestedOptionsFile]!;
// TODO(srawlins): This is temporary. By the end of this arc of work, we
// won't be reporting this. https://github.com/dart-lang/sdk/issues/63627
expect(nestedErrors, hasLength(1));
expect(nestedErrors[0].code, 'plugins_in_inner_options');
}
}