blob: 8d2834a31cb8841c9b5ce0dc6c365ff350e24b79 [file] [log] [blame]
// Copyright (c) 2019, 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:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/services/available_declarations.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:meta/meta.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AvailableDeclarationsTest);
});
}
class AbstractContextTest with ResourceProviderMixin {
final byteStore = MemoryByteStore();
AnalysisContextCollection analysisContextCollection;
AnalysisContext testAnalysisContext;
void addDotPackagesDependency(String path, String name, String rootPath) {
var packagesFile = getFile(path);
String packagesContent;
try {
packagesContent = packagesFile.readAsStringSync();
} catch (_) {
packagesContent = '';
}
// Ignore if there is already the same package dependency.
if (packagesContent.contains('$name:file://')) {
return;
}
rootPath = convertPath(rootPath);
packagesContent += '$name:${toUri('$rootPath/lib')}\n';
packagesFile.writeAsStringSync(packagesContent);
createAnalysisContexts();
}
void addTestPackageDependency(String name, String rootPath) {
addDotPackagesDependency('/home/test/.packages', name, rootPath);
}
/// Create all analysis contexts in `/home`.
void createAnalysisContexts() {
analysisContextCollection = AnalysisContextCollectionImpl(
includedPaths: [convertPath('/home')],
resourceProvider: resourceProvider,
sdkPath: convertPath('/sdk'),
);
var testPath = convertPath('/home/test');
testAnalysisContext = getContext(testPath);
}
/// Return the existing analysis context that should be used to analyze the
/// given [path], or throw [StateError] if the [path] is not analyzed in any
/// of the created analysis contexts.
AnalysisContext getContext(String path) {
path = convertPath(path);
return analysisContextCollection.contextFor(path);
}
setUp() {
new MockSdk(resourceProvider: resourceProvider);
newFolder('/home/test');
newFile('/home/test/.packages', content: '''
test:${toUri('/home/test/lib')}
''');
createAnalysisContexts();
}
}
@reflectiveTest
class AvailableDeclarationsTest extends AbstractContextTest {
DeclarationsTracker tracker;
final List<LibraryChange> changes = [];
final Map<int, Library> idToLibrary = {};
final Map<String, Library> uriToLibrary = {};
@override
setUp() {
super.setUp();
_createTracker();
}
test_changeFile_added_exported() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var c = convertPath('/home/test/lib/c.dart');
var d = convertPath('/home/test/lib/d.dart');
newFile(a, content: r'''
export 'b.dart';
class A {}
''');
newFile(b, content: r'''
export 'c.dart';
class B {}
''');
newFile(d, content: r'''
class D {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
_assertHasNoLibrary('package:test/c.dart');
_assertHasLibrary('package:test/d.dart', declarations: [
_ExpectedDeclaration('D', DeclarationKind.CLASS),
]);
newFile(c, content: r'''
class C {}
''');
tracker.changeFile(c);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/d.dart', declarations: [
_ExpectedDeclaration('D', DeclarationKind.CLASS),
]);
}
test_changeFile_added_library() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
newFile(a, content: r'''
class A {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
]);
_assertHasNoLibrary('package:test/b.dart');
newFile(b, content: r'''
class B {}
''');
tracker.changeFile(b);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
}
test_changeFile_added_part() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var c = convertPath('/home/test/lib/c.dart');
newFile(a, content: r'''
part 'b.dart';
class A {}
''');
newFile(c, content: r'''
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
]);
_assertHasNoLibrary('package:test/b.dart');
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
newFile(b, content: r'''
part of 'a.dart';
class B {}
''');
tracker.changeFile(b);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
_assertHasNoLibrary('package:test/b.dart');
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
}
test_changeFile_deleted_exported() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var c = convertPath('/home/test/lib/c.dart');
var d = convertPath('/home/test/lib/d.dart');
newFile(a, content: r'''
export 'b.dart';
class A {}
''');
newFile(b, content: r'''
export 'c.dart';
class B {}
''');
newFile(c, content: r'''
class C {}
''');
newFile(d, content: r'''
class D {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/d.dart', declarations: [
_ExpectedDeclaration('D', DeclarationKind.CLASS),
]);
deleteFile(c);
tracker.changeFile(c);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
_assertHasNoLibrary('package:test/c.dart');
_assertHasLibrary('package:test/d.dart', declarations: [
_ExpectedDeclaration('D', DeclarationKind.CLASS),
]);
}
test_changeFile_deleted_library() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
newFile(a, content: '');
newFile(b, content: '');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart');
_assertHasLibrary('package:test/b.dart');
deleteFile(a);
tracker.changeFile(a);
await _doAllTrackerWork();
_assertHasNoLibrary('package:test/a.dart');
_assertHasLibrary('package:test/b.dart');
}
test_changeFile_deleted_part() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var c = convertPath('/home/test/lib/c.dart');
newFile(a, content: r'''
part 'b.dart';
class A {}
''');
newFile(b, content: r'''
part of 'a.dart';
class B {}
''');
newFile(c, content: r'''
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
deleteFile(b);
tracker.changeFile(b);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
}
test_changeFile_updated_exported() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var c = convertPath('/home/test/lib/c.dart');
var d = convertPath('/home/test/lib/d.dart');
newFile(a, content: r'''
export 'b.dart';
class A {}
''');
newFile(b, content: r'''
export 'c.dart';
class B {}
''');
newFile(c, content: r'''
class C {}
''');
newFile(d, content: r'''
class D {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/d.dart', declarations: [
_ExpectedDeclaration('D', DeclarationKind.CLASS),
]);
newFile(c, content: r'''
class C2 {}
''');
tracker.changeFile(c);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C2', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
_ExpectedDeclaration('C2', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C2', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/d.dart', declarations: [
_ExpectedDeclaration('D', DeclarationKind.CLASS),
]);
}
test_changeFile_updated_library() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
newFile(a, content: r'''
class A {}
''');
newFile(b, content: r'''
class B {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
newFile(a, content: r'''
class A2 {}
''');
tracker.changeFile(a);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A2', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
}
test_changeFile_updated_part() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var c = convertPath('/home/test/lib/c.dart');
newFile(a, content: r'''
part 'b.dart';
class A {}
''');
newFile(b, content: r'''
part of 'a.dart';
class B {}
''');
newFile(c, content: r'''
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
newFile(b, content: r'''
part of 'a.dart';
class B2 {}
''');
tracker.changeFile(b);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration('A', DeclarationKind.CLASS),
_ExpectedDeclaration('B2', DeclarationKind.CLASS),
]);
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration('C', DeclarationKind.CLASS),
]);
}
test_export() async {
newFile('/home/test/lib/a.dart', content: r'''
class A {}
class B {}
''');
newFile('/home/test/lib/test.dart', content: r'''
export 'a.dart';
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
_ExpectedDeclaration.class_('C'),
]);
}
test_export_combinators_hide() async {
newFile('/home/test/lib/a.dart', content: r'''
class A {}
class B {}
class C {}
''');
newFile('/home/test/lib/test.dart', content: r'''
export 'a.dart' hide B;
class D {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('C'),
_ExpectedDeclaration.class_('D'),
]);
}
test_export_combinators_show() async {
newFile('/home/test/lib/a.dart', content: r'''
class A {}
class B {}
class C {}
''');
newFile('/home/test/lib/test.dart', content: r'''
export 'a.dart' show B;
class D {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('B'),
_ExpectedDeclaration.class_('D'),
]);
}
test_export_cycle() async {
newFile('/home/test/lib/a.dart', content: r'''
export 'b.dart';
class A {}
''');
newFile('/home/test/lib/b.dart', content: r'''
export 'a.dart';
class B {}
''');
newFile('/home/test/lib/test.dart', content: r'''
export 'b.dart';
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
]);
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
_ExpectedDeclaration.class_('C'),
]);
}
test_export_missing() async {
newFile('/home/test/lib/test.dart', content: r'''
export 'a.dart';
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('C'),
]);
}
test_export_sequence() async {
newFile('/home/test/lib/a.dart', content: r'''
class A {}
''');
newFile('/home/test/lib/b.dart', content: r'''
export 'a.dart';
class B {}
''');
newFile('/home/test/lib/test.dart', content: r'''
export 'b.dart';
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/a.dart', declarations: [
_ExpectedDeclaration.class_('A'),
]);
_assertHasLibrary('package:test/b.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
]);
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
_ExpectedDeclaration.class_('C'),
]);
}
test_export_shadowedByLocal() async {
newFile('/home/test/lib/a.dart', content: r'''
class A {}
class B {}
''');
newFile('/home/test/lib/test.dart', content: r'''
export 'a.dart';
mixin B {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.mixin('B'),
]);
}
test_getLibraries_bazel() async {
newFile('/home/aaa/lib/a.dart', content: 'class A {}');
newFile('/home/aaa/lib/src/a2.dart', content: 'class A2 {}');
newFile('/home/bbb/lib/b.dart', content: 'class B {}');
newFile('/home/bbb/lib/src/b2.dart', content: 'class B2 {}');
newFile('/home/material_button/BUILD', content: '');
newFile(
'/home/material_button/lib/button.dart',
content: 'class MaterialButton {}',
);
newFile(
'/home/material_button/test/button_test.dart',
content: 'class MaterialButtonTest {}',
);
newFile('/home/material_button/testing/BUILD', content: '');
newFile(
'/home/material_button/testing/lib/material_button_po.dart',
content: 'class MaterialButtonPO {}',
);
var packagesFilePath = '/home/material_button/.packages';
addDotPackagesDependency(packagesFilePath, 'aaa', '/home/aaa');
addDotPackagesDependency(packagesFilePath, 'bbb', '/home/bbb');
addDotPackagesDependency(
packagesFilePath,
'material_button',
'/home/material_button',
);
addDotPackagesDependency(
packagesFilePath,
'material_button_testing',
'/home/material_button/testing',
);
var analysisContext = analysisContextCollection.contextFor(
convertPath('/home/material_button'),
);
var context = tracker.addContext(analysisContext);
context.setDependencies({
convertPath('/home/material_button'): [convertPath('/home/aaa/lib')],
convertPath('/home/material_button/testing'): [
convertPath('/home/bbb/lib'),
convertPath('/home/material_button/lib'),
],
});
await _doAllTrackerWork();
_assertHasLibrary('package:aaa/a.dart', declarations: [
_ExpectedDeclaration.class_('A'),
]);
_assertHasNoLibrary('package:aaa/src/a2.dart');
_assertHasLibrary('package:bbb/b.dart', declarations: [
_ExpectedDeclaration.class_('B'),
]);
_assertHasNoLibrary('package:bbb/src/b2.dart');
_assertHasLibrary('package:material_button/button.dart', declarations: [
_ExpectedDeclaration.class_('MaterialButton'),
]);
_assertHasLibrary(
toUri('/home/material_button/test/button_test.dart').toString(),
declarations: [
_ExpectedDeclaration.class_('MaterialButtonTest'),
],
);
_assertHasLibrary(
'package:material_button_testing/material_button_po.dart',
declarations: [
_ExpectedDeclaration.class_('MaterialButtonPO'),
],
);
{
var path = convertPath('/home/material_button/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
_assertHasLibraries(
libraries.context,
uriList: [
'package:material_button/button.dart',
],
only: true,
);
}
{
var path = convertPath('/home/material_button/test/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
_assertHasLibraries(
libraries.context,
uriList: [
'package:material_button/button.dart',
toUri('/home/material_button/test/button_test.dart').toString(),
],
only: true,
);
}
{
var path = convertPath('/home/material_button/testing/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:bbb/b.dart',
'package:material_button/button.dart',
],
only: true,
);
_assertHasLibraries(
libraries.context,
uriList: [
'package:material_button_testing/material_button_po.dart',
],
only: true,
);
}
}
test_getLibraries_pub() async {
newFile('/home/aaa/lib/a.dart', content: 'class A {}');
newFile('/home/aaa/lib/src/a2.dart', content: 'class A2 {}');
newFile('/home/bbb/lib/b.dart', content: 'class B {}');
newFile('/home/bbb/lib/src/b2.dart', content: 'class B2 {}');
newFile('/home/ccc/lib/c.dart', content: 'class C {}');
newFile('/home/ccc/lib/src/c2.dart', content: 'class C2 {}');
newFile('/home/test/pubspec.yaml', content: r'''
name: test
dependencies:
aaa: any
dev_dependencies:
bbb: any
''');
newFile('/home/test/lib/t.dart', content: 'class T {}');
newFile('/home/test/lib/src/t2.dart', content: 'class T2 {}');
newFile('/home/test/bin/t3.dart', content: 'class T3 {}');
newFile('/home/test/test/t4.dart', content: 'class T4 {}');
newFile('/home/test/samples/basic/pubspec.yaml', content: r'''
name: test
dependencies:
ccc: any
test: any
''');
newFile('/home/test/samples/basic/lib/s.dart', content: 'class S {}');
addTestPackageDependency('aaa', '/home/aaa');
addTestPackageDependency('bbb', '/home/bbb');
addTestPackageDependency('ccc', '/home/ccc');
addTestPackageDependency('basic', '/home/test/samples/basic');
var context = tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:aaa/a.dart', declarations: [
_ExpectedDeclaration.class_('A'),
]);
_assertHasNoLibrary('package:aaa/src/a2.dart');
_assertHasLibrary('package:bbb/b.dart', declarations: [
_ExpectedDeclaration.class_('B'),
]);
_assertHasNoLibrary('package:bbb/src/b2.dart');
_assertHasLibrary('package:ccc/c.dart', declarations: [
_ExpectedDeclaration.class_('C'),
]);
_assertHasNoLibrary('package:ccc/src/c2.dart');
_assertHasLibrary('package:test/t.dart', declarations: [
_ExpectedDeclaration.class_('T'),
]);
_assertHasLibrary('package:test/src/t2.dart', declarations: [
_ExpectedDeclaration.class_('T2'),
]);
_assertHasLibrary('package:basic/s.dart', declarations: [
_ExpectedDeclaration.class_('S'),
]);
{
var path = convertPath('/home/test/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
// Note, no `bin/` or `test/` libraries.
// Note, has `lib/src` library.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
],
only: true,
);
}
{
var path = convertPath('/home/test/bin/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:aaa/a.dart',
'package:bbb/b.dart',
],
only: true,
);
// Note, no `test/` libraries.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/bin/t3.dart').toString(),
],
only: true,
);
}
{
var path = convertPath('/home/test/test/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:aaa/a.dart',
'package:bbb/b.dart',
],
only: true,
);
// Note, no `bin/` libraries.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/test/t4.dart').toString(),
],
only: true,
);
}
{
var path = convertPath('/home/test/samples/basic/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:ccc/c.dart',
'package:test/t.dart',
],
only: true,
);
// Note, no `package:test` libraries.
_assertHasLibraries(
libraries.context,
uriList: [
'package:basic/s.dart',
],
only: true,
);
}
}
test_getLibraries_setDependencies() async {
newFile('/home/aaa/lib/a.dart', content: r'''
export 'src/a2.dart' show A2;
class A1 {}
''');
newFile('/home/aaa/lib/src/a2.dart', content: r'''
class A2 {}
class A3 {}
''');
newFile('/home/bbb/lib/b.dart', content: r'''
class B {}
''');
addTestPackageDependency('aaa', '/home/aaa');
addTestPackageDependency('bbb', '/home/bbb');
newFile('/home/test/lib/t.dart', content: 'class T {}');
newFile('/home/test/lib/src/t2.dart', content: 'class T2 {}');
newFile('/home/test/test/t3.dart', content: 'class T3 {}');
var context = tracker.addContext(testAnalysisContext);
context.setDependencies({
convertPath('/home/test'): [
convertPath('/home/aaa/lib'),
convertPath('/home/bbb/lib'),
],
convertPath('/home/test/lib'): [convertPath('/home/aaa/lib')],
});
await _doAllTrackerWork();
_assertHasLibrary('package:aaa/a.dart', declarations: [
_ExpectedDeclaration.class_('A1'),
_ExpectedDeclaration.class_('A2'),
]);
_assertHasNoLibrary('package:aaa/src/a2.dart');
_assertHasLibrary('package:bbb/b.dart', declarations: [
_ExpectedDeclaration.class_('B'),
]);
_assertHasLibrary('package:test/t.dart', declarations: [
_ExpectedDeclaration.class_('T'),
]);
_assertHasLibrary('package:test/src/t2.dart', declarations: [
_ExpectedDeclaration.class_('T2'),
]);
_assertHasLibrary(
toUri('/home/test/test/t3.dart').toString(),
declarations: [
_ExpectedDeclaration.class_('T3'),
],
);
// `lib/` is configured to see `package:aaa`.
{
var path = convertPath('/home/test/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
// Not in a package, so all context files are visible.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/test/t3.dart').toString(),
],
only: true,
);
}
// `test/` is configured to see `package:aaa` and `package:bbb`.
{
var path = convertPath('/home/test/bin/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:aaa/a.dart',
'package:bbb/b.dart',
],
only: true,
);
// Not in a package, so all context files are visible.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/test/t3.dart').toString(),
],
only: true,
);
}
}
test_getLibraries_setDependencies_twice() async {
newFile('/home/aaa/lib/a.dart', content: r'''
class A {}
''');
newFile('/home/bbb/lib/b.dart', content: r'''
class B {}
''');
addTestPackageDependency('aaa', '/home/aaa');
addTestPackageDependency('bbb', '/home/bbb');
newFile('/home/test/lib/test.dart', content: r'''
class C {}
''');
var context = tracker.addContext(testAnalysisContext);
var aUri = 'package:aaa/a.dart';
var bUri = 'package:bbb/b.dart';
context.setDependencies({
convertPath('/home/test'): [convertPath('/home/aaa/lib')],
});
await _doAllTrackerWork();
_assertHasLibrary(aUri, declarations: [
_ExpectedDeclaration.class_('A'),
]);
_assertHasNoLibrary(bUri);
// The package can see package:aaa, but not package:bbb
{
var path = convertPath('/home/test/lib/a.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
}
context.setDependencies({
convertPath('/home/test'): [convertPath('/home/bbb/lib')],
});
await _doAllTrackerWork();
_assertHasLibrary(aUri, declarations: [
_ExpectedDeclaration.class_('A'),
]);
_assertHasLibrary(bUri, declarations: [
_ExpectedDeclaration.class_('B'),
]);
// The package can see package:bbb, but not package:aaa
{
var path = convertPath('/home/test/lib/a.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:bbb/b.dart'],
only: true,
);
}
}
test_kindsOfDeclarations() async {
newFile('/home/test/lib/test.dart', content: r'''
class MyClass {}
class MyClassTypeAlias = Object with MyMixin;
enum MyEnum {a, b, c}
void myFunction() {}
typedef MyFunctionTypeAlias = void Function();
mixin MyMixin {}
var myVariable1, myVariable2;
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('MyClass'),
_ExpectedDeclaration.classTypeAlias('MyClassTypeAlias'),
_ExpectedDeclaration.enum_('MyEnum'),
_ExpectedDeclaration.function('myFunction'),
_ExpectedDeclaration.functionTypeAlias('MyFunctionTypeAlias'),
_ExpectedDeclaration.mixin('MyMixin'),
_ExpectedDeclaration.variable('myVariable1'),
_ExpectedDeclaration.variable('myVariable2'),
]);
}
test_parts() async {
newFile('/home/test/lib/a.dart', content: r'''
part of 'test.dart';
class A {}
''');
newFile('/home/test/lib/b.dart', content: r'''
part of 'test.dart';
class B {}
''');
newFile('/home/test/lib/test.dart', content: r'''
part 'a.dart';
part 'b.dart';
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
_ExpectedDeclaration.class_('C'),
]);
}
test_publicOnly() async {
newFile('/home/test/lib/a.dart', content: r'''
part of 'test.dart';
class A {}
class _A {}
''');
newFile('/home/test/lib/test.dart', content: r'''
part 'a.dart';
class B {}
class _B {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
]);
}
test_readByteStore() async {
newFile('/home/test/lib/a.dart', content: r'''
class A {}
''');
newFile('/home/test/lib/b.dart', content: r'''
class B {}
''');
newFile('/home/test/lib/test.dart', content: r'''
export 'a.dart' show A;
part 'b.dart';
class C {}
''');
// The byte store is empty, fill it.
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
// Re-create tracker, will read from byte store.
_createTracker();
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/test.dart', declarations: [
_ExpectedDeclaration.class_('A'),
_ExpectedDeclaration.class_('B'),
_ExpectedDeclaration.class_('C'),
]);
}
test_removeContext_afterAddContext() async {
newFile('/home/test/lib/test.dart', content: r'''
class A {}
''');
// No libraries initially.
expect(uriToLibrary, isEmpty);
// Add the context, and remove it immediately.
tracker.addContext(testAnalysisContext);
tracker.removeContext(testAnalysisContext);
// There is no work to do.
expect(tracker.hasWork, isFalse);
await _doAllTrackerWork();
// So, there are no new libraries.
expect(uriToLibrary, isEmpty);
}
void _assertHasDeclaration(Library library, _ExpectedDeclaration expected) {
expect(
library.declarations,
contains(predicate((Declaration d) {
return d.name == expected.name && d.kind == expected.kind;
})),
reason: '$expected',
);
}
/// Assert that the current state has the library with the given [uri].
///
/// If [declarations] provided, also checks that the library has exactly
/// these declarations.
void _assertHasLibrary(String uri,
{List<_ExpectedDeclaration> declarations}) {
var library = uriToLibrary[uri];
expect(library, isNotNull);
if (declarations != null) {
expect(library.declarations, hasLength(declarations.length));
for (var expected in declarations) {
_assertHasDeclaration(library, expected);
}
}
}
void _assertHasNoLibrary(String uri) {
expect(uriToLibrary, isNot(contains(uri)));
}
void _createTracker() {
uriToLibrary.clear();
tracker = DeclarationsTracker(byteStore, resourceProvider);
tracker.changes.listen((change) {
changes.add(change);
for (var library in change.changed) {
var uriStr = library.uri.toString();
idToLibrary[library.id] = library;
uriToLibrary[uriStr] = library;
}
idToLibrary.removeWhere((uriStr, library) {
return change.removed.contains(library.id);
});
uriToLibrary.removeWhere((uriStr, library) {
return change.removed.contains(library.id);
});
});
}
Future<void> _doAllTrackerWork() async {
while (tracker.hasWork) {
tracker.doWork();
}
await pumpEventQueue();
}
static Future pumpEventQueue([int times = 5000]) {
if (times == 0) return new Future.value();
return new Future.delayed(Duration.zero, () => pumpEventQueue(times - 1));
}
static void _assertHasLibraries(List<Library> libraries,
{@required List<String> uriList, bool only = false}) {
var actualUriList = libraries.map((lib) => lib.uri.toString()).toList();
if (only) {
expect(actualUriList, unorderedEquals(uriList));
} else {
expect(actualUriList, containsAll(uriList));
}
}
}
//class _ExpectedLibrary {
// final Uri uri;
// final String path;
//}
class _ExpectedDeclaration {
final String name;
final DeclarationKind kind;
_ExpectedDeclaration(this.name, this.kind);
_ExpectedDeclaration.class_(String name) : this(name, DeclarationKind.CLASS);
_ExpectedDeclaration.classTypeAlias(String name)
: this(name, DeclarationKind.CLASS_TYPE_ALIAS);
_ExpectedDeclaration.enum_(String name) : this(name, DeclarationKind.ENUM);
_ExpectedDeclaration.function(String name)
: this(name, DeclarationKind.FUNCTION);
_ExpectedDeclaration.functionTypeAlias(String name)
: this(name, DeclarationKind.FUNCTION_TYPE_ALIAS);
_ExpectedDeclaration.mixin(String name) : this(name, DeclarationKind.MIXIN);
_ExpectedDeclaration.variable(String name)
: this(name, DeclarationKind.VARIABLE);
@override
String toString() {
return '($name, $kind)';
}
}