|  | // 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/memory.dart'; | 
|  | import 'package:flutter_tools/src/artifacts.dart'; | 
|  | import 'package:flutter_tools/src/base/io.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 'package:process/process.dart'; | 
|  | import 'package:test/fake.dart'; | 
|  |  | 
|  | import '../src/common.dart'; | 
|  | import '../src/fake_process_manager.dart'; | 
|  | import '../src/fakes.dart'; | 
|  |  | 
|  | void main() { | 
|  | late FakeProcessManager processManager; | 
|  | late ResidentCompiler generator; | 
|  | late MemoryIOSink frontendServerStdIn; | 
|  | late StreamController<String> stdErrStreamController; | 
|  | late BufferLogger testLogger; | 
|  | late MemoryFileSystem fileSystem; | 
|  |  | 
|  | setUp(() { | 
|  | testLogger = BufferLogger.test(); | 
|  | processManager = FakeProcessManager(); | 
|  | frontendServerStdIn = MemoryIOSink(); | 
|  | fileSystem = MemoryFileSystem.test(); | 
|  | generator = ResidentCompiler( | 
|  | 'sdkroot', | 
|  | buildMode: BuildMode.debug, | 
|  | artifacts: Artifacts.test(), | 
|  | processManager: processManager, | 
|  | logger: testLogger, | 
|  | platform: FakePlatform(), | 
|  | fileSystem: fileSystem, | 
|  | ); | 
|  |  | 
|  | stdErrStreamController = StreamController<String>(); | 
|  | processManager.process.stdin = frontendServerStdIn; | 
|  | processManager.process.stderr = stdErrStreamController.stream.transform(utf8.encoder); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('compile expression fails if not previously compiled', () async { | 
|  | final CompilerOutput? result = await generator.compileExpression( | 
|  | '2+2', null, null, null, null, null, null, null, null, false); | 
|  |  | 
|  | expect(result, isNull); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('compile expression can compile single expression', () async { | 
|  | final Completer<List<int>> compileResponseCompleter = | 
|  | Completer<List<int>>(); | 
|  | final Completer<List<int>> compileExpressionResponseCompleter = | 
|  | Completer<List<int>>(); | 
|  | fileSystem.file('/path/to/main.dart.dill') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsBytesSync(<int>[1, 2, 3, 4]); | 
|  |  | 
|  | processManager.process.stdout = Stream<List<int>>.fromFutures( | 
|  | <Future<List<int>>>[ | 
|  | compileResponseCompleter.future, | 
|  | compileExpressionResponseCompleter.future, | 
|  | ], | 
|  | ); | 
|  | compileResponseCompleter.complete(Future<List<int>>.value(utf8.encode( | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n' | 
|  | ))); | 
|  |  | 
|  | await generator.recompile( | 
|  | Uri.file('/path/to/main.dart'), | 
|  | null, /* invalidatedFiles */ | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | projectRootPath: '', | 
|  | fs: fileSystem, | 
|  | ).then((CompilerOutput? output) { | 
|  | expect(frontendServerStdIn.getAndClear(), | 
|  | 'compile file:///path/to/main.dart\n'); | 
|  | expect(testLogger.errorText, | 
|  | equals('line1\nline2\n')); | 
|  | expect(output!.outputFilename, equals('/path/to/main.dart.dill')); | 
|  |  | 
|  | compileExpressionResponseCompleter.complete( | 
|  | Future<List<int>>.value(utf8.encode( | 
|  | 'result def\nline1\nline2\ndef\ndef /path/to/main.dart.dill.incremental 0\n' | 
|  | ))); | 
|  | generator.compileExpression( | 
|  | '2+2', null, null, null, null, null, null, null, null, false).then( | 
|  | (CompilerOutput? outputExpression) { | 
|  | expect(outputExpression, isNotNull); | 
|  | expect(outputExpression!.expressionData, <int>[1, 2, 3, 4]); | 
|  | } | 
|  | ); | 
|  | }); | 
|  | }); | 
|  |  | 
|  | testWithoutContext('compile expressions without awaiting', () async { | 
|  | final Completer<List<int>> compileResponseCompleter = Completer<List<int>>(); | 
|  | final Completer<List<int>> compileExpressionResponseCompleter1 = Completer<List<int>>(); | 
|  | final Completer<List<int>> compileExpressionResponseCompleter2 = Completer<List<int>>(); | 
|  |  | 
|  |  | 
|  | processManager.process.stdout = | 
|  | Stream<List<int>>.fromFutures( | 
|  | <Future<List<int>>>[ | 
|  | compileResponseCompleter.future, | 
|  | compileExpressionResponseCompleter1.future, | 
|  | compileExpressionResponseCompleter2.future, | 
|  | ]); | 
|  |  | 
|  | // The test manages timing via completers. | 
|  | unawaited( | 
|  | generator.recompile( | 
|  | Uri.parse('/path/to/main.dart'), | 
|  | null, /* invalidatedFiles */ | 
|  | outputPath: '/build/', | 
|  | packageConfig: PackageConfig.empty, | 
|  | projectRootPath: '', | 
|  | fs: MemoryFileSystem(), | 
|  | ).then((CompilerOutput? outputCompile) { | 
|  | expect(testLogger.errorText, | 
|  | equals('line1\nline2\n')); | 
|  | expect(outputCompile!.outputFilename, equals('/path/to/main.dart.dill')); | 
|  |  | 
|  | fileSystem.file('/path/to/main.dart.dill.incremental') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsBytesSync(<int>[0, 1, 2, 3]); | 
|  | compileExpressionResponseCompleter1.complete(Future<List<int>>.value(utf8.encode( | 
|  | 'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n' | 
|  | ))); | 
|  | }), | 
|  | ); | 
|  |  | 
|  | // The test manages timing via completers. | 
|  | final Completer<bool> lastExpressionCompleted = Completer<bool>(); | 
|  | unawaited( | 
|  | generator.compileExpression('0+1', null, null, null, null, null, null, | 
|  | null, null, false).then( | 
|  | (CompilerOutput? outputExpression) { | 
|  | expect(outputExpression, isNotNull); | 
|  | expect(outputExpression!.expressionData, <int>[0, 1, 2, 3]); | 
|  |  | 
|  | fileSystem.file('/path/to/main.dart.dill.incremental') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsBytesSync(<int>[4, 5, 6, 7]); | 
|  | compileExpressionResponseCompleter2.complete(Future<List<int>>.value(utf8.encode( | 
|  | 'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n' | 
|  | ))); | 
|  | }, | 
|  | ), | 
|  | ); | 
|  |  | 
|  | // The test manages timing via completers. | 
|  | unawaited( | 
|  | generator.compileExpression('1+1', null, null, null, null, null, null, | 
|  | null, null, false).then( | 
|  | (CompilerOutput? outputExpression) { | 
|  | expect(outputExpression, isNotNull); | 
|  | expect(outputExpression!.expressionData, <int>[4, 5, 6, 7]); | 
|  | lastExpressionCompleted.complete(true); | 
|  | }, | 
|  | ), | 
|  | ); | 
|  |  | 
|  | compileResponseCompleter.complete(Future<List<int>>.value(utf8.encode( | 
|  | 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n' | 
|  | ))); | 
|  |  | 
|  | expect(await lastExpressionCompleted.future, isTrue); | 
|  | }); | 
|  | } | 
|  |  | 
|  | class FakeProcess extends Fake implements Process { | 
|  | @override | 
|  | Stream<List<int>> stdout = const Stream<List<int>>.empty(); | 
|  |  | 
|  | @override | 
|  | Stream<List<int>> stderr = const Stream<List<int>>.empty(); | 
|  |  | 
|  | @override | 
|  | IOSink stdin = IOSink(StreamController<List<int>>().sink); | 
|  |  | 
|  | @override | 
|  | Future<int> get exitCode => Completer<int>().future; | 
|  | } | 
|  |  | 
|  | class FakeProcessManager extends Fake implements ProcessManager { | 
|  | final FakeProcess process = FakeProcess(); | 
|  |  | 
|  | @override | 
|  | bool canRun(dynamic executable, {String? workingDirectory}) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | @override | 
|  | Future<Process> start(List<Object> command, {String? workingDirectory, Map<String, String>? environment, bool includeParentEnvironment = true, bool runInShell = false, ProcessStartMode mode = ProcessStartMode.normal}) async { | 
|  | return process; | 
|  | } | 
|  | } |