Unverified Commit 64add554 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

handle unexpected exit from frontend server (#38497)

parent cbad1c41
...@@ -569,6 +569,7 @@ class ResidentCompiler { ...@@ -569,6 +569,7 @@ class ResidentCompiler {
// process has died unexpectedly. // process has died unexpectedly.
if (!_stdoutHandler.compilerOutput.isCompleted) { if (!_stdoutHandler.compilerOutput.isCompleted) {
_stdoutHandler.compilerOutput.complete(null); _stdoutHandler.compilerOutput.complete(null);
throwToolExit('the Dart compiler exited unexpectedly.');
} }
}); });
...@@ -577,6 +578,12 @@ class ResidentCompiler { ...@@ -577,6 +578,12 @@ class ResidentCompiler {
.transform<String>(const LineSplitter()) .transform<String>(const LineSplitter())
.listen((String message) { printError(message); }); .listen((String message) { printError(message); });
unawaited(_server.exitCode.then((int code) {
if (code != 0) {
throwToolExit('the Dart compiler exited unexpectedly.');
}
}));
_server.stdin.writeln('compile $scriptUri'); _server.stdin.writeln('compile $scriptUri');
printTrace('<- compile $scriptUri'); printTrace('<- compile $scriptUri');
......
// Copyright 2017 The Chromium 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: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/base/terminal.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:mockito/mockito.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;
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) => Future<Process>.value(mockFrontendServer));
when(mockFrontendServer.exitCode).thenAnswer((_) async => 0);
});
testUsingContext('batch compile single dart successful compilation', () async {
final BufferLogger bufferLogger = logger;
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 = await kernelCompilerFactory.create(null);
final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
trackWidgetCreation: false,
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(bufferLogger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
expect(output.outputFilename, equals('/path/to/main.dart.dill'));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('batch compile single dart failed compilation', () async {
final BufferLogger bufferLogger = logger;
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
'result abc\nline1\nline2\nabc\nabc'
))
));
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(null);
final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
trackWidgetCreation: false,
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(bufferLogger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
expect(output, equals(null));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('batch compile single dart abnormal compiler termination', () async {
when(mockFrontendServer.exitCode).thenAnswer((_) async => 255);
final BufferLogger bufferLogger = logger;
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
'result abc\nline1\nline2\nabc\nabc'
))
));
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(null);
final CompilerOutput output = await kernelCompiler.compile(
sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
trackWidgetCreation: false,
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(bufferLogger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
expect(output, equals(null));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
}
class MockProcess extends Mock implements Process {}
class MockProcessManager extends Mock implements ProcessManager {}
// Copyright 2017 The Chromium 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:flutter_tools/src/base/common.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/base/terminal.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
ProcessManager mockProcessManager;
ResidentCompiler generator;
MockProcess mockFrontendServer;
MockStdIn mockFrontendServerStdIn;
MockStream mockFrontendServerStdErr;
StreamController<String> stdErrStreamController;
setUp(() {
generator = ResidentCompiler('sdkroot');
mockProcessManager = MockProcessManager();
mockFrontendServer = MockProcess();
mockFrontendServerStdIn = MockStdIn();
mockFrontendServerStdErr = MockStream();
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
when(mockFrontendServer.stderr)
.thenAnswer((Invocation invocation) => mockFrontendServerStdErr);
when(mockFrontendServer.exitCode).thenAnswer((Invocation invocation) {
return Completer<int>().future;
});
stdErrStreamController = StreamController<String>();
when(mockFrontendServerStdErr.transform<String>(any))
.thenAnswer((Invocation invocation) => stdErrStreamController.stream);
when(mockProcessManager.canRun(any)).thenReturn(true);
when(mockProcessManager.start(any)).thenAnswer(
(Invocation invocation) =>
Future<Process>.value(mockFrontendServer)
);
});
testUsingContext('compile expression fails if not previously compiled', () async {
final CompilerOutput result = await generator.compileExpression(
'2+2', null, null, null, null, false);
expect(result, isNull);
});
testUsingContext('compile expression can compile single expression', () async {
final BufferLogger bufferLogger = logger;
final Completer<List<int>> compileResponseCompleter =
Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter =
Completer<List<int>>();
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) =>
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(
'/path/to/main.dart',
null, /* invalidatedFiles */
outputPath: '/build/',
).then((CompilerOutput output) {
expect(mockFrontendServerStdIn.getAndClear(),
'compile /path/to/main.dart\n');
verifyNoMoreInteractions(mockFrontendServerStdIn);
expect(bufferLogger.errorText,
equals('\nCompiler message:\nline1\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, false).then(
(CompilerOutput outputExpression) {
expect(outputExpression, isNotNull);
expect(outputExpression.outputFilename, equals('/path/to/main.dart.dill.incremental'));
expect(outputExpression.errorCount, 0);
}
);
});
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Logger: () => BufferLogger(),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('compile expressions without awaiting', () async {
final BufferLogger bufferLogger = logger;
final Completer<List<int>> compileResponseCompleter = Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter1 = Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter2 = Completer<List<int>>();
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) =>
Stream<List<int>>.fromFutures(
<Future<List<int>>>[
compileResponseCompleter.future,
compileExpressionResponseCompleter1.future,
compileExpressionResponseCompleter2.future,
]));
// The test manages timing via completers.
unawaited(
generator.recompile(
'/path/to/main.dart',
null, /* invalidatedFiles */
outputPath: '/build/',
).then((CompilerOutput outputCompile) {
expect(bufferLogger.errorText,
equals('\nCompiler message:\nline1\nline2\n'));
expect(outputCompile.outputFilename, equals('/path/to/main.dart.dill'));
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, false).then(
(CompilerOutput outputExpression) {
expect(outputExpression, isNotNull);
expect(outputExpression.outputFilename,
equals('/path/to/main.dart.dill.incremental'));
expect(outputExpression.errorCount, 0);
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, false).then(
(CompilerOutput outputExpression) {
expect(outputExpression, isNotNull);
expect(outputExpression.outputFilename,
equals('/path/to/main.dart.dill.incremental'));
expect(outputExpression.errorCount, 0);
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);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
}
class MockProcess extends Mock implements Process {}
class MockProcessManager extends Mock implements ProcessManager {}
// Copyright 2017 The Chromium 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:flutter_tools/src/base/async_guard.dart';
import 'package:flutter_tools/src/base/common.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/base/terminal.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
ProcessManager mockProcessManager;
ResidentCompiler generator;
MockProcess mockFrontendServer;
MockStdIn mockFrontendServerStdIn;
MockStream mockFrontendServerStdErr;
StreamController<String> stdErrStreamController;
setUp(() {
generator = ResidentCompiler('sdkroot');
mockProcessManager = MockProcessManager();
mockFrontendServer = MockProcess();
mockFrontendServerStdIn = MockStdIn();
mockFrontendServerStdErr = MockStream();
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
when(mockFrontendServer.stderr)
.thenAnswer((Invocation invocation) => mockFrontendServerStdErr);
when(mockFrontendServer.exitCode).thenAnswer((Invocation invocation) {
return Completer<int>().future;
});
stdErrStreamController = StreamController<String>();
when(mockFrontendServerStdErr.transform<String>(any))
.thenAnswer((Invocation invocation) => stdErrStreamController.stream);
when(mockProcessManager.canRun(any)).thenReturn(true);
when(mockProcessManager.start(any)).thenAnswer(
(Invocation invocation) => Future<Process>.value(mockFrontendServer)
);
});
testUsingContext('incremental compile single dart compile', () async {
final BufferLogger bufferLogger = logger;
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 CompilerOutput output = await generator.recompile(
'/path/to/main.dart',
null /* invalidatedFiles */,
outputPath: '/build/',
);
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
verifyNoMoreInteractions(mockFrontendServerStdIn);
expect(bufferLogger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
expect(output.outputFilename, equals('/path/to/main.dart.dill'));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile single dart compile abnormally terminates', () async {
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => const Stream<List<int>>.empty()
);
expect(asyncGuard(() => generator.recompile(
'/path/to/main.dart',
null, /* invalidatedFiles */
outputPath: '/build/',
)), throwsA(isInstanceOf<ToolExit>()));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile single dart compile abnormally terminates via exitCode', () async {
when(mockFrontendServer.exitCode)
.thenAnswer((Invocation invocation) async => 1);
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => const Stream<List<int>>.empty()
);
expect(asyncGuard(() => generator.recompile(
'/path/to/main.dart',
null, /* invalidatedFiles */
outputPath: '/build/',
)), throwsA(isInstanceOf<ToolExit>()));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile and recompile', () async {
final BufferLogger bufferLogger = logger;
final StreamController<List<int>> streamController = StreamController<List<int>>();
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => streamController.stream);
streamController.add(utf8.encode('result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n'));
await generator.recompile(
'/path/to/main.dart',
null, /* invalidatedFiles */
outputPath: '/build/',
);
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
// No accept or reject commands should be issued until we
// send recompile request.
await _accept(streamController, generator, mockFrontendServerStdIn, '');
await _reject(streamController, generator, mockFrontendServerStdIn, '', '');
await _recompile(streamController, generator, mockFrontendServerStdIn,
'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n');
await _accept(streamController, generator, mockFrontendServerStdIn, '^accept\\n\$');
await _recompile(streamController, generator, mockFrontendServerStdIn,
'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n');
// No sources returned from reject command.
await _reject(streamController, generator, mockFrontendServerStdIn, 'result abc\nabc\n',
'^reject\\n\$');
verifyNoMoreInteractions(mockFrontendServerStdIn);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(bufferLogger.errorText, equals(
'\nCompiler message:\nline0\nline1\n'
'\nCompiler message:\nline1\nline2\n'
'\nCompiler message:\nline1\nline2\n'
));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile and recompile twice', () async {
final BufferLogger bufferLogger = logger;
final StreamController<List<int>> streamController = StreamController<List<int>>();
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => streamController.stream);
streamController.add(utf8.encode(
'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n'
));
await generator.recompile('/path/to/main.dart', null /* invalidatedFiles */, outputPath: '/build/');
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
await _recompile(streamController, generator, mockFrontendServerStdIn,
'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n');
await _recompile(streamController, generator, mockFrontendServerStdIn,
'result abc\nline2\nline3\nabc\nabc /path/to/main.dart.dill 0\n');
verifyNoMoreInteractions(mockFrontendServerStdIn);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(bufferLogger.errorText, equals(
'\nCompiler message:\nline0\nline1\n'
'\nCompiler message:\nline1\nline2\n'
'\nCompiler message:\nline2\nline3\n'
));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
}
Future<void> _recompile(
StreamController<List<int>> streamController,
ResidentCompiler generator,
MockStdIn mockFrontendServerStdIn,
String mockCompilerOutput,
) async {
// Put content into the output stream after generator.recompile gets
// going few lines below, resets completer.
scheduleMicrotask(() {
streamController.add(utf8.encode(mockCompilerOutput));
});
final CompilerOutput output = await generator.recompile(
null /* mainPath */,
<Uri>[Uri.parse('/path/to/main.dart')],
outputPath: '/build/',
);
expect(output.outputFilename, equals('/path/to/main.dart.dill'));
final String commands = mockFrontendServerStdIn.getAndClear();
final RegExp re = RegExp('^recompile (.*)\\n/path/to/main.dart\\n(.*)\\n\$');
expect(commands, matches(re));
final Match match = re.firstMatch(commands);
expect(match[1] == match[2], isTrue);
mockFrontendServerStdIn.stdInWrites.clear();
}
Future<void> _accept(
StreamController<List<int>> streamController,
ResidentCompiler generator,
MockStdIn mockFrontendServerStdIn,
String expected,
) async {
// Put content into the output stream after generator.recompile gets
// going few lines below, resets completer.
generator.accept();
final String commands = mockFrontendServerStdIn.getAndClear();
final RegExp re = RegExp(expected);
expect(commands, matches(re));
mockFrontendServerStdIn.stdInWrites.clear();
}
Future<void> _reject(
StreamController<List<int>> streamController,
ResidentCompiler generator,
MockStdIn mockFrontendServerStdIn,
String mockCompilerOutput,
String expected,
) async {
// Put content into the output stream after generator.recompile gets
// going few lines below, resets completer.
scheduleMicrotask(() {
streamController.add(utf8.encode(mockCompilerOutput));
});
final CompilerOutput output = await generator.reject();
expect(output, isNull);
final String commands = mockFrontendServerStdIn.getAndClear();
final RegExp re = RegExp(expected);
expect(commands, matches(re));
mockFrontendServerStdIn.stdInWrites.clear();
}
class MockProcess extends Mock implements Process {}
class MockProcessManager extends Mock implements ProcessManager {}
// Copyright 2017 The Chromium 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 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
import '../src/context.dart';
const String packagesContents = r'''
xml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/xml-3.2.3/lib/
yaml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib/
example:file:///example/lib/
''';
const String multiRootPackagesContents = r'''
xml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/xml-3.2.3/lib/
yaml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib/
example:org-dartlang-app:/
''';
void main() {
MockFileSystem mockFileSystem;
MockFile mockFile;
setUp(() {
mockFileSystem = MockFileSystem();
mockFile = MockFile();
when(mockFileSystem.path).thenReturn(fs.path);
when(mockFileSystem.file(any)).thenReturn(mockFile);
when(mockFile.readAsBytesSync()).thenReturn(utf8.encode(packagesContents));
});
testUsingContext('Can map main.dart to correct package', () async {
final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
expect(packageUriMapper.map('/example/lib/main.dart').toString(),
'package:example/main.dart');
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
});
testUsingContext('single-root maps file from other package to null', () async {
final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
expect(packageUriMapper.map('/xml/lib/xml.dart'), null);
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
});
testUsingContext('single-root maps non-main file from same package', () async {
final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
expect(packageUriMapper.map('/example/lib/src/foo.dart').toString(),
'package:example/src/foo.dart');
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
});
testUsingContext('multi-root maps main file from same package on multiroot scheme', () async {
final MockFileSystem mockFileSystem = MockFileSystem();
final MockFile mockFile = MockFile();
when(mockFileSystem.path).thenReturn(fs.path);
when(mockFileSystem.file(any)).thenReturn(mockFile);
when(mockFile.readAsBytesSync())
.thenReturn(utf8.encode(multiRootPackagesContents));
final PackageUriMapper packageUriMapper = PackageUriMapper(
'/example/lib/main.dart',
'.packages',
'org-dartlang-app',
<String>['/example/lib/', '/gen/lib/']);
expect(packageUriMapper.map('/example/lib/main.dart').toString(),
'package:example/main.dart');
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
});
}
class MockFileSystem extends Mock implements FileSystem {}
class MockFile extends Mock implements File {}
...@@ -9,6 +9,7 @@ import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException; ...@@ -9,6 +9,7 @@ import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException;
import 'package:flutter_tools/src/android/android_device.dart'; import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/android/android_sdk.dart' show AndroidSdk; import 'package:flutter_tools/src/android/android_sdk.dart' show AndroidSdk;
import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart' hide IOSink; import 'package:flutter_tools/src/base/file_system.dart' hide IOSink;
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
...@@ -25,6 +26,8 @@ import 'package:process/process.dart'; ...@@ -25,6 +26,8 @@ import 'package:process/process.dart';
import 'common.dart'; import 'common.dart';
final Generator kNoColorTerminalPlatform = () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false;
class MockApplicationPackageStore extends ApplicationPackageStore { class MockApplicationPackageStore extends ApplicationPackageStore {
MockApplicationPackageStore() : super( MockApplicationPackageStore() : super(
android: AndroidApk( android: AndroidApk(
...@@ -611,3 +614,25 @@ class FakeProcessResult implements ProcessResult { ...@@ -611,3 +614,25 @@ class FakeProcessResult implements ProcessResult {
@override @override
String toString() => stdout?.toString() ?? stderr?.toString() ?? runtimeType.toString(); String toString() => stdout?.toString() ?? stderr?.toString() ?? runtimeType.toString();
} }
class MockStdIn extends Mock implements IOSink {
final StringBuffer stdInWrites = StringBuffer();
String getAndClear() {
final String result = stdInWrites.toString();
stdInWrites.clear();
return result;
}
@override
void write([ Object o = '' ]) {
stdInWrites.write(o);
}
@override
void writeln([ Object o = '' ]) {
stdInWrites.writeln(o);
}
}
class MockStream extends Mock implements Stream<List<int>> {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment