// 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/build_info.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:package_config/package_config.dart'; import '../../src/common.dart'; void main() { testWithoutContext('DoctorResultEvent sends usage event for each sub validator', () async { final TestUsage usage = TestUsage(); 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); expect(usage.events.length, 3); expect(usage.events, contains( const TestUsageEvent('doctor-result', 'FakeDoctorValidator', label: 'crash'), )); }); 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 TestUsage usage = TestUsage(); 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); expect(usage.events.length, 1); expect(usage.events, contains( const TestUsageEvent('doctor-result', 'FakeGroupedValidator', label: 'crash'), )); }); testWithoutContext('Reports null safe analytics events', () { final TestUsage usage = TestUsage(); final PackageConfig packageConfig = PackageConfig(<Package>[ Package('foo', Uri.parse('file:///foo/'), languageVersion: LanguageVersion(2, 12)), Package('bar', Uri.parse('file:///fizz/'), languageVersion: LanguageVersion(2, 1)), Package('baz', Uri.parse('file:///bar/'), languageVersion: LanguageVersion(2, 2)), ]); NullSafetyAnalysisEvent( packageConfig, NullSafetyMode.sound, 'foo', usage, ).send(); expect(usage.events, unorderedEquals(<TestUsageEvent>[ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'), TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: CustomDimensions.fromMap(<String, String>{ 'cd49': '1', 'cd50': '3', })), const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: '2.12'), ])); }); testWithoutContext('Does not crash if main package is missing', () { final TestUsage usage = TestUsage(); final PackageConfig packageConfig = PackageConfig(<Package>[ Package('foo', Uri.parse('file:///foo/lib/'), languageVersion: LanguageVersion(2, 12)), Package('bar', Uri.parse('file:///fizz/lib/'), languageVersion: LanguageVersion(2, 1)), Package('baz', Uri.parse('file:///bar/lib/'), languageVersion: LanguageVersion(2, 2)), ]); NullSafetyAnalysisEvent( packageConfig, NullSafetyMode.sound, 'something-unrelated', usage, ).send(); expect(usage.events, unorderedEquals(<TestUsageEvent>[ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'), TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: CustomDimensions.fromMap(<String, String>{ 'cd49': '1', 'cd50': '3', })), ])); }); testWithoutContext('a null language version is treated as unmigrated', () { final TestUsage usage = TestUsage(); final PackageConfig packageConfig = PackageConfig(<Package>[ Package('foo', Uri.parse('file:///foo/lib/')), ]); NullSafetyAnalysisEvent( packageConfig, NullSafetyMode.sound, 'something-unrelated', usage, ).send(); expect(usage.events, unorderedEquals(<TestUsageEvent>[ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'), TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: CustomDimensions.fromMap(<String, String>{ 'cd49': '0', 'cd50': '1', })), ])); }); } class FakeGroupedValidator extends GroupedValidator { FakeGroupedValidator(super.subValidators); } class FakeDoctorValidator extends DoctorValidator { FakeDoctorValidator(super.title); @override Future<ValidationResult> validate() async { return ValidationResult.crash(Object()); } }