blob: 34d6706d7b0d8f895face6b9159fb642523e299b [file] [log] [blame]
// 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/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
ProcessManager mockProcessManager;
MockProcess mockFrontendServer;
MockStdIn mockFrontendServerStdIn;
MockStream mockFrontendServerStdErr;
List<String> latestCommand;
setUp(() {
mockProcessManager = MockProcessManager();
mockFrontendServer = MockProcess();
mockFrontendServerStdIn = MockStdIn();
mockFrontendServerStdErr = MockStream();
when(mockFrontendServer.stderr)
.thenAnswer((Invocation invocation) => mockFrontendServerStdErr);
final StreamController<String> stdErrStreamController = StreamController<String>();
when(mockFrontendServerStdErr.transform<String>(any)).thenAnswer((_) => stdErrStreamController.stream);
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
when(mockProcessManager.canRun(any)).thenReturn(true);
when(mockProcessManager.start(any)).thenAnswer(
(Invocation invocation) {
latestCommand = invocation.positionalArguments.first as List<String>;
return Future<Process>.value(mockFrontendServer);
});
when(mockFrontendServer.exitCode).thenAnswer((_) async => 0);
});
testWithoutContext('batch compile single dart successful compilation', () async {
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0'
))
));
final BufferLogger logger = BufferLogger.test();
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: MemoryFileSystem.test(),
fileSystemRoots: <String>[],
fileSystemScheme: '',
logger: logger,
processManager: mockProcessManager
);
final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(logger.errorText, equals('line1\nline2\n'));
expect(output.outputFilename, equals('/path/to/main.dart.dill'));
final VerificationResult argVerification = verify(mockProcessManager.start(captureAny));
expect(argVerification.captured.single, containsAll(<String>[
'-Ddart.developer.causal_async_stacks=true',
]));
});
testWithoutContext('passes correct AOT config to kernel compiler in aot/profile mode', () async {
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0'
))
));
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: MemoryFileSystem.test(),
fileSystemRoots: <String>[],
fileSystemScheme: '',
logger: BufferLogger.test(),
processManager: mockProcessManager
);
await 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',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
final VerificationResult argVerification = verify(mockProcessManager.start(captureAny));
expect(argVerification.captured.single, containsAll(<String>[
'--aot',
'--tfa',
'-Ddart.vm.profile=true',
'-Ddart.vm.product=false',
'--bytecode-options=source-positions',
'-Ddart.developer.causal_async_stacks=false',
]));
});
testWithoutContext('passes correct AOT config to kernel compiler in aot/release mode', () async {
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0'
))
));
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: MemoryFileSystem.test(),
fileSystemRoots: <String>[],
fileSystemScheme: '',
logger: BufferLogger.test(),
processManager: mockProcessManager
);
await 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',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
final VerificationResult argVerification = verify(mockProcessManager.start(captureAny));
expect(argVerification.captured.single, containsAll(<String>[
'--aot',
'--tfa',
'-Ddart.vm.profile=false',
'-Ddart.vm.product=true',
'--bytecode-options=source-positions',
'-Ddart.developer.causal_async_stacks=false',
]));
});
testWithoutContext('batch compile single dart failed compilation', () async {
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
'result abc\nline1\nline2\nabc\nabc'
))
));
final BufferLogger logger = BufferLogger.test();
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: MemoryFileSystem.test(),
fileSystemRoots: <String>[],
fileSystemScheme: '',
logger: logger,
processManager: mockProcessManager
);
final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(logger.errorText, equals('line1\nline2\n'));
expect(output, equals(null));
});
testWithoutContext('batch compile single dart abnormal compiler termination', () async {
when(mockFrontendServer.exitCode).thenAnswer((_) async => 255);
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
'result abc\nline1\nline2\nabc\nabc'
))
));
final BufferLogger logger = BufferLogger.test();
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: MemoryFileSystem.test(),
fileSystemRoots: <String>[],
fileSystemScheme: '',
logger: logger,
processManager: mockProcessManager
);
final CompilerOutput output = await kernelCompiler.compile(
sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(logger.errorText, equals('line1\nline2\n'));
expect(output, equals(null));
});
testWithoutContext('passes dartDefines to the kernel compiler', () async {
// Use unsuccessful result because it's easier to setup in test. We only care about arguments passed to the compiler.
when(mockFrontendServer.exitCode).thenAnswer((_) async => 255);
when(mockFrontendServer.stdout).thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(<int>[])
));
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: MemoryFileSystem.test(),
fileSystemRoots: <String>[],
fileSystemScheme: '',
logger: BufferLogger.test(),
processManager: mockProcessManager
);
await 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',
);
expect(latestCommand, containsAllInOrder(<String>['-DFOO=bar', '-DBAZ=qux']));
});
testWithoutContext('maps a file to a multiroot scheme if providfed', () async {
// Use unsuccessful result because it's easier to setup in test. We only care about arguments passed to the compiler.
when(mockFrontendServer.exitCode).thenAnswer((_) async => 255);
when(mockFrontendServer.stdout).thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(<int>[])
));
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: MemoryFileSystem.test(),
fileSystemRoots: <String>[
'/foo/bar/fizz',
],
fileSystemScheme: 'scheme',
logger: BufferLogger.test(),
processManager: mockProcessManager
);
await 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',
);
expect(latestCommand, containsAll(<String>['scheme:///main.dart']));
});
}
class MockProcess extends Mock implements Process {}
class MockProcessManager extends Mock implements ProcessManager {}