[flutter_tools] fix crash if grouped doctor validator crashes (#60658)
diff --git a/packages/flutter_tools/lib/src/reporting/events.dart b/packages/flutter_tools/lib/src/reporting/events.dart
index 310b55e..d357bd9 100644
--- a/packages/flutter_tools/lib/src/reporting/events.dart
+++ b/packages/flutter_tools/lib/src/reporting/events.dart
@@ -103,11 +103,12 @@
DoctorResultEvent({
@required this.validator,
@required this.result,
+ Usage flutterUsage,
}) : super(
'doctor-result',
'${validator.runtimeType}',
label: result.typeStr,
- flutterUsage: globals.flutterUsage,
+ flutterUsage: flutterUsage ?? globals.flutterUsage,
);
final DoctorValidator validator;
@@ -120,10 +121,15 @@
return;
}
final GroupedValidator group = validator as GroupedValidator;
+ // The validator crashed.
+ if (group.subResults == null) {
+ flutterUsage.sendEvent(category, parameter, label: label);
+ return;
+ }
for (int i = 0; i < group.subValidators.length; i++) {
final DoctorValidator v = group.subValidators[i];
final ValidationResult r = group.subResults[i];
- DoctorResultEvent(validator: v, result: r).send();
+ DoctorResultEvent(validator: v, result: r, flutterUsage: flutterUsage).send();
}
}
}
diff --git a/packages/flutter_tools/test/general.shard/reporting/events_test.dart b/packages/flutter_tools/test/general.shard/reporting/events_test.dart
new file mode 100644
index 0000000..f12d2d3
--- /dev/null
+++ b/packages/flutter_tools/test/general.shard/reporting/events_test.dart
@@ -0,0 +1,68 @@
+// Copyright 2014 The Flutter Authors. 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:flutter_tools/src/doctor.dart';
+import 'package:flutter_tools/src/reporting/reporting.dart';
+import 'package:mockito/mockito.dart';
+
+import '../../src/common.dart';
+
+void main() {
+ testWithoutContext('DoctorResultEvent sends usage event for each sub validator', () async {
+ final Usage usage = MockUsage();
+ final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[
+ FakeDoctorValidator('a'),
+ FakeDoctorValidator('b'),
+ FakeDoctorValidator('c'),
+ ]);
+ final ValidationResult result = await groupedValidator.validate();
+
+ final DoctorResultEvent doctorResultEvent = DoctorResultEvent(
+ validator: groupedValidator,
+ result: result,
+ flutterUsage: usage,
+ );
+
+ expect(() => doctorResultEvent.send(), returnsNormally);
+
+ verify(usage.sendEvent('doctor-result', any, label: anyNamed('label'))).called(3);
+ });
+
+ testWithoutContext('DoctorResultEvent does not crash if a synthetic crash result was used instead'
+ ' of validation. This happens when a grouped validator throws an exception, causing subResults to never '
+ ' be instantiated.', () async {
+ final Usage usage = MockUsage();
+ final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[
+ FakeDoctorValidator('a'),
+ FakeDoctorValidator('b'),
+ FakeDoctorValidator('c'),
+ ]);
+ final ValidationResult result = ValidationResult.crash(Object());
+
+ final DoctorResultEvent doctorResultEvent = DoctorResultEvent(
+ validator: groupedValidator,
+ result: result,
+ flutterUsage: usage,
+ );
+
+ expect(() => doctorResultEvent.send(), returnsNormally);
+
+ verify(usage.sendEvent('doctor-result', any, label: anyNamed('label'))).called(1);
+ });
+}
+
+class FakeGroupedValidator extends GroupedValidator {
+ FakeGroupedValidator(List<DoctorValidator> subValidators) : super(subValidators);
+}
+
+class FakeDoctorValidator extends DoctorValidator {
+ FakeDoctorValidator(String title) : super(title);
+
+ @override
+ Future<ValidationResult> validate() async {
+ return ValidationResult.crash(Object());
+ }
+}
+
+class MockUsage extends Mock implements Usage {}