Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b71b366

Browse files
authored
Do not run real processes in clang_tidy_test.dart (#45748)
Partial work towards flutter/flutter#133190. Some context, from @zanderso on chat: @matanlurey: > For [`clang_tidy_test.dart`](https://github.com/flutter/engine/blob/c020936303cb0646cd10593e6e427d8c5aa6ce52/tools/clang_tidy/test/clang_tidy_test.dart), what is your vision there? I remember we ran into problems with it actually executing `clang.run()` in too many of the test cases, but I don't remember (or seem to have written down) what we decided to do 🙂 @zanderso: > The existing tests are calling `computeFilesOfInterest` and `getLintCommandsForFiles` and inspecting the results for positive tests instead of hitting a real clang-tidy invocation. Tests of command line flags that call `clangTidy.run()` are also testing cases that short-circuit or fail before making a real invocation. Making it harder to do a real invocation from a unit test probably requires plumbing a fake-able ProcessRunner or ProcessManager object through to the ClangTidy constructor. --- All this PR does is allow providing a `ProcessManager` (defaults to `LocalProcessManager`, i.e. `dart:io`) throughout the tool. Then, for tests, I've implemented a _very_ minimal fake of both `ProcessManager` and `Process` (it would be nice to share code w/ say, `flutter_tool`, but lots of work/overhead for very little surface area). After this CL, no tests in `clang_tidy_test.dart` actually run a process. This should unblock adding new features (i.e. original intent of flutter/flutter#133190) without causing headaches for others/CI?
1 parent 3b6d0ea commit b71b366

File tree

5 files changed

+303
-125
lines changed

5 files changed

+303
-125
lines changed

tools/clang_tidy/lib/clang_tidy.dart

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'dart:io' as io show File, stderr, stdout;
77

88
import 'package:meta/meta.dart';
99
import 'package:path/path.dart' as path;
10+
import 'package:process/process.dart';
1011
import 'package:process_runner/process_runner.dart';
1112

1213
import 'src/command.dart';
@@ -43,17 +44,34 @@ class _SetStatusCommand {
4344
/// A class that runs clang-tidy on all or only the changed files in a git
4445
/// repo.
4546
class ClangTidy {
46-
/// Given the path to the build commands for a repo and its root, builds
47-
/// an instance of [ClangTidy].
47+
/// Builds an instance of [ClangTidy] using a repo's [buildCommandPath].
4848
///
49-
/// `buildCommandsPath` is the path to the build_commands.json file.
50-
/// `repoPath` is the path to the Engine repo.
51-
/// `checksArg` are specific checks for clang-tidy to do.
52-
/// `lintAll` when true indicates that all files should be linted.
53-
/// `outSink` when provided is the destination for normal log messages, which
54-
/// will otherwise go to stdout.
55-
/// `errSink` when provided is the destination for error messages, which
56-
/// will otherwise go to stderr.
49+
/// ## Required
50+
/// - [buildCommandsPath] is the path to the build_commands.json file.
51+
///
52+
/// ## Optional
53+
/// - [checksArg] are specific checks for clang-tidy to do.
54+
///
55+
/// If omitted, checks will be determined by the `.clang-tidy` file in the
56+
/// repo.
57+
/// - [lintAll] when true indicates that all files should be linted.
58+
///
59+
/// ## Optional (Test Overrides)
60+
///
61+
/// _Most usages of this class will not need to override the following, which
62+
/// are primarily used for testing (i.e. to avoid real interaction with I/O)._
63+
///
64+
/// - [outSink] when provided is the destination for normal log messages.
65+
///
66+
/// If omitted, [io.stdout] will be used.
67+
///
68+
/// - [errSink] when provided is the destination for error messages.
69+
///
70+
/// If omitted, [io.stderr] will be used.
71+
///
72+
/// - [processManager] when provided is delegated to for running processes.
73+
///
74+
/// If omitted, [LocalProcessManager] will be used.
5775
ClangTidy({
5876
required io.File buildCommandsPath,
5977
String checksArg = '',
@@ -62,6 +80,7 @@ class ClangTidy {
6280
bool fix = false,
6381
StringSink? outSink,
6482
StringSink? errSink,
83+
ProcessManager processManager = const LocalProcessManager(),
6584
}) :
6685
options = Options(
6786
buildCommandsPath: buildCommandsPath,
@@ -72,22 +91,26 @@ class ClangTidy {
7291
errSink: errSink,
7392
),
7493
_outSink = outSink ?? io.stdout,
75-
_errSink = errSink ?? io.stderr;
94+
_errSink = errSink ?? io.stderr,
95+
_processManager = processManager;
7696

7797
/// Builds an instance of [ClangTidy] from a command line.
7898
ClangTidy.fromCommandLine(
7999
List<String> args, {
80100
StringSink? outSink,
81101
StringSink? errSink,
102+
ProcessManager processManager = const LocalProcessManager(),
82103
}) :
83104
options = Options.fromCommandLine(args, errSink: errSink),
84105
_outSink = outSink ?? io.stdout,
85-
_errSink = errSink ?? io.stderr;
106+
_errSink = errSink ?? io.stderr,
107+
_processManager = processManager;
86108

87109
/// The [Options] that specify how this [ClangTidy] operates.
88110
final Options options;
89111
final StringSink _outSink;
90112
final StringSink _errSink;
113+
final ProcessManager _processManager;
91114

92115
late final DateTime _startTime;
93116

@@ -185,6 +208,7 @@ class ClangTidy {
185208

186209
final GitRepo repo = GitRepo(
187210
options.repoPath,
211+
processManager: _processManager,
188212
verbose: options.verbose,
189213
);
190214
if (options.lintHead) {
@@ -351,7 +375,10 @@ class ClangTidy {
351375
totalJobs, completed, inProgress, pending, failed));
352376
}
353377

354-
final ProcessPool pool = ProcessPool(printReport: reporter);
378+
final ProcessPool pool = ProcessPool(
379+
printReport: reporter,
380+
processRunner: ProcessRunner(processManager: _processManager),
381+
);
355382
await for (final WorkerJob job in pool.startWorkers(jobs)) {
356383
pendingJobs.remove(job.name);
357384
if (pendingJobs.isNotEmpty && pendingJobs.length <= 3) {

tools/clang_tidy/lib/src/git_repo.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,26 @@
55
import 'dart:io' as io show Directory, File;
66

77
import 'package:path/path.dart' as path;
8+
import 'package:process/process.dart';
89
import 'package:process_runner/process_runner.dart';
910

1011
/// Utility methods for working with a git repo.
1112
class GitRepo {
1213
/// The git repository rooted at `root`.
1314
GitRepo(this.root, {
1415
this.verbose = false,
15-
});
16+
ProcessManager processManager = const LocalProcessManager(),
17+
}) : _processManager = processManager;
1618

1719
/// Whether to produce verbose log output.
1820
final bool verbose;
1921

2022
/// The root of the git repo.
2123
final io.Directory root;
2224

25+
/// The delegate to use for running processes.
26+
final ProcessManager _processManager;
27+
2328
List<io.File>? _changedFiles;
2429

2530
/// Returns a list of all non-deleted files which differ from the nearest
@@ -41,6 +46,7 @@ class GitRepo {
4146
Future<List<io.File>> _getChangedFiles() async {
4247
final ProcessRunner processRunner = ProcessRunner(
4348
defaultWorkingDirectory: root,
49+
processManager: _processManager,
4450
);
4551
await _fetch(processRunner);
4652
ProcessRunnerResult mergeBaseResult = await processRunner.runProcess(

tools/clang_tidy/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dependencies:
2020
args: any
2121
meta: any
2222
path: any
23+
process: any
2324
process_runner: any
2425

2526
dev_dependencies:

0 commit comments

Comments
 (0)