|  | // Copyright 2014 The Flutter Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | import 'dart:async'; | 
|  |  | 
|  | import 'package:file/file.dart'; | 
|  | import 'package:file/memory.dart'; | 
|  | import 'package:flutter_tools/src/artifacts.dart'; | 
|  | import 'package:flutter_tools/src/base/async_guard.dart'; | 
|  | import 'package:flutter_tools/src/base/logger.dart'; | 
|  | import 'package:flutter_tools/src/base/platform.dart'; | 
|  | import 'package:flutter_tools/src/build_info.dart'; | 
|  | import 'package:flutter_tools/src/compile.dart'; | 
|  | import 'package:flutter_tools/src/convert.dart'; | 
|  | import 'package:package_config/package_config.dart'; | 
|  |  | 
|  | import '../src/common.dart'; | 
|  | import '../src/fake_process_manager.dart'; | 
|  | import '../src/fakes.dart'; | 
|  |  | 
|  | void main() { | 
|  | late ResidentCompiler generator; | 
|  | late ResidentCompiler generatorWithScheme; | 
|  | late ResidentCompiler generatorWithPlatformDillAndLibrariesSpec; | 
|  | late MemoryIOSink frontendServerStdIn; | 
|  | late BufferLogger testLogger; | 
|  | late StdoutHandler generatorStdoutHandler; | 
|  | late StdoutHandler generatorWithSchemeStdoutHandler; | 
|  | late FakeProcessManager fakeProcessManager; | 
|  |  | 
|  | const List<String> frontendServerCommand = <String>[ | 
|  | 'Artifact.engineDartBinary', | 
|  | '--disable-dart-dev', | 
|  | 'Artifact.frontendServerSnapshotForEngineDartSdk', | 
|  | '--sdk-root', | 
|  | 'sdkroot/', | 
|  | '--incremental', | 
|  | '--target=flutter', | 
|  | '--experimental-emit-debug-metadata', | 
|  | '--output-dill', | 
|  | '/build/', | 
|  | '-Ddart.vm.profile=false', | 
|  | '-Ddart.vm.product=false', | 
|  | '--enable-asserts', | 
|  | '--track-widget-creation', | 
|  | ]; | 
|  |  | 
|  | setUp(() { | 
|  | testLogger = BufferLogger.test(); | 
|  | frontendServerStdIn = MemoryIOSink(); | 
|  |  | 
|  | fakeProcessManager = FakeProcessManager.empty(); | 
|  | generatorStdoutHandler = StdoutHandler(logger: testLogger, fileSystem: MemoryFileSystem.test()); | 
|  | generatorWithSchemeStdoutHandler = StdoutHandler(logger: testLogger, fileSystem: MemoryFileSystem.test()); | 
|  | generator = DefaultResidentCompiler( | 
|  | 'sdkroot', | 
|  | buildMode: BuildMode.debug, | 
|  | logger: testLogger, | 
|  | processManager: fakeProcessManager, | 
|  | artifacts: Artifacts.test(), | 
|  | platform: FakePlatform(), | 
|  | fileSystem: MemoryFileSystem.test(), | 
|  | stdoutHandler: generatorStdoutHandler, | 
|  | ); | 
|  | generatorWithScheme = DefaultResidentCompiler( | 
|  | 'sdkroot', | 
|  | buildMode: BuildMode.debug, | 
|  | logger: testLogger, | 
|  | processManager: fakeProcessManager, | 
|  | artifacts: Artifacts.test(), | 
|  | platform: FakePlatform(), | 
|  | fileSystemRoots: <String>[ | 
|  | '/foo/bar/fizz', | 
|  | ], | 
|  | fileSystemScheme: 'scheme', | 
|  | fileSystem: MemoryFileSystem.test(), | 
|  | stdoutHandler: generatorWithSchemeStdoutHandler, | 
|  | ); | 
|  | generatorWithPlatformDillAndLibrariesSpec = DefaultResidentCompiler( | 
|  | 'sdkroot', | 
|  | buildMode: BuildMode.debug, | 
|  | logger: testLogger, | 
|  | processManager: fakeProcessManager, | 
|  | artifacts: Artifacts.test(), | 
|  | platform: FakePlatform(), | 
|  | fileSystem: MemoryFileSystem.test(), | 
|  | stdoutHandler: generatorStdoutHandler, | 
|  | platformDill: '/foo/platform.dill', | 
|  | librariesSpec: '/bar/libraries.json', | 
|  | ); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile single dart compile', () async { | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[...frontendServerCommand, '--verbosity=error'], | 
|  | stdout: 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | )); | 
|  |  | 
|  | final CompilerOutput? output = await generator.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | null /* invalidatedFiles */, | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); | 
|  | expect(testLogger.errorText, equals('line1\nline2\n')); | 
|  | expect(output?.outputFilename, equals('/path/to/main.dart.dill')); | 
|  | expect(fakeProcessManager, hasNoRemainingExpectations); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile single dart compile with filesystem scheme', () async { | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[ | 
|  | ...frontendServerCommand, | 
|  | '--filesystem-root', | 
|  | '/foo/bar/fizz', | 
|  | '--filesystem-scheme', | 
|  | 'scheme', | 
|  | '--verbosity=error', | 
|  | ], | 
|  | stdout: 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | )); | 
|  |  | 
|  | final CompilerOutput? output = await generatorWithScheme.recompile( | 
|  | Uri.parse('file:///foo/bar/fizz/main.dart'), | 
|  | null /* invalidatedFiles */, | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n'); | 
|  | expect(testLogger.errorText, equals('line1\nline2\n')); | 
|  | expect(output?.outputFilename, equals('/path/to/main.dart.dill')); | 
|  | expect(fakeProcessManager, hasNoRemainingExpectations); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile single dart compile abnormally terminates', () async { | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[...frontendServerCommand, '--verbosity=error'], | 
|  | stdin: frontendServerStdIn, | 
|  | )); | 
|  |  | 
|  | expect(asyncGuard(() => generator.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | null, /* invalidatedFiles */ | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | )), throwsToolExit()); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile single dart compile abnormally terminates via exitCode', () async { | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[...frontendServerCommand, '--verbosity=error'], | 
|  | stdin: frontendServerStdIn, | 
|  | exitCode: 1, | 
|  | )); | 
|  |  | 
|  | expect(asyncGuard(() => generator.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | null, /* invalidatedFiles */ | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | )), throwsToolExit(message: 'the Dart compiler exited unexpectedly.')); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile and recompile', () async { | 
|  | final Completer<void> completer = Completer<void>(); | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[...frontendServerCommand, '--verbosity=error'], | 
|  | stdout: 'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | completer: completer, | 
|  | )); | 
|  |  | 
|  | await generator.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | null, /* invalidatedFiles */ | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | projectRootPath: '', | 
|  | fs: MemoryFileSystem(), | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); | 
|  |  | 
|  | // No accept or reject commands should be issued until we | 
|  | // send recompile request. | 
|  | await _accept(generator, frontendServerStdIn, ''); | 
|  | await _reject(generatorStdoutHandler, generator, frontendServerStdIn, '', ''); | 
|  |  | 
|  | await _recompile(generatorStdoutHandler, generator, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'); | 
|  |  | 
|  | await _accept(generator, frontendServerStdIn, r'^accept\n$'); | 
|  |  | 
|  | await _recompile(generatorStdoutHandler, generator, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'); | 
|  | // No sources returned from reject command. | 
|  | await _reject(generatorStdoutHandler, generator, frontendServerStdIn, 'result abc\nabc\n', | 
|  | r'^reject\n$'); | 
|  | completer.complete(); | 
|  | expect(frontendServerStdIn.getAndClear(), isEmpty); | 
|  | expect(testLogger.errorText, equals( | 
|  | 'line0\nline1\n' | 
|  | 'line1\nline2\n' | 
|  | 'line1\nline2\n' | 
|  | )); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile and recompile with filesystem scheme', () async { | 
|  | final Completer<void> completer = Completer<void>(); | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[ | 
|  | ...frontendServerCommand, | 
|  | '--filesystem-root', | 
|  | '/foo/bar/fizz', | 
|  | '--filesystem-scheme', | 
|  | 'scheme', | 
|  | '--verbosity=error', | 
|  | ], | 
|  | stdout: 'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | completer: completer, | 
|  | )); | 
|  | await generatorWithScheme.recompile( | 
|  | Uri.parse('file:///foo/bar/fizz/main.dart'), | 
|  | null, /* invalidatedFiles */ | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n'); | 
|  |  | 
|  | // No accept or reject commands should be issued until we | 
|  | // send recompile request. | 
|  | await _accept(generatorWithScheme, frontendServerStdIn, ''); | 
|  | await _reject(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, '', ''); | 
|  |  | 
|  | await _recompile(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n', | 
|  | mainUri: Uri.parse('file:///foo/bar/fizz/main.dart'), | 
|  | expectedMainUri: 'scheme:///main.dart'); | 
|  |  | 
|  | await _accept(generatorWithScheme, frontendServerStdIn, r'^accept\n$'); | 
|  |  | 
|  | await _recompile(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n', | 
|  | mainUri: Uri.parse('file:///foo/bar/fizz/main.dart'), | 
|  | expectedMainUri: 'scheme:///main.dart'); | 
|  | // No sources returned from reject command. | 
|  | await _reject(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, 'result abc\nabc\n', | 
|  | r'^reject\n$'); | 
|  | completer.complete(); | 
|  | expect(frontendServerStdIn.getAndClear(), isEmpty); | 
|  | expect(testLogger.errorText, equals( | 
|  | 'line0\nline1\n' | 
|  | 'line1\nline2\n' | 
|  | 'line1\nline2\n' | 
|  | )); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile and recompile non-entrypoint file with filesystem scheme', () async { | 
|  | final Uri mainUri = Uri.parse('file:///foo/bar/fizz/main.dart'); | 
|  | const String expectedMainUri = 'scheme:///main.dart'; | 
|  | final List<Uri> updatedUris = <Uri>[ | 
|  | mainUri, | 
|  | Uri.parse('file:///foo/bar/fizz/other.dart'), | 
|  | ]; | 
|  | const List<String> expectedUpdatedUris = <String>[ | 
|  | expectedMainUri, | 
|  | 'scheme:///other.dart', | 
|  | ]; | 
|  |  | 
|  | final Completer<void> completer = Completer<void>(); | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[ | 
|  | ...frontendServerCommand, | 
|  | '--filesystem-root', | 
|  | '/foo/bar/fizz', | 
|  | '--filesystem-scheme', | 
|  | 'scheme', | 
|  | '--verbosity=error', | 
|  | ], | 
|  | stdout: 'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | completer: completer, | 
|  | )); | 
|  | await generatorWithScheme.recompile( | 
|  | Uri.parse('file:///foo/bar/fizz/main.dart'), | 
|  | null, /* invalidatedFiles */ | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n'); | 
|  |  | 
|  | // No accept or reject commands should be issued until we | 
|  | // send recompile request. | 
|  | await _accept(generatorWithScheme, frontendServerStdIn, ''); | 
|  | await _reject(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, '', ''); | 
|  |  | 
|  | await _recompile(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n', | 
|  | mainUri: mainUri, | 
|  | expectedMainUri: expectedMainUri, | 
|  | updatedUris: updatedUris, | 
|  | expectedUpdatedUris: expectedUpdatedUris); | 
|  |  | 
|  | await _accept(generatorWithScheme, frontendServerStdIn, r'^accept\n$'); | 
|  |  | 
|  | await _recompile(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n', | 
|  | mainUri: mainUri, | 
|  | expectedMainUri: expectedMainUri, | 
|  | updatedUris: updatedUris, | 
|  | expectedUpdatedUris: expectedUpdatedUris); | 
|  | // No sources returned from reject command. | 
|  | await _reject(generatorWithSchemeStdoutHandler, generatorWithScheme, frontendServerStdIn, 'result abc\nabc\n', | 
|  | r'^reject\n$'); | 
|  | completer.complete(); | 
|  | expect(frontendServerStdIn.getAndClear(), isEmpty); | 
|  | expect(testLogger.errorText, equals( | 
|  | 'line0\nline1\n' | 
|  | 'line1\nline2\n' | 
|  | 'line1\nline2\n' | 
|  | )); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile can suppress errors', () async { | 
|  | final Completer<void> completer = Completer<void>(); | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[...frontendServerCommand, '--verbosity=error'], | 
|  | stdout: 'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | completer: completer, | 
|  | )); | 
|  |  | 
|  | await generator.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | <Uri>[], | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); | 
|  |  | 
|  | await _recompile(generatorStdoutHandler, generator, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'); | 
|  |  | 
|  | await _accept(generator, frontendServerStdIn, r'^accept\n$'); | 
|  |  | 
|  | await _recompile(generatorStdoutHandler, generator, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n', suppressErrors: true); | 
|  |  | 
|  | completer.complete(); | 
|  | expect(frontendServerStdIn.getAndClear(), isEmpty); | 
|  |  | 
|  | // Compiler message is not printed with suppressErrors: true above. | 
|  | expect(testLogger.errorText, isNot(equals( | 
|  | 'line1\nline2\n' | 
|  | ))); | 
|  | expect(testLogger.traceText, contains( | 
|  | 'line1\nline2\n' | 
|  | )); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile and recompile twice', () async { | 
|  | final Completer<void> completer = Completer<void>(); | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[...frontendServerCommand, '--verbosity=error'], | 
|  | stdout: 'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | completer: completer, | 
|  | )); | 
|  | await generator.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | null /* invalidatedFiles */, | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); | 
|  |  | 
|  | await _recompile(generatorStdoutHandler, generator, frontendServerStdIn, | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'); | 
|  | await _recompile(generatorStdoutHandler, generator, frontendServerStdIn, | 
|  | 'result abc\nline2\nline3\nabc\nabc /path/to/main.dart.dill 0\n'); | 
|  |  | 
|  | completer.complete(); | 
|  | expect(frontendServerStdIn.getAndClear(), isEmpty); | 
|  | expect(testLogger.errorText, equals( | 
|  | 'line0\nline1\n' | 
|  | 'line1\nline2\n' | 
|  | 'line2\nline3\n' | 
|  | )); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('incremental compile with dartPluginRegistrant', () async { | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[ | 
|  | ...frontendServerCommand, | 
|  | '--filesystem-root', | 
|  | '/foo/bar/fizz', | 
|  | '--filesystem-scheme', | 
|  | 'scheme', | 
|  | '--source', | 
|  | 'some/dir/plugin_registrant.dart', | 
|  | '--source', | 
|  | 'package:flutter/src/dart_plugin_registrant.dart', | 
|  | '-Dflutter.dart_plugin_registrant=some/dir/plugin_registrant.dart', | 
|  | '--verbosity=error', | 
|  | ], | 
|  | stdout: 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | )); | 
|  |  | 
|  | final MemoryFileSystem fs = MemoryFileSystem(); | 
|  | final File dartPluginRegistrant = fs.file('some/dir/plugin_registrant.dart')..createSync(recursive: true); | 
|  | final CompilerOutput? output = await generatorWithScheme.recompile( | 
|  | Uri.parse('file:///foo/bar/fizz/main.dart'), | 
|  | null /* invalidatedFiles */, | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: fs, | 
|  | projectRootPath: '', | 
|  | checkDartPluginRegistry: true, | 
|  | dartPluginRegistrant: dartPluginRegistrant, | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n'); | 
|  | expect(testLogger.errorText, equals('line1\nline2\n')); | 
|  | expect(output?.outputFilename, equals('/path/to/main.dart.dill')); | 
|  | expect(fakeProcessManager, hasNoRemainingExpectations); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('compile does not pass libraries-spec when using a platform dill', () async { | 
|  | fakeProcessManager.addCommand(FakeCommand( | 
|  | command: const <String>[ | 
|  | ...frontendServerCommand, | 
|  | '--platform', | 
|  | '/foo/platform.dill', | 
|  | '--verbosity=error' | 
|  | ], | 
|  | stdout: 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0', | 
|  | stdin: frontendServerStdIn, | 
|  | )); | 
|  |  | 
|  | final CompilerOutput? output = await generatorWithPlatformDillAndLibrariesSpec.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | null /* invalidatedFiles */, | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  | expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); | 
|  | expect(testLogger.errorText, equals('line1\nline2\n')); | 
|  | expect(output?.outputFilename, equals('/path/to/main.dart.dill')); | 
|  | expect(fakeProcessManager, hasNoRemainingExpectations); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future<void> _recompile( | 
|  | StdoutHandler stdoutHandler, | 
|  | ResidentCompiler generator, | 
|  | MemoryIOSink frontendServerStdIn, | 
|  | String mockCompilerOutput, { | 
|  | bool suppressErrors = false, | 
|  | Uri? mainUri, | 
|  | String expectedMainUri = '/path/to/main.dart', | 
|  | List<Uri>? updatedUris, | 
|  | List<String>? expectedUpdatedUris, | 
|  | }) async { | 
|  | mainUri ??= Uri.parse('/path/to/main.dart'); | 
|  | updatedUris ??= <Uri>[mainUri]; | 
|  | expectedUpdatedUris ??= <String>[expectedMainUri]; | 
|  |  | 
|  | final Future<CompilerOutput?> recompileFuture = generator.recompile( | 
|  | mainUri, | 
|  | updatedUris, | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | suppressErrors: suppressErrors, | 
|  | fs: MemoryFileSystem(), | 
|  | projectRootPath: '', | 
|  | ); | 
|  |  | 
|  | // Put content into the output stream after generator.recompile gets | 
|  | // going few lines below, resets completer. | 
|  | scheduleMicrotask(() { | 
|  | LineSplitter.split(mockCompilerOutput).forEach(stdoutHandler.handler); | 
|  | }); | 
|  | final CompilerOutput? output = await recompileFuture; | 
|  | expect(output?.outputFilename, equals('/path/to/main.dart.dill')); | 
|  | final String commands = frontendServerStdIn.getAndClear(); | 
|  | final RegExp whitespace = RegExp(r'\s+'); | 
|  | final List<String> parts = commands.split(whitespace); | 
|  |  | 
|  | // Test that uuid matches at beginning and end. | 
|  | expect(parts[2], equals(parts[3 + updatedUris.length])); | 
|  | expect(parts[1], equals(expectedMainUri)); | 
|  | for (int i = 0; i < expectedUpdatedUris.length; i++) { | 
|  | expect(parts[3 + i], equals(expectedUpdatedUris[i])); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<void> _accept( | 
|  | ResidentCompiler generator, | 
|  | MemoryIOSink frontendServerStdIn, | 
|  | String expected, | 
|  | ) async { | 
|  | generator.accept(); | 
|  | final String commands = frontendServerStdIn.getAndClear(); | 
|  | final RegExp re = RegExp(expected); | 
|  | expect(commands, matches(re)); | 
|  | } | 
|  |  | 
|  | Future<void> _reject( | 
|  | StdoutHandler stdoutHandler, | 
|  | ResidentCompiler generator, | 
|  | MemoryIOSink frontendServerStdIn, | 
|  | String mockCompilerOutput, | 
|  | String expected, | 
|  | ) async { | 
|  | // Put content into the output stream after generator.recompile gets | 
|  | // going few lines below, resets completer. | 
|  | final Future<CompilerOutput?> rejectFuture = generator.reject(); | 
|  | scheduleMicrotask(() { | 
|  | LineSplitter.split(mockCompilerOutput).forEach(stdoutHandler.handler); | 
|  | }); | 
|  | final CompilerOutput? output = await rejectFuture; | 
|  | expect(output, isNull); | 
|  |  | 
|  | final String commands = frontendServerStdIn.getAndClear(); | 
|  | final RegExp re = RegExp(expected); | 
|  | expect(commands, matches(re)); | 
|  | } |