Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

feat: add 'include-methods' config to 'missing-test-assertion' rule #1026

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* feat: add 'include-methods' config to static code diagnostic [`missing-test-assertion`](https://dartcodemetrics.dev/docs/rules/common/missing-test-assertion)
* fix: add rule 'missing-test-assertion' in rules factory.
* feat: add static code diagnostic [`missing-test-assertion`](https://dartcodemetrics.dev/docs/rules/common/missing-test-assertion).
* feat: add support for presets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ part of 'missing_test_assertion_rule.dart';

class _ConfigParser {
static const _includeAssertionsConfig = 'include-assertions';
static const _includeMethodsConfig = 'include-methods';

static Iterable<String> parseIncludeAssertions(Map<String, Object> config) =>
config.containsKey(_includeAssertionsConfig) &&
config[_includeAssertionsConfig] is Iterable
? List<String>.from(config[_includeAssertionsConfig] as Iterable)
: <String>[];

static Iterable<String> parseIncludeMethods(Map<String, Object> config) =>
config.containsKey(_includeMethodsConfig) &&
config[_includeMethodsConfig] is Iterable
? List<String>.from(config[_includeMethodsConfig] as Iterable)
: <String>[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import '../../models/common_rule.dart';
import '../../rule_utils.dart';

part 'config_parser.dart';

part 'visitor.dart';

class MissingTestAssertionRule extends CommonRule {
Expand All @@ -20,9 +21,11 @@ class MissingTestAssertionRule extends CommonRule {
static const _warningMessage = 'Missing test assertion.';

final Iterable<String> _includeAssertions;
final Iterable<String> _includeMethods;

MissingTestAssertionRule([Map<String, Object> config = const {}])
: _includeAssertions = _ConfigParser.parseIncludeAssertions(config),
_includeMethods = _ConfigParser.parseIncludeMethods(config),
super(
id: ruleId,
severity: readSeverity(config, Severity.warning),
Expand All @@ -32,7 +35,7 @@ class MissingTestAssertionRule extends CommonRule {

@override
Iterable<Issue> check(InternalResolvedUnitResult source) {
final visitor = _Visitor(_includeAssertions);
final visitor = _Visitor(_includeAssertions, _includeMethods);

source.unit.visitChildren(visitor);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ class _Visitor extends RecursiveAstVisitor<void> {
Iterable<AstNode> get nodes => _nodes;

final Iterable<String> _includeAssertions;
final Iterable<String> _includeMethods;

_Visitor(this._includeAssertions);
_Visitor(this._includeAssertions, this._includeMethods);

@override
void visitFunctionDeclaration(FunctionDeclaration node) {
Expand All @@ -16,14 +17,14 @@ class _Visitor extends RecursiveAstVisitor<void> {
return;
}

final visitor = _MethodTestVisitor(_includeAssertions);
final visitor = _MethodTestVisitor(_includeAssertions, _includeMethods);
node.visitChildren(visitor);
_nodes.addAll(visitor.nodes);
}
}

class _MethodTestVisitor extends RecursiveAstVisitor<void> {
static const _testMethodNameList = <String>{
final _testMethodNameList = <String>{
'test',
'testWidgets',
};
Expand All @@ -34,7 +35,9 @@ class _MethodTestVisitor extends RecursiveAstVisitor<void> {

final Iterable<String> _includeAssertions;

_MethodTestVisitor(this._includeAssertions);
_MethodTestVisitor(this._includeAssertions, Iterable<String> includeMethods) {
_testMethodNameList.addAll(includeMethods);
}

@override
void visitMethodInvocation(MethodInvocation node) {
Expand Down Expand Up @@ -73,10 +76,8 @@ class _MethodAssertionVisitor extends RecursiveAstVisitor<void> {
'expectLater',
};

final Iterable<String> _includeAssertions;

_MethodAssertionVisitor(this._includeAssertions) {
_assertionMethodNameList.addAll(_includeAssertions);
_MethodAssertionVisitor(Iterable<String> includeAssertions) {
_assertionMethodNameList.addAll(includeAssertions);
}

bool hasContainedAssertion = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
void main() {
print('Hello');

customTest(null, () => 1 == 1); // LINT

otherTestMethod(null, () => 1 == 1); // LINT

excludedTestMethod(null, () => 1 == 1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const _incorrectExamplePath =
'missing_test_assertion/examples/incorrect_example.dart';
const _customAssertionsExamplePath =
'missing_test_assertion/examples/custom_assertions_example.dart';
const _customMethodsExamplePath =
'missing_test_assertion/examples/custom_methods_example.dart';

void main() {
group('MissingTestAssertion', () {
Expand All @@ -31,7 +33,7 @@ void main() {
RuleTestHelper.verifyNoIssues(issues);
});

test('with custom config reports no issues', () async {
test('with custom assertions config reports no issues', () async {
final unit =
await RuleTestHelper.resolveFromFile(_customAssertionsExamplePath);
final config = {
Expand Down Expand Up @@ -71,5 +73,31 @@ void main() {
],
);
});

test('with custom methods config reports about found issues', () async {
final unit =
await RuleTestHelper.resolveFromFile(_customMethodsExamplePath);
final config = {
'include-methods': [
'customTest',
'otherTestMethod',
],
};
final issues = MissingTestAssertionRule(config).check(unit);

RuleTestHelper.verifyIssues(
issues: issues,
startLines: [4, 6],
startColumns: [3, 3],
locationTexts: [
'customTest(null, () => 1 == 1)',
'otherTestMethod(null, () => 1 == 1)',
],
messages: [
'Missing test assertion.',
'Missing test assertion.',
],
);
});
});
}
8 changes: 7 additions & 1 deletion website/docs/rules/common/missing-test-assertion.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import RuleDetails from '@site/src/components/RuleDetails';

<RuleDetails version="4.21.0" severity="style" />
<RuleDetails version="4.21.0" severity="warning" />

Warns that there is no assertion in the test.

Use `include-assertions` configuration, if you want to include specific assertions.
Defaults to Dart default assertions including expect, expectLater and all expectAsync variants.

Use `include-methods` configuration, if you want the linter to check particular test methods for missing assertions.
Defaults to `test` and `testWidgets` methods.

### ⚙️ Config example {#config-example}

Expand All @@ -16,6 +20,8 @@ dart_code_metrics:
- missing-test-assertion:
include-assertions:
- verify
include-methods:
- customTest
```

### Example {#example}
Expand Down