9cdc4a1963
Something seems wrong with the previous formatting. This change formats with language version 3.8 again. Change-Id: I077d635d815fa82ddf1153122ee3082787e1dd73 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/433301 Commit-Queue: Nicholas Shahan <nshahan@google.com> Reviewed-by: Mayank Patke <fishythefish@google.com>
406 lines
13 KiB
Dart
406 lines
13 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';
|
|
import 'package:bazel_worker/testing.dart';
|
|
import 'package:path/path.dart' as p;
|
|
import 'package:test/test.dart';
|
|
|
|
Directory tmp = Directory.systemTemp.createTempSync('ddc_worker_test');
|
|
File file(String path) => File.fromUri(tmp.uri.resolve(path));
|
|
String _resolvePath(String executableRelativePath) {
|
|
return Uri.file(
|
|
Platform.resolvedExecutable,
|
|
).resolve(executableRelativePath).toFilePath();
|
|
}
|
|
|
|
void main() {
|
|
var baseArgs = <String>[];
|
|
var sdkPath = p.dirname(Platform.executable);
|
|
var dartAotRuntime = p.absolute(
|
|
sdkPath,
|
|
Platform.isWindows
|
|
? 'dartaotruntime_product.exe'
|
|
: 'dartaotruntime_product',
|
|
);
|
|
var snapshotName = _resolvePath('gen/dartdevc_aot_product.dart.snapshot');
|
|
if (!File(dartAotRuntime).existsSync()) {
|
|
dartAotRuntime = p.absolute(
|
|
sdkPath,
|
|
Platform.isWindows
|
|
? 'dartaotruntime_product.exe'
|
|
: 'dartaotruntime_product',
|
|
);
|
|
snapshotName = _resolvePath('gen/dartdevc_aot.dart.snapshot');
|
|
}
|
|
final executableArgs = <String>[
|
|
snapshotName,
|
|
'--dart-sdk-summary',
|
|
_resolvePath('ddc_outline.dill'),
|
|
];
|
|
group('DDC: 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(dartAotRuntime, 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(dartAotRuntime, 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(dartAotRuntime, 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(dartAotRuntime, 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(dartAotRuntime, args);
|
|
await 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 DDC modules', () async {
|
|
var args = List<String>.from(executableArgs)
|
|
..add('--modules')
|
|
..add('ddc')
|
|
..addAll(compilerArgs);
|
|
var result = Process.runSync(dartAotRuntime, args);
|
|
|
|
expect(result.exitCode, EXIT_CODE_OK);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, isEmpty);
|
|
expect(outputJsFile.existsSync(), isTrue);
|
|
});
|
|
});
|
|
|
|
group('DDC: Hello World with Summaries', () {
|
|
final greetingDart = file('greeting.dart');
|
|
final helloDart = file('hello.dart');
|
|
|
|
final greetingJS = file('greeting.js');
|
|
final greetingSummary = file('greeting.dill');
|
|
final helloJS = file('hello_world.js');
|
|
|
|
final greeting2JS = file('greeting2.js');
|
|
final greeting2Summary = file('greeting2.dill');
|
|
|
|
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(
|
|
dartAotRuntime,
|
|
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(
|
|
dartAotRuntime,
|
|
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(
|
|
dartAotRuntime,
|
|
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(
|
|
dartAotRuntime,
|
|
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(
|
|
dartAotRuntime,
|
|
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('DDC: 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(
|
|
dartAotRuntime,
|
|
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(
|
|
dartAotRuntime,
|
|
executableArgs +
|
|
baseArgs +
|
|
['--no-source-map', '-o', badFileJs.path, badFileDart.path],
|
|
);
|
|
expect(result.exitCode, 1);
|
|
expect(result.stdout, contains(RegExp(r"Expected (to find )?\';\'")));
|
|
});
|
|
});
|
|
|
|
group('DDC: 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(
|
|
dartAotRuntime,
|
|
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(
|
|
dartAotRuntime,
|
|
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);
|
|
});
|
|
});
|
|
}
|
|
|
|
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';
|
|
}
|
|
}
|