simple fix driver tool
Work to support https://github.com/dart-lang/sdk/issues/44272.
(Sure to evolve w/ some testing but I think there's enough to iterate on.)
Change-Id: Ieaab218ad8850631f4b16838d3b3821eaf7bd747
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175005
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/dartdev/test/fix_driver_test.dart b/pkg/dartdev/test/fix_driver_test.dart
new file mode 100644
index 0000000..35ec72a
--- /dev/null
+++ b/pkg/dartdev/test/fix_driver_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, 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 'package:test/test.dart';
+
+import '../tool/fix_driver.dart';
+import 'utils.dart';
+
+void main() {
+ group('Driver', _driver);
+}
+
+Future<FixOutput> runFix(List<String> args) async {
+ var runner = FixRunner(logger: CapturingLogger());
+ var result = await runner.runFix(args);
+ return FixOutput(result);
+}
+
+void _driver() {
+ TestProject p;
+ tearDown(() => p?.dispose());
+
+ test('no fixes', () async {
+ p = project(mainSrc: 'int get foo => 1;\n');
+ var result = await runFix(['--apply', p.dirPath]);
+ expect(result.stdout, contains('Nothing to fix!'));
+ expect(result.returnCode, 0);
+ });
+}
+
+class FixOutput {
+ final FixResult<CapturingLogger> result;
+ FixOutput(this.result);
+
+ int get returnCode => result.returnCode;
+ String get stderr => result.logger.output.stderr.toString();
+ String get stdout => result.logger.output.stdout.toString();
+}
diff --git a/pkg/dartdev/test/test_all.dart b/pkg/dartdev/test/test_all.dart
index 2576ac9..edd644b 100644
--- a/pkg/dartdev/test/test_all.dart
+++ b/pkg/dartdev/test/test_all.dart
@@ -18,6 +18,7 @@
import 'commands/test_test.dart' as test;
import 'core_test.dart' as core;
import 'experiments_test.dart' as experiments;
+import 'fix_driver_test.dart' as fix_driver;
import 'no_such_file_test.dart' as no_such_file;
import 'sdk_test.dart' as sdk;
import 'smoke/implicit_smoke_test.dart' as implicit_smoke;
@@ -32,6 +33,7 @@
create.main();
experiments.main();
fix.main();
+ fix_driver.main();
flag.main();
format.main();
help.main();
diff --git a/pkg/dartdev/tool/fix_driver.dart b/pkg/dartdev/tool/fix_driver.dart
new file mode 100644
index 0000000..17f246a
--- /dev/null
+++ b/pkg/dartdev/tool/fix_driver.dart
@@ -0,0 +1,140 @@
+// Copyright (c) 2020, 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 'package:args/args.dart';
+import 'package:args/command_runner.dart';
+import 'package:cli_util/cli_logging.dart';
+import 'package:dartdev/src/commands/fix.dart';
+import 'package:dartdev/src/core.dart';
+import 'package:dartdev/src/utils.dart';
+import 'package:meta/meta.dart';
+
+Future<void> main(List<String> args) async {
+ var runner = FixRunner(logger: Logger.standard());
+ var result = await runner.runFix(args);
+ return result.returnCode;
+}
+
+class CapturedProgress extends Progress {
+ final LoggerOutput output;
+
+ bool canceled = false;
+ bool finished = false;
+
+ CapturedProgress(this.output, String message) : super(message) {
+ output.progress.writeln(message);
+ }
+
+ @override
+ void cancel() {
+ canceled = true;
+ }
+
+ @override
+ void finish({String message, bool showTiming = false}) {
+ // todo (pq): consider capturing / tracking finish display updates.
+ finished = true;
+ }
+}
+
+class CapturingLogger implements Logger {
+ final LoggerOutput output = LoggerOutput();
+
+ @override
+ final Ansi ansi = Ansi(Ansi.terminalSupportsAnsi);
+
+ @override
+ bool isVerbose;
+
+ CapturingLogger({this.isVerbose = false});
+
+ @override
+ void flush() {
+ // deprecated.
+ }
+
+ @override
+ Progress progress(String message) => CapturedProgress(output, message);
+
+ @override
+ void stderr(String message) {
+ output.stderr.writeln(message);
+ }
+
+ @override
+ void stdout(String message) {
+ output.stdout.writeln(message);
+ }
+
+ @override
+ void trace(String message) {
+ output.trace.writeln(message);
+ }
+
+ @override
+ void write(String message) {
+ output.stdout.write(message);
+ }
+
+ @override
+ void writeCharCode(int charCode) {
+ output.stdout.writeCharCode(charCode);
+ }
+}
+
+class FixResult<T extends Logger> {
+ /// The value returned by [FixCommand.run].
+ final int returnCode;
+
+ /// The logger used in driving fixes.
+ final T logger;
+
+ FixResult(this.logger, this.returnCode);
+}
+
+class FixRunner<T extends Logger> extends CommandRunner<int> {
+ final _supportedOptions = ['dry-run', 'apply'];
+
+ T logger;
+
+ @override
+ final ArgParser argParser = ArgParser(
+ usageLineLength: dartdevUsageLineLength,
+ allowTrailingOptions: false,
+ );
+
+ FixRunner({@required this.logger})
+ : super('fix_runner',
+ 'A command-line utility for testing the `dart fix` command.') {
+ addCommand(FixCommand());
+ _supportedOptions.forEach(argParser.addOption);
+ }
+
+ @override
+ Future<int> runCommand(ArgResults topLevelResults) async {
+ var result = await super.runCommand(topLevelResults);
+ return result;
+ }
+
+ Future<FixResult<T>> runFix(List<String> args) async {
+ log = logger;
+ var argResults = argParser.parse(['fix', ...?args]);
+ var result = await runCommand(argResults);
+ return FixResult(logger, result);
+ }
+}
+
+class LoggerOutput {
+ /// Messages reported to progress.
+ final StringBuffer progress = StringBuffer();
+
+ /// Messages reported to stdout.
+ final StringBuffer stdout = StringBuffer();
+
+ /// Messages reported to stderr.
+ final StringBuffer stderr = StringBuffer();
+
+ /// Messages reported to trace.
+ final StringBuffer trace = StringBuffer();
+}