Unverified Commit 6ecb8cbc authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Replace MockUsage with TestUsage (#74946)

parent 0491db4a
...@@ -473,6 +473,7 @@ class TestUsage implements Usage { ...@@ -473,6 +473,7 @@ class TestUsage implements Usage {
final List<TestUsageEvent> events = <TestUsageEvent>[]; final List<TestUsageEvent> events = <TestUsageEvent>[];
final List<dynamic> exceptions = <dynamic>[]; final List<dynamic> exceptions = <dynamic>[];
final List<TestTimingEvent> timings = <TestTimingEvent>[]; final List<TestTimingEvent> timings = <TestTimingEvent>[];
int ensureAnalyticsSentCalls = 0;
@override @override
bool enabled = true; bool enabled = true;
...@@ -484,8 +485,8 @@ class TestUsage implements Usage { ...@@ -484,8 +485,8 @@ class TestUsage implements Usage {
String get clientId => 'test-client'; String get clientId => 'test-client';
@override @override
Future<void> ensureAnalyticsSent() { Future<void> ensureAnalyticsSent() async {
throw UnimplementedError(); ensureAnalyticsSentCalls++;
} }
@override @override
......
...@@ -25,7 +25,7 @@ void main() { ...@@ -25,7 +25,7 @@ void main() {
MockAndroidStudio mockAndroidStudio; MockAndroidStudio mockAndroidStudio;
MockAndroidSdk mockAndroidSdk; MockAndroidSdk mockAndroidSdk;
MockFlutterVersion mockFlutterVersion; MockFlutterVersion mockFlutterVersion;
MockUsage mockUsage; TestUsage testUsage;
setUpAll(() { setUpAll(() {
Cache.disableLocking(); Cache.disableLocking();
...@@ -35,27 +35,13 @@ void main() { ...@@ -35,27 +35,13 @@ void main() {
mockAndroidStudio = MockAndroidStudio(); mockAndroidStudio = MockAndroidStudio();
mockAndroidSdk = MockAndroidSdk(); mockAndroidSdk = MockAndroidSdk();
mockFlutterVersion = MockFlutterVersion(); mockFlutterVersion = MockFlutterVersion();
mockUsage = MockUsage(); testUsage = TestUsage();
}); });
void verifyNoAnalytics() { void verifyNoAnalytics() {
verifyNever(mockUsage.sendCommand( expect(testUsage.commands, isEmpty);
any, expect(testUsage.events, isEmpty);
parameters: anyNamed('parameters'), expect(testUsage.timings, isEmpty);
));
verifyNever(mockUsage.sendEvent(
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
parameters: anyNamed('parameters'),
));
verifyNever(mockUsage.sendTiming(
any,
any,
any,
label: anyNamed('label'),
));
} }
group('config', () { group('config', () {
...@@ -76,7 +62,7 @@ void main() { ...@@ -76,7 +62,7 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidStudio: () => mockAndroidStudio, AndroidStudio: () => mockAndroidStudio,
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('Can set build-dir', () async { testUsingContext('Can set build-dir', () async {
...@@ -91,7 +77,7 @@ void main() { ...@@ -91,7 +77,7 @@ void main() {
expect(getBuildDirectory(), 'foo'); expect(getBuildDirectory(), 'foo');
verifyNoAnalytics(); verifyNoAnalytics();
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('throws error on absolute path to build-dir', () async { testUsingContext('throws error on absolute path to build-dir', () async {
...@@ -104,7 +90,7 @@ void main() { ...@@ -104,7 +90,7 @@ void main() {
]), throwsToolExit()); ]), throwsToolExit());
verifyNoAnalytics(); verifyNoAnalytics();
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('allows setting and removing feature flags', () async { testUsingContext('allows setting and removing feature flags', () async {
...@@ -149,7 +135,7 @@ void main() { ...@@ -149,7 +135,7 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidStudio: () => mockAndroidStudio, AndroidStudio: () => mockAndroidStudio,
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('warns the user to reload IDE', () async { testUsingContext('warns the user to reload IDE', () async {
...@@ -166,7 +152,7 @@ void main() { ...@@ -166,7 +152,7 @@ void main() {
containsIgnoringWhitespace('You may need to restart any open editors'), containsIgnoringWhitespace('You may need to restart any open editors'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('displays which config settings are available on stable', () async { testUsingContext('displays which config settings are available on stable', () async {
...@@ -207,49 +193,33 @@ void main() { ...@@ -207,49 +193,33 @@ void main() {
AndroidStudio: () => mockAndroidStudio, AndroidStudio: () => mockAndroidStudio,
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
FlutterVersion: () => mockFlutterVersion, FlutterVersion: () => mockFlutterVersion,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('no-analytics flag flips usage flag and sends event', () async { testUsingContext('no-analytics flag flips usage flag and sends event', () async {
final ConfigCommand configCommand = ConfigCommand(); final ConfigCommand configCommand = ConfigCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand); final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
when(mockUsage.sendEvent( expect(testUsage.enabled, true);
captureAny,
captureAny,
label: captureAnyNamed('label'),
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).thenAnswer((Invocation invocation) async {
expect(mockUsage.enabled, true);
expect(invocation.positionalArguments, <String>['analytics', 'enabled']);
expect(invocation.namedArguments[#label], 'false');
});
await commandRunner.run(<String>[ await commandRunner.run(<String>[
'config', 'config',
'--no-analytics', '--no-analytics',
]); ]);
expect(mockUsage.enabled, false); expect(testUsage.enabled, false);
// Verify that we flushed the analytics queue. // Verify that we flushed the analytics queue.
verify(mockUsage.ensureAnalyticsSent()); expect(testUsage.ensureAnalyticsSentCalls, 1);
// Verify that we only send the analytics disable event, and no other // Verify that we only send the analytics disable event, and no other
// info. // info.
verifyNever(mockUsage.sendCommand( expect(testUsage.events, equals(<TestUsageEvent>[
any, const TestUsageEvent('analytics', 'enabled', label: 'false'),
parameters: anyNamed('parameters'), ]));
)); expect(testUsage.commands, isEmpty);
verifyNever(mockUsage.sendTiming( expect(testUsage.timings, isEmpty);
any,
any,
any,
label: anyNamed('label'),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('analytics flag flips usage flag and sends event', () async { testUsingContext('analytics flag flips usage flag and sends event', () async {
...@@ -261,39 +231,24 @@ void main() { ...@@ -261,39 +231,24 @@ void main() {
'--analytics', '--analytics',
]); ]);
expect(mockUsage.enabled, true); expect(testUsage.enabled, true);
// Verify that we only send the analytics disable event, and no other // Verify that we only send the analytics enable event, and no other
// info. // info.
verifyNever(mockUsage.sendCommand( expect(testUsage.events, equals(<TestUsageEvent>[
any, const TestUsageEvent('analytics', 'enabled', label: 'true'),
parameters: anyNamed('parameters'), ]));
)); expect(testUsage.commands, isEmpty);
verifyNever(mockUsage.sendTiming( expect(testUsage.timings, isEmpty);
any,
any,
any,
label: anyNamed('label'),
));
expect(verify(mockUsage.sendEvent(
captureAny,
captureAny,
label: captureAnyNamed('label'),
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).captured,
<dynamic>['analytics', 'enabled', 'true'],
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('analytics reported disabled when suppressed', () async { testUsingContext('analytics reported disabled when suppressed', () async {
final ConfigCommand configCommand = ConfigCommand(); final ConfigCommand configCommand = ConfigCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand); final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
mockUsage.suppressAnalytics = true; testUsage.suppressAnalytics = true;
await commandRunner.run(<String>[ await commandRunner.run(<String>[
'config', 'config',
...@@ -304,7 +259,7 @@ void main() { ...@@ -304,7 +259,7 @@ void main() {
containsIgnoringWhitespace('Analytics reporting is currently disabled'), containsIgnoringWhitespace('Analytics reporting is currently disabled'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
} }
...@@ -320,11 +275,3 @@ class MockAndroidSdk extends Mock implements AndroidSdk { ...@@ -320,11 +275,3 @@ class MockAndroidSdk extends Mock implements AndroidSdk {
} }
class MockFlutterVersion extends Mock implements FlutterVersion {} class MockFlutterVersion extends Mock implements FlutterVersion {}
class MockUsage extends Mock implements Usage {
@override
bool enabled = true;
@override
bool suppressAnalytics = false;
}
...@@ -221,132 +221,123 @@ void main() { ...@@ -221,132 +221,123 @@ void main() {
}); });
group('doctor usage params', () { group('doctor usage params', () {
Usage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
}); });
testUsingContext('contains installed', () async { testUsingContext('contains installed', () async {
final Doctor doctor = Doctor(logger: logger); final Doctor doctor = Doctor(logger: logger);
await doctor.diagnose(verbose: false); await doctor.diagnose(verbose: false);
expect( expect(testUsage.events.length, 3);
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
const TestUsageEvent(
'doctor-result', 'doctor-result',
'PassingValidator', 'PassingValidator',
label: captureAnyNamed('label'), label: 'installed',
)).captured, ),
<dynamic>['installed', 'installed', 'installed'], ));
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
DoctorValidatorsProvider: () => FakeDoctorValidatorsProvider(), DoctorValidatorsProvider: () => FakeDoctorValidatorsProvider(),
Platform: _kNoColorOutputPlatform, Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('contains installed and partial', () async { testUsingContext('contains installed and partial', () async {
await FakePassingDoctor(logger).diagnose(verbose: false); await FakePassingDoctor(logger).diagnose(verbose: false);
expect( expect(testUsage.events, unorderedEquals(<TestUsageEvent>[
verify(mockUsage.sendEvent( const TestUsageEvent(
'doctor-result', 'doctor-result',
'PassingValidator', 'PassingValidator',
label: captureAnyNamed('label'), label: 'installed',
)).captured, ),
<dynamic>['installed', 'installed'], const TestUsageEvent(
); 'doctor-result',
expect( 'PassingValidator',
verify(mockUsage.sendEvent( label: 'installed',
),
const TestUsageEvent(
'doctor-result', 'doctor-result',
'PartialValidatorWithHintsOnly', 'PartialValidatorWithHintsOnly',
label: captureAnyNamed('label'), label: 'partial',
)).captured, ),
<dynamic>['partial'], const TestUsageEvent(
);
expect(
verify(mockUsage.sendEvent(
'doctor-result', 'doctor-result',
'PartialValidatorWithErrors', 'PartialValidatorWithErrors',
label: captureAnyNamed('label'), label: 'partial',
)).captured, ),
<dynamic>['partial'], ]));
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: _kNoColorOutputPlatform, Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('contains installed, missing and partial', () async { testUsingContext('contains installed, missing and partial', () async {
await FakeDoctor(logger).diagnose(verbose: false); await FakeDoctor(logger).diagnose(verbose: false);
expect( expect(testUsage.events, unorderedEquals(<TestUsageEvent>[
verify(mockUsage.sendEvent( const TestUsageEvent(
'doctor-result', 'doctor-result',
'PassingValidator', 'PassingValidator',
label: captureAnyNamed('label'), label: 'installed',
)).captured, ),
<dynamic>['installed'], const TestUsageEvent(
);
expect(
verify(mockUsage.sendEvent(
'doctor-result', 'doctor-result',
'MissingValidator', 'MissingValidator',
label: captureAnyNamed('label'), label: 'missing',
)).captured, ),
<dynamic>['missing'], const TestUsageEvent(
);
expect(
verify(mockUsage.sendEvent(
'doctor-result', 'doctor-result',
'NotAvailableValidator', 'NotAvailableValidator',
label: captureAnyNamed('label'), label: 'notAvailable',
)).captured, ),
<dynamic>['notAvailable'], const TestUsageEvent(
);
expect(
verify(mockUsage.sendEvent(
'doctor-result', 'doctor-result',
'PartialValidatorWithHintsOnly', 'PartialValidatorWithHintsOnly',
label: captureAnyNamed('label'), label: 'partial',
)).captured, ),
<dynamic>['partial'], const TestUsageEvent(
);
expect(
verify(mockUsage.sendEvent(
'doctor-result', 'doctor-result',
'PartialValidatorWithErrors', 'PartialValidatorWithErrors',
label: captureAnyNamed('label'), label: 'partial',
)).captured, ),
<dynamic>['partial'], ]));
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: _kNoColorOutputPlatform, Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('events for grouped validators are properly decomposed', () async { testUsingContext('events for grouped validators are properly decomposed', () async {
await FakeGroupedDoctor(logger).diagnose(verbose: false); await FakeGroupedDoctor(logger).diagnose(verbose: false);
expect( expect(testUsage.events, unorderedEquals(<TestUsageEvent>[
verify(mockUsage.sendEvent( const TestUsageEvent(
'doctor-result', 'doctor-result',
'PassingGroupedValidator', 'PassingGroupedValidator',
label: captureAnyNamed('label'), label: 'installed',
)).captured, ),
<dynamic>['installed', 'installed', 'installed'], const TestUsageEvent(
); 'doctor-result',
expect( 'PassingGroupedValidator',
verify(mockUsage.sendEvent( label: 'installed',
),
const TestUsageEvent(
'doctor-result',
'PassingGroupedValidator',
label: 'installed',
),
const TestUsageEvent(
'doctor-result', 'doctor-result',
'MissingGroupedValidator', 'MissingGroupedValidator',
label: captureAnyNamed('label'), label: 'missing',
)).captured, ),
<dynamic>['missing'], ]));
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: _kNoColorOutputPlatform, Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
...@@ -726,8 +717,6 @@ class NoOpDoctor implements Doctor { ...@@ -726,8 +717,6 @@ class NoOpDoctor implements Doctor {
List<Workflow> get workflows => <Workflow>[]; List<Workflow> get workflows => <Workflow>[];
} }
class MockUsage extends Mock implements Usage {}
class PassingValidator extends DoctorValidator { class PassingValidator extends DoctorValidator {
PassingValidator(String name) : super(name); PassingValidator(String name) : super(name);
......
...@@ -484,7 +484,6 @@ void main() { ...@@ -484,7 +484,6 @@ void main() {
} }
class MockCache extends Mock implements Cache {} class MockCache extends Mock implements Cache {}
class MockUsage extends Mock implements Usage {}
class MockDeviceManager extends Mock implements DeviceManager {} class MockDeviceManager extends Mock implements DeviceManager {}
class MockDevice extends Mock implements Device { class MockDevice extends Mock implements Device {
......
...@@ -41,10 +41,10 @@ void main() { ...@@ -41,10 +41,10 @@ void main() {
group('Usage', () { group('Usage', () {
Directory tempDir; Directory tempDir;
Usage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
}); });
...@@ -96,17 +96,17 @@ void main() { ...@@ -96,17 +96,17 @@ void main() {
await runCommandIn(projectPath, await runCommandIn(projectPath,
arguments: <String>['--target-platform=android-arm']); arguments: <String>['--target-platform=android-arm']);
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
'tool-command-result', const TestUsageEvent(
'aar', 'tool-command-result',
label: 'success', 'aar',
value: anyNamed('value'), label: 'success',
parameters: anyNamed('parameters'), ),
)).called(1); ));
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(), AndroidBuilder: () => FakeAndroidBuilder(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
...@@ -297,4 +297,3 @@ class MockAndroidBuilder extends Mock implements AndroidBuilder {} ...@@ -297,4 +297,3 @@ class MockAndroidBuilder extends Mock implements AndroidBuilder {}
class MockAndroidSdk extends Mock implements AndroidSdk {} class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {} class MockProcess extends Mock implements Process {}
class MockUsage extends Mock implements Usage {}
...@@ -30,10 +30,10 @@ void main() { ...@@ -30,10 +30,10 @@ void main() {
group('Usage', () { group('Usage', () {
Directory tempDir; Directory tempDir;
Usage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
}); });
...@@ -103,17 +103,17 @@ void main() { ...@@ -103,17 +103,17 @@ void main() {
await runBuildApkCommand(projectPath); await runBuildApkCommand(projectPath);
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
'tool-command-result', const TestUsageEvent(
'apk', 'tool-command-result',
label: 'success', 'apk',
value: anyNamed('value'), label: 'success',
parameters: anyNamed('parameters'), ),
)).called(1); ));
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(), AndroidBuilder: () => FakeAndroidBuilder(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
...@@ -122,10 +122,10 @@ void main() { ...@@ -122,10 +122,10 @@ void main() {
ProcessManager mockProcessManager; ProcessManager mockProcessManager;
String gradlew; String gradlew;
AndroidSdk mockAndroidSdk; AndroidSdk mockAndroidSdk;
Usage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', 'android', gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', 'android',
...@@ -390,18 +390,20 @@ void main() { ...@@ -390,18 +390,20 @@ void main() {
containsIgnoringWhitespace('To learn more, see: https://developer.android.com/studio/build/shrink-code'), containsIgnoringWhitespace('To learn more, see: https://developer.android.com/studio/build/shrink-code'),
); );
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
'build', const TestUsageEvent(
'apk', 'build',
label: 'gradle-r8-failure', 'apk',
parameters: anyNamed('parameters'), label: 'gradle-r8-failure',
)).called(1); parameters: <String, String>{},
),
));
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext("reports when the app isn't using AndroidX", () async { testUsingContext("reports when the app isn't using AndroidX", () async {
...@@ -452,18 +454,21 @@ void main() { ...@@ -452,18 +454,21 @@ void main() {
'following the steps on https://goo.gl/CP92wY' 'following the steps on https://goo.gl/CP92wY'
), ),
); );
verify(mockUsage.sendEvent(
'build', expect(testUsage.events, contains(
'apk', const TestUsageEvent(
label: 'app-not-using-android-x', 'build',
parameters: anyNamed('parameters'), 'apk',
)).called(1); label: 'app-not-using-android-x',
parameters: <String, String>{},
),
));
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('reports when the app is using AndroidX', () async { testUsingContext('reports when the app is using AndroidX', () async {
...@@ -505,18 +510,21 @@ void main() { ...@@ -505,18 +510,21 @@ void main() {
), ),
isFalse, isFalse,
); );
verify(mockUsage.sendEvent(
'build', expect(testUsage.events, contains(
'apk', const TestUsageEvent(
label: 'app-using-android-x', 'build',
parameters: anyNamed('parameters'), 'apk',
)).called(1); label: 'app-using-android-x',
parameters: <String, String>{},
),
));
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
} }
...@@ -539,4 +547,3 @@ Future<BuildApkCommand> runBuildApkCommand( ...@@ -539,4 +547,3 @@ Future<BuildApkCommand> runBuildApkCommand(
class MockAndroidSdk extends Mock implements AndroidSdk {} class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {} class MockProcess extends Mock implements Process {}
class MockUsage extends Mock implements Usage {}
...@@ -29,11 +29,11 @@ void main() { ...@@ -29,11 +29,11 @@ void main() {
group('Usage', () { group('Usage', () {
Directory tempDir; Directory tempDir;
Usage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
mockUsage = MockUsage(); testUsage = TestUsage();
}); });
tearDown(() { tearDown(() {
...@@ -85,17 +85,13 @@ void main() { ...@@ -85,17 +85,13 @@ void main() {
await runBuildAppBundleCommand(projectPath); await runBuildAppBundleCommand(projectPath);
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
'tool-command-result', const TestUsageEvent('tool-command-result', 'appbundle', label: 'success'),
'appbundle', ));
label: 'success',
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).called(1);
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(), AndroidBuilder: () => FakeAndroidBuilder(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
...@@ -104,10 +100,10 @@ void main() { ...@@ -104,10 +100,10 @@ void main() {
ProcessManager mockProcessManager; ProcessManager mockProcessManager;
MockAndroidSdk mockAndroidSdk; MockAndroidSdk mockAndroidSdk;
String gradlew; String gradlew;
Usage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', 'android', gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', 'android',
globals.platform.isWindows ? 'gradlew.bat' : 'gradlew'); globals.platform.isWindows ? 'gradlew.bat' : 'gradlew');
...@@ -254,18 +250,21 @@ void main() { ...@@ -254,18 +250,21 @@ void main() {
'following the steps on https://goo.gl/CP92wY' 'following the steps on https://goo.gl/CP92wY'
), ),
); );
verify(mockUsage.sendEvent(
'build', expect(testUsage.events, contains(
'appbundle', const TestUsageEvent(
label: 'app-not-using-android-x', 'build',
parameters: anyNamed('parameters'), 'appbundle',
)).called(1); label: 'app-not-using-android-x',
parameters: <String, String>{},
),
));
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('reports when the app is using AndroidX', () async { testUsingContext('reports when the app is using AndroidX', () async {
...@@ -310,18 +309,21 @@ void main() { ...@@ -310,18 +309,21 @@ void main() {
'following the steps on https://goo.gl/CP92wY'), 'following the steps on https://goo.gl/CP92wY'),
) )
); );
verify(mockUsage.sendEvent(
'build', expect(testUsage.events, contains(
'appbundle', const TestUsageEvent(
label: 'app-using-android-x', 'build',
parameters: anyNamed('parameters'), 'appbundle',
)).called(1); label: 'app-using-android-x',
parameters: <String, String>{},
),
));
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
} }
...@@ -348,4 +350,3 @@ Matcher not(Matcher target){ ...@@ -348,4 +350,3 @@ Matcher not(Matcher target){
class MockAndroidSdk extends Mock implements AndroidSdk {} class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {} class MockProcess extends Mock implements Process {}
class MockUsage extends Mock implements Usage {}
...@@ -153,7 +153,7 @@ void main() { ...@@ -153,7 +153,7 @@ void main() {
group('analytics with mocks', () { group('analytics with mocks', () {
MemoryFileSystem memoryFileSystem; MemoryFileSystem memoryFileSystem;
MockStdio mockStdio; MockStdio mockStdio;
Usage mockUsage; TestUsage testUsage;
SystemClock mockClock; SystemClock mockClock;
Doctor mockDoctor; Doctor mockDoctor;
List<int> mockTimes; List<int> mockTimes;
...@@ -161,7 +161,7 @@ void main() { ...@@ -161,7 +161,7 @@ void main() {
setUp(() { setUp(() {
memoryFileSystem = MemoryFileSystem.test(); memoryFileSystem = MemoryFileSystem.test();
mockStdio = MockStdio(); mockStdio = MockStdio();
mockUsage = MockUsage(); testUsage = TestUsage();
mockClock = MockClock(); mockClock = MockClock();
mockDoctor = MockDoctor(); mockDoctor = MockDoctor();
when(mockClock.now()).thenAnswer( when(mockClock.now()).thenAnswer(
...@@ -182,19 +182,15 @@ void main() { ...@@ -182,19 +182,15 @@ void main() {
verify(mockClock.now()).called(2); verify(mockClock.now()).called(2);
expect( expect(testUsage.timings, contains(
verify(mockUsage.sendTiming( const TestTimingEvent(
captureAny, 'flutter', 'doctor', Duration(milliseconds: 1000), label: 'success',
captureAny, ),
captureAny, ));
label: captureAnyNamed('label'),
)).captured,
<dynamic>['flutter', 'doctor', const Duration(milliseconds: 1000), 'success'],
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
SystemClock: () => mockClock, SystemClock: () => mockClock,
Doctor: () => mockDoctor, Doctor: () => mockDoctor,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('doctor fail sends warning', () async { testUsingContext('doctor fail sends warning', () async {
...@@ -207,19 +203,15 @@ void main() { ...@@ -207,19 +203,15 @@ void main() {
verify(mockClock.now()).called(2); verify(mockClock.now()).called(2);
expect( expect(testUsage.timings, contains(
verify(mockUsage.sendTiming( const TestTimingEvent(
captureAny, 'flutter', 'doctor', Duration(milliseconds: 1000), label: 'warning',
captureAny, ),
captureAny, ));
label: captureAnyNamed('label'),
)).captured,
<dynamic>['flutter', 'doctor', const Duration(milliseconds: 1000), 'warning'],
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
SystemClock: () => mockClock, SystemClock: () => mockClock,
Doctor: () => mockDoctor, Doctor: () => mockDoctor,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('single command usage path', () async { testUsingContext('single command usage path', () async {
...@@ -227,7 +219,7 @@ void main() { ...@@ -227,7 +219,7 @@ void main() {
expect(await doctorCommand.usagePath, 'doctor'); expect(await doctorCommand.usagePath, 'doctor');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('compound command usage path', () async { testUsingContext('compound command usage path', () async {
...@@ -236,7 +228,7 @@ void main() { ...@@ -236,7 +228,7 @@ void main() {
expect(await buildApkCommand.usagePath, 'build/apk'); expect(await buildApkCommand.usagePath, 'build/apk');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('command sends localtime', () async { testUsingContext('command sends localtime', () async {
...@@ -383,8 +375,6 @@ class FakeFlutterCommand extends FlutterCommand { ...@@ -383,8 +375,6 @@ class FakeFlutterCommand extends FlutterCommand {
} }
} }
class MockUsage extends Mock implements Usage {}
class MockDoctor extends Mock implements Doctor {} class MockDoctor extends Mock implements Doctor {}
class MockFlutterConfig extends Mock implements Config {} class MockFlutterConfig extends Mock implements Config {}
...@@ -24,7 +24,7 @@ import '../../src/mocks.dart'; ...@@ -24,7 +24,7 @@ import '../../src/mocks.dart';
void main() { void main() {
group('gradleErrors', () { group('gradleErrors', () {
test('list of errors', () { testWithoutContext('list of errors', () {
// If you added a new Gradle error, please update this test. // If you added a new Gradle error, please update this test.
expect(gradleErrors, expect(gradleErrors,
equals(<GradleHandledError>[ equals(<GradleHandledError>[
...@@ -325,9 +325,9 @@ Command: /home/android/gradlew assembleRelease ...@@ -325,9 +325,9 @@ Command: /home/android/gradlew assembleRelease
}); });
group('AndroidX', () { group('AndroidX', () {
final Usage mockUsage = MockUsage(); final TestUsage testUsage = TestUsage();
test('pattern', () { testWithoutContext('pattern', () {
expect(androidXFailureHandler.test( expect(androidXFailureHandler.test(
'AAPT: error: resource android:attr/fontVariationSettings not found.' 'AAPT: error: resource android:attr/fontVariationSettings not found.'
), isTrue); ), isTrue);
...@@ -357,20 +357,22 @@ Command: /home/android/gradlew assembleRelease ...@@ -357,20 +357,22 @@ Command: /home/android/gradlew assembleRelease
final GradleBuildStatus status = await androidXFailureHandler final GradleBuildStatus status = await androidXFailureHandler
.handler(line: '', project: FlutterProject.current()); .handler(line: '', project: FlutterProject.current());
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
any, const TestUsageEvent(
any, 'build',
label: 'gradle-android-x-failure', 'unspecified',
parameters: <String, String>{ label: 'gradle-android-x-failure',
'cd43': 'app-not-using-plugins', parameters: <String, String>{
}, 'cd43': 'app-not-using-plugins',
)).called(1); },
),
));
expect(status, equals(GradleBuildStatus.exit)); expect(status, equals(GradleBuildStatus.exit));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(), ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('handler - plugins and no AndroidX', () async { testUsingContext('handler - plugins and no AndroidX', () async {
...@@ -389,20 +391,23 @@ Command: /home/android/gradlew assembleRelease ...@@ -389,20 +391,23 @@ Command: /home/android/gradlew assembleRelease
'Please migrate your app to AndroidX. See https://goo.gl/CP92wY .' 'Please migrate your app to AndroidX. See https://goo.gl/CP92wY .'
) )
); );
verify(mockUsage.sendEvent(
any, expect(testUsage.events, contains(
any, const TestUsageEvent(
label: 'gradle-android-x-failure', 'build',
parameters: <String, String>{ 'unspecified',
'cd43': 'app-not-using-androidx', label: 'gradle-android-x-failure',
}, parameters: <String, String>{
)).called(1); 'cd43': 'app-not-using-androidx',
},
),
));
expect(status, equals(GradleBuildStatus.exit)); expect(status, equals(GradleBuildStatus.exit));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(), ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('handler - plugins, AndroidX, and AAR', () async { testUsingContext('handler - plugins, AndroidX, and AAR', () async {
...@@ -415,20 +420,22 @@ Command: /home/android/gradlew assembleRelease ...@@ -415,20 +420,22 @@ Command: /home/android/gradlew assembleRelease
shouldBuildPluginAsAar: true, shouldBuildPluginAsAar: true,
); );
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
any, const TestUsageEvent(
any, 'build',
label: 'gradle-android-x-failure', 'unspecified',
parameters: <String, String>{ label: 'gradle-android-x-failure',
'cd43': 'using-jetifier', parameters: <String, String>{
}, 'cd43': 'using-jetifier',
)).called(1); },
),
));
expect(status, equals(GradleBuildStatus.exit)); expect(status, equals(GradleBuildStatus.exit));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(), ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('handler - plugins, AndroidX, and no AAR', () async { testUsingContext('handler - plugins, AndroidX, and no AAR', () async {
...@@ -447,19 +454,22 @@ Command: /home/android/gradlew assembleRelease ...@@ -447,19 +454,22 @@ Command: /home/android/gradlew assembleRelease
'The tool is about to try using Jetifier to solve the incompatibility.' 'The tool is about to try using Jetifier to solve the incompatibility.'
) )
); );
verify(mockUsage.sendEvent(
any, expect(testUsage.events, contains(
any, const TestUsageEvent(
label: 'gradle-android-x-failure', 'build',
parameters: <String, String>{ 'unspecified',
'cd43': 'not-using-jetifier', label: 'gradle-android-x-failure',
}, parameters: <String, String>{
)).called(1); 'cd43': 'not-using-jetifier',
},
),
));
expect(status, equals(GradleBuildStatus.retryWithAarPlugins)); expect(status, equals(GradleBuildStatus.retryWithAarPlugins));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(), ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
...@@ -490,7 +500,7 @@ Command: /home/android/gradlew assembleRelease ...@@ -490,7 +500,7 @@ Command: /home/android/gradlew assembleRelease
}); });
group('license not accepted', () { group('license not accepted', () {
test('pattern', () { testWithoutContext('pattern', () {
expect( expect(
licenseNotAcceptedHandler.test( licenseNotAcceptedHandler.test(
'You have not accepted the license agreements of the following SDK components' 'You have not accepted the license agreements of the following SDK components'
...@@ -525,7 +535,7 @@ Command: /home/android/gradlew assembleRelease ...@@ -525,7 +535,7 @@ Command: /home/android/gradlew assembleRelease
mockProcessManager = MockProcessManager(); mockProcessManager = MockProcessManager();
}); });
test('pattern', () { testWithoutContext('pattern', () {
expect( expect(
flavorUndefinedHandler.test( flavorUndefinedHandler.test(
'Task assembleFooRelease not found in root project.' 'Task assembleFooRelease not found in root project.'
...@@ -657,8 +667,6 @@ assembleProfile ...@@ -657,8 +667,6 @@ assembleProfile
}); });
} }
class MockUsage extends Mock implements Usage {}
bool formatTestErrorMessage(String errorMessage, GradleHandledError error) { bool formatTestErrorMessage(String errorMessage, GradleHandledError error) {
return errorMessage return errorMessage
.split('\n') .split('\n')
......
...@@ -22,7 +22,6 @@ import 'package:flutter_tools/src/base/terminal.dart'; ...@@ -22,7 +22,6 @@ import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -139,11 +138,11 @@ void main() { ...@@ -139,11 +138,11 @@ void main() {
group('findBundleFile', () { group('findBundleFile', () {
FileSystem fileSystem; FileSystem fileSystem;
Usage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
mockUsage = MockUsage(); testUsage = TestUsage();
}); });
testWithoutContext('Finds app bundle when flavor contains underscores in release mode', () { testWithoutContext('Finds app bundle when flavor contains underscores in release mode', () {
...@@ -312,20 +311,20 @@ void main() { ...@@ -312,20 +311,20 @@ void main() {
"was generated under ${project.android.buildDirectory.path}, but the tool couldn't find it." "was generated under ${project.android.buildDirectory.path}, but the tool couldn't find it."
) )
); );
verify( expect(testUsage.events, contains(
mockUsage.sendEvent( const TestUsageEvent(
any, 'build',
any, 'unspecified',
label: 'gradle-expected-file-not-found', label: 'gradle-expected-file-not-found',
parameters: const <String, String> { parameters: <String, String> {
'cd37': 'androidGradlePluginVersion: 6.7, fileExtension: .aab', 'cd37': 'androidGradlePluginVersion: 6.7, fileExtension: .aab',
}, },
), ),
).called(1); ));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
Usage: () => mockUsage, Usage: () => testUsage,
}); });
}); });
...@@ -1007,7 +1006,7 @@ plugin1=${plugin1.path} ...@@ -1007,7 +1006,7 @@ plugin1=${plugin1.path}
}); });
group('gradle build', () { group('gradle build', () {
Usage mockUsage; TestUsage testUsage;
MockAndroidSdk mockAndroidSdk; MockAndroidSdk mockAndroidSdk;
MockAndroidStudio mockAndroidStudio; MockAndroidStudio mockAndroidStudio;
MockLocalEngineArtifacts mockArtifacts; MockLocalEngineArtifacts mockArtifacts;
...@@ -1018,7 +1017,7 @@ plugin1=${plugin1.path} ...@@ -1018,7 +1017,7 @@ plugin1=${plugin1.path}
Cache cache; Cache cache;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
fileSystemUtils = MockFileSystemUtils(); fileSystemUtils = MockFileSystemUtils();
mockAndroidSdk = MockAndroidSdk(); mockAndroidSdk = MockAndroidSdk();
...@@ -1117,20 +1116,21 @@ plugin1=${plugin1.path} ...@@ -1117,20 +1116,21 @@ plugin1=${plugin1.path}
expect(handlerCalled, isTrue); expect(handlerCalled, isTrue);
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
any, const TestUsageEvent(
any, 'build',
label: 'gradle-random-event-label-failure', 'unspecified',
parameters: anyNamed('parameters'), label: 'gradle-random-event-label-failure',
)).called(1); parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Cache: () => cache, Cache: () => cache,
Platform: () => android, Platform: () => android,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('recognizes common errors - retry build', () async { testUsingContext('recognizes common errors - retry build', () async {
...@@ -1198,21 +1198,21 @@ plugin1=${plugin1.path} ...@@ -1198,21 +1198,21 @@ plugin1=${plugin1.path}
)); ));
expect(testFnCalled, equals(2)); expect(testFnCalled, equals(2));
expect(testUsage.events, contains(
verify(mockUsage.sendEvent( const TestUsageEvent(
any, 'build',
any, 'unspecified',
label: 'gradle-random-event-label-failure', label: 'gradle-random-event-label-failure',
parameters: anyNamed('parameters'), parameters: <String, String>{},
)).called(1); ),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Cache: () => cache, Cache: () => cache,
Platform: () => android, Platform: () => android,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('recognizes process exceptions - tool exit', () async { testUsingContext('recognizes process exceptions - tool exit', () async {
...@@ -1273,20 +1273,21 @@ plugin1=${plugin1.path} ...@@ -1273,20 +1273,21 @@ plugin1=${plugin1.path}
expect(handlerCalled, isTrue); expect(handlerCalled, isTrue);
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
any, const TestUsageEvent(
any, 'build',
label: 'gradle-random-event-label-failure', 'unspecified',
parameters: anyNamed('parameters'), label: 'gradle-random-event-label-failure',
)).called(1); parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Cache: () => cache, Cache: () => cache,
Platform: () => android, Platform: () => android,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('rethrows unrecognized ProcessException', () async { testUsingContext('rethrows unrecognized ProcessException', () async {
...@@ -1406,19 +1407,21 @@ plugin1=${plugin1.path} ...@@ -1406,19 +1407,21 @@ plugin1=${plugin1.path}
], ],
); );
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
any, const TestUsageEvent(
any, 'build',
label: 'gradle-random-event-label-success', 'unspecified',
parameters: anyNamed('parameters'), label: 'gradle-random-event-label-success',
)).called(1); parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Cache: () => cache, Cache: () => cache,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Platform: () => android, Platform: () => android,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('performs code size analysis and sends analytics', () async { testUsingContext('performs code size analysis and sends analytics', () async {
...@@ -1492,17 +1495,19 @@ plugin1=${plugin1.path} ...@@ -1492,17 +1495,19 @@ plugin1=${plugin1.path}
localGradleErrors: <GradleHandledError>[], localGradleErrors: <GradleHandledError>[],
); );
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
'code-size-analysis', const TestUsageEvent(
'apk', 'code-size-analysis',
)).called(1); 'apk',
),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Cache: () => cache, Cache: () => cache,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Platform: () => android, Platform: () => android,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('recognizes common errors - retry build with AAR plugins', () async { testUsingContext('recognizes common errors - retry build with AAR plugins', () async {
...@@ -1576,20 +1581,21 @@ plugin1=${plugin1.path} ...@@ -1576,20 +1581,21 @@ plugin1=${plugin1.path}
expect(testFnCalled, equals(2)); expect(testFnCalled, equals(2));
expect(builtPluginAsAar, isTrue); expect(builtPluginAsAar, isTrue);
verify(mockUsage.sendEvent( expect(testUsage.events, contains(
any, const TestUsageEvent(
any, 'build',
label: 'gradle-random-event-label-failure', 'unspecified',
parameters: anyNamed('parameters'), label: 'gradle-random-event-label-failure',
)).called(1); parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk, AndroidSdk: () => mockAndroidSdk,
Cache: () => cache, Cache: () => cache,
Platform: () => android, Platform: () => android,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Usage: () => mockUsage, Usage: () => testUsage,
}); });
testUsingContext('indicates that an APK has been built successfully', () async { testUsingContext('indicates that an APK has been built successfully', () async {
...@@ -2797,11 +2803,7 @@ class FakeGradleUtils extends GradleUtils { ...@@ -2797,11 +2803,7 @@ class FakeGradleUtils extends GradleUtils {
class MockAndroidSdk extends Mock implements AndroidSdk {} class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockAndroidProject extends Mock implements AndroidProject {} class MockAndroidProject extends Mock implements AndroidProject {}
class MockAndroidStudio extends Mock implements AndroidStudio {} class MockAndroidStudio extends Mock implements AndroidStudio {}
class MockDirectory extends Mock implements Directory {}
class MockFile extends Mock implements File {}
class MockFileSystemUtils extends Mock implements FileSystemUtils {} class MockFileSystemUtils extends Mock implements FileSystemUtils {}
class MockFlutterProject extends Mock implements FlutterProject {} class MockFlutterProject extends Mock implements FlutterProject {}
class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {} class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
class MockUsage extends Mock implements Usage {}
...@@ -25,7 +25,6 @@ class MockPathContext extends Mock implements path.Context {} ...@@ -25,7 +25,6 @@ class MockPathContext extends Mock implements path.Context {}
class MockDirectory extends Mock implements Directory {} class MockDirectory extends Mock implements Directory {}
class MockRandomAccessFile extends Mock implements RandomAccessFile {} class MockRandomAccessFile extends Mock implements RandomAccessFile {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockUsage extends Mock implements Usage {}
final Platform windowsPlatform = FakePlatform( final Platform windowsPlatform = FakePlatform(
operatingSystem: 'windows', operatingSystem: 'windows',
...@@ -927,9 +926,11 @@ void main() { ...@@ -927,9 +926,11 @@ void main() {
fileSystem.file('source').copySync('dest'); fileSystem.file('source').copySync('dest');
expect(memoryDest.readAsBytesSync(), expectedBytes); expect(memoryDest.readAsBytesSync(), expectedBytes);
verify(globals.flutterUsage.sendEvent('error-handling', 'copy-fallback')).called(1); expect((globals.flutterUsage as TestUsage).events, contains(
const TestUsageEvent('error-handling', 'copy-fallback'),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => TestUsage(),
}); });
// Uses context for analytics. // Uses context for analytics.
...@@ -963,7 +964,7 @@ void main() { ...@@ -963,7 +964,7 @@ void main() {
verify(dest.deleteSync(recursive: true)).called(1); verify(dest.deleteSync(recursive: true)).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => TestUsage(),
}); });
}); });
} }
......
...@@ -17,7 +17,6 @@ import 'package:flutter_tools/src/project.dart'; ...@@ -17,7 +17,6 @@ import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:http/testing.dart'; import 'package:http/testing.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
...@@ -26,16 +25,14 @@ import '../src/testbed.dart'; ...@@ -26,16 +25,14 @@ import '../src/testbed.dart';
void main() { void main() {
BufferLogger logger; BufferLogger logger;
FileSystem fs; FileSystem fs;
MockUsage mockUsage; TestUsage testUsage;
Platform platform; Platform platform;
OperatingSystemUtils operatingSystemUtils; OperatingSystemUtils operatingSystemUtils;
setUp(() async { setUp(() async {
logger = BufferLogger.test(); logger = BufferLogger.test();
fs = MemoryFileSystem.test(); fs = MemoryFileSystem.test();
testUsage = TestUsage();
mockUsage = MockUsage();
when(mockUsage.clientId).thenReturn('00000000-0000-4000-0000-000000000000');
platform = FakePlatform(environment: <String, String>{}, operatingSystem: 'linux'); platform = FakePlatform(environment: <String, String>{}, operatingSystem: 'linux');
operatingSystemUtils = OperatingSystemUtils( operatingSystemUtils = OperatingSystemUtils(
...@@ -63,7 +60,7 @@ void main() { ...@@ -63,7 +60,7 @@ void main() {
'version': 'test-version', 'version': 'test-version',
}, },
)); ));
expect(crashInfo.fields['uuid'], '00000000-0000-4000-0000-000000000000'); expect(crashInfo.fields['uuid'], testUsage.clientId);
expect(crashInfo.fields['product'], 'Flutter_Tools'); expect(crashInfo.fields['product'], 'Flutter_Tools');
expect(crashInfo.fields['version'], 'test-version'); expect(crashInfo.fields['version'], 'test-version');
expect(crashInfo.fields['osName'], 'linux'); expect(crashInfo.fields['osName'], 'linux');
...@@ -101,11 +98,11 @@ void main() { ...@@ -101,11 +98,11 @@ void main() {
}); });
testWithoutContext('suppress analytics', () async { testWithoutContext('suppress analytics', () async {
when(mockUsage.suppressAnalytics).thenReturn(true); testUsage.suppressAnalytics = true;
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const SocketException('no internets')), client: CrashingCrashReportSender(const SocketException('no internets')),
usage: mockUsage, usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -123,7 +120,7 @@ void main() { ...@@ -123,7 +120,7 @@ void main() {
group('allow analytics', () { group('allow analytics', () {
setUp(() async { setUp(() async {
when(mockUsage.suppressAnalytics).thenReturn(false); testUsage.suppressAnalytics = false;
}); });
testWithoutContext('should send crash reports', () async { testWithoutContext('should send crash reports', () async {
...@@ -131,7 +128,7 @@ void main() { ...@@ -131,7 +128,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: MockCrashReportSender(requestInfo), client: MockCrashReportSender(requestInfo),
usage: mockUsage, usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -150,7 +147,7 @@ void main() { ...@@ -150,7 +147,7 @@ void main() {
testWithoutContext('should print an explanatory message when there is a SocketException', () async { testWithoutContext('should print an explanatory message when there is a SocketException', () async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const SocketException('no internets')), client: CrashingCrashReportSender(const SocketException('no internets')),
usage: mockUsage, usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -169,7 +166,7 @@ void main() { ...@@ -169,7 +166,7 @@ void main() {
testWithoutContext('should print an explanatory message when there is an HttpException', () async { testWithoutContext('should print an explanatory message when there is an HttpException', () async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const HttpException('no internets')), client: CrashingCrashReportSender(const HttpException('no internets')),
usage: mockUsage, usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -188,7 +185,7 @@ void main() { ...@@ -188,7 +185,7 @@ void main() {
testWithoutContext('should print an explanatory message when there is a ClientException', () async { testWithoutContext('should print an explanatory message when there is a ClientException', () async {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const HttpException('no internets')), client: CrashingCrashReportSender(const HttpException('no internets')),
usage: mockUsage, usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -209,7 +206,7 @@ void main() { ...@@ -209,7 +206,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: MockCrashReportSender(requestInfo), client: MockCrashReportSender(requestInfo),
usage: mockUsage, usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -263,7 +260,7 @@ void main() { ...@@ -263,7 +260,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: mockClient, client: mockClient,
usage: mockUsage, usage: testUsage,
platform: platform, platform: platform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -301,7 +298,7 @@ void main() { ...@@ -301,7 +298,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender( final CrashReportSender crashReportSender = CrashReportSender(
client: mockClient, client: mockClient,
usage: mockUsage, usage: testUsage,
platform: environmentPlatform, platform: environmentPlatform,
logger: logger, logger: logger,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
...@@ -392,5 +389,3 @@ class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider { ...@@ -392,5 +389,3 @@ class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider {
@override @override
List<Workflow> get workflows => <Workflow>[]; List<Workflow> get workflows => <Workflow>[];
} }
class MockUsage extends Mock implements Usage {}
...@@ -48,7 +48,7 @@ void main() { ...@@ -48,7 +48,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -86,7 +86,7 @@ void main() { ...@@ -86,7 +86,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -124,7 +124,7 @@ void main() { ...@@ -124,7 +124,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -162,7 +162,7 @@ void main() { ...@@ -162,7 +162,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -199,7 +199,7 @@ void main() { ...@@ -199,7 +199,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -238,7 +238,7 @@ void main() { ...@@ -238,7 +238,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -279,7 +279,7 @@ void main() { ...@@ -279,7 +279,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -304,7 +304,7 @@ void main() { ...@@ -304,7 +304,7 @@ void main() {
fileSystem: MockFileSystem(), fileSystem: MockFileSystem(),
logger: logger, logger: logger,
processManager: processMock, processManager: processMock,
usage: MockUsage(), usage: TestUsage(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{}, environment: const <String, String>{},
), ),
...@@ -374,7 +374,7 @@ void main() { ...@@ -374,7 +374,7 @@ void main() {
platform: FakePlatform(environment: const <String, String>{}), platform: FakePlatform(environment: const <String, String>{}),
fileSystem: MockFileSystem(), fileSystem: MockFileSystem(),
logger: logger, logger: logger,
usage: MockUsage(), usage: TestUsage(),
botDetector: const BotDetectorAlwaysNo(), botDetector: const BotDetectorAlwaysNo(),
processManager: MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'), processManager: MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'),
); );
...@@ -403,7 +403,7 @@ void main() { ...@@ -403,7 +403,7 @@ void main() {
final MockFileSystem fsMock = MockFileSystem(); final MockFileSystem fsMock = MockFileSystem();
final Pub pub = Pub( final Pub pub = Pub(
platform: FakePlatform(environment: const <String, String>{}), platform: FakePlatform(environment: const <String, String>{}),
usage: MockUsage(), usage: TestUsage(),
fileSystem: fsMock, fileSystem: fsMock,
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: processMock, processManager: processMock,
...@@ -432,7 +432,7 @@ void main() { ...@@ -432,7 +432,7 @@ void main() {
fileSystem: MockFileSystem(), fileSystem: MockFileSystem(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: processMock, processManager: processMock,
usage: MockUsage(), usage: TestUsage(),
botDetector: const BotDetectorAlwaysNo(), botDetector: const BotDetectorAlwaysNo(),
platform: FakePlatform( platform: FakePlatform(
environment: const <String, String>{ environment: const <String, String>{
...@@ -461,7 +461,7 @@ void main() { ...@@ -461,7 +461,7 @@ void main() {
testWithoutContext('analytics sent on success', () async { testWithoutContext('analytics sent on success', () async {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final MockUsage usage = MockUsage(); final TestUsage usage = TestUsage();
final Pub pub = Pub( final Pub pub = Pub(
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
...@@ -484,13 +484,14 @@ void main() { ...@@ -484,13 +484,14 @@ void main() {
context: PubContext.flutterTests, context: PubContext.flutterTests,
generateSyntheticPackage: true, generateSyntheticPackage: true,
); );
expect(usage.events, contains(
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1); const TestUsageEvent('pub-result', 'flutter-tests', label: 'success'),
));
}); });
testWithoutContext('package_config_subset file is generated from packages and not timestamp', () async { testWithoutContext('package_config_subset file is generated from packages and not timestamp', () async {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final MockUsage usage = MockUsage(); final TestUsage usage = TestUsage();
final Pub pub = Pub( final Pub pub = Pub(
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
...@@ -536,7 +537,7 @@ void main() { ...@@ -536,7 +537,7 @@ void main() {
testWithoutContext('analytics sent on failure', () async { testWithoutContext('analytics sent on failure', () async {
MockDirectory.findCache = true; MockDirectory.findCache = true;
final MockUsage usage = MockUsage(); final TestUsage usage = TestUsage();
final Pub pub = Pub( final Pub pub = Pub(
usage: usage, usage: usage,
fileSystem: MockFileSystem(), fileSystem: MockFileSystem(),
...@@ -555,11 +556,13 @@ void main() { ...@@ -555,11 +556,13 @@ void main() {
// Ignore. // Ignore.
} }
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1); expect(usage.events, contains(
const TestUsageEvent('pub-result', 'flutter-tests', label: 'failure'),
));
}); });
testWithoutContext('analytics sent on failed version solve', () async { testWithoutContext('analytics sent on failed version solve', () async {
final MockUsage usage = MockUsage(); final TestUsage usage = TestUsage();
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final Pub pub = Pub( final Pub pub = Pub(
fileSystem: fileSystem, fileSystem: fileSystem,
...@@ -584,7 +587,9 @@ void main() { ...@@ -584,7 +587,9 @@ void main() {
// Ignore. // Ignore.
} }
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1); expect(usage.events, contains(
const TestUsageEvent('pub-result', 'flutter-tests', label: 'version-solving-failed'),
));
}); });
testWithoutContext('Pub error handling', () async { testWithoutContext('Pub error handling', () async {
...@@ -633,7 +638,7 @@ void main() { ...@@ -633,7 +638,7 @@ void main() {
), ),
]); ]);
final Pub pub = Pub( final Pub pub = Pub(
usage: MockUsage(), usage: TestUsage(),
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
...@@ -763,5 +768,3 @@ class MockDirectory implements Directory { ...@@ -763,5 +768,3 @@ class MockDirectory implements Directory {
} }
class MockRandomAccessFile extends Mock implements RandomAccessFile {} class MockRandomAccessFile extends Mock implements RandomAccessFile {}
class MockUsage extends Mock implements Usage {}
...@@ -23,9 +23,9 @@ import '../../src/common.dart'; ...@@ -23,9 +23,9 @@ import '../../src/common.dart';
void main () { void main () {
group('iOS migration', () { group('iOS migration', () {
MockUsage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
}); });
testWithoutContext('migrators succeed', () { testWithoutContext('migrators succeed', () {
...@@ -61,10 +61,10 @@ void main () { ...@@ -61,10 +61,10 @@ void main () {
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage testUsage
); );
expect(iosProjectMigration.migrate(), isTrue); expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value'))); expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.existsSync(), isFalse); expect(xcodeProjectInfoFile.existsSync(), isFalse);
...@@ -81,10 +81,10 @@ void main () { ...@@ -81,10 +81,10 @@ void main () {
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate(), isTrue); expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value'))); expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified); expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified);
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -102,7 +102,7 @@ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend. ...@@ -102,7 +102,7 @@ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate(), isTrue); expect(iosProjectMigration.migrate(), isTrue);
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -130,10 +130,10 @@ keep this 2 ...@@ -130,10 +130,10 @@ keep this 2
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate(), isTrue); expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value'))); expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.readAsStringSync(), r''' expect(xcodeProjectInfoFile.readAsStringSync(), r'''
keep this 1 keep this 1
...@@ -154,11 +154,13 @@ keep this 2 ...@@ -154,11 +154,13 @@ keep this 2
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null)); expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
}); });
testWithoutContext('migration fails with leftover Flutter.framework reference', () { testWithoutContext('migration fails with leftover Flutter.framework reference', () {
...@@ -172,10 +174,12 @@ keep this 2 ...@@ -172,10 +174,12 @@ keep this 2
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null)); expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
}); });
testWithoutContext('migration fails without Xcode installed', () { testWithoutContext('migration fails without Xcode installed', () {
...@@ -188,10 +192,12 @@ keep this 2 ...@@ -188,10 +192,12 @@ keep this 2
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null)); expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
}); });
testWithoutContext('migration fails on Xcode < 11.4', () { testWithoutContext('migration fails on Xcode < 11.4', () {
...@@ -205,10 +211,10 @@ keep this 2 ...@@ -205,10 +211,10 @@ keep this 2
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate(), isTrue); expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value'))); expect(testUsage.events, isEmpty);
expect(testLogger.errorText, isEmpty); expect(testLogger.errorText, isEmpty);
}); });
...@@ -223,10 +229,12 @@ keep this 2 ...@@ -223,10 +229,12 @@ keep this 2
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null)); expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
}); });
testWithoutContext('migration fails on Xcode 12,0', () { testWithoutContext('migration fails on Xcode 12,0', () {
...@@ -240,10 +248,12 @@ keep this 2 ...@@ -240,10 +248,12 @@ keep this 2
mockIosProject, mockIosProject,
testLogger, testLogger,
mockXcode, mockXcode,
mockUsage, testUsage,
); );
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration')); expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null)); expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
}); });
}); });
...@@ -556,7 +566,6 @@ keep this 3 ...@@ -556,7 +566,6 @@ keep this 3
class MockIosProject extends Mock implements IosProject {} class MockIosProject extends Mock implements IosProject {}
class MockXcode extends Mock implements Xcode {} class MockXcode extends Mock implements Xcode {}
class MockUsage extends Mock implements Usage {}
class FakeIOSMigrator extends ProjectMigrator { class FakeIOSMigrator extends ProjectMigrator {
FakeIOSMigrator({@required this.succeeds}) FakeIOSMigrator({@required this.succeeds})
......
...@@ -129,13 +129,13 @@ void main() { ...@@ -129,13 +129,13 @@ void main() {
group('Diagnose Xcode build failure', () { group('Diagnose Xcode build failure', () {
Map<String, String> buildSettings; Map<String, String> buildSettings;
MockUsage mockUsage; TestUsage testUsage;
setUp(() { setUp(() {
buildSettings = <String, String>{ buildSettings = <String, String>{
'PRODUCT_BUNDLE_IDENTIFIER': 'test.app', 'PRODUCT_BUNDLE_IDENTIFIER': 'test.app',
}; };
mockUsage = MockUsage(); testUsage = TestUsage();
}); });
testUsingContext('Sends analytics when bitcode fails', () async { testUsingContext('Sends analytics when bitcode fails', () async {
...@@ -151,14 +151,18 @@ void main() { ...@@ -151,14 +151,18 @@ void main() {
), ),
); );
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger); await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
verify(mockUsage.sendEvent('build', expect(testUsage.events, contains(
any, TestUsageEvent(
label: 'xcode-bitcode-failure', 'build',
parameters: <String, String>{ 'unspecified',
cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(), label: 'xcode-bitcode-failure',
cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(), parameters: <String, String>{
})).called(1); cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(),
cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(),
},
),
));
}); });
testUsingContext('No provisioning profile shows message', () async { testUsingContext('No provisioning profile shows message', () async {
...@@ -227,7 +231,7 @@ Error launching application on iPhone.''', ...@@ -227,7 +231,7 @@ Error launching application on iPhone.''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger); await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect( expect(
logger.errorText, logger.errorText,
contains("No Provisioning Profile was found for your project's Bundle Identifier or your \ndevice."), contains("No Provisioning Profile was found for your project's Bundle Identifier or your \ndevice."),
...@@ -308,7 +312,7 @@ Could not build the precompiled application for the device.''', ...@@ -308,7 +312,7 @@ Could not build the precompiled application for the device.''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger); await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect( expect(
logger.errorText, logger.errorText,
contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'), contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'),
...@@ -345,7 +349,7 @@ Exited (sigterm)''', ...@@ -345,7 +349,7 @@ Exited (sigterm)''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger); await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect( expect(
logger.errorText, logger.errorText,
contains('Your Xcode project requires migration.'), contains('Your Xcode project requires migration.'),
...@@ -382,7 +386,7 @@ Exited (sigterm)''', ...@@ -382,7 +386,7 @@ Exited (sigterm)''',
), ),
); );
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger); await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect( expect(
logger.errorText, logger.errorText,
contains('Your Xcode project requires migration.'), contains('Your Xcode project requires migration.'),
...@@ -480,5 +484,3 @@ Exited (sigterm)''', ...@@ -480,5 +484,3 @@ Exited (sigterm)''',
}); });
}); });
} }
class MockUsage extends Mock implements Usage {}
...@@ -19,14 +19,14 @@ import 'package:mockito/mockito.dart'; ...@@ -19,14 +19,14 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart'; import '../../src/common.dart';
void main() { void main() {
MockUsage mockUsage; TestUsage testUsage;
MemoryFileSystem memoryFileSystem; MemoryFileSystem memoryFileSystem;
BufferLogger testLogger; BufferLogger testLogger;
MockMacOSProject mockMacOSProject; MockMacOSProject mockMacOSProject;
File xcodeProjectInfoFile; File xcodeProjectInfoFile;
setUp(() { setUp(() {
mockUsage = MockUsage(); testUsage = TestUsage();
memoryFileSystem = MemoryFileSystem.test(); memoryFileSystem = MemoryFileSystem.test();
xcodeProjectInfoFile = memoryFileSystem.file('project.pbxproj'); xcodeProjectInfoFile = memoryFileSystem.file('project.pbxproj');
...@@ -48,15 +48,10 @@ void main() { ...@@ -48,15 +48,10 @@ void main() {
RemoveMacOSFrameworkLinkAndEmbeddingMigration( RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject, mockMacOSProject,
testLogger, testLogger,
mockUsage, testUsage,
); );
expect(macosProjectMigration.migrate(), isTrue); expect(macosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent( expect(testUsage.events, isEmpty);
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
));
expect(xcodeProjectInfoFile.existsSync(), isFalse); expect(xcodeProjectInfoFile.existsSync(), isFalse);
...@@ -77,15 +72,10 @@ void main() { ...@@ -77,15 +72,10 @@ void main() {
RemoveMacOSFrameworkLinkAndEmbeddingMigration( RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject, mockMacOSProject,
testLogger, testLogger,
mockUsage, testUsage,
); );
expect(macosProjectMigration.migrate(), isTrue); expect(macosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent( expect(testUsage.events, isEmpty);
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
));
expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified); expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified);
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -103,7 +93,7 @@ shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/. ...@@ -103,7 +93,7 @@ shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.
RemoveMacOSFrameworkLinkAndEmbeddingMigration( RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject, mockMacOSProject,
testLogger, testLogger,
mockUsage, testUsage,
); );
expect(macosProjectMigration.migrate(), isTrue); expect(macosProjectMigration.migrate(), isTrue);
expect(xcodeProjectInfoFile.readAsStringSync(), contents); expect(xcodeProjectInfoFile.readAsStringSync(), contents);
...@@ -126,15 +116,10 @@ keep this 2 ...@@ -126,15 +116,10 @@ keep this 2
RemoveMacOSFrameworkLinkAndEmbeddingMigration( RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject, mockMacOSProject,
testLogger, testLogger,
mockUsage, testUsage,
); );
expect(macosProjectMigration.migrate(), isTrue); expect(macosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent( expect(testUsage.events, isEmpty);
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
));
expect(xcodeProjectInfoFile.readAsStringSync(), r''' expect(xcodeProjectInfoFile.readAsStringSync(), r'''
keep this 1 keep this 1
...@@ -154,13 +139,14 @@ keep this 2 ...@@ -154,13 +139,14 @@ keep this 2
RemoveMacOSFrameworkLinkAndEmbeddingMigration( RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject, mockMacOSProject,
testLogger, testLogger,
mockUsage, testUsage,
); );
expect(macosProjectMigration.migrate, expect(macosProjectMigration.migrate,
throwsToolExit(message: 'Your Xcode project requires migration')); throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('macos-migration', 'remove-frameworks', expect(testUsage.events, contains(
label: 'failure', value: null)); const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'),
));
}); });
testWithoutContext( testWithoutContext(
...@@ -173,19 +159,18 @@ keep this 2 ...@@ -173,19 +159,18 @@ keep this 2
RemoveMacOSFrameworkLinkAndEmbeddingMigration( RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject, mockMacOSProject,
testLogger, testLogger,
mockUsage, testUsage,
); );
expect(macosProjectMigration.migrate, expect(macosProjectMigration.migrate,
throwsToolExit(message: 'Your Xcode project requires migration')); throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('macos-migration', 'remove-frameworks', expect(testUsage.events, contains(
label: 'failure', value: null)); const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'),
));
}); });
} }
class MockMacOSProject extends Mock implements MacOSProject {} class MockMacOSProject extends Mock implements MacOSProject {}
class MockUsage extends Mock implements Usage {}
class FakeMacOSMigrator extends ProjectMigrator { class FakeMacOSMigrator extends ProjectMigrator {
FakeMacOSMigrator({@required this.succeeds}) : super(null); FakeMacOSMigrator({@required this.succeeds}) : super(null);
......
...@@ -7,14 +7,13 @@ ...@@ -7,14 +7,13 @@
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart'; import 'package:package_config/package_config.dart';
import '../../src/common.dart'; import '../../src/common.dart';
void main() { void main() {
testWithoutContext('DoctorResultEvent sends usage event for each sub validator', () async { testWithoutContext('DoctorResultEvent sends usage event for each sub validator', () async {
final Usage usage = MockUsage(); final TestUsage usage = TestUsage();
final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[ final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[
FakeDoctorValidator('a'), FakeDoctorValidator('a'),
FakeDoctorValidator('b'), FakeDoctorValidator('b'),
...@@ -29,14 +28,16 @@ void main() { ...@@ -29,14 +28,16 @@ void main() {
); );
expect(doctorResultEvent.send, returnsNormally); expect(doctorResultEvent.send, returnsNormally);
expect(usage.events.length, 3);
verify(usage.sendEvent('doctor-result', any, label: anyNamed('label'))).called(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' 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 ' ' of validation. This happens when a grouped validator throws an exception, causing subResults to never '
' be instantiated.', () async { ' be instantiated.', () async {
final Usage usage = MockUsage(); final TestUsage usage = TestUsage();
final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[ final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[
FakeDoctorValidator('a'), FakeDoctorValidator('a'),
FakeDoctorValidator('b'), FakeDoctorValidator('b'),
...@@ -52,11 +53,14 @@ void main() { ...@@ -52,11 +53,14 @@ void main() {
expect(doctorResultEvent.send, returnsNormally); expect(doctorResultEvent.send, returnsNormally);
verify(usage.sendEvent('doctor-result', any, label: anyNamed('label'))).called(1); expect(usage.events.length, 1);
expect(usage.events, contains(
const TestUsageEvent('doctor-result', 'FakeGroupedValidator', label: 'crash'),
));
}); });
testWithoutContext('Reports null safe analytics events', () { testWithoutContext('Reports null safe analytics events', () {
final Usage usage = MockUsage(); final TestUsage usage = TestUsage();
final PackageConfig packageConfig = PackageConfig(<Package>[ final PackageConfig packageConfig = PackageConfig(<Package>[
Package('foo', Uri.parse('file:///foo/'), languageVersion: LanguageVersion(2, 12)), Package('foo', Uri.parse('file:///foo/'), languageVersion: LanguageVersion(2, 12)),
Package('bar', Uri.parse('file:///fizz/'), languageVersion: LanguageVersion(2, 1)), Package('bar', Uri.parse('file:///fizz/'), languageVersion: LanguageVersion(2, 1)),
...@@ -70,15 +74,17 @@ void main() { ...@@ -70,15 +74,17 @@ void main() {
usage, usage,
).send(); ).send();
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound')).called(1); expect(usage.events, unorderedEquals(<TestUsageEvent>[
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'),
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
'cd49': '1', 'cd50': '3', 'cd49': '1', 'cd50': '3',
})).called(1); }),
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: '2.12')).called(1); const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: '2.12'),
]));
}); });
testWithoutContext('Does not crash if main package is missing', () { testWithoutContext('Does not crash if main package is missing', () {
final Usage usage = MockUsage(); final TestUsage usage = TestUsage();
final PackageConfig packageConfig = PackageConfig(<Package>[ final PackageConfig packageConfig = PackageConfig(<Package>[
Package('foo', Uri.parse('file:///foo/lib/'), languageVersion: LanguageVersion(2, 12)), Package('foo', Uri.parse('file:///foo/lib/'), languageVersion: LanguageVersion(2, 12)),
Package('bar', Uri.parse('file:///fizz/lib/'), languageVersion: LanguageVersion(2, 1)), Package('bar', Uri.parse('file:///fizz/lib/'), languageVersion: LanguageVersion(2, 1)),
...@@ -92,15 +98,16 @@ void main() { ...@@ -92,15 +98,16 @@ void main() {
usage, usage,
).send(); ).send();
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound')).called(1); expect(usage.events, unorderedEquals(<TestUsageEvent>[
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'),
'cd49': '1', 'cd50': '3', const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
})).called(1); 'cd49': '1', 'cd50': '3',
verifyNever(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: anyNamed('label'))); }),
]));
}); });
testWithoutContext('a null language version is treated as unmigrated', () { testWithoutContext('a null language version is treated as unmigrated', () {
final Usage usage = MockUsage(); final TestUsage usage = TestUsage();
final PackageConfig packageConfig = PackageConfig(<Package>[ final PackageConfig packageConfig = PackageConfig(<Package>[
Package('foo', Uri.parse('file:///foo/lib/'), languageVersion: null), Package('foo', Uri.parse('file:///foo/lib/'), languageVersion: null),
]); ]);
...@@ -112,11 +119,12 @@ void main() { ...@@ -112,11 +119,12 @@ void main() {
usage, usage,
).send(); ).send();
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound')).called(1); expect(usage.events, unorderedEquals(<TestUsageEvent>[
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'),
'cd49': '0', 'cd50': '1', const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
})).called(1); 'cd49': '0', 'cd50': '1',
verifyNever(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: anyNamed('label'))); }),
]));
}); });
} }
...@@ -132,5 +140,3 @@ class FakeDoctorValidator extends DoctorValidator { ...@@ -132,5 +140,3 @@ class FakeDoctorValidator extends DoctorValidator {
return ValidationResult.crash(Object()); return ValidationResult.crash(Object());
} }
} }
class MockUsage extends Mock implements Usage {}
...@@ -546,16 +546,18 @@ void main() { ...@@ -546,16 +546,18 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false); final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, true); expect(result.fatal, true);
expect(result.code, 1); expect(result.code, 1);
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{ expect((globals.flutterUsage as TestUsage).events, contains(
cdKey(CustomDimensions.hotEventTargetPlatform): TestUsageEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm), getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example', cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false', cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false', cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1); }),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => TestUsage(),
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher, DevtoolsLauncher: () => mockDevtoolsLauncher,
}); });
...@@ -633,16 +635,19 @@ void main() { ...@@ -633,16 +635,19 @@ void main() {
expect(result.fatal, true); expect(result.fatal, true);
expect(result.code, kIsolateReloadBarred); expect(result.code, kIsolateReloadBarred);
expect(result.message, contains('Unable to hot reload application due to an unrecoverable error')); expect(result.message, contains('Unable to hot reload application due to an unrecoverable error'));
verify(globals.flutterUsage.sendEvent('hot', 'reload-barred', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform): expect((globals.flutterUsage as TestUsage).events, contains(
TestUsageEvent('hot', 'reload-barred', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm), getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example', cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false', cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false', cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1); }),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => TestUsage(),
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher, DevtoolsLauncher: () => mockDevtoolsLauncher,
}); });
...@@ -700,17 +705,20 @@ void main() { ...@@ -700,17 +705,20 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false); final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, true); expect(result.fatal, true);
expect(result.code, 1); expect(result.code, 1);
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform): expect((globals.flutterUsage as TestUsage).events, contains(
TestUsageEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm), getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example', cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false', cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false', cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1); }),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher, DevtoolsLauncher: () => mockDevtoolsLauncher,
Usage: () => MockUsage(), Usage: () => TestUsage(),
})); }));
testUsingContext('ResidentRunner does not reload sources if no sources changed', () => testbed.run(() async { testUsingContext('ResidentRunner does not reload sources if no sources changed', () => testbed.run(() async {
...@@ -1021,13 +1029,16 @@ void main() { ...@@ -1021,13 +1029,16 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false); final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, false); expect(result.fatal, false);
expect(result.code, 0); expect(result.code, 0);
expect(verify(globals.flutterUsage.sendEvent('hot', 'reload',
parameters: captureAnyNamed('parameters'))).captured[0], final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first;
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform), expect(event.category, 'hot');
getNameForTargetPlatform(TargetPlatform.android_arm)), expect(event.parameter, 'reload');
); expect(event.parameters, containsPair(
cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm),
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => TestUsage(),
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher, DevtoolsLauncher: () => mockDevtoolsLauncher,
}); });
...@@ -1134,15 +1145,18 @@ void main() { ...@@ -1134,15 +1145,18 @@ void main() {
expect(result.fatal, false); expect(result.fatal, false);
expect(result.code, 0); expect(result.code, 0);
verify(globals.flutterUsage.sendEvent('hot', 'reload', parameters: argThat(
containsPair('cd48', 'true'), final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first;
named: 'parameters', expect(event.category, 'hot');
))).called(1); expect(event.parameter, 'reload');
expect(event.parameters, containsPair(
cdKey(CustomDimensions.fastReassemble), 'true',
));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(), FileSystem: () => MemoryFileSystem.test(),
Platform: () => FakePlatform(operatingSystem: 'linux'), Platform: () => FakePlatform(operatingSystem: 'linux'),
ProjectFileInvalidator: () => FakeProjectFileInvalidator(), ProjectFileInvalidator: () => FakeProjectFileInvalidator(),
Usage: () => MockUsage(), Usage: () => TestUsage(),
FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true), FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true),
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher, DevtoolsLauncher: () => mockDevtoolsLauncher,
...@@ -1208,14 +1222,16 @@ void main() { ...@@ -1208,14 +1222,16 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true); final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, false); expect(result.fatal, false);
expect(result.code, 0); expect(result.code, 0);
expect(verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured[0], final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first;
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform), expect(event.category, 'hot');
getNameForTargetPlatform(TargetPlatform.android_arm)), expect(event.parameter, 'restart');
); expect(event.parameters, containsPair(
cdKey(CustomDimensions.hotEventTargetPlatform), getNameForTargetPlatform(TargetPlatform.android_arm),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => TestUsage(),
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher, DevtoolsLauncher: () => mockDevtoolsLauncher,
}); });
...@@ -1473,16 +1489,19 @@ void main() { ...@@ -1473,16 +1489,19 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true); final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, true); expect(result.fatal, true);
expect(result.code, 1); expect(result.code, 1);
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform): expect((globals.flutterUsage as TestUsage).events, contains(
TestUsageEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm), getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example', cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false', cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'true', cdKey(CustomDimensions.hotEventFullRestart): 'true',
})).called(1); }),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Usage: () => MockUsage(), Usage: () => TestUsage(),
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher, DevtoolsLauncher: () => mockDevtoolsLauncher,
}); });
...@@ -3134,7 +3153,6 @@ class MockDevice extends Mock implements Device {} ...@@ -3134,7 +3153,6 @@ class MockDevice extends Mock implements Device {}
class MockDeviceLogReader extends Mock implements DeviceLogReader {} class MockDeviceLogReader extends Mock implements DeviceLogReader {}
class MockDevicePortForwarder extends Mock implements DevicePortForwarder {} class MockDevicePortForwarder extends Mock implements DevicePortForwarder {}
class MockDevtoolsLauncher extends Mock implements DevtoolsLauncher {} class MockDevtoolsLauncher extends Mock implements DevtoolsLauncher {}
class MockUsage extends Mock implements Usage {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
class MockResidentCompiler extends Mock implements ResidentCompiler {} class MockResidentCompiler extends Mock implements ResidentCompiler {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment