2017-08-31 20:35:55 +00:00
|
|
|
// 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 'dart:convert';
|
|
|
|
|
|
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
|
|
import 'package:flutter_tools/src/base/context.dart';
|
|
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
|
|
import 'package:flutter_tools/src/compile.dart';
|
|
|
|
import 'package:mockito/mockito.dart';
|
|
|
|
import 'package:process/process.dart';
|
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
import 'src/context.dart';
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
group('batch compile', () {
|
|
|
|
ProcessManager mockProcessManager;
|
|
|
|
MockProcess mockFrontendServer;
|
|
|
|
MockStdIn mockFrontendServerStdIn;
|
|
|
|
MockStream mockFrontendServerStdErr;
|
|
|
|
setUp(() {
|
|
|
|
mockProcessManager = new MockProcessManager();
|
|
|
|
mockFrontendServer = new MockProcess();
|
|
|
|
mockFrontendServerStdIn = new MockStdIn();
|
|
|
|
mockFrontendServerStdErr = new MockStream();
|
|
|
|
|
|
|
|
when(mockFrontendServer.stderr).thenReturn(mockFrontendServerStdErr);
|
|
|
|
final StreamController<String> stdErrStreamController = new StreamController<String>();
|
|
|
|
when(mockFrontendServerStdErr.transform<String>(any)).thenReturn(stdErrStreamController.stream);
|
|
|
|
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
|
|
|
|
when(mockProcessManager.start(any)).thenReturn(new Future<Process>.value(mockFrontendServer));
|
|
|
|
when(mockFrontendServer.exitCode).thenReturn(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
testUsingContext('single dart successful compilation', () async {
|
|
|
|
final BufferLogger logger = context[Logger];
|
|
|
|
when(mockFrontendServer.stdout).thenReturn(new Stream<List<int>>.fromFuture(
|
|
|
|
new Future<List<int>>.value(UTF8.encode(
|
|
|
|
'result abc\nline1\nline2\nabc /path/to/main.dart.dill'
|
|
|
|
))
|
|
|
|
));
|
|
|
|
final String output = await compile(sdkRoot: '/path/to/sdkroot',
|
|
|
|
mainPath: '/path/to/main.dart'
|
|
|
|
);
|
2017-10-25 06:25:44 +00:00
|
|
|
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
|
2017-08-31 20:35:55 +00:00
|
|
|
expect(logger.traceText, equals('compile debug message: line1\ncompile debug message: line2\n'));
|
|
|
|
expect(output, equals('/path/to/main.dart.dill'));
|
|
|
|
}, overrides: <Type, Generator>{
|
|
|
|
ProcessManager: () => mockProcessManager,
|
|
|
|
});
|
|
|
|
|
|
|
|
testUsingContext('single dart failed compilation', () async {
|
|
|
|
final BufferLogger logger = context[Logger];
|
|
|
|
|
|
|
|
when(mockFrontendServer.stdout).thenReturn(new Stream<List<int>>.fromFuture(
|
|
|
|
new Future<List<int>>.value(UTF8.encode(
|
|
|
|
'result abc\nline1\nline2\nabc'
|
|
|
|
))
|
|
|
|
));
|
|
|
|
|
|
|
|
final String output = await compile(sdkRoot: '/path/to/sdkroot',
|
|
|
|
mainPath: '/path/to/main.dart'
|
|
|
|
);
|
2017-10-25 06:25:44 +00:00
|
|
|
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
|
2017-08-31 20:35:55 +00:00
|
|
|
expect(logger.traceText, equals('compile debug message: line1\ncompile debug message: line2\n'));
|
|
|
|
expect(output, equals(null));
|
|
|
|
}, overrides: <Type, Generator>{
|
|
|
|
ProcessManager: () => mockProcessManager,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
group('incremental compile', () {
|
|
|
|
ProcessManager mockProcessManager;
|
|
|
|
ResidentCompiler generator;
|
|
|
|
MockProcess mockFrontendServer;
|
|
|
|
MockStdIn mockFrontendServerStdIn;
|
|
|
|
MockStream mockFrontendServerStdErr;
|
|
|
|
StreamController<String> stdErrStreamController;
|
|
|
|
|
|
|
|
setUp(() {
|
|
|
|
generator = new ResidentCompiler('sdkroot');
|
|
|
|
mockProcessManager = new MockProcessManager();
|
|
|
|
mockFrontendServer = new MockProcess();
|
|
|
|
mockFrontendServerStdIn = new MockStdIn();
|
|
|
|
mockFrontendServerStdErr = new MockStream();
|
|
|
|
|
|
|
|
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
|
|
|
|
when(mockFrontendServer.stderr).thenReturn(mockFrontendServerStdErr);
|
|
|
|
stdErrStreamController = new StreamController<String>();
|
|
|
|
when(mockFrontendServerStdErr.transform<String>(any)).thenReturn(stdErrStreamController.stream);
|
|
|
|
|
|
|
|
when(mockProcessManager.start(any)).thenReturn(
|
|
|
|
new Future<Process>.value(mockFrontendServer)
|
|
|
|
);
|
|
|
|
when(mockFrontendServer.exitCode).thenReturn(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
testUsingContext('single dart compile', () async {
|
|
|
|
final BufferLogger logger = context[Logger];
|
|
|
|
|
|
|
|
when(mockFrontendServer.stdout).thenReturn(new Stream<List<int>>.fromFuture(
|
|
|
|
new Future<List<int>>.value(UTF8.encode(
|
|
|
|
'result abc\nline1\nline2\nabc /path/to/main.dart.dill'
|
|
|
|
))
|
|
|
|
));
|
|
|
|
|
|
|
|
final String output = await generator.recompile(
|
|
|
|
'/path/to/main.dart', null /* invalidatedFiles */
|
|
|
|
);
|
2017-10-25 06:25:44 +00:00
|
|
|
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
|
2017-08-31 20:35:55 +00:00
|
|
|
verifyNoMoreInteractions(mockFrontendServerStdIn);
|
|
|
|
expect(logger.traceText, equals('compile debug message: line1\ncompile debug message: line2\n'));
|
|
|
|
expect(output, equals('/path/to/main.dart.dill'));
|
|
|
|
}, overrides: <Type, Generator>{
|
|
|
|
ProcessManager: () => mockProcessManager,
|
|
|
|
});
|
|
|
|
|
|
|
|
testUsingContext('compile and recompile', () async {
|
|
|
|
final BufferLogger logger = context[Logger];
|
|
|
|
|
2017-09-13 14:33:52 +00:00
|
|
|
final StreamController<List<int>> streamController = new StreamController<List<int>>();
|
|
|
|
when(mockFrontendServer.stdout).thenReturn(streamController.stream);
|
|
|
|
streamController.add(UTF8.encode('result abc\nline0\nline1\nabc /path/to/main.dart.dill\n'));
|
|
|
|
await generator.recompile('/path/to/main.dart', null /* invalidatedFiles */);
|
2017-10-25 06:25:44 +00:00
|
|
|
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
|
2017-09-13 14:33:52 +00:00
|
|
|
|
|
|
|
await _recompile(streamController, generator, mockFrontendServerStdIn,
|
|
|
|
'result abc\nline1\nline2\nabc /path/to/main.dart.dill\n');
|
|
|
|
|
|
|
|
verifyNoMoreInteractions(mockFrontendServerStdIn);
|
2017-10-25 06:25:44 +00:00
|
|
|
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
|
2017-09-13 14:33:52 +00:00
|
|
|
expect(logger.traceText, equals(
|
|
|
|
'compile debug message: line0\ncompile debug message: line1\n'
|
|
|
|
'compile debug message: line1\ncompile debug message: line2\n'
|
2017-08-31 20:35:55 +00:00
|
|
|
));
|
2017-09-13 14:33:52 +00:00
|
|
|
}, overrides: <Type, Generator>{
|
|
|
|
ProcessManager: () => mockProcessManager,
|
|
|
|
});
|
2017-08-31 20:35:55 +00:00
|
|
|
|
2017-09-13 14:33:52 +00:00
|
|
|
testUsingContext('compile and recompile twice', () async {
|
|
|
|
final BufferLogger logger = context[Logger];
|
|
|
|
|
|
|
|
final StreamController<List<int>> streamController = new StreamController<List<int>>();
|
|
|
|
when(mockFrontendServer.stdout).thenReturn(streamController.stream);
|
|
|
|
streamController.add(UTF8.encode(
|
|
|
|
'result abc\nline0\nline1\nabc /path/to/main.dart.dill\n'
|
|
|
|
));
|
2017-08-31 20:35:55 +00:00
|
|
|
await generator.recompile('/path/to/main.dart', null /* invalidatedFiles */);
|
2017-10-25 06:25:44 +00:00
|
|
|
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
|
2017-08-31 20:35:55 +00:00
|
|
|
|
2017-09-13 14:33:52 +00:00
|
|
|
await _recompile(streamController, generator, mockFrontendServerStdIn,
|
|
|
|
'result abc\nline1\nline2\nabc /path/to/main.dart.dill\n');
|
|
|
|
await _recompile(streamController, generator, mockFrontendServerStdIn,
|
|
|
|
'result abc\nline2\nline3\nabc /path/to/main.dart.dill\n');
|
|
|
|
|
2017-08-31 20:35:55 +00:00
|
|
|
verifyNoMoreInteractions(mockFrontendServerStdIn);
|
2017-10-25 06:25:44 +00:00
|
|
|
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
|
2017-09-13 14:33:52 +00:00
|
|
|
expect(logger.traceText, equals(
|
|
|
|
'compile debug message: line0\ncompile debug message: line1\n'
|
|
|
|
'compile debug message: line1\ncompile debug message: line2\n'
|
|
|
|
'compile debug message: line2\ncompile debug message: line3\n'
|
|
|
|
));
|
2017-08-31 20:35:55 +00:00
|
|
|
}, overrides: <Type, Generator>{
|
|
|
|
ProcessManager: () => mockProcessManager,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-09-13 14:33:52 +00:00
|
|
|
Future<Null> _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.
|
|
|
|
new Future<List<int>>(() {
|
|
|
|
streamController.add(UTF8.encode(mockCompilerOutput));
|
|
|
|
});
|
|
|
|
final String output = await generator.recompile(null /* mainPath */, <String>['/path/to/main.dart']);
|
|
|
|
expect(output, equals('/path/to/main.dart.dill'));
|
2017-10-25 06:25:44 +00:00
|
|
|
final String commands = mockFrontendServerStdIn.getAndClear();
|
|
|
|
final RegExp re = new RegExp(r'^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();
|
2017-09-13 14:33:52 +00:00
|
|
|
}
|
|
|
|
|
2017-08-31 20:35:55 +00:00
|
|
|
class MockProcessManager extends Mock implements ProcessManager {}
|
|
|
|
class MockProcess extends Mock implements Process {}
|
|
|
|
class MockStream extends Mock implements Stream<List<int>> {}
|
2017-10-25 06:25:44 +00:00
|
|
|
class MockStdIn extends Mock implements IOSink {
|
|
|
|
final StringBuffer _stdInWrites = new 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);
|
|
|
|
}
|
|
|
|
}
|