Skip to content

Commit f810790

Browse files
srawlinsCommit Queue
authored andcommitted
analyzer_testing: Move LintRuleTest and linter's PubPackageResolutionTest
Most of the behavior of LintRuleTest is extracted into a public class in analyzer_testing, AnalysisRuleTest. A little bit of code is left in LintRuleTest, so that first-party lint rules can be tested by registering the first-party lint rules. And those lint rules can declare the `lintRule` that each is concerned with, rather than the new `analysisRule` getter. PubPackageResolutionTest is left as private impl, because I think it may undergo some changes, and we may be merging more shared code, and the name may change. A few first-party lint rules have tests that refer to this class, which is OK. Other than that, no code or behavior changes are in this CL. Work towards #55660 Change-Id: I447850c438af7d0fe90889d2eaec6f2f8b4f8281 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/429420 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 5511fc3 commit f810790

File tree

8 files changed

+652
-586
lines changed

8 files changed

+652
-586
lines changed

pkg/analyzer_testing/api.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
package:analyzer_testing/analysis_rule/analysis_rule.dart:
2+
error (function: ExpectedDiagnostic Function(DiagnosticCode, int, int, {Pattern? messageContains}))
3+
AnalysisRuleTest (class extends PubPackageResolutionTest):
4+
new (constructor: AnalysisRuleTest Function())
5+
analysisRule (getter: String)
6+
assertNoPubspecDiagnostics (method: Future<void> Function(String))
7+
assertPubspecDiagnostics (method: Future<void> Function(String, List<ExpectedDiagnostic>))
8+
lint (method: ExpectedDiagnostic Function(int, int, {Pattern? correctionContains, Pattern? messageContains, String? name}))
9+
setUp (method: void Function())
110
package:analyzer_testing/experiments/experiments.dart:
211
experimentsForTests (static getter: List<String>)
312
experimentsForTests= (static setter: List<String>)
@@ -48,18 +57,27 @@ package:analyzer_testing/resource_provider_mixin.dart:
4857
newSinglePackageConfigJsonFile (method: void Function({required String name, required String packagePath}))
4958
toUri (method: Uri Function(String))
5059
toUriStr (method: String Function(String))
60+
package:analyzer_testing/src/analysis_rule/pub_package_resolution.dart:
61+
ExpectedDiagnostic (non-public)
62+
PubPackageResolutionTest (non-public)
5163
package:analyzer_testing/utilities/extensions/resource_provider.dart:
5264
ResourceProviderExtension (extension on ResourceProvider):
5365
convertPath (method: String Function(String))
5466
package:analyzer_testing/utilities/utilities.dart:
5567
analysisOptionsContent (function: String Function({List<String> experiments, List<String> includes, List<String> legacyPlugins, List<String> rules, bool strictCasts, bool strictInference, bool strictRawTypes, List<String> unignorableNames}))
5668
pubspecYamlContent (function: String Function({List<String> dependencies, String? name, String? sdkVersion}))
69+
dart:async:
70+
Future (referenced)
5771
dart:core:
5872
List (referenced)
5973
Object (referenced)
74+
Pattern (referenced)
6075
String (referenced)
6176
Uri (referenced)
6277
bool (referenced)
78+
int (referenced)
79+
package:_fe_analyzer_shared/src/base/errors.dart:
80+
DiagnosticCode (referenced)
6381
package:analyzer/file_system/file_system.dart:
6482
File (referenced)
6583
Folder (referenced)
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/diagnostic/diagnostic.dart';
6+
import 'package:analyzer/error/error.dart';
7+
import 'package:analyzer/error/listener.dart';
8+
import 'package:analyzer/source/file_source.dart';
9+
import 'package:analyzer/src/lint/linter.dart'; // ignore: implementation_imports
10+
import 'package:analyzer/src/lint/pub.dart'; // ignore: implementation_imports
11+
import 'package:analyzer/src/lint/registry.dart'; // ignore: implementation_imports
12+
import 'package:analyzer_testing/src/analysis_rule/pub_package_resolution.dart';
13+
import 'package:analyzer_testing/utilities/utilities.dart';
14+
import 'package:meta/meta.dart';
15+
16+
/// Returns an [ExpectedDiagnostic] with the given arguments.
17+
///
18+
/// Just a short-named helper for use in the `assert*Diagnostics` methods.
19+
ExpectedDiagnostic error(
20+
DiagnosticCode code,
21+
int offset,
22+
int length, {
23+
Pattern? messageContains,
24+
}) => ExpectedError(code, offset, length, messageContains: messageContains);
25+
26+
/// A base class for analysis rule tests that use test_reflective_loader.
27+
abstract class AnalysisRuleTest extends PubPackageResolutionTest {
28+
/// The name of the analysis rule which this test is concerned with.
29+
String get analysisRule;
30+
31+
/// Asserts that no diagnostics are reported when resolving [content].
32+
Future<void> assertNoPubspecDiagnostics(String content) async {
33+
newFile(testPackagePubspecPath, content);
34+
var errors = await _analyzePubspecFile(content);
35+
assertDiagnosticsIn(errors, []);
36+
}
37+
38+
/// Asserts that [expectedDiagnostics] are reported when resolving [content].
39+
Future<void> assertPubspecDiagnostics(
40+
String content,
41+
List<ExpectedDiagnostic> expectedDiagnostics,
42+
) async {
43+
newFile(testPackagePubspecPath, content);
44+
var errors = await _analyzePubspecFile(content);
45+
assertDiagnosticsIn(errors, expectedDiagnostics);
46+
}
47+
48+
/// Returns an "expected diagnostic" for [analysisRule] (or [name], if given)
49+
/// at [offset] and [length].
50+
///
51+
/// If given, [messageContains] is used to match against a diagnostic's
52+
/// message, and [correctionContains] is used to match against a diagnostic's
53+
/// correction message.
54+
ExpectedDiagnostic lint(
55+
int offset,
56+
int length, {
57+
Pattern? messageContains,
58+
Pattern? correctionContains,
59+
String? name,
60+
}) => ExpectedLint(
61+
name ?? analysisRule,
62+
offset,
63+
length,
64+
messageContains: messageContains,
65+
correctionContains: correctionContains,
66+
);
67+
68+
@mustCallSuper
69+
@override
70+
void setUp() {
71+
if (!Registry.ruleRegistry.any((r) => r.name == analysisRule)) {
72+
throw Exception("Unrecognized rule: '$analysisRule'");
73+
}
74+
super.setUp();
75+
newAnalysisOptionsYamlFile(
76+
testPackageRootPath,
77+
analysisOptionsContent(experiments: experiments, rules: [analysisRule]),
78+
);
79+
}
80+
81+
Future<List<Diagnostic>> _analyzePubspecFile(String content) async {
82+
var path = convertPath(testPackagePubspecPath);
83+
var pubspecRules = <AbstractAnalysisRule, PubspecVisitor<Object?>>{};
84+
var rules = Registry.ruleRegistry.where((r) => analysisRule == r.name);
85+
for (var rule in rules) {
86+
var visitor = rule.pubspecVisitor;
87+
if (visitor != null) {
88+
pubspecRules[rule] = visitor;
89+
}
90+
}
91+
92+
if (pubspecRules.isEmpty) {
93+
throw UnsupportedError(
94+
'Resolving pubspec files only supported with rules with '
95+
'PubspecVisitors.',
96+
);
97+
}
98+
99+
var sourceUri = resourceProvider.pathContext.toUri(path);
100+
var pubspecAst = Pubspec.parse(
101+
content,
102+
sourceUrl: sourceUri,
103+
resourceProvider: resourceProvider,
104+
);
105+
var listener = RecordingErrorListener();
106+
var file = resourceProvider.getFile(path);
107+
var reporter = ErrorReporter(listener, FileSource(file, sourceUri));
108+
for (var entry in pubspecRules.entries) {
109+
entry.key.reporter = reporter;
110+
pubspecAst.accept(entry.value);
111+
}
112+
return [...listener.errors];
113+
}
114+
}

0 commit comments

Comments
 (0)