blob: 0c6f59f29715d1a1d98870cab79261af9b5f3a52 [file] [log] [blame] [edit]
// 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/dart/ast/ast.dart' show AstNode, AstVisitor;
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/lint/io.dart';
import 'package:analyzer/src/lint/linter.dart' hide CamelCaseString;
import 'package:analyzer/src/lint/pub.dart';
import 'package:analyzer/src/string_source.dart' show StringSource;
import 'package:cli_util/cli_util.dart' show getSdkPath;
import 'package:linter/src/cli.dart' as cli;
import 'package:linter/src/utils.dart';
import 'package:test/test.dart';
import 'mocks.dart';
import 'test_constants.dart';
import 'util/test_utils.dart';
void main() {
defineLinterEngineTests();
}
/// Linter engine tests
void defineLinterEngineTests() {
group('engine', () {
setUp(setUpSharedTestEnvironment);
group('reporter', () {
void doTest(
String label, String expected, Function(PrintingReporter r) report) {
test(label, () {
String? msg;
var reporter = PrintingReporter((m) => msg = m);
report(reporter);
expect(msg, expected);
});
}
doTest('exception', 'EXCEPTION: LinterException: foo',
(r) => r.exception(LinterException('foo')));
doTest('warn', 'WARN: foo', (r) => r.warn('foo'));
});
group('exceptions', () {
test('message', () {
expect(const LinterException('foo').message, 'foo');
});
test('toString', () {
expect(const LinterException().toString(), 'LinterException');
expect(const LinterException('foo').toString(), 'LinterException: foo');
});
});
group('camel case', () {
test('humanize', () {
expect(CamelCaseString('FooBar').humanized, 'Foo Bar');
expect(CamelCaseString('Foo').humanized, 'Foo');
});
test('validation', () {
expect(() => CamelCaseString('foo'),
throwsA(TypeMatcher<ArgumentError>()));
});
test('toString', () {
expect(CamelCaseString('FooBar').toString(), 'FooBar');
});
});
group('groups', () {
test('factory', () {
expect(Group('style').custom, isFalse);
expect(Group('pub').custom, isFalse);
expect(Group('errors').custom, isFalse);
expect(Group('Kustom').custom, isTrue);
});
test('builtins', () {
expect(Group.builtin.contains(Group.style), isTrue);
expect(Group.builtin.contains(Group.errors), isTrue);
expect(Group.builtin.contains(Group.pub), isTrue);
});
});
group('lint driver', () {
test('pubspec', () {
bool? visited;
var options = LinterOptions([MockLinter((n) => visited = true)]);
SourceLinter(options).lintPubspecSource(contents: 'name: foo_bar');
expect(visited, isTrue);
});
test('error collecting', () {
var error = AnalysisError.tmp(
source: StringSource('foo', ''),
offset: 0,
length: 0,
errorCode: LintCode('MockLint', 'This is a test...'));
var linter = SourceLinter(LinterOptions([]))..onError(error);
expect(linter.errors.contains(error), isTrue);
});
});
group('main', () {
setUp(() {
exitCode = 0;
errorSink = MockIOSink();
});
tearDown(() {
exitCode = 0;
errorSink = stderr;
});
test('smoke', () async {
var firstRuleTest =
Directory(ruleTestDataDir).listSync().firstWhere(isDartFile);
await cli.run([firstRuleTest.path]);
expect(cli.isLinterErrorCode(exitCode), isFalse);
});
test('no args', () async {
await cli.run([]);
expect(exitCode, cli.unableToProcessExitCode);
});
test('help', () async {
await cli.run(['-h']);
// Help shouldn't generate an error code
expect(cli.isLinterErrorCode(exitCode), isFalse);
});
test('unknown arg', () async {
await cli.run(['-XXXXX']);
expect(exitCode, cli.unableToProcessExitCode);
});
test('custom sdk path', () async {
// Smoke test to ensure a custom sdk path doesn't sink the ship
var firstRuleTest =
Directory(ruleTestDataDir).listSync().firstWhere(isDartFile);
var sdk = getSdkPath();
await cli.run(['--dart-sdk', sdk, firstRuleTest.path]);
expect(cli.isLinterErrorCode(exitCode), isFalse);
});
});
group('dtos', () {
group('hyperlink', () {
test('html', () {
var link = Hyperlink('dart', 'http://dart.dev');
expect(link.html, '<a href="http://dart.dev">dart</a>');
});
test('html - strong', () {
var link = Hyperlink('dart', 'http://dart.dev', bold: true);
expect(
link.html, '<a href="http://dart.dev"><strong>dart</strong></a>');
});
});
group('rule', () {
test('comparing', () {
LintRule r1 = MockLintRule('Bar', Group('acme'));
LintRule r2 = MockLintRule('Foo', Group('acme'));
expect(r1.compareTo(r2), -1);
LintRule r3 = MockLintRule('Bar', Group('acme'));
LintRule r4 = MockLintRule('Bar', Group('woody'));
expect(r3.compareTo(r4), -1);
});
});
group('maturity', () {
test('comparing', () {
// Custom
var m1 = Maturity('foo', ordinal: 0);
var m2 = Maturity('bar', ordinal: 1);
expect(m1.compareTo(m2), -1);
// Builtin
expect(Maturity.stable.compareTo(Maturity.experimental), -1);
});
});
});
});
}
typedef NodeVisitor = void Function(Object node);
class MockLinter extends LintRule {
final NodeVisitor nodeVisitor;
MockLinter(this.nodeVisitor)
: super(
name: 'MockLint',
group: Group.style,
description: 'Desc',
details: 'And so on...');
@override
PubspecVisitor getPubspecVisitor() => MockPubspecVisitor(nodeVisitor);
@override
AstVisitor getVisitor() => MockVisitor(nodeVisitor);
}
class MockLintRule extends LintRule {
MockLintRule(String name, Group group)
: super(name: name, group: group, description: '', details: '');
@override
AstVisitor getVisitor() => MockVisitor(null);
}
class MockPubspecVisitor extends PubspecVisitor {
final NodeVisitor? nodeVisitor;
MockPubspecVisitor(this.nodeVisitor);
@override
void visitPackageName(PSEntry node) {
nodeVisitor?.call(node);
}
}
class MockVisitor extends GeneralizingAstVisitor {
final NodeVisitor? nodeVisitor;
MockVisitor(this.nodeVisitor);
@override
void visitNode(AstNode node) {
nodeVisitor?.call(node);
}
}