Simplify how patch files are specified to analyzer.

After discussion with kmillikin@, sigmund@, and scheglov@, we decided
that specifying the patch files in libraries.dart is more complex (and
less flexible) than we'd like.  This CL changes things so that the
patch files are specified in analysis options using a simple map from
library name (e.g. "dart:core") to a list of patch file paths.

Clients are now allowed to put patch files wherever they want; they
don't need to be inside the sdk directory.

Note that we no longer include the patch configuration in
encodeCrossContextOptions.  This should be ok, since we don't have any
use case in which a single instance of analyzer needs to accommodate
multiple patch configurations.

R=scheglov@google.com

Review-Url: https://codereview.chromium.org/2560323002 .
This commit is contained in:
Paul Berry 2016-12-12 10:15:18 -08:00
parent d217b21ca6
commit 02fe40c6f7
10 changed files with 81 additions and 348 deletions

View file

@ -439,7 +439,4 @@ class MockSdkLibrary implements SdkLibrary {
bool get isVmLibrary => throw unimplemented;
UnimplementedError get unimplemented => new UnimplementedError();
@override
List<String> getPatches(int platform) => const <String>[];
}

View file

@ -301,7 +301,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
this._options.enableStrictCallChecks !=
options.enableStrictCallChecks ||
this._options.enableSuperMixins != options.enableSuperMixins ||
this._options.patchPlatform != options.patchPlatform;
!_samePatchPaths(this._options.patchPaths, options.patchPaths);
this._options.analyzeFunctionBodiesPredicate =
options.analyzeFunctionBodiesPredicate;
this._options.generateImplicitErrors = options.generateImplicitErrors;
@ -329,7 +329,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
this._options.trackCacheDependencies = options.trackCacheDependencies;
this._options.disableCacheFlushing = options.disableCacheFlushing;
this._options.finerGrainedInvalidation = options.finerGrainedInvalidation;
this._options.patchPlatform = options.patchPlatform;
this._options.patchPaths = options.patchPaths;
if (options is AnalysisOptionsImpl) {
this._options.strongModeHints = options.strongModeHints;
this._options.implicitCasts = options.implicitCasts;
@ -1967,6 +1967,21 @@ class AnalysisContextImpl implements InternalAnalysisContext {
return true;
});
}
static bool _samePatchPaths(
Map<String, List<String>> a, Map<String, List<String>> b) {
if (a.length != b.length) return false;
for (var key in a.keys) {
if (!b.containsKey(key)) return false;
var aValue = a[key];
var bValue = b[key];
if (aValue.length != bValue.length) return false;
for (var i = 0; i < aValue.length; i++) {
if (aValue[i] != bValue[i]) return false;
}
}
return true;
}
}
/**

View file

@ -10,12 +10,9 @@ import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:meta/meta.dart';
import 'package:path/src/context.dart';
/**
* [SdkPatcher] applies patches to SDK [CompilationUnit].
@ -28,12 +25,13 @@ class SdkPatcher {
/**
* Patch the given [unit] of a SDK [source] with the patches defined in
* the [sdk] for the given [platform]. Throw [ArgumentError] if a patch
* [allPatchPaths]. Throw [ArgumentError] if a patch
* file cannot be read, or the contents violates rules for patch files.
*/
void patch(
FolderBasedDartSdk sdk,
int platform,
ResourceProvider resourceProvider,
bool strongMode,
Map<String, List<String>> allPatchPaths,
AnalysisErrorListener errorListener,
Source source,
CompilationUnit unit) {
@ -53,21 +51,10 @@ class SdkPatcher {
_allowNewPublicNames = libraryName == '_internal';
}
// Prepare the patch files to apply.
List<String> patchPaths;
{
SdkLibrary sdkLibrary = sdk.getSdkLibrary(libraryUriStr);
if (sdkLibrary == null) {
throw new ArgumentError(
'The library $libraryUriStr is not defined in the SDK.');
}
patchPaths = sdkLibrary.getPatches(platform);
}
List<String> patchPaths = allPatchPaths[libraryUriStr];
bool strongMode = sdk.context.analysisOptions.strongMode;
Context pathContext = sdk.resourceProvider.pathContext;
for (String path in patchPaths) {
String pathInLib = pathContext.joinAll(path.split('/'));
File patchFile = sdk.libraryDirectory.getChildAssumingFile(pathInLib);
File patchFile = resourceProvider.getFile(path);
if (!patchFile.exists) {
throw new ArgumentError(
'The patch file ${patchFile.path} for $source does not exist.');

View file

@ -1131,7 +1131,7 @@ abstract class AnalysisOptions {
/**
* The length of the list returned by [encodeCrossContextOptions].
*/
static const int crossContextOptionsLength = 2;
static const int crossContextOptionsLength = 1;
/**
* Function that returns `true` if analysis is to parse and analyze function
@ -1296,10 +1296,10 @@ abstract class AnalysisOptions {
List<Linter> get lintRules;
/**
* Return the "platform" bit mask which should be used to apply patch files,
* or `0` if no patch files should be applied.
* A mapping from Dart SDK library name (e.g. "dart:core") to a list of paths
* to patch files that should be applied to the library.
*/
int get patchPlatform;
Map<String, List<String>> get patchPaths;
/**
* Return `true` if analysis is to parse comments.
@ -1453,8 +1453,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
*/
List<Linter> _lintRules;
@override
int patchPlatform = 0;
Map<String, List<String>> patchPaths = {};
@override
bool preserveComments = true;
@ -1544,7 +1543,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
trackCacheDependencies = options.trackCacheDependencies;
disableCacheFlushing = options.disableCacheFlushing;
finerGrainedInvalidation = options.finerGrainedInvalidation;
patchPlatform = options.patchPlatform;
patchPaths = options.patchPaths;
}
bool get analyzeFunctionBodies {
@ -1655,7 +1654,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
(enableSuperMixins ? ENABLE_SUPER_MIXINS_FLAG : 0) |
(strongMode ? ENABLE_STRONG_MODE_FLAG : 0) |
(strongModeHints ? ENABLE_STRONG_MODE_HINTS_FLAG : 0);
return <int>[flags, patchPlatform];
return <int>[flags];
}
@override
@ -1682,7 +1681,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
lint = false;
_lintRules = null;
nonnullableTypes = NONNULLABLE_TYPES;
patchPlatform = 0;
patchPaths = {};
preserveComments = true;
strongMode = false;
strongModeHints = false;
@ -1698,7 +1697,6 @@ class AnalysisOptionsImpl implements AnalysisOptions {
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
}
patchPlatform = options.patchPlatform;
}
/**

View file

@ -7,7 +7,6 @@ library analyzer.src.generated.sdk;
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisOptions, AnalysisOptionsImpl;
@ -290,11 +289,6 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor<Object> {
*/
static String _DART2JS_PATH = "dart2jsPath";
/**
* The name of the `dart2js` platform.
*/
static String _DART2JS_PLATFORM = 'DART2JS_PLATFORM';
/**
* The name of the optional parameter used to indicate whether the library is
* documented.
@ -307,12 +301,6 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor<Object> {
*/
static String _CATEGORIES = "categories";
/**
* The name of the optional parameter used to specify the patches for
* the library.
*/
static String _PATCHES = "patches";
/**
* The name of the optional parameter used to specify the platforms on which
* the library can be used.
@ -391,30 +379,6 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor<Object> {
library._implementation = (expression as BooleanLiteral).value;
} else if (name == _DOCUMENTED) {
library.documented = (expression as BooleanLiteral).value;
} else if (name == _PATCHES) {
if (expression is MapLiteral) {
expression.entries.forEach((MapLiteralEntry entry) {
int platforms = _convertPlatforms(entry.key);
Expression pathsListLiteral = entry.value;
if (pathsListLiteral is ListLiteral) {
List<String> paths = <String>[];
pathsListLiteral.elements.forEach((Expression pathExpr) {
if (pathExpr is SimpleStringLiteral) {
String path = pathExpr.value;
_validatePatchPath(path);
paths.add(path);
} else {
throw new ArgumentError(
'The "patch" argument items must be simple strings.');
}
});
library.setPatchPaths(platforms, paths);
} else {
throw new ArgumentError(
'The "patch" argument values must be list literals.');
}
});
}
} else if (name == _PLATFORMS) {
if (expression is SimpleIdentifier) {
String identifier = expression.name;
@ -435,61 +399,6 @@ class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor<Object> {
}
return null;
}
/**
* Validate the given [path] to a patch file. Throw [ArgumentError] if not a
* valid path: is absolute, or contains `..`.
*/
void _validatePatchPath(String path) {
if (path.contains(r'\')) {
throw new ArgumentError('The path to a patch file must be posix: $path');
}
if (path.contains('..')) {
throw new ArgumentError(
'The path to a patch file cannot contain "..": $path');
}
if (path.startsWith('/')) {
throw new ArgumentError(
'The path to a patch file cannot be absolute: $path');
}
}
/**
* Return the platform constant value for the given [expr].
* Throw [ArgumentError] if not a valid platform name given.
*/
static int _convertPlatform(Expression expr) {
if (expr is SimpleIdentifier) {
String name = expr.name;
if (name == _DART2JS_PLATFORM) {
return SdkLibraryImpl.DART2JS_PLATFORM;
}
if (name == _VM_PLATFORM) {
return SdkLibraryImpl.VM_PLATFORM;
}
throw new ArgumentError('Invalid platform name: $name');
}
throw new ArgumentError('Invalid platform type: ${expr.runtimeType}');
}
/**
* Return the platforms combination value for the [expr], which should be
* either `name1 | name2` or `name`. Throw [ArgumentError] if any of the
* names is not a valid platform name.
*/
static int _convertPlatforms(Expression expr) {
if (expr is BinaryExpression) {
TokenType operator = expr.operator?.type;
if (operator == TokenType.BAR) {
return _convertPlatforms(expr.leftOperand) |
_convertPlatforms(expr.rightOperand);
} else {
throw new ArgumentError('Invalid platforms combination: $operator');
}
} else {
return _convertPlatform(expr);
}
}
}
/**
@ -542,12 +451,6 @@ abstract class SdkLibrary {
* including `dart:`.
*/
String get shortName;
/**
* Return the list of paths to the patch files that should be applied
* to this library for the given [platform], not `null`.
*/
List<String> getPatches(int platform);
}
/**
@ -599,14 +502,6 @@ class SdkLibraryImpl implements SdkLibrary {
*/
int _platforms = 0;
/**
* The mapping from the platform combination to the list of paths (relative
* to the `sdk/lib` folder) of patches that should be applied to this library
* on every platform in the combination.
*/
final Map<int, List<String>> _platformsToPatchPaths =
new HashMap<int, List<String>>();
/**
* Initialize a newly created library to represent the library with the given
* [name].
@ -638,17 +533,6 @@ class SdkLibraryImpl implements SdkLibrary {
@override
bool get isVmLibrary => (_platforms & VM_PLATFORM) != 0;
@override
List<String> getPatches(int platform) {
List<String> paths = <String>[];
_platformsToPatchPaths.forEach((int platforms, List<String> value) {
if ((platforms & platform) != 0) {
paths.addAll(value);
}
});
return paths;
}
/**
* Record that this library can be compiled to JavaScript by dart2js.
*/
@ -656,14 +540,6 @@ class SdkLibraryImpl implements SdkLibrary {
_platforms |= DART2JS_PLATFORM;
}
/**
* Add a new patch with the given [path] that should be applied for the
* given [platforms].
*/
void setPatchPaths(int platforms, List<String> paths) {
_platformsToPatchPaths[platforms] = paths;
}
/**
* Record that this library can be run on the VM.
*/

View file

@ -25,6 +25,7 @@ import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/dart/sdk/patch.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/error/pending_error.dart';
import 'package:analyzer/src/generated/constant.dart';
@ -4061,9 +4062,17 @@ class ParseDartTask extends SourceBasedAnalysisTask {
CompilationUnit unit = parser.parseCompilationUnit(tokenStream);
unit.lineInfo = lineInfo;
if (options.patchPlatform != 0 && _source.uri.scheme == 'dart') {
new SdkPatcher().patch(context.sourceFactory.dartSdk,
options.patchPlatform, errorListener, _source, unit);
if (options.patchPaths.isNotEmpty && _source.uri.scheme == 'dart') {
var resourceProvider =
(context.sourceFactory.dartSdk as FolderBasedDartSdk)
.resourceProvider;
new SdkPatcher().patch(
resourceProvider,
context.analysisOptions.strongMode,
context.analysisOptions.patchPaths,
errorListener,
_source,
unit);
}
bool hasNonPartOfDirective = false;

View file

@ -58,7 +58,9 @@ class AnalysisOptionsImplTest {
modifiedOptions.incrementalValidation = true;
modifiedOptions.lint = true;
modifiedOptions.lintRules = [null];
modifiedOptions.patchPlatform = 3;
modifiedOptions.patchPaths = {
'dart:core': ['/dart_core.patch.dart']
};
modifiedOptions.preserveComments = false;
modifiedOptions.strongMode = true;
modifiedOptions.trackCacheDependencies = false;
@ -91,7 +93,7 @@ class AnalysisOptionsImplTest {
defaultOptions.incrementalValidation);
expect(modifiedOptions.lint, defaultOptions.lint);
expect(modifiedOptions.lintRules, defaultOptions.lintRules);
expect(modifiedOptions.patchPlatform, defaultOptions.patchPlatform);
expect(modifiedOptions.patchPaths, defaultOptions.patchPaths);
expect(modifiedOptions.preserveComments, defaultOptions.preserveComments);
expect(modifiedOptions.strongMode, defaultOptions.strongMode);
expect(modifiedOptions.trackCacheDependencies,

View file

@ -521,9 +521,6 @@ class _MockSdkLibrary implements SdkLibrary {
@override
bool get isVmLibrary => throw new UnimplementedError();
@override
List<String> getPatches(int platform) => const <String>[];
}
/**

View file

@ -9,7 +9,6 @@ import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/dart/sdk/patch.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/util/fast_uri.dart';
import 'package:test/test.dart';
@ -453,30 +452,21 @@ import 'c.dart';
"import 'a.dart'; part 'b.dart'; import 'c.dart'; int bar() => 0;");
}
test_fail_noSuchLibrary() {
expect(() {
_setSdkLibraries('const LIBRARIES = const {};');
_createSdk();
File file = provider.newFile(_p('/sdk/lib/test/test.dart'), '');
Source source = file.createSource(FastUri.parse('dart:test'));
CompilationUnit unit = SdkPatcher.parse(source, true, listener);
patcher.patch(sdk, SdkLibraryImpl.VM_PLATFORM, listener, source, unit);
}, throwsArgumentError);
}
test_fail_patchFileDoesNotExist() {
expect(() {
_setSdkLibraries(r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'test' : const LibraryInfo(
'test/test.dart',
patches: {VM_PLATFORM: ['does_not_exists.dart']}),
'test/test.dart'),
};''');
_createSdk();
var patchPaths = {
'dart:test': [_p('/sdk/lib/does_not_exist.dart')]
};
File file = provider.newFile(_p('/sdk/lib/test/test.dart'), '');
Source source = file.createSource(FastUri.parse('dart:test'));
CompilationUnit unit = SdkPatcher.parse(source, true, listener);
patcher.patch(sdk, SdkLibraryImpl.VM_PLATFORM, listener, source, unit);
patcher.patch(provider, true, patchPaths, listener, source, unit);
}, throwsArgumentError);
}
@ -484,9 +474,11 @@ final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
_setSdkLibraries(r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'_internal' : const LibraryInfo(
'internal/internal.dart',
patches: {VM_PLATFORM: ['internal/internal_patch.dart']}),
'internal/internal.dart'),
};''');
var patchPaths = {
'dart:_internal': [_p('/sdk/lib/internal/internal_patch.dart')]
};
File file = provider.newFile(
_p('/sdk/lib/internal/internal.dart'),
r'''
@ -513,7 +505,7 @@ int newFunction() => 2;
Source source = file.createSource(FastUri.parse('dart:_internal'));
CompilationUnit unit = SdkPatcher.parse(source, true, listener);
patcher.patch(sdk, SdkLibraryImpl.VM_PLATFORM, listener, source, unit);
patcher.patch(provider, true, patchPaths, listener, source, unit);
_assertUnitCode(
unit,
'library dart._internal; class A {} '
@ -537,6 +529,9 @@ final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'test/test.dart',
patches: {VM_PLATFORM: ['test/test_patch.dart']}),
};''');
var patchPaths = {
'dart:test': [_p('/sdk/lib/test/test_patch.dart')]
};
File fileLib = provider.newFile(_p('/sdk/lib/test/test.dart'), baseLibCode);
File filePart =
provider.newFile(_p('/sdk/lib/test/test_part.dart'), basePartCode);
@ -564,7 +559,7 @@ class _C {}
Uri uri = FastUri.parse('dart:test');
Source source = fileLib.createSource(uri);
CompilationUnit unit = SdkPatcher.parse(source, true, listener);
patcher.patch(sdk, SdkLibraryImpl.VM_PLATFORM, listener, source, unit);
patcher.patch(provider, true, patchPaths, listener, source, unit);
_assertUnitCode(
unit,
"library test; part 'test_part.dart'; import 'foo.dart'; "
@ -575,7 +570,7 @@ class _C {}
Uri uri = FastUri.parse('dart:test/test_part.dart');
Source source = filePart.createSource(uri);
CompilationUnit unit = SdkPatcher.parse(source, true, listener);
patcher.patch(sdk, SdkLibraryImpl.VM_PLATFORM, listener, source, unit);
patcher.patch(provider, true, patchPaths, listener, source, unit);
_assertUnitCode(unit, "part of test; class B {int _b() => 1;}");
}
}
@ -621,20 +616,6 @@ class B {}
}, throwsArgumentError);
}
test_topLevel_topLevelVariable_append() {
CompilationUnit unit = _doTopLevelPatching(
r'''
int foo() => 0;
''',
r'''
int _bar;
''');
_assertUnitCode(unit, 'int foo() => 0; int _bar;');
FunctionDeclaration a = unit.declarations[0];
TopLevelVariableDeclaration b = unit.declarations[1];
_assertPrevNextToken(a.endToken, b.beginToken);
}
test_topLevel_function_append() {
CompilationUnit unit = _doTopLevelPatching(
r'''
@ -798,6 +779,20 @@ void set foo(int val) {}
_assertUnitCode(unit, 'void set foo(int val) {} int bar() => 2;');
}
test_topLevel_topLevelVariable_append() {
CompilationUnit unit = _doTopLevelPatching(
r'''
int foo() => 0;
''',
r'''
int _bar;
''');
_assertUnitCode(unit, 'int foo() => 0; int _bar;');
FunctionDeclaration a = unit.declarations[0];
TopLevelVariableDeclaration b = unit.declarations[1];
_assertPrevNextToken(a.endToken, b.beginToken);
}
void _assertUnitCode(CompilationUnit unit, String expectedCode) {
expect(unit.toSource(), expectedCode);
}
@ -811,9 +806,11 @@ void set foo(int val) {}
_setSdkLibraries(r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'test' : const LibraryInfo(
'test/test.dart',
patches: {VM_PLATFORM: ['test/test_patch.dart']}),
'test/test.dart'),
};''');
var patchPaths = {
'dart:test': [_p('/sdk/lib/test/test_patch.dart')]
};
File file = provider.newFile(_p('/sdk/lib/test/test.dart'), baseCode);
provider.newFile(_p('/sdk/lib/test/test_patch.dart'), patchCode);
@ -821,7 +818,7 @@ final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
Source source = file.createSource(FastUri.parse('dart:test'));
CompilationUnit unit = SdkPatcher.parse(source, true, listener);
patcher.patch(sdk, SdkLibraryImpl.VM_PLATFORM, listener, source, unit);
patcher.patch(provider, true, patchPaths, listener, source, unit);
return unit;
}

View file

@ -26,7 +26,6 @@ main() {
defineReflectiveTests(FolderBasedDartSdkTest);
defineReflectiveTests(SdkExtensionFinderTest);
defineReflectiveTests(SdkLibrariesReaderTest);
defineReflectiveTests(SdkLibraryImplTest);
});
}
@ -474,148 +473,4 @@ final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
expect(second.isImplementation, true);
expect(second.isVmLibrary, false);
}
void test_readFrom_patches() {
LibraryMap libraryMap = new SdkLibrariesReader(false).readFromFile(
resourceProvider.getFile('/libs.dart'),
r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'foo' : const LibraryInfo(
'foo/foo.dart',
patches: {
DART2JS_PLATFORM | VM_PLATFORM: ['a', 'b'],
DART2JS_PLATFORM: ['c', 'd'],
VM_PLATFORM: ['e']}),
};''');
expect(libraryMap, isNotNull);
expect(libraryMap.size(), 1);
SdkLibrary library = libraryMap.getLibrary('dart:foo');
expect(library, isNotNull);
expect(library.path, 'foo/foo.dart');
expect(library.shortName, 'dart:foo');
expect(library.getPatches(SdkLibraryImpl.DART2JS_PLATFORM),
unorderedEquals(['a', 'b', 'c', 'd']));
expect(library.getPatches(SdkLibraryImpl.VM_PLATFORM),
unorderedEquals(['a', 'b', 'e']));
}
void test_readFrom_patches_invalid_notList() {
expect(() {
new SdkLibrariesReader(false).readFromFile(
resourceProvider.getFile('/libs.dart'),
r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'foo' : const LibraryInfo(
'foo/foo.dart',
patches: {
VM_PLATFORM: 'X'}),
};''');
}, throwsArgumentError);
}
void test_readFrom_patches_invalid_notString_inList() {
expect(() {
new SdkLibrariesReader(false).readFromFile(
resourceProvider.getFile('/libs.dart'),
r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'foo' : const LibraryInfo(
'foo/foo.dart',
patches: {
VM_PLATFORM: [42]}),
};''');
}, throwsArgumentError);
}
void test_readFrom_patches_invalid_path_hasDotDot() {
_assertPatchPathIsInvalid('foo/../bar.dart');
_assertPatchPathIsInvalid('../foo/bar.dart');
_assertPatchPathIsInvalid('foo/bar..dart');
}
void test_readFrom_patches_invalid_path_isAbsolute() {
_assertPatchPathIsInvalid('/foo.dart');
_assertPatchPathIsInvalid('/foo/bar.dart');
}
void test_readFrom_patches_invalid_path_notPosix() {
_assertPatchPathIsInvalid(r'foo\bar.dart');
}
void test_readFrom_patches_invalid_platformCombinator() {
expect(() {
new SdkLibrariesReader(false).readFromFile(
resourceProvider.getFile('/libs.dart'),
r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'foo' : const LibraryInfo(
'foo/foo.dart',
patches: {
DART2JS_PLATFORM + VM_PLATFORM: ['X']}),
};''');
}, throwsArgumentError);
}
void test_readFrom_patches_invalid_unknownPlatform() {
expect(() {
new SdkLibrariesReader(false).readFromFile(
resourceProvider.getFile('/libs.dart'),
r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'foo' : const LibraryInfo(
'foo/foo.dart',
patches: {
MY_UNKNOWN_PLATFORM: ['foo/bar_patch.dart']}),
};''');
}, throwsArgumentError);
}
void test_readFrom_patches_no() {
LibraryMap libraryMap = new SdkLibrariesReader(false).readFromFile(
resourceProvider.getFile('/libs.dart'),
r'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'my' : const LibraryInfo('my/my.dart')
};''');
expect(libraryMap, isNotNull);
expect(libraryMap.size(), 1);
SdkLibrary library = libraryMap.getLibrary('dart:my');
expect(library, isNotNull);
expect(library.path, 'my/my.dart');
expect(library.shortName, 'dart:my');
expect(library.getPatches(SdkLibraryImpl.VM_PLATFORM), isEmpty);
expect(library.getPatches(SdkLibraryImpl.DART2JS_PLATFORM), isEmpty);
}
void _assertPatchPathIsInvalid(String patchPath) {
expect(() {
new SdkLibrariesReader(false).readFromFile(
resourceProvider.getFile('/libs.dart'),
'''
final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
'foo' : const LibraryInfo(
'foo/foo.dart',
patches: {
VM_PLATFORM: [r'$patchPath']}),
};''');
}, throwsArgumentError);
}
}
@reflectiveTest
class SdkLibraryImplTest extends EngineTestCase {
void test_patches() {
SdkLibraryImpl library = new SdkLibraryImpl('dart:foo');
// Set patches.
library.setPatchPaths(
SdkLibraryImpl.DART2JS_PLATFORM | SdkLibraryImpl.VM_PLATFORM,
['a', 'b']);
library.setPatchPaths(SdkLibraryImpl.DART2JS_PLATFORM, ['c', 'd']);
library.setPatchPaths(SdkLibraryImpl.VM_PLATFORM, ['e']);
// Get patches.
expect(library.getPatches(SdkLibraryImpl.DART2JS_PLATFORM),
unorderedEquals(['a', 'b', 'c', 'd']));
expect(library.getPatches(SdkLibraryImpl.VM_PLATFORM),
unorderedEquals(['a', 'b', 'e']));
}
}