ca9bbd39d5
We do not expect any client uses of the precompiled SDK in this module format. The only know use case builds the SDK manually first. Add simple tests that files can be compiled with `--modules legacy` option. Issue: #35988 Change-Id: Ie2c4244e5876bb04f968b0198f5763ff3d29c01c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99921 Reviewed-by: Jenny Messerly <jmesserly@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
418 lines
14 KiB
Dart
418 lines
14 KiB
Dart
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
|
// for details. 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 'dart:io';
|
|
|
|
import 'package:bazel_worker/bazel_worker.dart';
|
|
// TODO(jakemac): Remove once this is a part of the testing library.
|
|
import 'package:bazel_worker/src/async_message_grouper.dart';
|
|
import 'package:bazel_worker/testing.dart';
|
|
import 'package:path/path.dart' show dirname, join, joinAll;
|
|
import 'package:test/test.dart';
|
|
|
|
Directory tmp = Directory.systemTemp.createTempSync('ddc_worker_test');
|
|
File file(String path) => File(join(tmp.path, joinAll(path.split('/'))));
|
|
|
|
void main() {
|
|
runTests(false);
|
|
runTests(true);
|
|
}
|
|
|
|
void runTests(bool isKernel) {
|
|
String mode = isKernel ? 'DDK' : 'DDC';
|
|
List<String> baseArgs = isKernel ? ['-k'] : [];
|
|
String ext = isKernel ? 'dill' : 'sum';
|
|
final binDir = dirname(Platform.resolvedExecutable);
|
|
// Note, the bots use the dart binary in the top-level build directory.
|
|
// On windows, this is a .bat file.
|
|
final dartdevc = 'dartdevc${Platform.isWindows ? ".bat" : ""}';
|
|
final executable = binDir.endsWith('bin')
|
|
? join(binDir, dartdevc)
|
|
: join(binDir, 'dart-sdk', 'bin', dartdevc);
|
|
final executableArgs = <String>[];
|
|
group('$mode: Hello World', () {
|
|
final argsFile = file('hello_world.args');
|
|
final inputDartFile = file('hello_world.dart');
|
|
final outputJsFile = file('out/hello_world.js');
|
|
final compilerArgs = baseArgs +
|
|
[
|
|
'--no-source-map',
|
|
'--no-summarize',
|
|
'-o',
|
|
outputJsFile.path,
|
|
inputDartFile.path,
|
|
];
|
|
|
|
setUp(() {
|
|
inputDartFile.createSync();
|
|
inputDartFile.writeAsStringSync('main() => print("hello world");');
|
|
});
|
|
|
|
tearDown(() {
|
|
if (inputDartFile.existsSync()) inputDartFile.deleteSync();
|
|
if (outputJsFile.parent.existsSync()) {
|
|
outputJsFile.parent.deleteSync(recursive: true);
|
|
}
|
|
if (argsFile.existsSync()) argsFile.deleteSync();
|
|
});
|
|
|
|
test('can compile in worker mode', () async {
|
|
var args = executableArgs.toList()..add('--persistent_worker');
|
|
var process = await Process.start(executable, args);
|
|
var messageGrouper = AsyncMessageGrouper(process.stdout);
|
|
|
|
var request = WorkRequest();
|
|
request.arguments.addAll(compilerArgs);
|
|
process.stdin.add(protoToDelimitedBuffer(request));
|
|
|
|
var response = await _readResponse(messageGrouper);
|
|
expect(response.exitCode, EXIT_CODE_OK, reason: response.output);
|
|
expect(response.output, isEmpty);
|
|
|
|
expect(outputJsFile.existsSync(), isTrue);
|
|
expect(outputJsFile.readAsStringSync(), contains('hello world'));
|
|
|
|
/// Now update hello_world.dart and send another [WorkRequest].
|
|
inputDartFile.writeAsStringSync('main() => print("goodbye world");');
|
|
process.stdin.add(protoToDelimitedBuffer(request));
|
|
|
|
response = await _readResponse(messageGrouper);
|
|
expect(response.exitCode, EXIT_CODE_OK, reason: response.output);
|
|
expect(response.output, isEmpty);
|
|
expect(outputJsFile.readAsStringSync(), contains('goodbye world'));
|
|
|
|
// Try to compile an error.
|
|
inputDartFile.writeAsStringSync('main() { int x = "hello"; }');
|
|
process.stdin.add(protoToDelimitedBuffer(request));
|
|
|
|
response = await _readResponse(messageGrouper);
|
|
expect(response.exitCode, 1, reason: response.output);
|
|
expect(
|
|
response.output,
|
|
contains(
|
|
'A value of type \'String\' can\'t be assigned to a variable of type \'int\'.'));
|
|
|
|
process.kill();
|
|
|
|
// TODO(jakemac): This shouldn't be necessary, but it is for the process
|
|
// to exit properly.
|
|
expect(await messageGrouper.next, isNull);
|
|
});
|
|
|
|
test('can compile in basic mode', () {
|
|
var args = executableArgs.toList()..addAll(compilerArgs);
|
|
var result = Process.runSync(executable, args);
|
|
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(outputJsFile.existsSync(), isTrue);
|
|
});
|
|
|
|
test('unknown options', () {
|
|
var args = List<String>.from(executableArgs)
|
|
..add('--does-not-exist')
|
|
..addAll(compilerArgs);
|
|
var result = Process.runSync(executable, args);
|
|
|
|
expect(result.exitCode, 64);
|
|
expect(result.stdout,
|
|
contains('Could not find an option named "does-not-exist"'));
|
|
expect(result.stderr, isEmpty);
|
|
expect(outputJsFile.existsSync(), isFalse);
|
|
});
|
|
|
|
test('unknown options ignored', () {
|
|
var args = List<String>.from(executableArgs)
|
|
..add('--does-not-exist')
|
|
..add('--ignore-unrecognized-flags')
|
|
..addAll(compilerArgs);
|
|
var result = Process.runSync(executable, args);
|
|
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(outputJsFile.existsSync(), isTrue);
|
|
});
|
|
|
|
test('can compile in basic mode with args in a file', () async {
|
|
argsFile.createSync();
|
|
argsFile.writeAsStringSync(compilerArgs.join('\n'));
|
|
var args = executableArgs.toList()..add('@${argsFile.path}');
|
|
var process = await Process.start(executable, args);
|
|
stderr.addStream(process.stderr);
|
|
var futureProcessOutput = process.stdout.map(utf8.decode).toList();
|
|
|
|
expect(await process.exitCode, EXIT_CODE_OK);
|
|
expect((await futureProcessOutput).join(), isEmpty);
|
|
expect(outputJsFile.existsSync(), isTrue);
|
|
});
|
|
|
|
test('can compile in basic mode with "legacy" modules', () async {
|
|
var args = List<String>.from(executableArgs)
|
|
..add('--modules')
|
|
..add('legacy')
|
|
..addAll(compilerArgs);
|
|
var result = Process.runSync(executable, args);
|
|
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(outputJsFile.existsSync(), isTrue);
|
|
});
|
|
});
|
|
|
|
group('$mode: Hello World with Summaries', () {
|
|
final greetingDart = file('greeting.dart');
|
|
final helloDart = file('hello.dart');
|
|
|
|
final greetingJS = file('greeting.js');
|
|
final greetingSummary = file('greeting.$ext');
|
|
final helloJS = file('hello_world.js');
|
|
|
|
final greeting2JS = file('greeting2.js');
|
|
final greeting2Summary = file('greeting2.$ext');
|
|
|
|
setUp(() {
|
|
greetingDart.writeAsStringSync('String greeting = "hello";');
|
|
helloDart.writeAsStringSync('import "greeting.dart";'
|
|
'main() => print(greeting);');
|
|
});
|
|
|
|
tearDown(() {
|
|
if (greetingDart.existsSync()) greetingDart.deleteSync();
|
|
if (helloDart.existsSync()) helloDart.deleteSync();
|
|
if (greetingJS.existsSync()) greetingJS.deleteSync();
|
|
if (greetingSummary.existsSync()) greetingSummary.deleteSync();
|
|
if (greeting2JS.existsSync()) greeting2JS.deleteSync();
|
|
if (greeting2Summary.existsSync()) greeting2Summary.deleteSync();
|
|
if (helloJS.existsSync()) helloJS.deleteSync();
|
|
});
|
|
|
|
test('can compile in basic mode', () {
|
|
var result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-source-map',
|
|
'-o',
|
|
greetingJS.path,
|
|
greetingDart.path,
|
|
]);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(greetingJS.existsSync(), isTrue);
|
|
expect(greetingSummary.existsSync(), isTrue);
|
|
|
|
result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-source-map',
|
|
'--no-summarize',
|
|
'-s',
|
|
greetingSummary.path,
|
|
'-o',
|
|
helloJS.path,
|
|
helloDart.path,
|
|
]);
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(helloJS.existsSync(), isTrue);
|
|
});
|
|
|
|
test('reports error on overlapping summaries', () {
|
|
var result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-source-map',
|
|
'-o',
|
|
greetingJS.path,
|
|
greetingDart.path,
|
|
]);
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(greetingJS.existsSync(), isTrue);
|
|
expect(greetingSummary.existsSync(), isTrue);
|
|
|
|
result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-source-map',
|
|
'-o',
|
|
greeting2JS.path,
|
|
greetingDart.path,
|
|
]);
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(greeting2JS.existsSync(), isTrue);
|
|
expect(greeting2Summary.existsSync(), isTrue);
|
|
|
|
result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-source-map',
|
|
'--no-summarize',
|
|
'-s',
|
|
greetingSummary.path,
|
|
'-s',
|
|
greeting2Summary.path,
|
|
'-o',
|
|
helloJS.path,
|
|
helloDart.path,
|
|
]);
|
|
// TODO(vsm): Re-enable when we turn this check back on.
|
|
expect(result.exitCode, 0);
|
|
// expect(result.exitCode, 65);
|
|
// expect(result.stdout, contains("conflict"));
|
|
// expect(result.stdout, contains('${toUri(greetingDart.path)}'));
|
|
// expect(helloJS.existsSync(), isFalse);
|
|
});
|
|
});
|
|
|
|
group('$mode: Error handling', () {
|
|
final badFileDart = file('bad.dart');
|
|
final badFileJs = file('bad.js');
|
|
|
|
tearDown(() {
|
|
if (badFileDart.existsSync()) badFileDart.deleteSync();
|
|
if (badFileJs.existsSync()) badFileJs.deleteSync();
|
|
});
|
|
|
|
test('incorrect usage', () {
|
|
var result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'oops',
|
|
]);
|
|
expect(result.exitCode, 64);
|
|
expect(
|
|
result.stdout, contains('Please specify the output file location.'));
|
|
expect(result.stdout, isNot(contains('#0')));
|
|
});
|
|
|
|
test('compile errors', () {
|
|
badFileDart.writeAsStringSync('main() => "hello world"');
|
|
var result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-source-map',
|
|
'-o',
|
|
badFileJs.path,
|
|
badFileDart.path,
|
|
]);
|
|
expect(result.exitCode, 1);
|
|
expect(result.stdout, contains(RegExp(r"Expected (to find )?\';\'")));
|
|
});
|
|
});
|
|
|
|
group('$mode: Parts', () {
|
|
final partFile = file('greeting.dart');
|
|
final libraryFile = file('hello.dart');
|
|
|
|
final outJS = file('output.js');
|
|
|
|
setUp(() {
|
|
partFile.writeAsStringSync('part of hello;\n'
|
|
'String greeting = "hello";');
|
|
libraryFile.writeAsStringSync('library hello;\n'
|
|
'part "greeting.dart";\n'
|
|
'main() => print(greeting);\n');
|
|
});
|
|
|
|
tearDown(() {
|
|
if (partFile.existsSync()) partFile.deleteSync();
|
|
if (libraryFile.existsSync()) libraryFile.deleteSync();
|
|
if (outJS.existsSync()) outJS.deleteSync();
|
|
});
|
|
|
|
test('works if part and library supplied', () {
|
|
var result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-summarize',
|
|
'--no-source-map',
|
|
'-o',
|
|
outJS.path,
|
|
partFile.path,
|
|
libraryFile.path,
|
|
]);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(outJS.existsSync(), isTrue);
|
|
});
|
|
|
|
test('works if part is not supplied', () {
|
|
var result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-summarize',
|
|
'--no-source-map',
|
|
'-o',
|
|
outJS.path,
|
|
libraryFile.path,
|
|
]);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(outJS.existsSync(), isTrue);
|
|
});
|
|
|
|
if (!isKernel) {
|
|
// TODO(vsm): Consider dropping this test. Kernel behavior is better.
|
|
test('part without library is silently ignored', () {
|
|
var result = Process.runSync(
|
|
executable,
|
|
executableArgs +
|
|
baseArgs +
|
|
[
|
|
'--no-summarize',
|
|
'--no-source-map',
|
|
'-o',
|
|
outJS.path,
|
|
partFile.path,
|
|
]);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(outJS.existsSync(), isTrue);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<WorkResponse> _readResponse(MessageGrouper messageGrouper) async {
|
|
var buffer = (await messageGrouper.next) as List<int>;
|
|
try {
|
|
return WorkResponse.fromBuffer(buffer);
|
|
} catch (_) {
|
|
var bufferAsString =
|
|
buffer == null ? '' : 'String: ${utf8.decode(buffer)}\n';
|
|
throw 'Failed to parse response:\nbytes: $buffer\n$bufferAsString';
|
|
}
|
|
}
|