blob: db515e72e1e7a31403ac16df5265aef8e0756efd [file] [log] [blame]
// 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 'dart:io';
import 'package:analyzer/src/lint/io.dart';
import 'package:linter/src/analyzer.dart';
import 'package:linter/src/cli.dart' as cli;
import 'package:linter/src/rules.dart';
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';
import '../test_data/rules/experiments/experiments.dart';
import 'integration/always_require_non_null_named_parameters.dart'
as always_require_non_null_named_parameters;
import 'integration/avoid_private_typedef_functions.dart'
as avoid_private_typedef_functions;
import 'integration/avoid_relative_lib_imports.dart'
as avoid_relative_lib_imports;
import 'integration/avoid_renaming_method_parameters.dart'
as avoid_renaming_method_parameters;
import 'integration/avoid_web_libraries_in_flutter.dart'
as avoid_web_libraries_in_flutter;
import 'integration/cancel_subscriptions.dart' as cancel_subscriptions;
import 'integration/close_sinks.dart' as close_sinks;
import 'integration/depend_on_referenced_packages.dart'
as depend_on_referenced_packages;
import 'integration/directives_ordering.dart' as directives_ordering;
import 'integration/exhaustive_cases.dart' as exhaustive_cases;
import 'integration/file_names.dart' as file_names;
import 'integration/flutter_style_todos.dart' as flutter_style_todos;
import 'integration/lines_longer_than_80_chars.dart'
as lines_longer_than_80_chars;
import 'integration/only_throw_errors.dart' as only_throw_errors;
import 'integration/overridden_fields.dart' as overridden_fields;
import 'integration/packages_file_test.dart' as packages_file_test;
import 'integration/prefer_asserts_in_initializer_lists.dart'
as prefer_asserts_in_initializer_lists;
import 'integration/prefer_const_constructors_in_immutables.dart'
as prefer_const_constructors_in_immutables;
import 'integration/prefer_mixin.dart' as prefer_mixin;
import 'integration/prefer_relative_imports.dart' as prefer_relative_imports;
import 'integration/public_member_api_docs.dart' as public_member_api_docs;
import 'integration/sort_pub_dependencies.dart' as sort_pub_dependencies;
import 'integration/unnecessary_lambdas.dart' as unnecessary_lambdas;
import 'integration/unnecessary_string_escapes.dart'
as unnecessary_string_escapes;
import 'integration/use_build_context_synchronously.dart'
as use_build_context_synchronously;
import 'mocks.dart';
import 'test_constants.dart';
void main() {
group('integration', () {
ruleTests();
coreTests();
});
}
void coreTests() {
group('core', () {
group('config', () {
var currentOut = outSink;
var collectingOut = CollectingSink();
setUp(() {
exitCode = 0;
outSink = collectingOut;
});
tearDown(() {
collectingOut.buffer.clear();
outSink = currentOut;
exitCode = 0;
});
test('excludes', () async {
await cli.run([
'$integrationTestDir/p2',
'-c',
'$integrationTestDir/p2/lintconfig.yaml'
]);
expect(
collectingOut.trim(),
stringContainsInOrder(
['4 files analyzed, 1 issue found (2 filtered), in']));
expect(exitCode, 1);
});
test('overrides', () async {
await cli.run([
'$integrationTestDir/p2',
'-c',
'$integrationTestDir/p2/lintconfig2.yaml'
]);
expect(collectingOut.trim(),
stringContainsInOrder(['4 files analyzed, 0 issues found, in']));
expect(exitCode, 0);
});
test('default', () async {
await cli.run(['$integrationTestDir/p2']);
expect(collectingOut.trim(),
stringContainsInOrder(['4 files analyzed, 3 issues found, in']));
expect(exitCode, 1);
});
});
group('pubspec', () {
var currentOut = outSink;
var collectingOut = CollectingSink();
setUp(() => outSink = collectingOut);
tearDown(() {
collectingOut.buffer.clear();
outSink = currentOut;
});
test('bad pubspec', () async {
await cli.run([
'$integrationTestDir/p3',
'$integrationTestDir/p3/_pubpspec.yaml'
]);
expect(collectingOut.trim(),
startsWith('1 file analyzed, 0 issues found, in'));
});
});
group('canonicalization', () {
var currentOut = outSink;
var collectingOut = CollectingSink();
setUp(() => outSink = collectingOut);
tearDown(() {
collectingOut.buffer.clear();
outSink = currentOut;
});
test('no warnings due to bad canonicalization', () async {
var packagesFilePath =
File('$integrationTestDir/p4/_packages').absolute.path;
await cli.runLinter(
['--packages', packagesFilePath, '$integrationTestDir/p4'],
LinterOptions([]));
expect(collectingOut.trim(),
startsWith('3 files analyzed, 0 issues found, in'));
});
});
group('examples', () {
test('all.yaml', () {
var src = readFile('example/all.yaml');
var options = _getOptionsFromString(src);
var configuredLints =
// ignore: cast_nullable_to_non_nullable
(options['linter'] as YamlMap)['rules'] as YamlList;
// rules are sorted
expect(
configuredLints, orderedEquals(configuredLints.toList()..sort()));
registerLintRules();
var registered = Analyzer.facade.registeredRules
.where((r) =>
r.maturity != Maturity.deprecated && !experiments.contains(r))
.map((r) => r.name);
for (var l in configuredLints) {
if (!registered.contains(l)) {
print(l);
}
}
expect(
configuredLints,
unorderedEquals(Analyzer.facade.registeredRules
.where((r) =>
r.maturity != Maturity.deprecated &&
!experiments.contains(r))
.map((r) => r.name)));
});
});
});
}
void ruleTests() {
group('rule', () {
unnecessary_lambdas.main();
exhaustive_cases.main();
avoid_web_libraries_in_flutter.main();
packages_file_test.main();
overridden_fields.main();
close_sinks.main();
cancel_subscriptions.main();
depend_on_referenced_packages.main();
directives_ordering.main();
file_names.main();
flutter_style_todos.main();
lines_longer_than_80_chars.main();
only_throw_errors.main();
always_require_non_null_named_parameters.main();
prefer_asserts_in_initializer_lists.main();
prefer_const_constructors_in_immutables.main();
avoid_relative_lib_imports.main();
prefer_relative_imports.main();
public_member_api_docs.main();
avoid_renaming_method_parameters.main();
avoid_private_typedef_functions.main();
sort_pub_dependencies.main();
unnecessary_string_escapes.main();
prefer_mixin.main();
use_build_context_synchronously.main();
});
}
/// Provide the options found in [optionsSource].
Map<String, YamlNode> _getOptionsFromString(String? optionsSource) {
var options = <String, YamlNode>{};
if (optionsSource == null) {
return options;
}
var doc = loadYamlNode(optionsSource);
// Empty options.
if (doc is YamlScalar && doc.value == null) {
return options;
}
if (doc is! YamlMap) {
throw Exception(
'Bad options file format (expected map, got ${doc.runtimeType})');
}
if (doc is YamlMap) {
doc.nodes.forEach((k, YamlNode v) {
Object? key;
if (k is YamlScalar) {
key = k.value;
}
if (key is! String) {
throw Exception('Bad options file format (expected String scope key, '
'got ${k.runtimeType})');
}
if (v is! YamlNode) {
throw Exception('Bad options file format (expected Node value, '
'got ${v.runtimeType}: `${v.toString()}`)');
}
options[key] = v;
});
}
return options;
}