567bf3337b
Given that the standalone target for dart2wasm is feature-complete now, it makes sense to include it in released SDKs. This adds the platform and outline files to built SDKs and exposes the `--standalone` flag in `dart compile wasm`. It also documents the standalone target in `pkg/dart2wasm/doc`, which should be helpful as a starting point to use these compiled modules. Change-Id: I5bd86e9670f03f2955e31789095dd5c462bf149e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506920 Reviewed-by: Slava Egorov <vegorov@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
1532 lines
45 KiB
Dart
1532 lines
45 KiB
Dart
// Copyright (c) 2020, 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:io';
|
|
import 'dart:math';
|
|
|
|
import 'package:code_assets/code_assets.dart';
|
|
import 'package:dart2native/dart2native_macho.dart' show pipeStream;
|
|
import 'package:dart2native/macho.dart';
|
|
import 'package:dartdev/src/commands/compile.dart'
|
|
show compileErrorExitCode, genericErrorExitCode;
|
|
import 'package:hooks_runner/hooks_runner.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:test/test.dart';
|
|
|
|
import '../utils.dart';
|
|
|
|
void main() {
|
|
ensureRunFromSdkBinDart();
|
|
|
|
group('compile -', defineCompileTests, timeout: longTimeout);
|
|
}
|
|
|
|
const String soundNullSafetyMessage = 'Info: Compiling with sound null safety';
|
|
const String soundNullSafetyWarning =
|
|
"Warning: Option '--sound-null-safety' is deprecated.";
|
|
|
|
const String failedAssertionError = 'Failed assertion: line';
|
|
String usingTargetOSMessage(OS targetOS) =>
|
|
'Specializing Platform getters for target OS $targetOS.';
|
|
final String targetingHostOSMessage = usingTargetOSMessage(Target.current.os);
|
|
|
|
void defineCompileTests() {
|
|
// AOT compilation is not available on IA32.
|
|
final bool isRunningOnIA32 = Target.current.architecture == Architecture.ia32;
|
|
|
|
if (Platform.isMacOS) {
|
|
test('Compile exe for MacOS signing', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(
|
|
path.join(p.dirPath, p.relativeFilePath),
|
|
);
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
final result = await p.run(['compile', 'exe', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
if (!MachOFile.containsSnapshot(File(outFile))) {
|
|
throw FormatException('Snapshot not found in standalone executable');
|
|
}
|
|
|
|
// Ensure that the exe can be signed.
|
|
final codeSigningProcess = await Process.start('codesign', [
|
|
'-o',
|
|
'runtime',
|
|
'-s',
|
|
'-',
|
|
outFile,
|
|
]);
|
|
|
|
final signingResult = await codeSigningProcess.exitCode;
|
|
expect(signingResult, 0);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Changing snapshot contents fails to validate', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(
|
|
path.join(p.dirPath, p.relativeFilePath),
|
|
);
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
final corruptedFile = path.canonicalize(
|
|
path.join(p.dirPath, 'myexe-corrupted'),
|
|
);
|
|
|
|
var result = await p.run(['compile', 'exe', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
final macho = MachOFile.fromFile(File(outFile));
|
|
final snapshotNote = macho.snapshotNote;
|
|
if (snapshotNote == null) {
|
|
throw FormatException('Snapshot not found in standalone executable');
|
|
}
|
|
|
|
if (macho.hasCodeSignature) {
|
|
// Verify the resulting executable using codesign.
|
|
result = Process.runSync('codesign', ['-v', outFile]);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
} else {
|
|
// Sign the executable first.
|
|
final codeSigningProcess = await Process.start('codesign', [
|
|
'-o',
|
|
'runtime',
|
|
'-s',
|
|
'-',
|
|
outFile,
|
|
]);
|
|
|
|
final signingResult = await codeSigningProcess.exitCode;
|
|
expect(signingResult, 0);
|
|
}
|
|
|
|
// Pick a random range of bytes within the snapshot.
|
|
final rand = Random();
|
|
final offset1 = rand.nextInt(snapshotNote.fileSize);
|
|
final offset2 = rand.nextInt(snapshotNote.fileSize);
|
|
final int start = snapshotNote.fileOffset + min(offset1, offset2);
|
|
final int size = max(offset1, offset2) - min(offset1, offset2);
|
|
|
|
// Write the corrupted version of the executable, corrupting the bytes in
|
|
// the calculated range by incrementing them (modulo 256).
|
|
final original = File(outFile).openSync();
|
|
final corrupted = File(corruptedFile).openSync(mode: FileMode.write);
|
|
await pipeStream(original, corrupted, numToWrite: start);
|
|
final bytesToCorrupt = original.readSync(size);
|
|
for (int i = 0; i < bytesToCorrupt.length; i++) {
|
|
bytesToCorrupt[i] = (bytesToCorrupt[i] + 1) % 256;
|
|
}
|
|
corrupted.writeFromSync(bytesToCorrupt);
|
|
await pipeStream(original, corrupted);
|
|
|
|
// (Fail to) verify the resulting executable using codesign.
|
|
result = Process.runSync('codesign', ['-v', corruptedFile]);
|
|
|
|
expect(result.stderr, isNotEmpty);
|
|
expect(result.exitCode, 1);
|
|
}, skip: isRunningOnIA32);
|
|
}
|
|
|
|
// *** NOTE ***: These tests *must* be run with the `--use-sdk` option
|
|
// as they depend on a fully built SDK to resolve various snapshot files
|
|
// used by compilation.
|
|
test('Running from built SDK', () {
|
|
final Directory binDir = File(Platform.resolvedExecutable).parent;
|
|
expect(binDir.path, contains('bin'));
|
|
});
|
|
|
|
test('Implicit --help', () async {
|
|
final p = project();
|
|
final result = await p.run(['compile']);
|
|
expect(result.stderr, contains('Compile Dart'));
|
|
expect(result.stderr, isNot(contains('js-dev')));
|
|
expect(result.exitCode, 64);
|
|
});
|
|
|
|
test('--help', () async {
|
|
final p = project();
|
|
final result = await p.run(['compile', '--help']);
|
|
expect(result.stdout, contains('Compile Dart'));
|
|
expect(
|
|
result.stdout,
|
|
contains('Usage: dart compile <subcommand> [arguments]'),
|
|
);
|
|
|
|
expect(result.stdout, contains('jit-snapshot'));
|
|
expect(result.stdout, contains('kernel'));
|
|
expect(result.stdout, contains('js'));
|
|
expect(result.stderr, isNot(contains('js-dev')));
|
|
expect(result.stdout, contains('aot-snapshot'));
|
|
expect(result.stdout, contains('exe'));
|
|
expect(result.exitCode, 0);
|
|
});
|
|
|
|
test('--help --verbose', () async {
|
|
final p = project();
|
|
final result = await p.run(['compile', '--help', '--verbose']);
|
|
expect(result.stdout, contains('Compile Dart'));
|
|
expect(result.stdout, isNot(contains('js-dev')));
|
|
expect(
|
|
result.stdout,
|
|
contains('Usage: dart [vm-options] compile <subcommand> [arguments]'),
|
|
);
|
|
expect(result.exitCode, 0);
|
|
});
|
|
|
|
test('Compile and run jit snapshot', () async {
|
|
final p = project(mainSrc: 'void main() { print("I love jit"); }');
|
|
final outFile = path.join(p.dirPath, 'main.jit');
|
|
var result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'-o',
|
|
outFile,
|
|
p.relativeFilePath,
|
|
]);
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
result = await p.run(['run', 'main.jit']);
|
|
expect(result.stdout, contains('I love jit'));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
});
|
|
|
|
test('Compile and run jit snapshot with environment variables', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
print('1: ' + const String.fromEnvironment('foo'));
|
|
print('2: ' + const String.fromEnvironment('bar'));
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'main.jit'));
|
|
|
|
var result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'-Dfoo=bar',
|
|
'--define=bar=foo',
|
|
'-o',
|
|
outFile,
|
|
'-v',
|
|
inFile,
|
|
]);
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
final file = File(outFile);
|
|
expect(file.existsSync(), true, reason: 'File not found: $outFile');
|
|
|
|
result = await p.run(['run', 'main.jit']);
|
|
|
|
// Ensure the -D and --define arguments were processed correctly.
|
|
expect(result.stdout, contains('1: bar'));
|
|
expect(result.stdout, contains('2: foo'));
|
|
});
|
|
|
|
Future<void> basicCompileTest() async {
|
|
final p = project(mainSrc: 'void main() { print("I love executables"); }');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'lib', 'main.exe'));
|
|
|
|
var result = await p.run(['compile', 'exe', '-v', inFile]);
|
|
|
|
// Executables should be (host) OS-specific by default.
|
|
expect(result.stdout, contains(targetingHostOSMessage));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
if (Platform.isMacOS && Target.current.architecture == Architecture.arm64) {
|
|
// Also check that the resulting executable is properly signed on ARM64
|
|
// macOS, since executables are required to be signed there and checking
|
|
// this prior to running the executable gives us a clearer test failure
|
|
// message if for some reason the generated signature was invalid.
|
|
result = await Process.run('codesign', ['-v', outFile]);
|
|
|
|
printOnFailure(
|
|
'Subcommand terminated with exit code ${result.exitCode}.',
|
|
);
|
|
printOnFailure('Subcommand stdout:\n${result.stdout}');
|
|
printOnFailure('Subcommand stderr:\n${result.stderr}');
|
|
expect(result.exitCode, 0);
|
|
}
|
|
|
|
result = Process.runSync(outFile, []);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(result.stdout, contains('I love executables'));
|
|
}
|
|
|
|
test('Compile and run executable', basicCompileTest, skip: isRunningOnIA32);
|
|
|
|
test('Compile to executable disabled on IA32', () async {
|
|
final p = project(mainSrc: 'void main() { print("I love executables"); }');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
|
|
final result = await p.run(['compile', 'exe', inFile]);
|
|
|
|
expect(
|
|
result.stderr,
|
|
"'dart compile exe' is not supported on x86 architectures.\n",
|
|
);
|
|
expect(result.exitCode, 64);
|
|
}, skip: !isRunningOnIA32);
|
|
|
|
test('Compile to AOT snapshot disabled on IA32', () async {
|
|
final p = project(mainSrc: 'void main() { print("I love executables"); }');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
|
|
final result = await p.run(['compile', 'aot-snapshot', inFile]);
|
|
|
|
expect(
|
|
result.stderr,
|
|
"'dart compile aot-snapshot' is not supported on x86 architectures.\n",
|
|
);
|
|
expect(result.exitCode, 64);
|
|
}, skip: !isRunningOnIA32);
|
|
|
|
test('Compile and run executable with options', () async {
|
|
final p = project(
|
|
mainSrc: 'void main() {print(const String.fromEnvironment("life"));}',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
var result = await p.run([
|
|
'compile',
|
|
'exe',
|
|
'-v',
|
|
'--define',
|
|
'life=42',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, contains(targetingHostOSMessage));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
result = Process.runSync(outFile, []);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(result.stdout, contains('42'));
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test(
|
|
'Regression test for https://github.com/dart-lang/sdk/issues/45347',
|
|
() async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
import "dart:developer";
|
|
import "dart:isolate";
|
|
void main() {
|
|
final id = Service.getIsolateId(Isolate.current)?? "NA";
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(
|
|
path.join(p.dirPath, p.relativeFilePath),
|
|
);
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
var result = await p.run(['compile', 'exe', '-v', '-o', outFile, inFile]);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
result = Process.runSync(outFile, []);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
},
|
|
skip: isRunningOnIA32,
|
|
);
|
|
|
|
test('Compile and run aot snapshot', () async {
|
|
final p = project(mainSrc: 'void main() { print("I love AOT"); }');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'main.aot'));
|
|
|
|
var result = await p.run([
|
|
'compile',
|
|
'aot-snapshot',
|
|
'-v',
|
|
'-o',
|
|
'main.aot',
|
|
inFile,
|
|
]);
|
|
|
|
// AOT snapshots should be OS-specific by default.
|
|
expect(result.stdout, contains(targetingHostOSMessage));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
var magic = (await File(outFile).readAsBytes()).sublist(0, 4);
|
|
if (Platform.isMacOS) {
|
|
expect(magic, equals([0xCF, 0xFA, 0xED, 0xFE])); // Mach-O
|
|
} else {
|
|
expect(magic, equals([0x7F, 0x45, 0x4C, 0x46])); // ELF
|
|
}
|
|
|
|
final Directory binDir = File(Platform.resolvedExecutable).parent;
|
|
result = Process.runSync(path.join(binDir.path, 'dartaotruntime'), [
|
|
outFile,
|
|
]);
|
|
|
|
expect(result.stdout, contains('I love AOT'));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
for (var sanitizer in ['asan', 'msan', 'tsan']) {
|
|
test('Compile and run aot snapshot - $sanitizer', () async {
|
|
final p = project(
|
|
mainSrc:
|
|
'void main() { print(const String.fromEnvironment("dart.vm.$sanitizer")); }',
|
|
);
|
|
final inFile = path.canonicalize(
|
|
path.join(p.dirPath, p.relativeFilePath),
|
|
);
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'main.aot'));
|
|
|
|
var result = await p.run([
|
|
'compile',
|
|
'aot-snapshot',
|
|
'--target-sanitizer',
|
|
sanitizer,
|
|
'-v',
|
|
'-o',
|
|
'main.aot',
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
final Directory binDir = File(Platform.resolvedExecutable).parent;
|
|
result = Process.runSync(
|
|
path.join(binDir.path, 'dartaotruntime_$sanitizer'),
|
|
[outFile],
|
|
);
|
|
|
|
expect(result.stdout, contains('true'));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
}, skip: !Platform.isLinux);
|
|
}
|
|
|
|
test('Compile and run kernel snapshot', () async {
|
|
final p = project(mainSrc: 'void main() { print("I love kernel"); }');
|
|
final outFile = path.join(p.dirPath, 'main.dill');
|
|
var result = await p.run([
|
|
'compile',
|
|
'kernel',
|
|
'-v',
|
|
'-o',
|
|
outFile,
|
|
p.relativeFilePath,
|
|
]);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
|
|
result = await p.run(['run', 'main.dill']);
|
|
expect(result.stdout, contains('I love kernel'));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
});
|
|
|
|
test('Compile JS', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
print('1: ' + const String.fromEnvironment('foo'));
|
|
print('2: ' + const String.fromEnvironment('bar'));
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'main.js'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'js',
|
|
'-m',
|
|
'-Dfoo=bar',
|
|
'--define=bar=foo',
|
|
'-o',
|
|
outFile,
|
|
'-v',
|
|
inFile,
|
|
]);
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
final file = File(outFile);
|
|
expect(file.existsSync(), true, reason: 'File not found: $outFile');
|
|
|
|
// Ensure the -D and --define arguments were processed correctly.
|
|
final contents = file.readAsStringSync();
|
|
expect(contents.contains('1: bar'), true);
|
|
expect(contents.contains('2: foo'), true);
|
|
});
|
|
|
|
test('Compile JS DDC', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
print('1: ' + const String.fromEnvironment('foo'));
|
|
print('2: ' + const String.fromEnvironment('bar'));
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'main.js'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'js-dev',
|
|
'-Dfoo=bar',
|
|
'--define=bar=foo',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
final file = File(outFile);
|
|
expect(file.existsSync(), true, reason: 'File not found: $outFile');
|
|
|
|
final contents = file.readAsStringSync();
|
|
expect(contents.contains('"1: " + "bar"'), true);
|
|
expect(contents.contains('"2: " + "foo"'), true);
|
|
});
|
|
|
|
test('Compile exe with error', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
int? i;
|
|
i.isEven;
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
final result = await p.run(['compile', 'exe', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, contains('Error: '));
|
|
// The CFE doesn't print to stderr, so all output is piped to stderr, even
|
|
// including info-only output:
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, compileErrorExitCode);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
false,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile exe with sound null safety', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
final result = await p.run(['compile', 'exe', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile and run exe (default sound null safety)', () async {
|
|
final p = project(
|
|
mainSrc: '''void main() {
|
|
print((<int?>[] is List<int>) ? 'oh no' : 'sound');
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
var result = await p.run(['compile', 'exe', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
result = Process.runSync(outFile, []);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(result.stdout, contains('sound'));
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile and run exe with DART_VM_OPTIONS', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
import 'dart:math';
|
|
void main() {
|
|
print(Random().nextInt(1000));
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
var result = await p.run(['compile', 'exe', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
// Verify CSV options are processed.
|
|
result = Process.runSync(
|
|
outFile,
|
|
[],
|
|
environment: <String, String>{'DART_VM_OPTIONS': '--help,--verbose'},
|
|
);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
// vm_name is a verbose flag and will only be shown if --verbose is
|
|
// processed.
|
|
expect(result.stdout, contains('vm_name'));
|
|
expect(result.exitCode, 0);
|
|
|
|
// Verify non-help options work.
|
|
//
|
|
// Regression test for https://github.com/dart-lang/sdk/issues/55767
|
|
result = Process.runSync(
|
|
outFile,
|
|
[],
|
|
environment: <String, String>{'DART_VM_OPTIONS': '--random_seed=42'},
|
|
);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
// This value should be consistent as long as --random_seed is processed.
|
|
expect(result.stdout, contains('21'));
|
|
expect(result.exitCode, 0);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test(
|
|
'Compile and run exe with DART_VM_OPTIONS - multiple options',
|
|
() async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
import 'dart:io';
|
|
|
|
void main() {
|
|
print(Platform.executableArguments);
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(
|
|
path.join(p.dirPath, p.relativeFilePath),
|
|
);
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
var result = await p.run(['compile', 'exe', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
void testVmOptions(List<String> vmOptions) {
|
|
var result = Process.runSync(
|
|
outFile,
|
|
[],
|
|
environment: <String, String>{'DART_VM_OPTIONS': vmOptions.join(',')},
|
|
);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.stdout, contains(vmOptions.toString()));
|
|
expect(result.exitCode, 0);
|
|
}
|
|
|
|
testVmOptions([
|
|
'--use_compactor',
|
|
'--force_evacuation',
|
|
'--idle_duration_micros=0',
|
|
'--compactor_tasks=5',
|
|
'--marker_tasks=5',
|
|
'--scavenger_tasks=5',
|
|
'--old_gen_growth_time_ratio=50',
|
|
'--old_gen_growth_space_ratio=10',
|
|
]);
|
|
testVmOptions([
|
|
'--use_compactor',
|
|
'--force_evacuation',
|
|
'--idle_duration_micros=0',
|
|
'--compactor_tasks=5',
|
|
'--marker_tasks=5',
|
|
'--scavenger_tasks=5',
|
|
'--mark_when_idle',
|
|
'--old_gen_growth_time_ratio=50',
|
|
'--old_gen_growth_space_ratio=10',
|
|
]);
|
|
},
|
|
skip: isRunningOnIA32,
|
|
);
|
|
|
|
test('Compile exe without info', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'exe',
|
|
'--verbosity=warning',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
// Only printed when -v/--verbose is used, not --verbosity.
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile exe without warnings', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
int i = 0;
|
|
i?.isEven;
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'exe',
|
|
'--verbosity=error',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
// Only printed when -v/--verbose is used, not --verbosity.
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile exe with asserts', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
assert(int.parse('1') == 2);
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'exe',
|
|
'--enable-asserts',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
// Only printed when -v/--verbose is used, not --verbosity.
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
|
|
final runResult = await Process.run(outFile, []);
|
|
expect(runResult.stdout, isEmpty);
|
|
expect(runResult.stderr, contains(failedAssertionError));
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile exe from kernel', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final dillOutFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
|
|
final exeOutFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
|
|
|
|
var result = await p.run(['compile', 'kernel', '-o', dillOutFile, inFile]);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(dillOutFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $dillOutFile',
|
|
);
|
|
|
|
result = await p.run(['compile', 'exe', '-o', exeOutFile, dillOutFile]);
|
|
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(exeOutFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $exeOutFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile wasm with error', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
int? i;
|
|
i.isEven;
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'my.wasm'));
|
|
|
|
final result = await p.run(['compile', 'wasm', '-o', outFile, inFile]);
|
|
|
|
expect(result.stderr, contains('Error: '));
|
|
// The CFE doesn't print to stderr, so all output is piped to stderr, even
|
|
// including info-only output:
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, compileErrorExitCode);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
false,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile wasm standalone', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
print('hello world');
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'standalone.wasm'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'wasm',
|
|
'--standalone',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, isNot(contains('.mjs')));
|
|
expect(result.stdout, contains('standalone option is experimental'));
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'Expected output file to exist: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile JS with sound null safety', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjs'));
|
|
|
|
final result = await p.run(['compile', 'js', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyWarning)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile JS with sound null safety flag', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjs'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'js',
|
|
'--sound-null-safety',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stdout, contains(soundNullSafetyWarning));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile JS DDC with sound null safety', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjs'));
|
|
|
|
final result = await p.run(['compile', 'js-dev', '-o', outFile, inFile]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile JS without info', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjs'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'js',
|
|
'--verbosity=warning',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile JS without warnings', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
int i = 0;
|
|
i?.isEven;
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjs'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'js',
|
|
'--verbosity=error',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
});
|
|
|
|
test('Compile AOT snapshot with sound null safety', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'aot-snapshot',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile AOT snapshot without info', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'aot-snapshot',
|
|
'--verbosity=warning',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
// Only printed when -v/--verbose is used, not --verbosity.
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile AOT snapshot without warnings', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
int i = 0;
|
|
i?.isEven;
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'aot-snapshot',
|
|
'--verbosity=error',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
// Only printed when -v/--verbose is used, not --verbosity.
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile AOT snapshot with asserts', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
assert(int.parse('1') == 2);
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
|
|
|
|
var result = await p.run([
|
|
'compile',
|
|
'aot-snapshot',
|
|
'--enable-asserts',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
// Only printed when -v/--verbose is used, not --verbosity.
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
|
|
final Directory binDir = File(Platform.resolvedExecutable).parent;
|
|
result = await Process.run(path.join(binDir.path, 'dartaotruntime'), [
|
|
outFile,
|
|
]);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, contains(failedAssertionError));
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile AOT snapshot from kernel', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final dillOutFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
|
|
final aotOutFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
|
|
|
|
var result = await p.run(['compile', 'kernel', '-o', dillOutFile, inFile]);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(dillOutFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $dillOutFile',
|
|
);
|
|
|
|
result = await p.run([
|
|
'compile',
|
|
'aot-snapshot',
|
|
'-o',
|
|
aotOutFile,
|
|
dillOutFile,
|
|
]);
|
|
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(aotOutFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $aotOutFile',
|
|
);
|
|
}, skip: isRunningOnIA32);
|
|
|
|
test('Compile kernel with invalid output directory', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'kernel',
|
|
'--verbosity=warning',
|
|
'-o',
|
|
'/somewhere/nowhere/test.dill',
|
|
inFile,
|
|
]);
|
|
expect(
|
|
result.stderr,
|
|
predicate((dynamic o) => '$o'.contains('Unable to open file')),
|
|
);
|
|
expect(result.exitCode, genericErrorExitCode);
|
|
});
|
|
|
|
test('Compile kernel with invalid trailing argument', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'kernel',
|
|
'--verbosity=warning',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
'invalid-arg',
|
|
]);
|
|
|
|
expect(result.stdout, isEmpty);
|
|
expect(
|
|
result.stderr,
|
|
predicate(
|
|
(dynamic o) =>
|
|
'$o'.contains('Unexpected arguments after Dart entry point.'),
|
|
),
|
|
);
|
|
expect(result.exitCode, 64);
|
|
expect(File(outFile).existsSync(), false, reason: 'File found: $outFile');
|
|
});
|
|
|
|
test('Compile kernel with default (sound null safety)', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'kernel',
|
|
'-v',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile kernel with --sound-null-safety', () async {
|
|
final p = project(
|
|
mainSrc: '''void main() {
|
|
print((<int?>[] is List<int>) ? 'oh no' : 'sound');
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'kernel',
|
|
'--sound-null-safety',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile kernel without info', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'kernel',
|
|
'--verbosity=warning',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile kernel without warning', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
int i;
|
|
i?.isEven;
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'kernel',
|
|
'--verbosity=error',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, contains('must be assigned before it can be used'));
|
|
expect(result.exitCode, compileErrorExitCode);
|
|
});
|
|
|
|
test('Compile JIT snapshot with default (sound null safety)', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile JIT snapshot with (default sound null safety)', () async {
|
|
final p = project(
|
|
mainSrc: '''void main() {
|
|
print((<int?>[] is List<int>) ? 'oh no' : 'sound');
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile JIT snapshot with training args', () async {
|
|
final p = project(
|
|
mainSrc: '''void main(List<String> args) => print(args);''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
'foo',
|
|
// Ensure training args aren't parsed by the CLI.
|
|
// See https://github.com/dart-lang/sdk/issues/49302
|
|
'-e',
|
|
'--foobar=bar',
|
|
]);
|
|
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(
|
|
result.stdout,
|
|
predicate((dynamic o) => '$o'.contains('[foo, -e, --foobar=bar]')),
|
|
);
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile JIT snapshot without info', () async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'--verbosity=warning',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
});
|
|
|
|
test('Compile JIT snapshot without warnings', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
int i;
|
|
i?.isEven;
|
|
}''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'--verbosity=error',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, contains('must be assigned before it can be used'));
|
|
expect(result.exitCode, 254);
|
|
});
|
|
|
|
test('Compile JIT snapshot with asserts', () async {
|
|
final p = project(
|
|
mainSrc: '''
|
|
void main() {
|
|
assert(int.parse('1') == 2);
|
|
}
|
|
''',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
|
|
|
|
var result = await p.run([
|
|
'compile',
|
|
'jit-snapshot',
|
|
'--enable-asserts',
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
// Only printed when -v/--verbose is used, not --verbosity.
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(soundNullSafetyMessage)));
|
|
expect(result.stderr, contains(failedAssertionError));
|
|
expect(result.exitCode, genericErrorExitCode);
|
|
|
|
result = await p.run(['--enable-asserts', outFile]);
|
|
expect(result.stdout, isEmpty);
|
|
expect(result.stderr, contains(failedAssertionError));
|
|
});
|
|
|
|
// Tests for --depfile for compiling to AOT snapshots, executables and
|
|
// kernel.
|
|
group('depfiles', () {
|
|
Future<void> testDepFileGeneration(String subcommand) async {
|
|
final p = project(mainSrc: '''void main() {}''');
|
|
final inFile = path.canonicalize(
|
|
path.join(p.dirPath, p.relativeFilePath),
|
|
);
|
|
final outFile = path.canonicalize(
|
|
path.join(p.dirPath, 'output.$subcommand'),
|
|
);
|
|
final depFile = path.canonicalize(
|
|
path.join(p.dirPath, 'output.$subcommand.d'),
|
|
);
|
|
|
|
final result = await p.run([
|
|
'compile',
|
|
subcommand,
|
|
'--depfile',
|
|
depFile,
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
|
|
expect(File(depFile).existsSync(), isTrue);
|
|
|
|
final depFileContent = File(depFile).readAsStringSync();
|
|
|
|
String escapePath(String path) =>
|
|
path.replaceAll('\\', '\\\\').replaceAll(' ', '\\ ');
|
|
|
|
expect(depFileContent, startsWith('${escapePath(outFile)}: '));
|
|
expect(depFileContent, contains(escapePath(inFile)));
|
|
}
|
|
|
|
test(
|
|
'compile aot-snapshot',
|
|
() => testDepFileGeneration('aot-snapshot'),
|
|
skip: isRunningOnIA32,
|
|
);
|
|
test(
|
|
'compile exe',
|
|
() => testDepFileGeneration('exe'),
|
|
skip: isRunningOnIA32,
|
|
);
|
|
test(
|
|
'compile kernel',
|
|
() => testDepFileGeneration('kernel'),
|
|
skip: isRunningOnIA32,
|
|
);
|
|
});
|
|
}
|