mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:27:17 +00:00
8652404193
Change-Id: Iecf2f40dd1bc8c0fffd877911e81ccd6055d9dc0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/136121 Reviewed-by: Karl Klose <karlklose@google.com> Commit-Queue: Jens Johansen <jensj@google.com>
365 lines
11 KiB
Dart
365 lines
11 KiB
Dart
import 'dart:async' show StreamController;
|
|
import 'dart:convert' show utf8, LineSplitter;
|
|
import 'dart:io' show Directory, File, FileSystemEntity, IOSink, exitCode;
|
|
|
|
import 'package:kernel/ast.dart' show Component;
|
|
import 'package:kernel/kernel.dart' show loadComponentFromBytes;
|
|
import 'package:kernel/verifier.dart' show verifyComponent;
|
|
|
|
import '../lib/frontend_server.dart';
|
|
|
|
main(List<String> args) async {
|
|
String flutterDir;
|
|
String flutterPlatformDir;
|
|
for (String arg in args) {
|
|
if (arg.startsWith("--flutterDir=")) {
|
|
flutterDir = arg.substring(13);
|
|
} else if (arg.startsWith("--flutterPlatformDir=")) {
|
|
flutterPlatformDir = arg.substring(21);
|
|
}
|
|
}
|
|
|
|
await compileTests(flutterDir, flutterPlatformDir, new StdoutLogger());
|
|
}
|
|
|
|
Future compileTests(String flutterDir, String flutterPlatformDir, Logger logger,
|
|
{String filter}) async {
|
|
if (flutterDir == null || !(new Directory(flutterDir).existsSync())) {
|
|
throw "Didn't get a valid flutter directory to work with.";
|
|
}
|
|
Directory flutterDirectory = new Directory(flutterDir);
|
|
// Ensure the path ends in a slash.
|
|
flutterDirectory = new Directory.fromUri(flutterDirectory.uri);
|
|
|
|
List<FileSystemEntity> allFlutterFiles =
|
|
flutterDirectory.listSync(recursive: true, followLinks: false);
|
|
Directory flutterPlatformDirectory;
|
|
|
|
if (flutterPlatformDir == null) {
|
|
List<File> platformFiles = new List<File>.from(allFlutterFiles.where((f) =>
|
|
f.uri
|
|
.toString()
|
|
.endsWith("/flutter_patched_sdk/platform_strong.dill")));
|
|
if (platformFiles.length < 1) {
|
|
throw "Expected to find a flutter platform file but didn't.";
|
|
}
|
|
flutterPlatformDirectory = platformFiles.first.parent;
|
|
} else {
|
|
flutterPlatformDirectory = Directory(flutterPlatformDir);
|
|
}
|
|
if (!flutterPlatformDirectory.existsSync()) {
|
|
throw "$flutterPlatformDirectory doesn't exist.";
|
|
}
|
|
// Ensure the path ends in a slash.
|
|
flutterPlatformDirectory =
|
|
new Directory.fromUri(flutterPlatformDirectory.uri);
|
|
|
|
if (!new File.fromUri(
|
|
flutterPlatformDirectory.uri.resolve("platform_strong.dill"))
|
|
.existsSync()) {
|
|
throw "$flutterPlatformDirectory doesn't contain a "
|
|
"platform_strong.dill file.";
|
|
}
|
|
logger.notice("Using $flutterPlatformDirectory as platform directory.");
|
|
List<File> dotPackagesFiles = new List<File>.from(allFlutterFiles.where((f) =>
|
|
(f.uri.toString().contains("/examples/") ||
|
|
f.uri.toString().contains("/packages/")) &&
|
|
f.uri.toString().endsWith("/.packages")));
|
|
|
|
List<String> allCompilationErrors = [];
|
|
for (File dotPackage in dotPackagesFiles) {
|
|
Directory tempDir;
|
|
Directory systemTempDir = Directory.systemTemp;
|
|
tempDir = systemTempDir.createTempSync('flutter_frontend_test');
|
|
try {
|
|
Directory testDir =
|
|
new Directory.fromUri(dotPackage.parent.uri.resolve("test/"));
|
|
if (!testDir.existsSync()) continue;
|
|
if (testDir.toString().contains("packages/flutter_web_plugins/test/")) {
|
|
// TODO(jensj): Figure out which tests are web-tests, and compile those
|
|
// in a setup that can handle that.
|
|
continue;
|
|
}
|
|
logger.notice("Go for $testDir");
|
|
List<String> compilationErrors = await attemptStuff(
|
|
tempDir,
|
|
flutterPlatformDirectory,
|
|
dotPackage,
|
|
testDir,
|
|
flutterDirectory,
|
|
logger,
|
|
filter);
|
|
if (compilationErrors.isNotEmpty) {
|
|
logger.notice("Notice that we had ${compilationErrors.length} "
|
|
"compilation errors for $testDir");
|
|
allCompilationErrors.addAll(compilationErrors);
|
|
}
|
|
} finally {
|
|
tempDir.delete(recursive: true);
|
|
}
|
|
}
|
|
if (allCompilationErrors.isNotEmpty) {
|
|
logger.notice(
|
|
"Had a total of ${allCompilationErrors.length} compilation errors:");
|
|
allCompilationErrors.forEach(logger.notice);
|
|
exitCode = 1;
|
|
}
|
|
}
|
|
|
|
Future<List<String>> attemptStuff(
|
|
Directory tempDir,
|
|
Directory flutterPlatformDirectory,
|
|
File dotPackage,
|
|
Directory testDir,
|
|
Directory flutterDirectory,
|
|
Logger logger,
|
|
String filter) async {
|
|
List<File> testFiles =
|
|
new List<File>.from(testDir.listSync(recursive: true).where((f) {
|
|
if (!f.path.endsWith("_test.dart")) return false;
|
|
if (filter != null) {
|
|
String testName = f.path.substring(flutterDirectory.path.length);
|
|
if (!testName.startsWith(filter)) return false;
|
|
}
|
|
return true;
|
|
}));
|
|
if (testFiles.isEmpty) return [];
|
|
|
|
File dillFile = new File('${tempDir.path}/dill.dill');
|
|
if (dillFile.existsSync()) {
|
|
throw "$dillFile already exists.";
|
|
}
|
|
|
|
List<int> platformData = new File.fromUri(
|
|
flutterPlatformDirectory.uri.resolve("platform_strong.dill"))
|
|
.readAsBytesSync();
|
|
final List<String> args = <String>[
|
|
'--sdk-root',
|
|
flutterPlatformDirectory.path,
|
|
'--incremental',
|
|
'--target=flutter',
|
|
'--packages',
|
|
dotPackage.path,
|
|
'--output-dill=${dillFile.path}',
|
|
// '--unsafe-package-serialization',
|
|
];
|
|
|
|
Stopwatch stopwatch = new Stopwatch()..start();
|
|
|
|
final StreamController<List<int>> inputStreamController =
|
|
new StreamController<List<int>>();
|
|
final StreamController<List<int>> stdoutStreamController =
|
|
new StreamController<List<int>>();
|
|
final IOSink ioSink = new IOSink(stdoutStreamController.sink);
|
|
StreamController<Result> receivedResults = new StreamController<Result>();
|
|
|
|
final outputParser = new OutputParser(receivedResults);
|
|
stdoutStreamController.stream
|
|
.transform(utf8.decoder)
|
|
.transform(const LineSplitter())
|
|
.listen(outputParser.listener);
|
|
|
|
Iterator<File> testFileIterator = testFiles.iterator;
|
|
testFileIterator.moveNext();
|
|
|
|
final Future<int> result =
|
|
starter(args, input: inputStreamController.stream, output: ioSink);
|
|
String testName =
|
|
testFileIterator.current.path.substring(flutterDirectory.path.length);
|
|
|
|
logger.logTestStart(testName);
|
|
logger.notice(" => $testName");
|
|
Stopwatch stopwatch2 = new Stopwatch()..start();
|
|
inputStreamController
|
|
.add('compile ${testFileIterator.current.path}\n'.codeUnits);
|
|
int compilations = 0;
|
|
List<String> compilationErrors = [];
|
|
receivedResults.stream.listen((Result compiledResult) {
|
|
logger.notice(" --- done in ${stopwatch2.elapsedMilliseconds} ms\n");
|
|
stopwatch2.reset();
|
|
bool error = false;
|
|
try {
|
|
compiledResult.expectNoErrors();
|
|
logger.logExpectedResult(testName);
|
|
} catch (e) {
|
|
logger.log("Got errors. Compiler output for this compile:");
|
|
outputParser.allReceived.forEach(logger.log);
|
|
compilationErrors.add(testFileIterator.current.path);
|
|
error = true;
|
|
logger.logUnexpectedResult(testName);
|
|
}
|
|
if (!error) {
|
|
List<int> resultBytes = dillFile.readAsBytesSync();
|
|
Component component = loadComponentFromBytes(platformData);
|
|
component = loadComponentFromBytes(resultBytes, component);
|
|
verifyComponent(component);
|
|
logger
|
|
.log(" => verified in ${stopwatch2.elapsedMilliseconds} ms.");
|
|
}
|
|
stopwatch2.reset();
|
|
|
|
inputStreamController.add('accept\n'.codeUnits);
|
|
inputStreamController.add('reset\n'.codeUnits);
|
|
compilations++;
|
|
outputParser.allReceived.clear();
|
|
|
|
if (!testFileIterator.moveNext()) {
|
|
inputStreamController.add('quit\n'.codeUnits);
|
|
return;
|
|
}
|
|
|
|
testName =
|
|
testFileIterator.current.path.substring(flutterDirectory.path.length);
|
|
logger.logTestStart(testName);
|
|
logger.notice(" => $testName");
|
|
inputStreamController.add('recompile ${testFileIterator.current.path} abc\n'
|
|
'${testFileIterator.current.uri}\n'
|
|
'abc\n'
|
|
.codeUnits);
|
|
});
|
|
|
|
int resultDone = await result;
|
|
if (resultDone != 0) {
|
|
throw "Got $resultDone, expected 0";
|
|
}
|
|
|
|
inputStreamController.close();
|
|
|
|
logger.log("Did $compilations compilations and verifications in "
|
|
"${stopwatch.elapsedMilliseconds} ms.");
|
|
|
|
return compilationErrors;
|
|
}
|
|
|
|
// The below is copied from incremental_compiler_test.dart,
|
|
// but with expect stuff replaced with ifs and throws
|
|
// (expect can only be used in tests via the test framework).
|
|
|
|
class OutputParser {
|
|
OutputParser(this._receivedResults);
|
|
bool expectSources = true;
|
|
|
|
StreamController<Result> _receivedResults;
|
|
List<String> _receivedSources;
|
|
|
|
String _boundaryKey;
|
|
bool _readingSources;
|
|
|
|
List<String> allReceived = new List<String>();
|
|
|
|
void listener(String s) {
|
|
allReceived.add(s);
|
|
if (_boundaryKey == null) {
|
|
const String RESULT_OUTPUT_SPACE = 'result ';
|
|
if (s.startsWith(RESULT_OUTPUT_SPACE)) {
|
|
_boundaryKey = s.substring(RESULT_OUTPUT_SPACE.length);
|
|
}
|
|
_readingSources = false;
|
|
_receivedSources?.clear();
|
|
return;
|
|
}
|
|
|
|
if (s.startsWith(_boundaryKey)) {
|
|
// First boundaryKey separates compiler output from list of sources
|
|
// (if we expect list of sources, which is indicated by receivedSources
|
|
// being not null)
|
|
if (expectSources && !_readingSources) {
|
|
_readingSources = true;
|
|
return;
|
|
}
|
|
// Second boundaryKey indicates end of frontend server response
|
|
expectSources = true;
|
|
_receivedResults.add(new Result(
|
|
s.length > _boundaryKey.length
|
|
? s.substring(_boundaryKey.length + 1)
|
|
: null,
|
|
_receivedSources));
|
|
_boundaryKey = null;
|
|
} else {
|
|
if (_readingSources) {
|
|
if (_receivedSources == null) {
|
|
_receivedSources = <String>[];
|
|
}
|
|
_receivedSources.add(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class Result {
|
|
String status;
|
|
List<String> sources;
|
|
|
|
Result(this.status, this.sources);
|
|
|
|
void expectNoErrors({String filename}) {
|
|
CompilationResult result = new CompilationResult.parse(status);
|
|
if (result.errorsCount != 0) {
|
|
throw "Got ${result.errorsCount} errors. Expected 0.";
|
|
}
|
|
if (filename != null) {
|
|
if (result.filename != filename) {
|
|
throw "Got ${result.filename} errors. Expected $filename.";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class CompilationResult {
|
|
String filename;
|
|
int errorsCount;
|
|
|
|
CompilationResult.parse(String filenameAndErrorCount) {
|
|
if (filenameAndErrorCount == null) {
|
|
return;
|
|
}
|
|
int delim = filenameAndErrorCount.lastIndexOf(' ');
|
|
if (delim <= 0) {
|
|
throw "Expected $delim > 0...";
|
|
}
|
|
filename = filenameAndErrorCount.substring(0, delim);
|
|
errorsCount = int.parse(filenameAndErrorCount.substring(delim + 1).trim());
|
|
}
|
|
}
|
|
|
|
abstract class Logger {
|
|
void logTestStart(String testName);
|
|
void logExpectedResult(String testName);
|
|
void logUnexpectedResult(String testName);
|
|
void log(String s);
|
|
void notice(String s);
|
|
}
|
|
|
|
class StdoutLogger extends Logger {
|
|
List<String> _log = new List<String>();
|
|
|
|
@override
|
|
void logExpectedResult(String testName) {
|
|
print("$testName: OK.");
|
|
for (String s in _log) {
|
|
print(s);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void logTestStart(String testName) {
|
|
_log.clear();
|
|
}
|
|
|
|
@override
|
|
void logUnexpectedResult(String testName) {
|
|
print("$testName: Fail.");
|
|
for (String s in _log) {
|
|
print(s);
|
|
}
|
|
}
|
|
|
|
void log(String s) {
|
|
_log.add(s);
|
|
}
|
|
|
|
void notice(String s) {
|
|
print(s);
|
|
}
|
|
}
|