Introduce DoctorValidatorsProvider to improve extensibility of flutter_tools (#16918)
DoctorValidatorsProvider is injected into Doctor to allow
overriding of DoctorValidators without needing to override
the whole Doctor instance.
diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart
index 8b41406..28d2035 100644
--- a/packages/flutter_tools/lib/src/context_runner.dart
+++ b/packages/flutter_tools/lib/src/context_runner.dart
@@ -56,7 +56,8 @@
Config: () => new Config(),
DevFSConfig: () => new DevFSConfig(),
DeviceManager: () => new DeviceManager(),
- Doctor: () => new Doctor(),
+ Doctor: () => const Doctor(),
+ DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance,
Flags: () => const EmptyFlags(),
FlutterVersion: () => new FlutterVersion(const Clock()),
GenSnapshot: () => const GenSnapshot(),
diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart
index 8b31a4d..a988918 100644
--- a/packages/flutter_tools/lib/src/doctor.dart
+++ b/packages/flutter_tools/lib/src/doctor.dart
@@ -26,15 +26,19 @@
Doctor get doctor => context[Doctor];
-class ValidatorTask {
- ValidatorTask(this.validator, this.result);
- final DoctorValidator validator;
- final Future<ValidationResult> result;
+abstract class DoctorValidatorsProvider {
+ /// The singleton instance, pulled from the [AppContext].
+ static DoctorValidatorsProvider get instance => context[DoctorValidatorsProvider];
+
+ static final DoctorValidatorsProvider defaultInstance = new _DefaultDoctorValidatorsProvider();
+
+ List<DoctorValidator> get validators;
}
-class Doctor {
+class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
List<DoctorValidator> _validators;
+ @override
List<DoctorValidator> get validators {
if (_validators == null) {
_validators = <DoctorValidator>[];
@@ -60,6 +64,20 @@
}
return _validators;
}
+}
+
+class ValidatorTask {
+ ValidatorTask(this.validator, this.result);
+ final DoctorValidator validator;
+ final Future<ValidationResult> result;
+}
+
+class Doctor {
+ const Doctor();
+
+ List<DoctorValidator> get validators {
+ return DoctorValidatorsProvider.instance.validators;
+ }
/// Return a list of [ValidatorTask] objects and starts validation on all
/// objects in [validators].
diff --git a/packages/flutter_tools/test/commands/doctor_test.dart b/packages/flutter_tools/test/commands/doctor_test.dart
index 4d40ede..e94d355 100644
--- a/packages/flutter_tools/test/commands/doctor_test.dart
+++ b/packages/flutter_tools/test/commands/doctor_test.dart
@@ -82,7 +82,24 @@
});
});
- group('doctor with fake validators', () {
+ group('doctor with overriden validators', () {
+ testUsingContext('validate non-verbose output format for run without issues', () async {
+ expect(await doctor.diagnose(verbose: false), isTrue);
+ expect(testLogger.statusText, equals(
+ 'Doctor summary (to see all details, run flutter doctor -v):\n'
+ '[✓] Passing Validator (with statusInfo)\n'
+ '[✓] Another Passing Validator (with statusInfo)\n'
+ '[✓] Providing validators is fun (with statusInfo)\n'
+ '\n'
+ '• No issues found!\n'
+ ));
+ }, overrides: <Type, Generator>{
+ DoctorValidatorsProvider: () => new FakeDoctorValidatorsProvider()
+ });
+ });
+
+
+ group('doctor with fake validators', () {
testUsingContext('validate non-verbose output format for run without issues', () async {
expect(await new FakeQuietDoctor().diagnose(verbose: false), isTrue);
expect(testLogger.statusText, equals(
@@ -291,6 +308,19 @@
}
}
+/// A DoctorValidatorsProvider that overrides the default validators without
+/// overriding the doctor.
+class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider {
+ @override
+ List<DoctorValidator> get validators {
+ return <DoctorValidator>[
+ new PassingValidator('Passing Validator'),
+ new PassingValidator('Another Passing Validator'),
+ new PassingValidator('Providing validators is fun')
+ ];
+ }
+}
+
class VsCodeValidatorTestTargets extends VsCodeValidator {
static final String validInstall = fs.path.join('test', 'data', 'vscode', 'application');
static final String validExtensions = fs.path.join('test', 'data', 'vscode', 'extensions');