Create categories for doctor validators (#20758)

* First step in Flutter Doctor refactor. Assigns categories to all validators.

* Revert "Roll engine e54bc4ea1832..a84b210b3d26 (6 commits) (#20453)"

This reverts commit 05c2880a17.

* Split iOS and Android workflows into workflow and validator classes.

* Change ValidatorCategory to handle standalone validators that share a
category (e.g. IntelliJ).

Also make Android Studio and Android toolchain use separate categories.

At this stage, flutter doctor output matches what it was previously.
(The summary() method itself has not yet been changed )

* Change doctor summary code to support validator categories.

Output is still unchanged.

* Handle small formatting issues.

* Flip Flutter category's isGroup field to false until it's actually
needed.

* Revert auto-generated formatting changes to keep those lines from
muddying the pull.

* Small fixes pointed out by analyzer.

* Properly fix analyzer issues around const constructors.

* Small changes to address comments.

* Add tests to verify grouped validator behavior and validationtype
merging.

* Update doctor.dart

* Add comments for clarification.
This commit is contained in:
tonyzhao1 2018-09-04 19:36:47 -07:00 committed by Mehmet Fidanboylu
parent 88c94f57c7
commit 58d98ce31e
10 changed files with 312 additions and 47 deletions

View file

@ -13,7 +13,7 @@ import 'android_studio.dart';
class AndroidStudioValidator extends DoctorValidator {
final AndroidStudio _studio;
AndroidStudioValidator(this._studio) : super('Android Studio');
AndroidStudioValidator(this._studio) : super('Android Studio', ValidatorCategory.androidStudio);
static List<DoctorValidator> get allValidators {
final List<DoctorValidator> validators = <DoctorValidator>[];

View file

@ -18,6 +18,7 @@ import '../globals.dart';
import 'android_sdk.dart';
AndroidWorkflow get androidWorkflow => context[AndroidWorkflow];
AndroidValidator get androidValidator => context[AndroidValidator];
enum LicensesAccepted {
none,
@ -30,9 +31,7 @@ final RegExp licenseCounts = new RegExp(r'(\d+) of (\d+) SDK package licenses? n
final RegExp licenseNotAccepted = new RegExp(r'licenses? not accepted', caseSensitive: false);
final RegExp licenseAccepted = new RegExp(r'All SDK package licenses accepted.');
class AndroidWorkflow extends DoctorValidator implements Workflow {
AndroidWorkflow() : super('Android toolchain - develop for Android devices');
class AndroidWorkflow implements Workflow {
@override
bool get appliesToHostPlatform => true;
@ -44,6 +43,11 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
@override
bool get canListEmulators => getEmulatorPath(androidSdk) != null && getAvdPath() != null;
}
class AndroidValidator extends DoctorValidator {
AndroidValidator(): super('Android toolchain - develop for Android devices',
ValidatorCategory.androidToolchain);
static const String _jdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/';

View file

@ -47,6 +47,7 @@ Future<T> runInContext<T>(
AndroidSdk: AndroidSdk.locateAndroidSdk,
AndroidStudio: AndroidStudio.latestValid,
AndroidWorkflow: () => new AndroidWorkflow(),
AndroidValidator: () => new AndroidValidator(),
Artifacts: () => new CachedArtifacts(),
AssetBundleFactory: () => AssetBundleFactory.defaultInstance,
BotDetector: () => const BotDetector(),
@ -66,6 +67,7 @@ Future<T> runInContext<T>(
IMobileDevice: () => const IMobileDevice(),
IOSSimulatorUtils: () => new IOSSimulatorUtils(),
IOSWorkflow: () => const IOSWorkflow(),
IOSValidator: () => const IOSValidator(),
KernelCompiler: () => const KernelCompiler(),
Logger: () => platform.isWindows ? new WindowsStdoutLogger() : new StdoutLogger(),
OperatingSystemUtils: () => new OperatingSystemUtils(),

View file

@ -34,10 +34,12 @@ abstract class DoctorValidatorsProvider {
static final DoctorValidatorsProvider defaultInstance = new _DefaultDoctorValidatorsProvider();
List<DoctorValidator> get validators;
List<Workflow> get workflows;
}
class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
List<DoctorValidator> _validators;
List<Workflow> _workflows;
@override
List<DoctorValidator> get validators {
@ -46,10 +48,10 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
_validators.add(new _FlutterValidator());
if (androidWorkflow.appliesToHostPlatform)
_validators.add(androidWorkflow);
_validators.add(androidValidator);
if (iosWorkflow.appliesToHostPlatform)
_validators.add(iosWorkflow);
_validators.add(iosValidator);
final List<DoctorValidator> ideValidators = <DoctorValidator>[];
ideValidators.addAll(AndroidStudioValidator.allValidators);
@ -65,6 +67,13 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
}
return _validators;
}
@override
List<Workflow> get workflows {
_workflows ??= <Workflow>[iosWorkflow, androidWorkflow];
return _workflows;
}
}
class ValidatorTask {
@ -91,7 +100,7 @@ class Doctor {
}
List<Workflow> get workflows {
return validators.whereType<Workflow>().toList();
return DoctorValidatorsProvider.instance.workflows;
}
/// Print a summary of the state of the tooling, as well as how to get more info.
@ -104,8 +113,28 @@ class Doctor {
bool allGood = true;
final Set<ValidatorCategory> finishedGroups = new Set<ValidatorCategory>();
for (DoctorValidator validator in validators) {
final ValidationResult result = await validator.validate();
final ValidatorCategory currentCategory = validator.category;
ValidationResult result;
if (currentCategory.isGrouped) {
if (finishedGroups.contains(currentCategory)) {
// We already handled this category via a previous validator.
continue;
}
// Skip ahead and get results for the other validators in this category.
final List<ValidationResult> results = <ValidationResult>[];
for (DoctorValidator subValidator in validators.where(
(DoctorValidator v) => v.category == currentCategory)) {
results.add(await subValidator.validate());
}
result = _mergeValidationResults(results);
finishedGroups.add(currentCategory);
} else {
result = await validator.validate();
}
buffer.write('${result.leadingBox} ${validator.title} is ');
if (result.type == ValidationType.missing)
buffer.write('not installed.');
@ -121,6 +150,7 @@ class Doctor {
if (result.type != ValidationType.installed)
allGood = false;
}
if (!allGood) {
@ -134,7 +164,7 @@ class Doctor {
/// Print information about the state of installed tooling.
Future<bool> diagnose({ bool androidLicenses = false, bool verbose = true }) async {
if (androidLicenses)
return AndroidWorkflow.runLicenseManager();
return AndroidValidator.runLicenseManager();
if (!verbose) {
printStatus('Doctor summary (to see all details, run flutter doctor -v):');
@ -142,18 +172,42 @@ class Doctor {
bool doctorResult = true;
int issues = 0;
for (ValidatorTask validatorTask in startValidatorTasks()) {
final List<ValidatorTask> taskList = startValidatorTasks();
final Set<ValidatorCategory> finishedGroups = new Set<ValidatorCategory>();
for (ValidatorTask validatorTask in taskList) {
final DoctorValidator validator = validatorTask.validator;
final ValidatorCategory currentCategory = validator.category;
final Status status = new Status.withSpinner();
try {
await validatorTask.result;
} catch (exception) {
status.cancel();
rethrow;
ValidationResult result;
if (currentCategory.isGrouped) {
if (finishedGroups.contains(currentCategory)) {
continue;
}
final List<ValidationResult> results = <ValidationResult>[];
for (ValidatorTask subValidator in taskList.where(
(ValidatorTask t) => t.validator.category == currentCategory)) {
try {
results.add(await subValidator.result);
} catch (exception) {
status.cancel();
rethrow;
}
}
result = _mergeValidationResults(results);
finishedGroups.add(currentCategory);
} else {
try {
result = await validatorTask.result;
} catch (exception) {
status.cancel();
rethrow;
}
}
status.stop();
final ValidationResult result = await validatorTask.result;
if (result.type == ValidationType.missing) {
doctorResult = false;
}
@ -194,6 +248,35 @@ class Doctor {
return doctorResult;
}
ValidationResult _mergeValidationResults(List<ValidationResult> results) {
ValidationType mergedType = results[0].type;
final List<ValidationMessage> mergedMessages = <ValidationMessage>[];
for (ValidationResult result in results) {
switch (result.type) {
case ValidationType.installed:
if (mergedType == ValidationType.missing) {
mergedType = ValidationType.partial;
}
break;
case ValidationType.partial:
mergedType = ValidationType.partial;
break;
case ValidationType.missing:
if (mergedType == ValidationType.installed) {
mergedType = ValidationType.partial;
}
break;
default:
throw 'Unrecognized validation type: ' + result.type.toString();
}
mergedMessages.addAll(result.messages);
}
return new ValidationResult(mergedType, mergedMessages,
statusInfo: results[0].statusInfo);
}
bool get canListAnything => workflows.any((Workflow workflow) => workflow.canListDevices);
bool get canLaunchAnything {
@ -201,8 +284,11 @@ class Doctor {
return true;
return workflows.any((Workflow workflow) => workflow.canLaunchDevices);
}
}
/// A series of tools and required install steps for a target platform (iOS or Android).
abstract class Workflow {
/// Whether the workflow applies to this platform (as in, should we ever try and use it).
@ -224,10 +310,28 @@ enum ValidationType {
installed
}
/// Validator output is grouped by category.
class ValidatorCategory {
final String name;
// Whether we should bundle results for validators sharing this cateogry,
// or let each stand alone.
final bool isGrouped;
const ValidatorCategory(this.name, this.isGrouped);
static const ValidatorCategory androidToolchain = ValidatorCategory('androidToolchain', true);
static const ValidatorCategory androidStudio = ValidatorCategory('androidStudio', false);
static const ValidatorCategory ios = ValidatorCategory('ios', true);
static const ValidatorCategory flutter = ValidatorCategory('flutter', false);
static const ValidatorCategory ide = ValidatorCategory('ide', false);
static const ValidatorCategory device = ValidatorCategory('device', false);
static const ValidatorCategory other = ValidatorCategory('other', false);
}
abstract class DoctorValidator {
const DoctorValidator(this.title);
const DoctorValidator(this.title, [this.category = ValidatorCategory.other]);
final String title;
final ValidatorCategory category;
Future<ValidationResult> validate();
}
@ -271,7 +375,7 @@ class ValidationMessage {
}
class _FlutterValidator extends DoctorValidator {
_FlutterValidator() : super('Flutter');
_FlutterValidator() : super('Flutter', ValidatorCategory.flutter);
@override
Future<ValidationResult> validate() async {
@ -320,7 +424,7 @@ bool _genSnapshotRuns(String genSnapshotPath) {
}
class NoIdeValidator extends DoctorValidator {
NoIdeValidator() : super('Flutter IDE Support');
NoIdeValidator() : super('Flutter IDE Support',ValidatorCategory.ide);
@override
Future<ValidationResult> validate() async {
@ -333,7 +437,7 @@ class NoIdeValidator extends DoctorValidator {
abstract class IntelliJValidator extends DoctorValidator {
final String installPath;
IntelliJValidator(String title, this.installPath) : super(title);
IntelliJValidator(String title, this.installPath) : super(title, ValidatorCategory.ide);
String get version;
String get pluginsPath;
@ -498,7 +602,7 @@ class IntelliJValidatorOnMac extends IntelliJValidator {
validators.add(new ValidatorWithResult(
'Cannot determine if IntelliJ is installed',
new ValidationResult(ValidationType.missing, <ValidationMessage>[
new ValidationMessage.error(e.message),
new ValidationMessage.error(e.message),
]),
));
}
@ -528,7 +632,7 @@ class IntelliJValidatorOnMac extends IntelliJValidator {
}
class DeviceValidator extends DoctorValidator {
DeviceValidator() : super('Connected devices');
DeviceValidator() : super('Connected devices', ValidatorCategory.device);
@override
Future<ValidationResult> validate() async {

View file

@ -15,9 +15,10 @@ import 'mac.dart';
import 'plist_utils.dart' as plist;
IOSWorkflow get iosWorkflow => context[IOSWorkflow];
IOSValidator get iosValidator => context[IOSValidator];
class IOSWorkflow extends DoctorValidator implements Workflow {
const IOSWorkflow() : super('iOS toolchain - develop for iOS devices');
class IOSWorkflow implements Workflow {
const IOSWorkflow();
@override
bool get appliesToHostPlatform => platform.isMacOS;
@ -37,6 +38,12 @@ class IOSWorkflow extends DoctorValidator implements Workflow {
String getPlistValueFromFile(String path, String key) {
return plist.getValueFromFile(path, key);
}
}
class IOSValidator extends DoctorValidator {
const IOSValidator() : super('iOS toolchain - develop for iOS devices', ValidatorCategory.ios);
Future<bool> get hasIDeviceInstaller => exitsHappyAsync(<String>['ideviceinstaller', '-h']);

View file

@ -13,7 +13,7 @@ class VsCodeValidator extends DoctorValidator {
'https://marketplace.visualstudio.com/items?itemName=${VsCode.extensionIdentifier}';
final VsCode _vsCode;
VsCodeValidator(this._vsCode) : super(_vsCode.productName);
VsCodeValidator(this._vsCode) : super(_vsCode.productName, ValidatorCategory.ide);
static Iterable<DoctorValidator> get installedValidators {
return VsCode

View file

@ -40,8 +40,8 @@ void main() {
testUsingContext('licensesAccepted throws if cannot run sdkmanager', () async {
processManager.succeed = false;
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
final AndroidWorkflow androidWorkflow = new AndroidWorkflow();
expect(androidWorkflow.licensesAccepted, throwsToolExit());
final AndroidValidator androidValidator = new AndroidValidator();
expect(androidValidator.licensesAccepted, throwsToolExit());
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
FileSystem: () => fs,
@ -52,8 +52,8 @@ void main() {
testUsingContext('licensesAccepted handles garbage/no output', () async {
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
final AndroidWorkflow androidWorkflow = new AndroidWorkflow();
final LicensesAccepted result = await androidWorkflow.licensesAccepted;
final AndroidValidator androidValidator = new AndroidValidator();
final LicensesAccepted result = await androidValidator.licensesAccepted;
expect(result, equals(LicensesAccepted.unknown));
expect(processManager.commands.first, equals('/foo/bar/sdkmanager'));
expect(processManager.commands.last, equals('--licenses'));
@ -72,8 +72,8 @@ void main() {
'All SDK package licenses accepted.'
]);
final AndroidWorkflow androidWorkflow = new AndroidWorkflow();
final LicensesAccepted result = await androidWorkflow.licensesAccepted;
final AndroidValidator androidValidator = new AndroidValidator();
final LicensesAccepted result = await androidValidator.licensesAccepted;
expect(result, equals(LicensesAccepted.all));
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
@ -91,8 +91,8 @@ void main() {
'Review licenses that have not been accepted (y/N)?',
]);
final AndroidWorkflow androidWorkflow = new AndroidWorkflow();
final LicensesAccepted result = await androidWorkflow.licensesAccepted;
final AndroidValidator androidValidator = new AndroidValidator();
final LicensesAccepted result = await androidValidator.licensesAccepted;
expect(result, equals(LicensesAccepted.some));
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
@ -110,8 +110,8 @@ void main() {
'Review licenses that have not been accepted (y/N)?',
]);
final AndroidWorkflow androidWorkflow = new AndroidWorkflow();
final LicensesAccepted result = await androidWorkflow.licensesAccepted;
final AndroidValidator androidValidator = new AndroidValidator();
final LicensesAccepted result = await androidValidator.licensesAccepted;
expect(result, equals(LicensesAccepted.none));
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
@ -125,7 +125,7 @@ void main() {
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
when(sdk.sdkManagerVersion).thenReturn('26.0.0');
expect(await AndroidWorkflow.runLicenseManager(), isTrue);
expect(await AndroidValidator.runLicenseManager(), isTrue);
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
FileSystem: () => fs,
@ -138,7 +138,7 @@ void main() {
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
when(sdk.sdkManagerVersion).thenReturn('25.0.0');
expect(AndroidWorkflow.runLicenseManager(), throwsToolExit(message: 'To update, run'));
expect(AndroidValidator.runLicenseManager(), throwsToolExit(message: 'To update, run'));
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
FileSystem: () => fs,
@ -151,7 +151,7 @@ void main() {
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
when(sdk.sdkManagerVersion).thenReturn(null);
expect(AndroidWorkflow.runLicenseManager(), throwsToolExit(message: 'To update, run'));
expect(AndroidValidator.runLicenseManager(), throwsToolExit(message: 'To update, run'));
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
FileSystem: () => fs,
@ -164,7 +164,7 @@ void main() {
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
processManager.succeed = false;
expect(AndroidWorkflow.runLicenseManager(), throwsToolExit());
expect(AndroidValidator.runLicenseManager(), throwsToolExit());
}, overrides: <Type, Generator>{
AndroidSdk: () => sdk,
FileSystem: () => fs,

View file

@ -183,6 +183,86 @@ void main() {
));
});
});
group('doctor with grouped validators', () {
testUsingContext('validate diagnose combines validator output', () async {
expect(await new FakeGroupedDoctor().diagnose(), isTrue);
expect(testLogger.statusText, equals(
'[✓] Category 1\n'
' • A helpful message\n'
' • A helpful message\n'
'\n'
'[!] Category 2\n'
' • A helpful message\n'
' ✗ A useful error message\n'
'\n'
'! Doctor found issues in 1 category.\n'
));
});
testUsingContext('validate summary combines validator output', () async {
expect(await new FakeGroupedDoctor().summaryText, equals(
'[✓] Category 1 is fully installed.\n'
'[!] Category 2 is partially installed; more components are available.\n'
'\n'
'Run "flutter doctor" for information about installing additional components.\n'
));
});
});
group('doctor merging validator results', () {
final PassingGroupedValidator installed = new PassingGroupedValidator('Category', groupedCategory1);
final PartialGroupedValidator partial = new PartialGroupedValidator('Category', groupedCategory1);
final MissingGroupedValidator missing = new MissingGroupedValidator('Category', groupedCategory1);
testUsingContext('validate installed + installed = installed', () async {
expect(await new FakeSmallGroupDoctor(installed, installed).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[✓]'));
});
testUsingContext('validate installed + partial = partial', () async {
expect(await new FakeSmallGroupDoctor(installed, partial).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[!]'));
});
testUsingContext('validate installed + missing = partial', () async {
expect(await new FakeSmallGroupDoctor(installed, missing).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[!]'));
});
testUsingContext('validate partial + installed = partial', () async {
expect(await new FakeSmallGroupDoctor(partial, installed).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[!]'));
});
testUsingContext('validate partial + partial = partial', () async {
expect(await new FakeSmallGroupDoctor(partial, partial).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[!]'));
});
testUsingContext('validate partial + missing = partial', () async {
expect(await new FakeSmallGroupDoctor(partial, missing).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[!]'));
});
testUsingContext('validate missing + installed = partial', () async {
expect(await new FakeSmallGroupDoctor(missing, installed).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[!]'));
});
testUsingContext('validate missing + partial = partial', () async {
expect(await new FakeSmallGroupDoctor(missing, partial).diagnose(), isTrue);
expect(testLogger.statusText, startsWith('[!]'));
});
testUsingContext('validate missing + missing = missing', () async {
expect(await new FakeSmallGroupDoctor(missing, missing).diagnose(), isFalse);
expect(testLogger.statusText, startsWith('[✗]'));
});
});
}
class IntelliJValidatorTestTarget extends IntelliJValidator {
@ -319,6 +399,74 @@ class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider {
new PassingValidator('Providing validators is fun')
];
}
@override
List<Workflow> get workflows => <Workflow>[];
}
ValidatorCategory groupedCategory1 = const ValidatorCategory('group 1', true);
ValidatorCategory groupedCategory2 = const ValidatorCategory('group 2', true);
class PassingGroupedValidator extends DoctorValidator {
PassingGroupedValidator(String name, ValidatorCategory group) : super(name, group);
@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
messages.add(new ValidationMessage('A helpful message'));
return new ValidationResult(ValidationType.installed, messages);
}
}
class MissingGroupedValidator extends DoctorValidator {
MissingGroupedValidator(String name, ValidatorCategory group): super(name, group);
@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
messages.add(new ValidationMessage.error('A useful error message'));
return new ValidationResult(ValidationType.missing, messages);
}
}
class PartialGroupedValidator extends DoctorValidator {
PartialGroupedValidator(String name, ValidatorCategory group): super(name, group);
@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
messages.add(new ValidationMessage.error('An error message for partial installation'));
return new ValidationResult(ValidationType.partial, messages);
}
}
/// A doctor that has two category groups of two validators each.
class FakeGroupedDoctor extends Doctor {
List<DoctorValidator> _validators;
@override
List<DoctorValidator> get validators {
if (_validators == null) {
_validators = <DoctorValidator>[];
_validators.add(new PassingGroupedValidator('Category 1', groupedCategory1));
_validators.add(new PassingGroupedValidator('Category 1', groupedCategory1));
_validators.add(new PassingGroupedValidator('Category 2', groupedCategory2));
_validators.add(new MissingGroupedValidator('Category 2', groupedCategory2));
}
return _validators;
}
}
/// A doctor that takes any two validators. Used to check behavior when
/// merging ValidationTypes (installed, missing, partial).
class FakeSmallGroupDoctor extends Doctor {
List<DoctorValidator> _validators;
FakeSmallGroupDoctor(DoctorValidator val1, DoctorValidator val2) {
_validators = <DoctorValidator>[val1, val2];
}
@override
List<DoctorValidator> get validators => _validators;
}
class VsCodeValidatorTestTargets extends VsCodeValidator {
@ -326,14 +474,14 @@ class VsCodeValidatorTestTargets extends VsCodeValidator {
static final String validExtensions = fs.path.join('test', 'data', 'vscode', 'extensions');
static final String missingExtensions = fs.path.join('test', 'data', 'vscode', 'notExtensions');
VsCodeValidatorTestTargets._(String installDirectory, String extensionDirectory, {String edition})
: super(new VsCode.fromDirectory(installDirectory, extensionDirectory, edition: edition));
: super(new VsCode.fromDirectory(installDirectory, extensionDirectory, edition: edition));
static VsCodeValidatorTestTargets get installedWithExtension =>
new VsCodeValidatorTestTargets._(validInstall, validExtensions);
new VsCodeValidatorTestTargets._(validInstall, validExtensions);
static VsCodeValidatorTestTargets get installedWithExtension64bit =>
new VsCodeValidatorTestTargets._(validInstall, validExtensions, edition: '64-bit edition');
static VsCodeValidatorTestTargets get installedWithExtension64bit =>
new VsCodeValidatorTestTargets._(validInstall, validExtensions, edition: '64-bit edition');
static VsCodeValidatorTestTargets get installedWithoutExtension =>
new VsCodeValidatorTestTargets._(validInstall, missingExtensions);
new VsCodeValidatorTestTargets._(validInstall, missingExtensions);
}

View file

@ -308,7 +308,7 @@ class MockXcode extends Mock implements Xcode {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockCocoaPods extends Mock implements CocoaPods {}
class IOSWorkflowTestTarget extends IOSWorkflow {
class IOSWorkflowTestTarget extends IOSValidator {
IOSWorkflowTestTarget({
this.hasHomebrew = true,
bool hasIosDeploy = true,

View file

@ -178,7 +178,7 @@ class MockDeviceManager implements DeviceManager {
Future<List<String>> getDeviceDiagnostics() async => <String>[];
}
class MockAndroidWorkflowValidator extends AndroidWorkflow {
class MockAndroidWorkflowValidator extends AndroidValidator {
@override
Future<LicensesAccepted> get licensesAccepted async => LicensesAccepted.all;
}
@ -199,7 +199,7 @@ class MockDoctor extends Doctor {
List<DoctorValidator> get validators {
final List<DoctorValidator> superValidators = super.validators;
return superValidators.map((DoctorValidator v) {
if (v is AndroidWorkflow) {
if (v is AndroidValidator) {
return new MockAndroidWorkflowValidator();
}
return v;