| // 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 'dart:async'; |
| |
| import 'package:front_end/src/api_prototype/compiler_options.dart'; |
| import 'package:front_end/src/api_prototype/memory_file_system.dart'; |
| import 'package:front_end/src/base/processed_options.dart'; |
| import 'package:front_end/src/fasta/compiler_context.dart'; |
| import 'package:front_end/src/fasta/util/bytes_sink.dart' show BytesSink; |
| import 'package:front_end/src/fasta/fasta_codes.dart'; |
| import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter; |
| import 'package:kernel/kernel.dart' |
| show CanonicalName, Library, Program, loadProgramFromBytes; |
| import 'package:package_config/packages.dart' show Packages; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| main() { |
| CompilerContext.runWithDefaultOptions((_) { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(ProcessedOptionsTest); |
| }); |
| }); |
| } |
| |
| @reflectiveTest |
| class ProcessedOptionsTest { |
| MemoryFileSystem fileSystem = |
| new MemoryFileSystem(Uri.parse('org-dartlang-test:///')); |
| |
| Program _mockOutline; |
| |
| Program get mockSummary => _mockOutline ??= new Program( |
| libraries: [new Library(Uri.parse('org-dartlang-test:///a/b.dart'))]); |
| |
| test_compileSdk_false() { |
| for (var value in [false, true]) { |
| var raw = new CompilerOptions()..compileSdk = value; |
| var processed = new ProcessedOptions(raw); |
| expect(processed.compileSdk, value); |
| } |
| } |
| |
| test_sdk_summary_inferred() { |
| // The sdk-summary is inferred by default form sdk-root, when compile-sdk is |
| // false |
| var raw = new CompilerOptions() |
| ..sdkRoot = Uri.parse('org-dartlang-test:///sdk/dir/') |
| ..compileSdk = false; |
| expect(new ProcessedOptions(raw).sdkSummary, |
| Uri.parse('org-dartlang-test:///sdk/dir/vm_platform.dill')); |
| |
| // But it is left null when compile-sdk is true |
| raw = new CompilerOptions() |
| ..sdkRoot = Uri.parse('org-dartlang-test:///sdk/dir/') |
| ..compileSdk = true; |
| expect(new ProcessedOptions(raw).sdkSummary, null); |
| } |
| |
| test_fileSystem_noBazelRoots() { |
| // When no bazel roots are specified, the filesystem should be passed |
| // through unmodified. |
| var raw = new CompilerOptions()..fileSystem = fileSystem; |
| var processed = new ProcessedOptions(raw); |
| expect(processed.fileSystem, same(fileSystem)); |
| } |
| |
| test_getSdkSummaryBytes_summaryLocationProvided() async { |
| var uri = Uri.parse('org-dartlang-test:///sdkSummary'); |
| |
| writeMockSummaryTo(uri); |
| |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..sdkSummary = uri; |
| var processed = new ProcessedOptions(raw); |
| |
| var bytes = await processed.loadSdkSummaryBytes(); |
| expect(bytes, isNotEmpty); |
| |
| var sdkSummary = loadProgramFromBytes(bytes); |
| expect(sdkSummary.libraries.single.importUri, |
| mockSummary.libraries.single.importUri); |
| } |
| |
| test_getSdkSummary_summaryLocationProvided() async { |
| var uri = Uri.parse('org-dartlang-test:///sdkSummary'); |
| writeMockSummaryTo(uri); |
| checkMockSummary(new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..sdkSummary = uri); |
| } |
| |
| void writeMockSummaryTo(Uri uri) { |
| var sink = new BytesSink(); |
| new BinaryPrinter(sink).writeProgramFile(mockSummary); |
| fileSystem.entityForUri(uri).writeAsBytesSync(sink.builder.takeBytes()); |
| } |
| |
| Future<Null> checkMockSummary(CompilerOptions raw) async { |
| var processed = new ProcessedOptions(raw); |
| var sdkSummary = await processed.loadSdkSummary(new CanonicalName.root()); |
| expect(sdkSummary.libraries.single.importUri, |
| mockSummary.libraries.single.importUri); |
| } |
| |
| test_getUriTranslator_explicitLibrariesSpec() async { |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync(''); |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///libraries.json')) |
| .writeAsStringSync('{"vm":{"libraries":{"foo":{"uri":"bar.dart"}}}}'); |
| var raw = new CompilerOptions() |
| ..packagesFileUri = Uri.parse('org-dartlang-test:///.packages') |
| ..fileSystem = fileSystem |
| ..librariesSpecificationUri = |
| Uri.parse('org-dartlang-test:///libraries.json'); |
| var processed = new ProcessedOptions(raw); |
| var uriTranslator = await processed.getUriTranslator(); |
| expect(uriTranslator.dartLibraries.libraryInfoFor('foo').uri.path, |
| '/bar.dart'); |
| } |
| |
| test_getUriTranslator_inferredLibrariesSpec() async { |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync(''); |
| fileSystem |
| .entityForUri( |
| Uri.parse('org-dartlang-test:///mysdk/lib/libraries.json')) |
| .writeAsStringSync('{"vm":{"libraries":{"foo":{"uri":"bar.dart"}}}}'); |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..packagesFileUri = Uri.parse('org-dartlang-test:///.packages') |
| ..compileSdk = true |
| ..sdkRoot = Uri.parse('org-dartlang-test:///mysdk/'); |
| var processed = new ProcessedOptions(raw); |
| var uriTranslator = await processed.getUriTranslator(); |
| expect(uriTranslator.dartLibraries.libraryInfoFor('foo').uri.path, |
| '/mysdk/lib/bar.dart'); |
| } |
| |
| test_getUriTranslator_notInferredLibrariesSpec() async { |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync(''); |
| fileSystem |
| .entityForUri( |
| Uri.parse('org-dartlang-test:///mysdk/lib/libraries.json')) |
| .writeAsStringSync('{"vm":{"libraries":{"foo":{"uri":"bar.dart"}}}}'); |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..packagesFileUri = Uri.parse('org-dartlang-test:///.packages') |
| ..compileSdk = false // libraries.json is only inferred if true |
| ..sdkRoot = Uri.parse('org-dartlang-test:///mysdk/'); |
| var processed = new ProcessedOptions(raw); |
| var uriTranslator = await processed.getUriTranslator(); |
| expect(uriTranslator.dartLibraries.libraryInfoFor('foo'), isNull); |
| } |
| |
| checkPackageExpansion( |
| String packageName, String packageDir, Packages packages) { |
| var input = Uri.parse('package:$packageName/a.dart'); |
| var expected = Uri.parse('org-dartlang-test:///$packageDir/a.dart'); |
| expect(packages.resolve(input), expected); |
| } |
| |
| test_getUriTranslator_explicitPackagesFile() async { |
| // This .packages file should be ignored. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync('foo:bar\n'); |
| // This one should be used. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///explicit.packages')) |
| .writeAsStringSync('foo:baz\n'); |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..packagesFileUri = Uri.parse('org-dartlang-test:///explicit.packages'); |
| var processed = new ProcessedOptions(raw); |
| var uriTranslator = await processed.getUriTranslator(); |
| checkPackageExpansion('foo', 'baz', uriTranslator.packages); |
| } |
| |
| test_getUriTranslator_explicitPackagesFile_withBaseLocation() async { |
| // This .packages file should be ignored. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync('foo:bar\n'); |
| // This one should be used. |
| fileSystem |
| .entityForUri( |
| Uri.parse('org-dartlang-test:///base/location/explicit.packages')) |
| .writeAsStringSync('foo:baz\n'); |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..packagesFileUri = |
| Uri.parse('org-dartlang-test:///base/location/explicit.packages'); |
| var processed = new ProcessedOptions(raw); |
| var uriTranslator = await processed.getUriTranslator(); |
| checkPackageExpansion('foo', 'base/location/baz', uriTranslator.packages); |
| } |
| |
| test_getUriTranslator_implicitPackagesFile_ambiguous() async { |
| // This .packages file should be ignored. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync('foo:bar\n'); |
| // This one should be used. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///explicit.packages')) |
| .writeAsStringSync('foo:baz\n'); |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..packagesFileUri = Uri.parse('org-dartlang-test:///explicit.packages'); |
| var processed = new ProcessedOptions(raw); |
| var uriTranslator = await processed.getUriTranslator(); |
| checkPackageExpansion('foo', 'baz', uriTranslator.packages); |
| } |
| |
| test_getUriTranslator_implicitPackagesFile_nextToScript() async { |
| // Create the base directory. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/location/')) |
| .createDirectory(); |
| // Packages directory should be ignored (.packages file takes precedence). |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/location/packages/')) |
| .createDirectory(); |
| // This .packages file should be ignored. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync('foo:bar\n'); |
| // This one should be used. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/location/.packages')) |
| .writeAsStringSync('foo:baz\n'); |
| var raw = new CompilerOptions()..fileSystem = fileSystem; |
| var processed = new ProcessedOptions(raw, false, |
| [Uri.parse('org-dartlang-test:///base/location/script.dart')]); |
| var uriTranslator = await processed.getUriTranslator(); |
| checkPackageExpansion('foo', 'base/location/baz', uriTranslator.packages); |
| } |
| |
| test_getUriTranslator_implicitPackagesFile_searchAbove() async { |
| // Create the base directory. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/location/')) |
| .createDirectory(); |
| // This .packages file should be ignored. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync('foo:bar\n'); |
| // This one should be used. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/.packages')) |
| .writeAsStringSync('foo:baz\n'); |
| var raw = new CompilerOptions()..fileSystem = fileSystem; |
| var processed = new ProcessedOptions(raw, false, |
| [Uri.parse('org-dartlang-test:///base/location/script.dart')]); |
| var uriTranslator = await processed.getUriTranslator(); |
| checkPackageExpansion('foo', 'base/baz', uriTranslator.packages); |
| } |
| |
| test_getUriTranslator_implicitPackagesFile_packagesDirectory() async { |
| // Create the base directory. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/location/')) |
| .createDirectory(); |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/location/packages/')) |
| .createDirectory(); |
| |
| // Both of these .packages file should be ignored. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync('foo:bar\n'); |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/.packages')) |
| .writeAsStringSync('foo:baz\n'); |
| var raw = new CompilerOptions()..fileSystem = fileSystem; |
| var processed = new ProcessedOptions(raw, false, |
| [Uri.parse('org-dartlang-test:///base/location/script.dart')]); |
| var uriTranslator = await processed.getUriTranslator(); |
| checkPackageExpansion( |
| 'foo', 'base/location/packages/foo', uriTranslator.packages); |
| } |
| |
| test_getUriTranslator_implicitPackagesFile_noPackages() async { |
| // Create the base directory. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///base/location/')) |
| .createDirectory(); |
| var errors = []; |
| // .packages file should be ignored. |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var processed = new ProcessedOptions(raw, false, |
| [Uri.parse('org-dartlang-test:///base/location/script.dart')]); |
| var uriTranslator = await processed.getUriTranslator(); |
| expect(errors, isEmpty); |
| expect(uriTranslator.packages.asMap(), isEmpty); |
| } |
| |
| test_getUriTranslator_noPackages() async { |
| var errors = []; |
| // .packages file should be ignored. |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///.packages')) |
| .writeAsStringSync('foo:bar\n'); |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..packagesFileUri = new Uri() |
| ..onError = (e) => errors.add(e); |
| var processed = new ProcessedOptions(raw); |
| var uriTranslator = await processed.getUriTranslator(); |
| expect(uriTranslator.packages.asMap(), isEmpty); |
| expect(errors.single.message, |
| startsWith(_stringPrefixOf(templateCannotReadPackagesFile))); |
| } |
| |
| test_validateOptions_noInputs() async { |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///foo.dart')) |
| .writeAsStringSync('main(){}\n'); |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw); |
| var result = await options.validateOptions(); |
| expect(errors.single.message, messageMissingInput.message); |
| expect(result, isFalse); |
| } |
| |
| test_validateOptions_input_doesnt_exist() async { |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw, false, [Uri.parse('foo.dart')]); |
| var result = await options.validateOptions(); |
| expect(errors.single.message, |
| startsWith(_stringPrefixOf(templateInputFileNotFound))); |
| expect(result, isFalse); |
| } |
| |
| test_validateOptions_root_exists() async { |
| var sdkRoot = Uri.parse('org-dartlang-test:///sdk/root/'); |
| fileSystem |
| // Note: this test is a bit hackish because the memory file system |
| // doesn't have the notion of directories. |
| .entityForUri(sdkRoot) |
| .writeAsStringSync('\n'); |
| fileSystem |
| .entityForUri(sdkRoot.resolve('vm_platform.dill')) |
| .writeAsStringSync('\n'); |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///foo.dart')) |
| .writeAsStringSync('main(){}\n'); |
| |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..sdkRoot = sdkRoot |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw, false, [Uri.parse('foo.dart')]); |
| var result = await options.validateOptions(); |
| // Note: we check this first so test failures show the cause directly. |
| expect(errors, isEmpty); |
| expect(result, isTrue); |
| } |
| |
| test_validateOptions_root_doesnt_exists() async { |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///foo.dart')) |
| .writeAsStringSync('main(){}\n'); |
| var sdkRoot = Uri.parse('org-dartlang-test:///sdk/root'); |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..sdkRoot = sdkRoot |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw, false, [Uri.parse('foo.dart')]); |
| expect(await options.validateOptions(), isFalse); |
| expect(errors.first.message, |
| startsWith(_stringPrefixOf(templateSdkRootNotFound))); |
| } |
| |
| test_validateOptions_summary_exists() async { |
| var sdkSummary = Uri.parse('org-dartlang-test:///sdk/root/outline.dill'); |
| fileSystem.entityForUri(sdkSummary).writeAsStringSync('\n'); |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///foo.dart')) |
| .writeAsStringSync('main(){}\n'); |
| |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..sdkSummary = sdkSummary |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw, false, [Uri.parse('foo.dart')]); |
| var result = await options.validateOptions(); |
| expect(errors, isEmpty); |
| expect(result, isTrue); |
| } |
| |
| test_validateOptions_summary_doesnt_exists() async { |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///foo.dart')) |
| .writeAsStringSync('main(){}\n'); |
| var sdkSummary = Uri.parse('org-dartlang-test:///sdk/root/outline.dill'); |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..sdkSummary = sdkSummary |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw, false, [Uri.parse('foo.dart')]); |
| expect(await options.validateOptions(), isFalse); |
| expect(errors.single.message, |
| startsWith(_stringPrefixOf(templateSdkSummaryNotFound))); |
| } |
| |
| test_validateOptions_inferred_summary_exists() async { |
| var sdkRoot = Uri.parse('org-dartlang-test:///sdk/root/'); |
| var sdkSummary = |
| Uri.parse('org-dartlang-test:///sdk/root/vm_platform.dill'); |
| fileSystem.entityForUri(sdkRoot).writeAsStringSync('\n'); |
| fileSystem.entityForUri(sdkSummary).writeAsStringSync('\n'); |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///foo.dart')) |
| .writeAsStringSync('main(){}\n'); |
| |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..sdkRoot = sdkRoot |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw, false, [Uri.parse('foo.dart')]); |
| var result = await options.validateOptions(); |
| expect(errors, isEmpty); |
| expect(result, isTrue); |
| } |
| |
| test_validateOptions_inferred_summary_doesnt_exists() async { |
| var sdkRoot = Uri.parse('org-dartlang-test:///sdk/root/'); |
| var sdkSummary = Uri.parse('org-dartlang-test:///sdk/root/outline.dill'); |
| fileSystem.entityForUri(sdkRoot).writeAsStringSync('\n'); |
| fileSystem |
| .entityForUri(Uri.parse('org-dartlang-test:///foo.dart')) |
| .writeAsStringSync('main(){}\n'); |
| var errors = []; |
| var raw = new CompilerOptions() |
| ..sdkSummary = sdkSummary |
| ..fileSystem = fileSystem |
| ..onError = (e) => errors.add(e); |
| var options = new ProcessedOptions(raw, false, [Uri.parse('foo.dart')]); |
| expect(await options.validateOptions(), isFalse); |
| expect(errors.single.message, |
| startsWith(_stringPrefixOf(templateSdkSummaryNotFound))); |
| } |
| |
| /// Returns the longest prefix of the text in a message template that doesn't |
| /// mention a template argument. |
| _stringPrefixOf(Template template) { |
| var messageTemplate = template.messageTemplate; |
| var index = messageTemplate.indexOf('#'); |
| var prefix = messageTemplate.substring(0, index - 1); |
| |
| // Check that the prefix is not empty and that it contains more than one |
| // word. |
| expect(prefix.length > 0, isTrue); |
| expect(prefix.contains(' '), isTrue); |
| return prefix; |
| } |
| } |