blob: 7092dbf624518665573046b68a8eb8390409e27d [file] [log] [blame]
// 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.
// Test the command line options of dart2js.
import 'dart:async';
import 'package:expect/async_helper.dart';
import 'package:expect/expect.dart';
import 'package:compiler/compiler_api.dart' as api;
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/dart2js.dart' as entry;
import 'package:compiler/src/options.dart' show CompilerOptions, CompilerStage;
main() {
entry.enableWriteString = false;
asyncTest(() async {
// Full compile from Dart source
await test(['foo.dart'], out: 'out.js');
await test(['foo.dart', '-ofoo.js'], out: 'foo.js');
await test(['foo.dart', '--out=foo.js'], out: 'foo.js');
await test(['foo.dart', '--out=/some/path/'], out: '/some/path/out.js');
await test(['foo.dart', '--out=prefix-'], out: 'prefix-');
await test([
'foo.dart',
'--out=/some/path/prefix-',
], out: '/some/path/prefix-');
// Full compile from dill
await test(['foo.dill'], allFromDill: true, out: 'out.js');
await test(['foo.dill', '-ofoo.js'], allFromDill: true, out: 'foo.js');
await test(['foo.dill', '--out=foo.js'], allFromDill: true, out: 'foo.js');
await test(
['foo.dill', '--out=/some/path/'],
allFromDill: true,
out: '/some/path/out.js',
);
await test(
['foo.dill', '--out=prefix-'],
allFromDill: true,
out: 'prefix-',
);
await test(
['foo.dill', '--out=/some/path/prefix-'],
allFromDill: true,
out: '/some/path/prefix-',
);
// Run CFE only
await test(['${Flags.stage}=cfe', 'foo.dart'], out: 'out.dill');
await test([
'${Flags.stage}=cfe',
'--out=out1.dill',
'foo.dart',
], out: 'out1.dill');
await test([Flags.cfeOnly, 'foo.dart'], out: 'out.dill');
await test([
Flags.cfeOnly,
'foo.dart',
'--out=out1.dill',
], out: 'out1.dill');
await test([Flags.cfeOnly, 'foo.dart', '-oout1.dill'], out: 'out1.dill');
await test([Flags.cfeOnly, 'foo.dart', '--out=prefix-'], out: 'prefix-');
await test([
Flags.cfeOnly,
'foo.dart',
'--out=/some/path/prefix-',
], out: '/some/path/prefix-');
await test([
'foo.dart',
'${Flags.stage}=cfe',
'--out=/some/path/',
], out: '/some/path/out.dill');
await test([
'foo.dart',
'${Flags.stage}=cfe',
'--out=prefix-',
], out: 'prefix-out.dill');
await test([
'foo.dart',
'${Flags.stage}=cfe',
'--out=/some/path/prefix-',
], out: '/some/path/prefix-out.dill');
// Run CFE only from dill
await test(
['${Flags.stage}=cfe', 'foo.dill'],
cfeFromDill: true,
out: 'out.dill',
);
await test(
['${Flags.stage}=cfe', '--out=out1.dill', 'foo.dill'],
cfeFromDill: true,
out: 'out1.dill',
);
await test([Flags.cfeOnly, 'foo.dill'], cfeFromDill: true, out: 'out.dill');
await test([
Flags.cfeOnly,
'foo.dill',
'--out=out1.dill',
], out: 'out1.dill');
await test(
[Flags.cfeOnly, 'foo.dill', '-oout1.dill'],
cfeFromDill: true,
out: 'out1.dill',
);
await test(
[Flags.cfeOnly, 'foo.dill', '--out=prefix-'],
cfeFromDill: true,
out: 'prefix-',
);
await test(
[Flags.cfeOnly, 'foo.dill', '--out=/some/path/prefix-'],
cfeFromDill: true,
out: '/some/path/prefix-',
);
await test(
['foo.dill', '${Flags.stage}=cfe', '--out=/some/path/'],
cfeFromDill: true,
out: '/some/path/out.dill',
);
await test(
['foo.dill', '${Flags.stage}=cfe', '--out=prefix-'],
cfeFromDill: true,
out: 'prefix-out.dill',
);
await test(
['foo.dill', '${Flags.stage}=cfe', '--out=/some/path/prefix-'],
cfeFromDill: true,
out: '/some/path/prefix-out.dill',
);
// Run deferred load ids only
await test([
'${Flags.stage}=deferred-load-ids',
'foo.dill',
'${Flags.deferredLoadIdMapUri}=load_ids.data',
], writeDeferredLoadIds: 'load_ids.data');
await test([
'${Flags.stage}=deferred-load-ids',
'foo.dill',
], writeDeferredLoadIds: 'deferred_load_ids.data');
// Run closed world only
await test([
'${Flags.stage}=closed-world',
'foo.dill',
], writeClosedWorld: 'world.data');
await test([
'${Flags.stage}=closed-world',
'${Flags.inputDill}=foo.dill',
], writeClosedWorld: 'world.data');
await test([
'${Flags.stage}=closed-world',
'foo.dill',
], writeClosedWorld: 'world.data');
await test([
'${Flags.stage}=closed-world',
'${Flags.closedWorldUri}=world1.data',
'foo.dill',
], writeClosedWorld: 'world1.data');
await test([
'foo.dill',
'${Flags.stage}=closed-world',
'--out=/some/path/',
], writeClosedWorld: '/some/path/world.data');
await test([
'foo.dill',
'${Flags.stage}=closed-world',
'--out=prefix-',
], writeClosedWorld: 'prefix-world.data');
await test([
'foo.dill',
'${Flags.stage}=closed-world',
'--out=/some/path/prefix-',
], writeClosedWorld: '/some/path/prefix-world.data');
await test([
'${Flags.stage}=closed-world',
'foo.dart',
], writeClosedWorld: 'world.data');
// Run global inference only
await test(
['${Flags.stage}=global-inference', 'foo.dill'],
readClosedWorld: 'world.data',
writeData: 'global.data',
);
await test(
['${Flags.stage}=global-inference', '${Flags.inputDill}=foo.dill'],
readClosedWorld: 'world.data',
writeData: 'global.data',
);
await test(
[
'${Flags.stage}=global-inference',
'${Flags.closedWorldUri}=world1.data',
'foo.dill',
],
readClosedWorld: 'world1.data',
writeData: 'global.data',
);
await test(
[
'${Flags.stage}=global-inference',
'${Flags.globalInferenceUri}=global1.data',
'foo.dill',
],
readClosedWorld: 'world.data',
writeData: 'global1.data',
);
await test(
['foo.dill', '${Flags.stage}=global-inference', '--out=/some/path/'],
readClosedWorld: '/some/path/world.data',
writeData: '/some/path/global.data',
);
await test(
['foo.dill', '${Flags.stage}=global-inference', '--out=prefix-'],
readClosedWorld: 'prefix-world.data',
writeData: 'prefix-global.data',
);
await test(
[
'foo.dill',
'${Flags.stage}=global-inference',
'--out=/some/path/prefix-',
],
readClosedWorld: '/some/path/prefix-world.data',
writeData: '/some/path/prefix-global.data',
);
await test(
[
'foo.dill',
'${Flags.stage}=global-inference',
'--out=/some/path/foo.data',
],
readClosedWorld: '/some/path/foo.dataworld.data',
writeData: '/some/path/foo.dataglobal.data',
);
await test(
['foo.dart', '${Flags.stage}=global-inference'],
readClosedWorld: 'world.data',
writeData: 'global.data',
);
// Run codegen only
await test(
[
'${Flags.stage}=codegen',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
'foo.dill',
],
readClosedWorld: 'world.data',
readData: 'global.data',
writeCodegen: 'codegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'${Flags.stage}=codegen',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
'${Flags.inputDill}=foo.dill',
],
readClosedWorld: 'world.data',
readData: 'global.data',
writeCodegen: 'codegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'${Flags.stage}=codegen',
'${Flags.closedWorldUri}=world1.data',
'${Flags.globalInferenceUri}=global1.data',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
'foo.dill',
],
readClosedWorld: 'world1.data',
readData: 'global1.data',
writeCodegen: 'codegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'${Flags.stage}=codegen',
'${Flags.codegenUri}=codegen1',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
'foo.dill',
],
readClosedWorld: 'world.data',
readData: 'global.data',
writeCodegen: 'codegen1',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'foo.dill',
'${Flags.stage}=codegen',
'--out=/some/path/',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
],
readClosedWorld: '/some/path/world.data',
readData: '/some/path/global.data',
writeCodegen: '/some/path/codegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'foo.dill',
'${Flags.stage}=codegen',
'--out=prefix-',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
],
readClosedWorld: 'prefix-world.data',
readData: 'prefix-global.data',
writeCodegen: 'prefix-codegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'foo.dill',
'${Flags.stage}=codegen',
'--out=/some/path/prefix-',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
],
readClosedWorld: '/some/path/prefix-world.data',
readData: '/some/path/prefix-global.data',
writeCodegen: '/some/path/prefix-codegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'foo.dill',
'${Flags.stage}=codegen',
'--out=/some/path/foo.data',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
],
readClosedWorld: '/some/path/foo.dataworld.data',
readData: '/some/path/foo.dataglobal.data',
writeCodegen: '/some/path/foo.datacodegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'foo.dill',
'${Flags.stage}=codegen',
'--out=foo.data',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
],
readClosedWorld: 'foo.dataworld.data',
readData: 'foo.dataglobal.data',
writeCodegen: 'foo.datacodegen',
codegenShard: 10,
codegenShards: 11,
);
await test(
[
'${Flags.stage}=codegen',
'${Flags.codegenShard}=10',
'${Flags.codegenShards}=11',
'foo.dart',
],
readClosedWorld: 'world.data',
readData: 'global.data',
writeCodegen: 'codegen',
codegenShard: 10,
codegenShards: 11,
);
// Run emitter only
await test(
['${Flags.stage}=emit-js', '${Flags.codegenShards}=11', 'foo.dill'],
readClosedWorld: 'world.data',
readData: 'global.data',
readCodegen: 'codegen',
codegenShards: 11,
out: 'out.js',
);
await test(
[
'${Flags.stage}=emit-js',
'${Flags.codegenShards}=11',
'${Flags.inputDill}=foo.dill',
],
readClosedWorld: 'world.data',
readData: 'global.data',
readCodegen: 'codegen',
codegenShards: 11,
out: 'out.js',
);
await test(
[
'${Flags.stage}=emit-js',
'${Flags.closedWorldUri}=world1.data',
'${Flags.globalInferenceUri}=global1.data',
'${Flags.codegenUri}=codegen1',
'${Flags.codegenShards}=11',
'foo.dill',
],
readClosedWorld: 'world1.data',
readData: 'global1.data',
readCodegen: 'codegen1',
codegenShards: 11,
out: 'out.js',
);
await test(
[
'${Flags.stage}=emit-js',
'--out=out.js',
'${Flags.codegenShards}=11',
'foo.dill',
],
readClosedWorld: 'world.data',
readData: 'global.data',
readCodegen: 'codegen',
codegenShards: 11,
out: 'out.js',
);
await test(
[
'foo.dill',
'${Flags.stage}=emit-js',
'--out=/some/path/',
'${Flags.codegenShards}=11',
],
readClosedWorld: '/some/path/world.data',
readData: '/some/path/global.data',
readCodegen: '/some/path/codegen',
codegenShards: 11,
out: '/some/path/out.js',
);
await test(
[
'foo.dill',
'${Flags.stage}=emit-js',
'--out=prefix-',
'${Flags.codegenShards}=11',
],
readClosedWorld: 'prefix-world.data',
readData: 'prefix-global.data',
readCodegen: 'prefix-codegen',
codegenShards: 11,
out: 'prefix-out.js',
);
await test(
[
'foo.dill',
'${Flags.stage}=emit-js',
'--out=/some/path/prefix-',
'${Flags.codegenShards}=11',
],
readClosedWorld: '/some/path/prefix-world.data',
readData: '/some/path/prefix-global.data',
readCodegen: '/some/path/prefix-codegen',
codegenShards: 11,
out: '/some/path/prefix-out.js',
);
await test(
['${Flags.stage}=emit-js', '${Flags.codegenShards}=11', 'foo.dart'],
readClosedWorld: 'world.data',
readData: 'global.data',
readCodegen: 'codegen',
codegenShards: 11,
out: 'out.js',
);
// Run codegen and emitter only
await test(
['${Flags.stage}=codegen-emit-js', 'foo.dill'],
readClosedWorld: 'world.data',
readData: 'global.data',
out: 'out.js',
);
await test(
['${Flags.stage}=codegen-emit-js', '${Flags.inputDill}=foo.dill'],
readClosedWorld: 'world.data',
readData: 'global.data',
out: 'out.js',
);
await test(
[
'${Flags.stage}=codegen-emit-js',
'${Flags.closedWorldUri}=world1.data',
'${Flags.globalInferenceUri}=global1.data',
'foo.dill',
],
readClosedWorld: 'world1.data',
readData: 'global1.data',
out: 'out.js',
);
await test(
['${Flags.stage}=codegen-emit-js', '--out=out.js', 'foo.dill'],
readClosedWorld: 'world.data',
readData: 'global.data',
out: 'out.js',
);
await test(
['foo.dill', '${Flags.stage}=codegen-emit-js', '--out=/some/path/'],
readClosedWorld: '/some/path/world.data',
readData: '/some/path/global.data',
out: '/some/path/out.js',
);
await test(
['foo.dill', '${Flags.stage}=codegen-emit-js', '--out=prefix-'],
readClosedWorld: 'prefix-world.data',
readData: 'prefix-global.data',
out: 'prefix-out.js',
);
await test(
[
'foo.dill',
'${Flags.stage}=codegen-emit-js',
'--out=/some/path/prefix-',
],
readClosedWorld: '/some/path/prefix-world.data',
readData: '/some/path/prefix-global.data',
out: '/some/path/prefix-out.js',
);
await test(
['${Flags.stage}=codegen-emit-js', 'foo.dart'],
readClosedWorld: 'world.data',
readData: 'global.data',
out: 'out.js',
);
// Invalid states with stage flag
// Codegen stage
await test(
[
'${Flags.stage}=codegen',
'${Flags.codegenUri}=codegen',
'${Flags.codegenShards}=1',
'foo.dill',
],
readCodegen: 'codegen',
out: 'out.js',
exitCode: 1,
);
await test(
[
'${Flags.stage}=codegen',
'${Flags.codegenUri}=codegen',
'${Flags.codegenShard}=0',
'foo.dill',
],
readCodegen: 'codegen',
out: 'out.js',
exitCode: 1,
);
// JS Emitter stage
await test(['${Flags.stage}=emit-js', 'foo.dart'], exitCode: 1);
// Omit memory summary.
await test(['--omit-memory-summary', 'foo.dart'], out: 'out.js');
});
}
Future test(
List<String> arguments, {
int? exitCode,
String? out,
bool allFromDill = false,
bool cfeFromDill = false,
bool cfeModularAnalysis = false,
String? readClosedWorld,
String? writeClosedWorld,
String? writeDeferredLoadIds,
String? readData,
String? writeData,
String? readCodegen,
String? writeCodegen,
int? codegenShard,
int? codegenShards,
}) async {
print('--------------------------------------------------------------------');
print('dart2js ${arguments.join(' ')}');
print('--------------------------------------------------------------------');
entry.CompileFunc oldCompileFunc = entry.compileFunc;
entry.ExitFunc oldExitFunc = entry.exitFunc;
late final CompilerOptions options;
int? actualExitCode;
entry.compileFunc = (_options, input, diagnostics, output) {
options = _options;
return Future<api.CompilationResult>.value(api.CompilationResult(null));
};
entry.exitFunc = (_exitCode) {
actualExitCode = _exitCode;
throw 'exited';
};
try {
await entry.compilerMain(arguments);
} catch (e, s) {
Expect.equals('exited', e, "Unexpected exception: $e\n$s");
}
Expect.equals(exitCode, actualExitCode, "Unexpected exit code");
if (actualExitCode == null) {
Expect.equals(toUri(out), options.outputUri, "Unexpected output uri.");
if (allFromDill || cfeFromDill) {
Expect.isNotNull(options.compilationTarget.path.endsWith('.dill'));
}
if (writeDeferredLoadIds == null) {
Expect.notEquals(options.stage, CompilerStage.deferredLoadIds);
} else {
Expect.equals(options.stage, CompilerStage.deferredLoadIds);
Expect.equals(
toUri(writeDeferredLoadIds),
options.dataUriForStage(CompilerStage.deferredLoadIds),
"Unexpected writeDeferredLoadIds uri",
);
}
if (readClosedWorld == null) {
Expect.isFalse(options.stage.shouldReadClosedWorld);
} else {
Expect.isTrue(options.stage.shouldReadClosedWorld);
Expect.equals(
toUri(readClosedWorld),
options.dataUriForStage(CompilerStage.closedWorld),
"Unexpected readClosedWorld uri",
);
}
if (writeClosedWorld == null) {
Expect.notEquals(options.stage, CompilerStage.closedWorld);
} else {
Expect.equals(options.stage, CompilerStage.closedWorld);
Expect.equals(
toUri(writeClosedWorld),
options.dataUriForStage(CompilerStage.closedWorld),
"Unexpected writeClosedWorld uri",
);
}
if (readData == null) {
Expect.isFalse(options.stage.shouldReadGlobalInference);
} else {
Expect.isTrue(options.stage.shouldReadGlobalInference);
Expect.equals(
toUri(readData),
options.dataUriForStage(CompilerStage.globalInference),
"Unexpected readData uri",
);
}
if (writeData == null) {
Expect.notEquals(options.stage, CompilerStage.globalInference);
} else {
Expect.equals(options.stage, CompilerStage.globalInference);
Expect.equals(
toUri(writeData),
options.dataUriForStage(CompilerStage.globalInference),
"Unexpected writeData uri",
);
}
if (readCodegen == null) {
Expect.isFalse(options.stage.shouldReadCodegenShards);
} else {
Expect.isTrue(options.stage.shouldReadCodegenShards);
Expect.equals(
toUri(readCodegen),
options.dataUriForStage(CompilerStage.codegenSharded),
"Unexpected readCodegen uri",
);
}
if (writeCodegen == null) {
Expect.notEquals(options.stage, CompilerStage.codegenSharded);
} else {
Expect.equals(options.stage, CompilerStage.codegenSharded);
Expect.equals(
toUri(writeCodegen),
options.dataUriForStage(CompilerStage.codegenSharded),
"Unexpected writeCodegen uri",
);
}
Expect.equals(
codegenShard,
options.codegenShard,
"Unexpected codegenShard uri",
);
Expect.equals(
codegenShards,
options.codegenShards,
"Unexpected codegenShards uri",
);
}
entry.compileFunc = oldCompileFunc;
entry.exitFunc = oldExitFunc;
}
Uri? toUri(String? path) => path != null ? Uri.base.resolve(path) : null;