// 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/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:package_config/package_config.dart'; import '../src/common.dart'; import '../src/fake_process_manager.dart'; void main() { testWithoutContext('StdoutHandler can parse output for successful batch compilation', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); stdoutHandler.reset(); 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0'.split('\n').forEach(stdoutHandler.handler); final CompilerOutput? output = await stdoutHandler.compilerOutput?.future; expect(logger.errorText, equals('line1\nline2\n')); expect(output?.outputFilename, equals('/path/to/main.dart.dill')); }); testWithoutContext('StdoutHandler can parse output for failed batch compilation', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); stdoutHandler.reset(); 'result abc\nline1\nline2\nabc\nabc'.split('\n').forEach(stdoutHandler.handler); final CompilerOutput? output = await stdoutHandler.compilerOutput?.future; expect(logger.errorText, equals('line1\nline2\n')); expect(output, equals(null)); }); testWithoutContext('KernelCompiler passes correct configuration to frontend server process', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[], fileSystemScheme: '', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=false', '-Ddart.vm.product=false', '--enable-asserts', '--no-link-platform', '--packages', '.packages', '--verbosity=error', 'file:///path/to/main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/path/to/main.dart', buildMode: BuildMode.debug, trackWidgetCreation: false, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', ); stdoutHandler.compilerOutput?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); expect((await output)?.outputFilename, ''); }); testWithoutContext('KernelCompiler returns null if StdoutHandler returns null', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[], fileSystemScheme: '', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=false', '-Ddart.vm.product=false', '--enable-asserts', '--no-link-platform', '--packages', '.packages', '--verbosity=error', 'file:///path/to/main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/path/to/main.dart', buildMode: BuildMode.debug, trackWidgetCreation: false, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', ); stdoutHandler.compilerOutput?.complete(); completer.complete(); expect(await output, null); }); testWithoutContext('KernelCompiler returns null if frontend_server process exits with non-zero code', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[], fileSystemScheme: '', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=false', '-Ddart.vm.product=false', '--enable-asserts', '--no-link-platform', '--packages', '.packages', '--verbosity=error', 'file:///path/to/main.dart', ], completer: completer, exitCode: 127), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/path/to/main.dart', buildMode: BuildMode.debug, trackWidgetCreation: false, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', ); stdoutHandler.compilerOutput?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); expect(await output, null); }); testWithoutContext('KernelCompiler passes correct AOT config to frontend_server in aot/profile mode', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[], fileSystemScheme: '', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=true', '-Ddart.vm.product=false', '--delete-tostring-package-uri=dart:ui', '--delete-tostring-package-uri=package:flutter', '--no-link-platform', '--aot', '--tfa', '--packages', '.packages', '--verbosity=error', 'file:///path/to/main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/path/to/main.dart', buildMode: BuildMode.profile, trackWidgetCreation: false, aot: true, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', ); stdoutHandler.compilerOutput?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); expect((await output)?.outputFilename, ''); }); testWithoutContext('passes correct AOT config to kernel compiler in aot/release mode', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[], fileSystemScheme: '', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=false', '-Ddart.vm.product=true', '--delete-tostring-package-uri=dart:ui', '--delete-tostring-package-uri=package:flutter', '--no-link-platform', '--aot', '--tfa', '--packages', '.packages', '--verbosity=error', 'file:///path/to/main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/path/to/main.dart', buildMode: BuildMode.release, trackWidgetCreation: false, aot: true, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', ); stdoutHandler.compilerOutput?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); expect((await output)?.outputFilename, ''); }); testWithoutContext('KernelCompiler passes dartDefines to the frontend_server', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[], fileSystemScheme: '', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-DFOO=bar', '-DBAZ=qux', '-Ddart.vm.profile=false', '-Ddart.vm.product=false', '--enable-asserts', '--no-link-platform', '--packages', '.packages', '--verbosity=error', 'file:///path/to/main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/path/to/main.dart', buildMode: BuildMode.debug, trackWidgetCreation: false, dartDefines: const <String>['FOO=bar', 'BAZ=qux'], packageConfig: PackageConfig.empty, packagesPath: '.packages', ); stdoutHandler.compilerOutput?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); expect((await output)?.outputFilename, ''); }); testWithoutContext('KernelCompiler maps a file to a multi-root scheme if provided', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[ '/foo/bar/fizz', ], fileSystemScheme: 'scheme', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=false', '-Ddart.vm.product=false', '--enable-asserts', '--no-link-platform', '--packages', '.packages', '--verbosity=error', 'scheme:///main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/foo/bar/fizz/main.dart', buildMode: BuildMode.debug, trackWidgetCreation: false, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', ); stdoutHandler.compilerOutput?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); expect((await output)?.outputFilename, ''); }); testWithoutContext('KernelCompiler uses generated entrypoint', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final MemoryFileSystem fs = MemoryFileSystem.test(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: fs, fileSystemRoots: <String>[ '/foo/bar/fizz', ], fileSystemScheme: 'scheme', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=false', '-Ddart.vm.product=false', '--enable-asserts', '--no-link-platform', '--packages', '.packages', '--source', '.dart_tools/flutter_build/dart_plugin_registrant.dart', '--source', 'package:flutter/src/dart_plugin_registrant.dart', '-Dflutter.dart_plugin_registrant=.dart_tools/flutter_build/dart_plugin_registrant.dart', '--verbosity=error', 'scheme:///main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Directory buildDir = fs.directory('.dart_tools') .childDirectory('flutter_build') .childDirectory('test'); buildDir.parent.childFile('dart_plugin_registrant.dart').createSync(recursive: true); final Future<CompilerOutput?> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', mainPath: '/foo/bar/fizz/main.dart', buildMode: BuildMode.debug, trackWidgetCreation: false, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', buildDir: buildDir, checkDartPluginRegistry: true, ); stdoutHandler.compilerOutput?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); await output; }); testWithoutContext('KernelCompiler passes native assets', () async { final BufferLogger logger = BufferLogger.test(); final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); final Completer<void> completer = Completer<void>(); final KernelCompiler kernelCompiler = KernelCompiler( artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), fileSystemRoots: <String>[], fileSystemScheme: '', logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', '/path/to/sdkroot/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=false', '-Ddart.vm.product=false', '--enable-asserts', '--no-link-platform', '--packages', '.packages', '--native-assets', 'path/to/native_assets.yaml', '--verbosity=error', 'file:///path/to/main.dart', ], completer: completer), ]), stdoutHandler: stdoutHandler, ); final Future<CompilerOutput?> output = kernelCompiler.compile( sdkRoot: '/path/to/sdkroot', mainPath: '/path/to/main.dart', buildMode: BuildMode.debug, trackWidgetCreation: false, dartDefines: const <String>[], packageConfig: PackageConfig.empty, packagesPath: '.packages', nativeAssets: 'path/to/native_assets.yaml', ); stdoutHandler.compilerOutput ?.complete(const CompilerOutput('', 0, <Uri>[])); completer.complete(); expect((await output)?.outputFilename, ''); }); }