Break down flutter doctor validations and results (#34624)
diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index da7d33b..15526ca 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart
@@ -33,6 +33,7 @@ import 'macos/xcode_validator.dart'; import 'proxy_validator.dart'; import 'tester/flutter_tester.dart'; +import 'usage.dart'; import 'version.dart'; import 'vscode/vscode_validator.dart'; import 'web/web_validator.dart'; @@ -248,6 +249,8 @@ break; } + flutterUsage.sendEvent('doctorResult.${validator.runtimeType.toString()}', result.typeStr); + if (result.statusInfo != null) { printStatus('${result.coloredLeadingBox} ${validator.title} (${result.statusInfo})', hangingIndent: result.leadingBox.length + 1); @@ -327,6 +330,7 @@ abstract class DoctorValidator { const DoctorValidator(this.title); + /// This is displayed in the CLI. final String title; String get slowWarning => 'This is taking an unexpectedly long time...'; @@ -434,6 +438,22 @@ } return null; } + + /// The string representation of the type. + String get typeStr { + assert(type != null); + switch (type) { + case ValidationType.missing: + return 'missing'; + case ValidationType.installed: + return 'installed'; + case ValidationType.notAvailable: + return 'notAvailable'; + case ValidationType.partial: + return 'partial'; + } + return null; + } } class ValidationMessage {
diff --git a/packages/flutter_tools/test/commands/doctor_test.dart b/packages/flutter_tools/test/commands/doctor_test.dart index 45af935..3d38d58 100644 --- a/packages/flutter_tools/test/commands/doctor_test.dart +++ b/packages/flutter_tools/test/commands/doctor_test.dart
@@ -18,6 +18,7 @@ import 'package:flutter_tools/src/proxy_validator.dart'; import 'package:flutter_tools/src/vscode/vscode.dart'; import 'package:flutter_tools/src/vscode/vscode_validator.dart'; +import 'package:flutter_tools/src/usage.dart'; import '../src/common.dart'; import '../src/context.dart'; @@ -207,6 +208,75 @@ }); }); + group('doctor usage params', () { + Usage mockUsage; + + setUp(() { + mockUsage = MockUsage(); + when(mockUsage.isFirstRun).thenReturn(true); + }); + + testUsingContext('contains installed', () async { + await doctor.diagnose(verbose: false); + + expect( + verify(mockUsage.sendEvent('doctorResult.PassingValidator', captureAny)).captured, + <dynamic>['installed', 'installed', 'installed'], + ); + }, overrides: <Type, Generator>{ + DoctorValidatorsProvider: () => FakeDoctorValidatorsProvider(), + Platform: _kNoColorOutputPlatform, + Usage: () => mockUsage, + }); + + testUsingContext('contains installed and partial', () async { + await FakePassingDoctor().diagnose(verbose: false); + + expect( + verify(mockUsage.sendEvent('doctorResult.PassingValidator', captureAny)).captured, + <dynamic>['installed', 'installed'], + ); + expect( + verify(mockUsage.sendEvent('doctorResult.PartialValidatorWithHintsOnly', captureAny)).captured, + <dynamic>['partial'], + ); + expect( + verify(mockUsage.sendEvent('doctorResult.PartialValidatorWithErrors', captureAny)).captured, + <dynamic>['partial'], + ); + }, overrides: <Type, Generator>{ + Platform: _kNoColorOutputPlatform, + Usage: () => mockUsage, + }); + + testUsingContext('contains installed, missing and partial', () async { + await FakeDoctor().diagnose(verbose: false); + + expect( + verify(mockUsage.sendEvent('doctorResult.PassingValidator', captureAny)).captured, + <dynamic>['installed'], + ); + expect( + verify(mockUsage.sendEvent('doctorResult.MissingValidator', captureAny)).captured, + <dynamic>['missing'], + ); + expect( + verify(mockUsage.sendEvent('doctorResult.NotAvailableValidator', captureAny)).captured, + <dynamic>['notAvailable'], + ); + expect( + verify(mockUsage.sendEvent('doctorResult.PartialValidatorWithHintsOnly', captureAny)).captured, + <dynamic>['partial'], + ); + expect( + verify(mockUsage.sendEvent('doctorResult.PartialValidatorWithErrors', captureAny)).captured, + <dynamic>['partial'], + ); + }, overrides: <Type, Generator>{ + Platform: _kNoColorOutputPlatform, + Usage: () => mockUsage, + }); + }); group('doctor with fake validators', () { testUsingContext('validate non-verbose output format for run without issues', () async { @@ -486,6 +556,8 @@ }); } +class MockUsage extends Mock implements Usage {} + class IntelliJValidatorTestTarget extends IntelliJValidator { IntelliJValidatorTestTarget(String title, String installPath) : super(title, installPath); @@ -639,8 +711,6 @@ List<Workflow> get workflows => <Workflow>[]; } - - class PassingGroupedValidator extends DoctorValidator { PassingGroupedValidator(String name) : super(name); @@ -650,7 +720,6 @@ messages.add(ValidationMessage('A helpful message')); return ValidationResult(ValidationType.installed, messages); } - } class MissingGroupedValidator extends DoctorValidator {