| // Copyright (c) 2017, 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 'package:kernel/ast.dart' |
| show EmptyStatement, Component, ReturnStatement, StaticInvocation; |
| |
| import 'package:test/test.dart' |
| show |
| expect, |
| greaterThan, |
| group, |
| isEmpty, |
| isFalse, |
| isNotEmpty, |
| isNotNull, |
| isTrue, |
| same, |
| test; |
| |
| import 'package:front_end/src/api_prototype/front_end.dart' |
| show CompilerOptions; |
| |
| import 'package:front_end/src/fasta/fasta_codes.dart' show messageMissingMain; |
| |
| import 'package:front_end/src/fasta/kernel/utils.dart' show serializeComponent; |
| |
| import 'package:front_end/src/testing/compiler_common.dart' |
| show |
| compileScript, |
| compileUnit, |
| findLibrary, |
| invalidCoreLibsSpecUri, |
| isDartCoreLibrary; |
| |
| main() { |
| group('kernelForProgram', () { |
| test('compiler fails if it cannot find sdk sources', () async { |
| var errors = []; |
| var options = new CompilerOptions() |
| ..librariesSpecificationUri = invalidCoreLibsSpecUri |
| ..sdkSummary = null |
| ..compileSdk = true // To prevent FE from loading an sdk-summary. |
| ..onDiagnostic = errors.add; |
| |
| Component component = |
| (await compileScript('main() => print("hi");', options: options)) |
| ?.component; |
| expect(component, isNotNull); |
| expect(errors, isNotEmpty); |
| }); |
| |
| test('compiler fails if it cannot find sdk summary', () async { |
| var errors = []; |
| var options = new CompilerOptions() |
| ..sdkSummary = |
| Uri.parse('org-dartlang-test:///not_existing_summary_file') |
| ..onDiagnostic = errors.add; |
| |
| Component component = |
| (await compileScript('main() => print("hi");', options: options)) |
| ?.component; |
| expect(component, isNotNull); |
| expect(errors, isNotEmpty); |
| }); |
| |
| test('by default component is compiled using the full platform file', |
| () async { |
| var options = new CompilerOptions() |
| // Note: we define [librariesSpecificationUri] with a specification that |
| // contains broken URIs to ensure we do not attempt to lookup for |
| // sources of the sdk directly. |
| ..librariesSpecificationUri = invalidCoreLibsSpecUri; |
| Component component = |
| (await compileScript('main() => print("hi");', options: options)) |
| ?.component; |
| var core = component.libraries.firstWhere(isDartCoreLibrary); |
| var printMember = core.members.firstWhere((m) => m.name.name == 'print'); |
| |
| // Note: summaries created by the SDK today contain empty statements as |
| // method bodies. |
| expect(printMember.function.body is! EmptyStatement, isTrue); |
| }); |
| |
| test('compiler requires a main method', () async { |
| var errors = []; |
| var options = new CompilerOptions()..onDiagnostic = errors.add; |
| await compileScript('a() => print("hi");', options: options); |
| expect(errors.first.message, messageMissingMain.message); |
| }); |
| |
| test('generated program contains source-info', () async { |
| Component component = (await compileScript( |
| 'a() => print("hi"); main() {}', |
| fileName: 'a.dart')) |
| ?.component; |
| // Kernel always store an empty '' key in the map, so there is always at |
| // least one. Having more means that source-info is added. |
| expect(component.uriToSource.keys.length, greaterThan(1)); |
| expect( |
| component.uriToSource[Uri.parse('org-dartlang-test:///a/b/c/a.dart')], |
| isNotNull); |
| }); |
| |
| test('code from summary dependencies are marked external', () async { |
| Component component = (await compileScript( |
| 'a() => print("hi"); main() {}', |
| fileName: 'a.dart')) |
| ?.component; |
| for (var lib in component.libraries) { |
| if (lib.importUri.scheme == 'dart') { |
| expect(lib.isExternal, isTrue); |
| } |
| } |
| |
| // Pretend that the compiled code is a summary |
| var bytes = serializeComponent(component); |
| component = (await compileScript( |
| { |
| 'b.dart': 'import "a.dart" as m; b() => m.a(); main() {}', |
| 'summary.dill': bytes |
| }, |
| fileName: 'b.dart', |
| inputSummaries: ['summary.dill'])) |
| ?.component; |
| |
| var aLib = component.libraries |
| .firstWhere((lib) => lib.importUri.path == '/a/b/c/a.dart'); |
| expect(aLib.isExternal, isTrue); |
| }); |
| |
| test('code from linked dependencies are not marked external', () async { |
| Component component = (await compileScript( |
| 'a() => print("hi"); main() {}', |
| fileName: 'a.dart')) |
| ?.component; |
| for (var lib in component.libraries) { |
| if (lib.importUri.scheme == 'dart') { |
| expect(lib.isExternal, isTrue); |
| } |
| } |
| |
| var bytes = serializeComponent(component); |
| component = (await compileScript( |
| { |
| 'b.dart': 'import "a.dart" as m; b() => m.a(); main() {}', |
| 'link.dill': bytes |
| }, |
| fileName: 'b.dart', |
| linkedDependencies: ['link.dill'])) |
| ?.component; |
| |
| var aLib = component.libraries |
| .firstWhere((lib) => lib.importUri.path == '/a/b/c/a.dart'); |
| expect(aLib.isExternal, isFalse); |
| }); |
| |
| // TODO(sigmund): add tests discovering libraries.json |
| }); |
| |
| group('kernelForComponent', () { |
| test('compiler does not require a main method', () async { |
| var errors = []; |
| var options = new CompilerOptions()..onDiagnostic = errors.add; |
| await compileUnit(['a.dart'], {'a.dart': 'a() => print("hi");'}, |
| options: options); |
| expect(errors, isEmpty); |
| }); |
| |
| test('compiler is not hermetic by default', () async { |
| var errors = []; |
| var options = new CompilerOptions()..onDiagnostic = errors.add; |
| await compileUnit([ |
| 'a.dart' |
| ], { |
| 'a.dart': 'import "b.dart"; a() => print("hi");', |
| 'b.dart': '' |
| }, options: options); |
| expect(errors, isEmpty); |
| }); |
| |
| test('dependencies can be loaded in any order', () async { |
| var sources = <String, dynamic>{ |
| 'a.dart': 'a() => print("hi");', |
| 'b.dart': 'import "a.dart"; b() => a();', |
| 'c.dart': 'import "b.dart"; c() => b();', |
| 'd.dart': 'import "c.dart"; d() => c();', |
| }; |
| |
| var unitA = await compileUnit(['a.dart'], sources); |
| // Pretend that the compiled code is a summary |
| sources['a.dill'] = serializeComponent(unitA); |
| |
| var unitBC = await compileUnit(['b.dart', 'c.dart'], sources, |
| inputSummaries: ['a.dill']); |
| |
| // Pretend that the compiled code is a summary |
| sources['bc.dill'] = serializeComponent(unitBC); |
| |
| void checkDCallsC(Component component) { |
| var dLib = findLibrary(component, 'd.dart'); |
| var cLib = findLibrary(component, 'c.dart'); |
| var dMethod = dLib.procedures.first; |
| var dBody = dMethod.function.body; |
| var dCall = (dBody as ReturnStatement).expression; |
| var callTarget = |
| (dCall as StaticInvocation).targetReference.asProcedure; |
| expect(callTarget, same(cLib.procedures.first)); |
| } |
| |
| var unitD1 = await compileUnit(['d.dart'], sources, |
| inputSummaries: ['a.dill', 'bc.dill']); |
| checkDCallsC(unitD1); |
| |
| var unitD2 = await compileUnit(['d.dart'], sources, |
| inputSummaries: ['bc.dill', 'a.dill']); |
| checkDCallsC(unitD2); |
| }); |
| |
| // TODO(sigmund): add tests with trimming dependencies |
| }); |
| } |