blob: 10cd3fec8a3f8ccfe43730a8f0cb198c7829bc6d [file] [log] [blame]
// Copyright (c) 2014, 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:analysis_server/src/services/search/hierarchy.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../abstract_single_unit.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(GetHierarchyMembersTest);
defineReflectiveTests(HierarchyTest);
});
}
@reflectiveTest
class GetHierarchyMembersTest extends AbstractSingleUnitTest {
late SearchEngineImpl searchEngine;
@override
void setUp() {
super.setUp();
searchEngine = SearchEngineImpl([driverFor(testFile)]);
}
Future<void> test_constructors() async {
await resolveTestCode('''
class A {
A() {}
}
class B extends A {
B() {}
}
''');
var classA = findElement2.class_('A');
var classB = findElement2.class_('B');
var memberA = classA.constructors2[0];
var memberB = classB.constructors2[0];
var futureA = getHierarchyMembers(searchEngine, memberA).then((members) {
expect(members, unorderedEquals([memberA]));
});
var futureB = getHierarchyMembers(searchEngine, memberB).then((members) {
expect(members, unorderedEquals([memberB]));
});
await Future.wait([futureA, futureB]);
}
Future<void> test_fields() async {
await resolveTestCode('''
class A {
int? foo;
}
class B extends A {
get foo => null;
}
class C extends B {
set foo(x) {}
}
class D {
int? foo;
}
''');
var classA = findElement2.class_('A');
var classB = findElement2.class_('B');
var classC = findElement2.class_('C');
var classD = findElement2.class_('D');
var memberA = classA.fields2[0];
var memberB = classB.fields2[0];
var memberC = classC.fields2[0];
var memberD = classD.fields2[0];
var futureA = getHierarchyMembers(searchEngine, memberA).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberC]));
});
var futureB = getHierarchyMembers(searchEngine, memberB).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberC]));
});
var futureC = getHierarchyMembers(searchEngine, memberC).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberC]));
});
var futureD = getHierarchyMembers(searchEngine, memberD).then((members) {
expect(members, unorderedEquals([memberD]));
});
await Future.wait([futureA, futureB, futureC, futureD]);
}
Future<void> test_fields_static() async {
await resolveTestCode('''
class A {
static int? foo;
}
class B extends A {
static get foo => null;
}
class C extends B {
static set foo(x) {}
}
''');
var classA = findElement2.class_('A');
var classB = findElement2.class_('B');
var classC = findElement2.class_('C');
var memberA = classA.fields2[0];
var memberB = classB.fields2[0];
var memberC = classC.fields2[0];
{
var members = await getHierarchyMembers(searchEngine, memberA);
expect(members, unorderedEquals([memberA]));
}
{
var members = await getHierarchyMembers(searchEngine, memberB);
expect(members, unorderedEquals([memberB]));
}
{
var members = await getHierarchyMembers(searchEngine, memberC);
expect(members, unorderedEquals([memberC]));
}
}
Future<void> test_linear_number_of_calls() async {
const count = 150;
const last = count - 1;
StringBuffer sb = StringBuffer();
for (int i = 0; i < count; i++) {
if (i == 0) {
sb.writeln("class X0 { void foo() { print('hello'); } }");
} else {
sb.writeln(
"class X$i extends X${i - 1} { void foo() { print('hello'); } }",
);
}
}
await resolveTestCode(sb.toString());
var classLast = findElement2.class_('X$last');
var member =
classLast.methods2.where((element) => element.name3 == 'foo').single;
OperationPerformanceImpl performance = OperationPerformanceImpl('<root>');
var result = await performance.runAsync(
'getHierarchyMembers',
(performance) =>
getHierarchyMembers(searchEngine, member, performance: performance),
);
expect(result, hasLength(count));
var worklist = <OperationPerformance>[];
worklist.add(performance);
while (worklist.isNotEmpty) {
var performance = worklist.removeLast();
expect(
performance.count,
lessThanOrEqualTo(count + 1),
reason: performance.toString(),
);
worklist.addAll(performance.children);
}
}
Future<void> test_methods() async {
await resolveTestCode('''
class A {
foo() {}
}
class B extends A {
foo() {}
}
class C extends B {
foo() {}
}
class D {
foo() {}
}
class E extends D {
foo() {}
}
''');
var classA = findElement2.class_('A');
var classB = findElement2.class_('B');
var classC = findElement2.class_('C');
var classD = findElement2.class_('D');
var classE = findElement2.class_('E');
var memberA = classA.methods2[0];
var memberB = classB.methods2[0];
var memberC = classC.methods2[0];
var memberD = classD.methods2[0];
var memberE = classE.methods2[0];
var futureA = getHierarchyMembers(searchEngine, memberA).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberC]));
});
var futureB = getHierarchyMembers(searchEngine, memberB).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberC]));
});
var futureC = getHierarchyMembers(searchEngine, memberC).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberC]));
});
var futureD = getHierarchyMembers(searchEngine, memberD).then((members) {
expect(members, unorderedEquals([memberD, memberE]));
});
var futureE = getHierarchyMembers(searchEngine, memberE).then((members) {
expect(members, unorderedEquals([memberD, memberE]));
});
await Future.wait([futureA, futureB, futureC, futureD, futureE]);
}
Future<void> test_methods_private_superOtherLibrary() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
void _test() {}
}
''');
newFile('$testPackageLibPath/c.dart', r'''
import 'test.dart';
class E extends B {
void _test() {}
}
''');
await resolveTestCode('''
import 'a.dart';
class B extends A {
void _test() {}
}
class C extends A {
void _test() {}
}
class D extends B {
void _test() {}
}
''');
var methodB = findElement2.method('_test', of: 'B');
var methodD = findElement2.method('_test', of: 'D');
var members = await getHierarchyMembers(searchEngine, methodB);
expect(members, unorderedEquals([methodB, methodD]));
}
Future<void> test_methods_private_superSameLibrary() async {
newFile('$testPackageLibPath/c.dart', r'''
import 'test.dart';
class E extends B {
void _test() {}
}
''');
await resolveTestCode('''
class A {
void _test() {}
}
class B extends A {
void _test() {}
}
class C extends A {
void _test() {}
}
class D extends B {
void _test() {}
}
''');
var methodA = findElement2.method('_test', of: 'A');
var methodB = findElement2.method('_test', of: 'B');
var methodC = findElement2.method('_test', of: 'C');
var methodD = findElement2.method('_test', of: 'D');
var members = await getHierarchyMembers(searchEngine, methodB);
expect(members, unorderedEquals([methodA, methodB, methodC, methodD]));
}
Future<void> test_methods_static() async {
await resolveTestCode('''
class A {
static foo() {}
}
class B extends A {
static foo() {}
}
''');
var classA = findElement2.class_('A');
var classB = findElement2.class_('B');
var memberA = classA.methods2[0];
var memberB = classB.methods2[0];
{
var members = await getHierarchyMembers(searchEngine, memberA);
expect(members, unorderedEquals([memberA]));
}
{
var members = await getHierarchyMembers(searchEngine, memberB);
expect(members, unorderedEquals([memberB]));
}
}
Future<void> test_withInterfaces() async {
await resolveTestCode('''
class A {
foo() {}
}
class B implements A {
foo() {}
}
abstract class C implements A {
}
class D extends C {
foo() {}
}
class E {
foo() {}
}
''');
var classA = findElement2.class_('A');
var classB = findElement2.class_('B');
var classD = findElement2.class_('D');
var memberA = classA.methods2[0];
var memberB = classB.methods2[0];
var memberD = classD.methods2[0];
var futureA = getHierarchyMembers(searchEngine, memberA).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberD]));
});
var futureB = getHierarchyMembers(searchEngine, memberB).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberD]));
});
var futureD = getHierarchyMembers(searchEngine, memberD).then((members) {
expect(members, unorderedEquals([memberA, memberB, memberD]));
});
await Future.wait([futureA, futureB, futureD]);
}
}
@reflectiveTest
class HierarchyTest extends AbstractSingleUnitTest {
late SearchEngineImpl searchEngine;
@override
void setUp() {
super.setUp();
searchEngine = SearchEngineImpl([driverFor(testFile)]);
}
Future<void> test_getClassMembers() async {
await resolveTestCode('''
class A {
A() {}
var ma1;
ma2() {}
}
class B extends A {
B() {}
B.named() {}
var mb1;
mb2() {}
}
''');
{
var classA = findElement2.class_('A');
var members = getClassMembers(classA);
expect(members.map((e) => e.name3), unorderedEquals(['ma1', 'ma2']));
}
{
var classB = findElement2.class_('B');
var members = getClassMembers(classB);
expect(members.map((e) => e.name3), unorderedEquals(['mb1', 'mb2']));
}
}
Future<void> test_getHierarchyNamedParameters() async {
await resolveTestCode('''
class A {
foo({p}) {}
}
class B extends A {
foo({p}) {}
}
class C extends B {
foo({p}) {}
}
class D {
foo({p}) {}
}
class E extends D {
foo({p}) {}
}
''');
var classA = findElement2.class_('A');
var classB = findElement2.class_('B');
var classC = findElement2.class_('C');
var classD = findElement2.class_('D');
var classE = findElement2.class_('E');
var parameterA = classA.methods2[0].formalParameters[0];
var parameterB = classB.methods2[0].formalParameters[0];
var parameterC = classC.methods2[0].formalParameters[0];
var parameterD = classD.methods2[0].formalParameters[0];
var parameterE = classE.methods2[0].formalParameters[0];
{
var result = await getHierarchyNamedParameters(searchEngine, parameterA);
expect(result, unorderedEquals([parameterA, parameterB, parameterC]));
}
{
var result = await getHierarchyNamedParameters(searchEngine, parameterB);
expect(result, unorderedEquals([parameterA, parameterB, parameterC]));
}
{
var result = await getHierarchyNamedParameters(searchEngine, parameterC);
expect(result, unorderedEquals([parameterA, parameterB, parameterC]));
}
{
var result = await getHierarchyNamedParameters(searchEngine, parameterD);
expect(result, unorderedEquals([parameterD, parameterE]));
}
{
var result = await getHierarchyNamedParameters(searchEngine, parameterE);
expect(result, unorderedEquals([parameterD, parameterE]));
}
}
Future<void> test_getHierarchyNamedParameters_invalid_missing() async {
verifyNoTestUnitErrors = false;
await resolveTestCode('''
class A {
foo({p}) {}
}
class B extends A {
foo() {}
}
''');
var classA = findElement2.class_('A');
var parameterA = classA.methods2[0].formalParameters[0];
var result = await getHierarchyNamedParameters(searchEngine, parameterA);
expect(result, unorderedEquals([parameterA]));
}
Future<void> test_getHierarchyNamedParameters_invalid_notNamed() async {
verifyNoTestUnitErrors = false;
await resolveTestCode('''
class A {
foo({p}) {}
}
class B extends A {
foo(p) {}
}
''');
var classA = findElement2.class_('A');
var parameterA = classA.methods2[0].formalParameters[0];
var result = await getHierarchyNamedParameters(searchEngine, parameterA);
expect(result, unorderedEquals([parameterA]));
}
Future<void> test_getMembers() async {
await resolveTestCode('''
class A {
A() {}
var ma1;
ma2() {}
}
class B extends A {
B() {}
B.named() {}
var mb1;
mb2() {}
}
''');
{
var classA = findElement2.class_('A');
var members = getMembers(classA);
expect(
members.map((e) => e.name3),
unorderedEquals([
'ma1',
'ma2',
'==',
'toString',
'hashCode',
'noSuchMethod',
'runtimeType',
'hash',
'hashAll',
'hashAllUnordered',
]),
);
}
{
var classB = findElement2.class_('B');
var members = getMembers(classB);
expect(
members.map((e) => e.name3),
unorderedEquals([
'mb1',
'mb2',
'ma1',
'ma2',
'==',
'toString',
'hashCode',
'noSuchMethod',
'runtimeType',
'hash',
'hashAll',
'hashAllUnordered',
]),
);
}
}
}