[flutter_tools] remove mocks, globals from golden comparator and test runner tests (#81423)
diff --git a/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart b/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart index e7fd741..82d7a0e 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart
@@ -4,33 +4,44 @@ // @dart = 2.8 - import 'dart:async'; import 'dart:typed_data'; +import 'package:meta/meta.dart'; +import 'package:process/process.dart'; + import '../base/common.dart'; import '../base/file_system.dart'; import '../base/io.dart'; +import '../base/logger.dart'; import '../convert.dart'; -import '../globals_null_migrated.dart' as globals; import 'test_compiler.dart'; import 'test_config.dart'; /// Helper class to start golden file comparison in a separate process. /// -/// Golden file comparator is configured using flutter_test_config.dart and that +/// The golden file comparator is configured using flutter_test_config.dart and that /// file can contain arbitrary Dart code that depends on dart:ui. Thus it has to /// be executed in a `flutter_tester` environment. This helper class generates a /// Dart file configured with flutter_test_config.dart to perform the comparison /// of golden files. class TestGoldenComparator { /// Creates a [TestGoldenComparator] instance. - TestGoldenComparator(this.shellPath, this.compilerFactory) - : tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_web_platform.'); + TestGoldenComparator(this.shellPath, this.compilerFactory, { + @required Logger logger, + @required FileSystem fileSystem, + @required ProcessManager processManager, + }) : tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_web_platform.'), + _logger = logger, + _fileSystem = fileSystem, + _processManager = processManager; final String shellPath; final Directory tempDir; final TestCompiler Function() compilerFactory; + final Logger _logger; + final FileSystem _fileSystem; + final ProcessManager _processManager; TestCompiler _compiler; TestGoldenComparatorProcess _previousComparator; @@ -49,10 +60,10 @@ return _previousComparator; } - final String bootstrap = TestGoldenComparatorProcess.generateBootstrap(testUri); + final String bootstrap = TestGoldenComparatorProcess.generateBootstrap(_fileSystem.file(testUri), testUri, logger: _logger); final Process process = await _startProcess(bootstrap); unawaited(_previousComparator?.close()); - _previousComparator = TestGoldenComparatorProcess(process); + _previousComparator = TestGoldenComparatorProcess(process, logger: _logger); _previousTestUri = testUri; return _previousComparator; @@ -70,7 +81,7 @@ shellPath, '--disable-observatory', '--non-interactive', - '--packages=${globals.fs.path.join('.dart_tool', 'package_config.json')}', + '--packages=${_fileSystem.path.join('.dart_tool', 'package_config.json')}', output, ]; @@ -78,7 +89,7 @@ // Chrome is the only supported browser currently. 'FLUTTER_TEST_BROWSER': 'chrome', }; - return globals.processManager.start(command, environment: environment); + return _processManager.start(command, environment: environment); } Future<String> compareGoldens(Uri testUri, Uint8List bytes, Uri goldenKey, bool updateGoldens) async { @@ -100,7 +111,7 @@ /// handles communication with the child process. class TestGoldenComparatorProcess { /// Creates a [TestGoldenComparatorProcess] backed by [process]. - TestGoldenComparatorProcess(this.process) { + TestGoldenComparatorProcess(this.process, {@required Logger logger}) : _logger = logger { // Pipe stdout and stderr to printTrace and printError. // Also parse stdout as a stream of JSON objects. streamIterator = StreamIterator<Map<String, dynamic>>( @@ -108,7 +119,7 @@ .transform<String>(utf8.decoder) .transform<String>(const LineSplitter()) .where((String line) { - globals.printTrace('<<< $line'); + logger.printTrace('<<< $line'); return line.isNotEmpty && line[0] == '{'; }) .map<dynamic>(jsonDecode) @@ -118,16 +129,17 @@ .transform<String>(utf8.decoder) .transform<String>(const LineSplitter()) .forEach((String line) { - globals.printError('<<< $line'); + logger.printError('<<< $line'); }); } + final Logger _logger; final Process process; StreamIterator<Map<String, dynamic>> streamIterator; Future<void> close() async { - await process.stdin.close(); process.kill(); + await process.exitCode; } void sendCommand(File imageFile, Uri goldenKey, bool updateGoldens) { @@ -136,7 +148,7 @@ 'key': goldenKey.toString(), 'update': updateGoldens, }); - globals.printTrace('Preparing to send command: $command'); + _logger.printTrace('Preparing to send command: $command'); process.stdin.writeln(command); } @@ -146,8 +158,8 @@ return streamIterator.current; } - static String generateBootstrap(Uri testUri) { - final File testConfigFile = findTestConfigFile(globals.fs.file(testUri), globals.logger); + static String generateBootstrap(File testFile, Uri testUri, {@required Logger logger}) { + final File testConfigFile = findTestConfigFile(testFile, logger); // Generate comparator process for the file. return ''' import 'dart:convert'; // flutter_ignore: dart_convert_import
diff --git a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart index 3b9ad88..03a0762 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart
@@ -12,6 +12,7 @@ import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; import 'package:pool/pool.dart'; +import 'package:process/process.dart'; import 'package:shelf/shelf.dart' as shelf; import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:shelf_static/shelf_static.dart'; @@ -51,6 +52,7 @@ @required ChromiumLauncher chromiumLauncher, @required Logger logger, @required Artifacts artifacts, + @required ProcessManager processManager, }) : _fileSystem = fileSystem, _flutterToolPackageConfig = flutterToolPackageConfig, _chromiumLauncher = chromiumLauncher, @@ -75,6 +77,9 @@ _testGoldenComparator = TestGoldenComparator( shellPath, () => TestCompiler(buildInfo, flutterProject), + fileSystem: _fileSystem, + logger: _logger, + processManager: processManager, ); } @@ -111,6 +116,7 @@ @required Logger logger, @required ChromiumLauncher chromiumLauncher, @required Artifacts artifacts, + @required ProcessManager processManager, }) async { final shelf_io.IOServer server = shelf_io.IOServer(await HttpMultiServer.loopback(0)); final PackageConfig packageConfig = await loadPackageConfigWithLogging( @@ -138,6 +144,7 @@ artifacts: artifacts, logger: logger, nullAssertions: nullAssertions, + processManager: processManager, ); }
diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index 25c0eff..df23b33 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart
@@ -168,6 +168,7 @@ logger: globals.logger, fileSystem: globals.fs, artifacts: globals.artifacts, + processManager: globals.processManager, chromiumLauncher: ChromiumLauncher( fileSystem: globals.fs, platform: globals.platform,
diff --git a/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart b/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart index e5226fb..2bf8d87 100644 --- a/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart
@@ -17,8 +17,8 @@ import 'package:flutter_tools/src/test/flutter_tester_device.dart'; import 'package:flutter_tools/src/test/font_config_manager.dart'; import 'package:meta/meta.dart'; -import 'package:mockito/mockito.dart'; import 'package:stream_channel/stream_channel.dart'; +import 'package:test/fake.dart'; import '../src/common.dart'; import '../src/context.dart'; @@ -80,7 +80,7 @@ ], environment: <String, String>{ 'FLUTTER_TEST': expectedFlutterTestValue, 'FONTCONFIG_FILE': device.fontConfigManager.fontConfigFile.path, - 'SERVER_PORT': 'null', + 'SERVER_PORT': '0', 'APP_NAME': '', }); } @@ -244,17 +244,28 @@ @override Future<DartDevelopmentService> startDds(Uri uri) async { _ddsServiceUriCompleter.complete(uri); - final MockDartDevelopmentService mock = MockDartDevelopmentService(); - when(mock.uri).thenReturn(Uri.parse('http://localhost:${debuggingOptions.hostVmServicePort}')); - return mock; + return FakeDartDevelopmentService(Uri.parse('http://localhost:${debuggingOptions.hostVmServicePort}'), Uri.parse('http://localhost:8080')); } @override - Future<HttpServer> bind(InternetAddress host, int port) async => MockHttpServer(); + Future<HttpServer> bind(InternetAddress host, int port) async => FakeHttpServer(); @override Future<StreamChannel<String>> get remoteChannel async => StreamChannelController<String>().foreign; } -class MockDartDevelopmentService extends Mock implements DartDevelopmentService {} -class MockHttpServer extends Mock implements HttpServer {} +class FakeDartDevelopmentService extends Fake implements DartDevelopmentService { + FakeDartDevelopmentService(this.uri, this.original); + + final Uri original; + + @override + final Uri uri; + + @override + Uri get remoteVmServiceUri => original; +} +class FakeHttpServer extends Fake implements HttpServer { + @override + int get port => 0; +}
diff --git a/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart b/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart index efc85cd..e11e46e 100644 --- a/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart +++ b/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart
@@ -7,16 +7,14 @@ import 'dart:convert'; import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/test/flutter_web_goldens.dart'; import '../../src/common.dart'; import '../../src/fakes.dart'; -import '../../src/testbed.dart'; void main() { - final Testbed testbed = Testbed(); - group('Test that TestGoldenComparatorProcess', () { File imageFile; Uri goldenKey; @@ -35,7 +33,7 @@ ); }); - test('can pass data', () => testbed.run(() async { + testWithoutContext('can pass data', () async { final Map<String, dynamic> expectedResponse = <String, dynamic>{ 'success': true, 'message': 'some message', @@ -44,7 +42,7 @@ final FakeProcess mockProcess = createFakeProcess(jsonEncode(expectedResponse) + '\n'); final MemoryIOSink ioSink = mockProcess.stdin as MemoryIOSink; - final TestGoldenComparatorProcess process = TestGoldenComparatorProcess(mockProcess); + final TestGoldenComparatorProcess process = TestGoldenComparatorProcess(mockProcess, logger: BufferLogger.test()); process.sendCommand(imageFile, goldenKey, false); final Map<String, dynamic> response = await process.getResponse(); @@ -52,9 +50,9 @@ expect(response, expectedResponse); expect(stringToStdin, '{"imageFile":"test_image_file","key":"file://golden_key/","update":false}\n'); - })); + }); - test('can handle multiple requests', () => testbed.run(() async { + testWithoutContext('can handle multiple requests', () async { final Map<String, dynamic> expectedResponse1 = <String, dynamic>{ 'success': true, 'message': 'some message', @@ -67,7 +65,7 @@ final FakeProcess mockProcess = createFakeProcess(jsonEncode(expectedResponse1) + '\n' + jsonEncode(expectedResponse2) + '\n'); final MemoryIOSink ioSink = mockProcess.stdin as MemoryIOSink; - final TestGoldenComparatorProcess process = TestGoldenComparatorProcess(mockProcess); + final TestGoldenComparatorProcess process = TestGoldenComparatorProcess(mockProcess, logger: BufferLogger.test()); process.sendCommand(imageFile, goldenKey, false); final Map<String, dynamic> response1 = await process.getResponse(); @@ -80,9 +78,9 @@ expect(response1, expectedResponse1); expect(response2, expectedResponse2); expect(stringToStdin, '{"imageFile":"test_image_file","key":"file://golden_key/","update":false}\n{"imageFile":"second_test_image_file","key":"file://second_golden_key/","update":true}\n'); - })); + }); - test('ignores anything that does not look like JSON', () => testbed.run(() async { + testWithoutContext('ignores anything that does not look like JSON', () async { final Map<String, dynamic> expectedResponse = <String, dynamic>{ 'success': true, 'message': 'some message', @@ -97,7 +95,7 @@ '''); final MemoryIOSink ioSink = mockProcess.stdin as MemoryIOSink; - final TestGoldenComparatorProcess process = TestGoldenComparatorProcess(mockProcess); + final TestGoldenComparatorProcess process = TestGoldenComparatorProcess(mockProcess,logger: BufferLogger.test()); process.sendCommand(imageFile, goldenKey, false); final Map<String, dynamic> response = await process.getResponse(); @@ -105,7 +103,7 @@ expect(response, expectedResponse); expect(stringToStdin, '{"imageFile":"test_image_file","key":"file://golden_key/","update":false}\n'); - })); + }); }); }
diff --git a/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart b/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart index f740d49..78b8de0 100644 --- a/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart +++ b/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart
@@ -4,95 +4,91 @@ // @dart = 2.8 +import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; -import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/test/flutter_web_goldens.dart'; import 'package:flutter_tools/src/test/test_compiler.dart'; -import 'package:mockito/mockito.dart'; -import 'package:process/process.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; -import '../../src/fakes.dart'; -import '../../src/testbed.dart'; +import '../../src/context.dart'; + +final Uri goldenKey = Uri.parse('file://golden_key'); +final Uri goldenKey2 = Uri.parse('file://second_golden_key'); +final Uri testUri = Uri.parse('file://test_uri'); +final Uri testUri2 = Uri.parse('file://second_test_uri'); +final Uint8List imageBytes = Uint8List.fromList(<int>[1, 2, 3, 4, 5]); void main() { group('Test that TestGoldenComparator', () { - Testbed testbed; - Uri goldenKey; - Uri goldenKey2; - Uri testUri; - Uri testUri2; - Uint8List imageBytes; - MockProcessManager mockProcessManager; - MockTestCompiler mockCompiler; + FakeProcessManager processManager; setUp(() { - goldenKey = Uri.parse('file://golden_key'); - goldenKey2 = Uri.parse('file://second_golden_key'); - testUri = Uri.parse('file://test_uri'); - testUri2 = Uri.parse('file://second_test_uri'); - imageBytes = Uint8List.fromList(<int>[1,2,3,4,5]); - mockProcessManager = MockProcessManager(); - mockCompiler = MockTestCompiler(); - when(mockCompiler.compile(any)).thenAnswer((_) => Future<String>.value('compiler_output')); - - testbed = Testbed(overrides: <Type, Generator>{ - ProcessManager: () { - return mockProcessManager; - } - }); + processManager = FakeProcessManager.empty(); }); - test('succeed when golden comparison succeed', () => testbed.run(() async { + testWithoutContext('succeed when golden comparison succeed', () async { final Map<String, dynamic> expectedResponse = <String, dynamic>{ 'success': true, 'message': 'some message', }; - - when(mockProcessManager.start(any, environment: anyNamed('environment'))) - .thenAnswer((Invocation invocation) async { - return FakeProcess( - exitCode: Future<int>.value(0), - stdout: stdoutFromString(jsonEncode(expectedResponse) + '\n'), - ); - }); + processManager.addCommand(FakeCommand( + command: const <String>[ + 'shell', + '--disable-observatory', + '--non-interactive', + '--packages=.dart_tool/package_config.json', + 'compiler_output' + ], stdout: jsonEncode(expectedResponse) + '\n', + )); final TestGoldenComparator comparator = TestGoldenComparator( 'shell', - () => mockCompiler, + () => FakeTestCompiler(), + processManager: processManager, + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), ); final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result, null); - })); + }); - test('fail with error message when golden comparison failed', () => testbed.run(() async { + testWithoutContext('fail with error message when golden comparison failed', () async { final Map<String, dynamic> expectedResponse = <String, dynamic>{ 'success': false, 'message': 'some message', }; - when(mockProcessManager.start(any, environment: anyNamed('environment'))) - .thenAnswer((Invocation invocation) async { - return FakeProcess( - exitCode: Future<int>.value(0), - stdout: stdoutFromString(jsonEncode(expectedResponse) + '\n'), - ); - }); + processManager.addCommand(FakeCommand( + command: const <String>[ + 'shell', + '--disable-observatory', + '--non-interactive', + '--packages=.dart_tool/package_config.json', + 'compiler_output' + ], stdout: jsonEncode(expectedResponse) + '\n', + )); final TestGoldenComparator comparator = TestGoldenComparator( 'shell', - () => mockCompiler, + () => FakeTestCompiler(), + processManager: processManager, + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), ); final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result, 'some message'); - })); + }); - test('reuse the process for the same test file', () => testbed.run(() async { + testWithoutContext('reuse the process for the same test file', () async { final Map<String, dynamic> expectedResponse1 = <String, dynamic>{ 'success': false, 'message': 'some message', @@ -102,27 +98,32 @@ 'message': 'some other message', }; - when(mockProcessManager.start(any, environment: anyNamed('environment'))) - .thenAnswer((Invocation invocation) async { - return FakeProcess( - exitCode: Future<int>.value(0), - stdout: stdoutFromString(jsonEncode(expectedResponse1) + '\n' + jsonEncode(expectedResponse2) + '\n'), - ); - }); + processManager.addCommand(FakeCommand( + command: const <String>[ + 'shell', + '--disable-observatory', + '--non-interactive', + '--packages=.dart_tool/package_config.json', + 'compiler_output' + ], stdout: jsonEncode(expectedResponse1) + '\n' + jsonEncode(expectedResponse2) + '\n', + )); final TestGoldenComparator comparator = TestGoldenComparator( 'shell', - () => mockCompiler, + () => FakeTestCompiler(), + processManager: processManager, + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), ); final String result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result1, 'some message'); + final String result2 = await comparator.compareGoldens(testUri, imageBytes, goldenKey2, false); expect(result2, 'some other message'); - verify(mockProcessManager.start(any, environment: anyNamed('environment'))).called(1); - })); + }); - test('does not reuse the process for different test file', () => testbed.run(() async { + testWithoutContext('does not reuse the process for different test file', () async { final Map<String, dynamic> expectedResponse1 = <String, dynamic>{ 'success': false, 'message': 'some message', @@ -132,57 +133,82 @@ 'message': 'some other message', }; - when(mockProcessManager.start(any, environment: anyNamed('environment'))) - .thenAnswer((Invocation invocation) async { - return FakeProcess( - exitCode: Future<int>.value(0), - stdout: stdoutFromString(jsonEncode(expectedResponse1) + '\n' + jsonEncode(expectedResponse2) + '\n'), - ); - }); + processManager.addCommand(FakeCommand( + command: const <String>[ + 'shell', + '--disable-observatory', + '--non-interactive', + '--packages=.dart_tool/package_config.json', + 'compiler_output' + ], stdout: jsonEncode(expectedResponse1) + '\n', + )); + processManager.addCommand(FakeCommand( + command: const <String>[ + 'shell', + '--disable-observatory', + '--non-interactive', + '--packages=.dart_tool/package_config.json', + 'compiler_output' + ], stdout: jsonEncode(expectedResponse2) + '\n', + )); final TestGoldenComparator comparator = TestGoldenComparator( 'shell', - () => mockCompiler, + () => FakeTestCompiler(), + processManager: processManager, + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), ); final String result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result1, 'some message'); - final String result2 = await comparator.compareGoldens(testUri2, imageBytes, goldenKey2, false); - expect(result2, 'some message'); - verify(mockProcessManager.start(any, environment: anyNamed('environment'))).called(2); - })); - test('removes all temporary files when closed', () => testbed.run(() async { + final String result2 = await comparator.compareGoldens(testUri2, imageBytes, goldenKey2, false); + expect(result2, 'some other message'); + }); + + testWithoutContext('removes all temporary files when closed', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); final Map<String, dynamic> expectedResponse = <String, dynamic>{ 'success': true, 'message': 'some message', }; - - when(mockProcessManager.start(any, environment: anyNamed('environment'))) - .thenAnswer((Invocation invocation) async { - return FakeProcess( - exitCode: Future<int>.value(0), - stdout: stdoutFromString(jsonEncode(expectedResponse) + '\n'), - ); - }); + final StreamController<List<int>> controller = StreamController<List<int>>(); + final IOSink stdin = IOSink(controller.sink); + processManager.addCommand(FakeCommand( + command: const <String>[ + 'shell', + '--disable-observatory', + '--non-interactive', + '--packages=.dart_tool/package_config.json', + 'compiler_output' + ], stdout: jsonEncode(expectedResponse) + '\n', + stdin: stdin, + )); final TestGoldenComparator comparator = TestGoldenComparator( 'shell', - () => mockCompiler, + () => FakeTestCompiler(), + processManager: processManager, + fileSystem: fileSystem, + logger: BufferLogger.test(), ); final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result, null); await comparator.close(); - expect(globals.fs.systemTempDirectory.listSync(recursive: true), isEmpty); - })); + expect(fileSystem.systemTempDirectory.listSync(recursive: true), isEmpty); + }); }); } -Stream<List<int>> stdoutFromString(String string) => Stream<List<int>>.fromIterable(<List<int>>[ - utf8.encode(string), -]); +class FakeTestCompiler extends Fake implements TestCompiler { + @override + Future<String> compile(Uri mainDart) { + return Future<String>.value('compiler_output'); + } -class MockProcessManager extends Mock implements ProcessManager {} -class MockTestCompiler extends Mock implements TestCompiler {} + @override + Future<void> dispose() async { } +}