// 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/dart/element/element.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../../abstract_single_unit.dart'; void main() { defineReflectiveSuite(() { defineReflectiveTests(HierarchyTest); }); } @reflectiveTest class HierarchyTest extends AbstractSingleUnitTest { late SearchEngineImpl searchEngine; @override void setUp() { super.setUp(); searchEngine = SearchEngineImpl([driverFor(testFile)]); } Future test_getClassMembers() async { await _indexTestUnit(''' class A { A() {} var ma1; ma2() {} } class B extends A { B() {} B.named() {} var mb1; mb2() {} } '''); { var classA = findElement.class_('A'); var members = getClassMembers(classA); expect(members.map((e) => e.name), unorderedEquals(['ma1', 'ma2'])); } { var classB = findElement.class_('B'); var members = getClassMembers(classB); expect(members.map((e) => e.name), unorderedEquals(['mb1', 'mb2'])); } } Future test_getHierarchyMembers_constructors() async { await _indexTestUnit(''' class A { A() {} } class B extends A { B() {} } '''); var classA = findElement.class_('A'); var classB = findElement.class_('B'); ClassMemberElement memberA = classA.constructors[0]; ClassMemberElement memberB = classB.constructors[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 test_getHierarchyMembers_fields() async { await _indexTestUnit(''' class A { int foo; } class B extends A { get foo => null; } class C extends B { set foo(x) {} } class D { int foo; } '''); var classA = findElement.class_('A'); var classB = findElement.class_('B'); var classC = findElement.class_('C'); var classD = findElement.class_('D'); ClassMemberElement memberA = classA.fields[0]; ClassMemberElement memberB = classB.fields[0]; ClassMemberElement memberC = classC.fields[0]; ClassMemberElement memberD = classD.fields[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 test_getHierarchyMembers_fields_static() async { await _indexTestUnit(''' class A { static int foo; } class B extends A { static get foo => null; } class C extends B { static set foo(x) {} } '''); var classA = findElement.class_('A'); var classB = findElement.class_('B'); var classC = findElement.class_('C'); ClassMemberElement memberA = classA.fields[0]; ClassMemberElement memberB = classB.fields[0]; ClassMemberElement memberC = classC.fields[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 test_getHierarchyMembers_methods() async { await _indexTestUnit(''' class A { foo() {} } class B extends A { foo() {} } class C extends B { foo() {} } class D { foo() {} } class E extends D { foo() {} } '''); var classA = findElement.class_('A'); var classB = findElement.class_('B'); var classC = findElement.class_('C'); var classD = findElement.class_('D'); var classE = findElement.class_('E'); ClassMemberElement memberA = classA.methods[0]; ClassMemberElement memberB = classB.methods[0]; ClassMemberElement memberC = classC.methods[0]; ClassMemberElement memberD = classD.methods[0]; ClassMemberElement memberE = classE.methods[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 test_getHierarchyMembers_methods_static() async { await _indexTestUnit(''' class A { static foo() {} } class B extends A { static foo() {} } '''); var classA = findElement.class_('A'); var classB = findElement.class_('B'); ClassMemberElement memberA = classA.methods[0]; ClassMemberElement memberB = classB.methods[0]; { var members = await getHierarchyMembers(searchEngine, memberA); expect(members, unorderedEquals([memberA])); } { var members = await getHierarchyMembers(searchEngine, memberB); expect(members, unorderedEquals([memberB])); } } Future test_getHierarchyMembers_withInterfaces() async { await _indexTestUnit(''' class A { foo() {} } class B implements A { foo() {} } abstract class C implements A { } class D extends C { foo() {} } class E { foo() {} } '''); var classA = findElement.class_('A'); var classB = findElement.class_('B'); var classD = findElement.class_('D'); ClassMemberElement memberA = classA.methods[0]; ClassMemberElement memberB = classB.methods[0]; ClassMemberElement memberD = classD.methods[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]); } Future test_getHierarchyNamedParameters() async { await _indexTestUnit(''' 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 = findElement.class_('A'); var classB = findElement.class_('B'); var classC = findElement.class_('C'); var classD = findElement.class_('D'); var classE = findElement.class_('E'); var parameterA = classA.methods[0].parameters[0]; var parameterB = classB.methods[0].parameters[0]; var parameterC = classC.methods[0].parameters[0]; var parameterD = classD.methods[0].parameters[0]; var parameterE = classE.methods[0].parameters[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 test_getHierarchyNamedParameters_invalid_missing() async { verifyNoTestUnitErrors = false; await _indexTestUnit(''' class A { foo({p}) {} } class B extends A { foo() {} } '''); var classA = findElement.class_('A'); var parameterA = classA.methods[0].parameters[0]; var result = await getHierarchyNamedParameters(searchEngine, parameterA); expect(result, unorderedEquals([parameterA])); } Future test_getHierarchyNamedParameters_invalid_notNamed() async { verifyNoTestUnitErrors = false; await _indexTestUnit(''' class A { foo({p}) {} } class B extends A { foo(p) {} } '''); var classA = findElement.class_('A'); var parameterA = classA.methods[0].parameters[0]; var result = await getHierarchyNamedParameters(searchEngine, parameterA); expect(result, unorderedEquals([parameterA])); } Future test_getMembers() async { await _indexTestUnit(''' class A { A() {} var ma1; ma2() {} } class B extends A { B() {} B.named() {} var mb1; mb2() {} } '''); { var classA = findElement.class_('A'); var members = getMembers(classA); expect( members.map((e) => e.name), unorderedEquals([ 'ma1', 'ma2', '==', 'toString', 'hashCode', 'noSuchMethod', 'runtimeType' ])); } { var classB = findElement.class_('B'); var members = getMembers(classB); expect( members.map((e) => e.name), unorderedEquals([ 'mb1', 'mb2', 'ma1', 'ma2', '==', 'toString', 'hashCode', 'noSuchMethod', 'runtimeType' ])); } } Future test_getSuperClasses() async { await _indexTestUnit(''' class A {} class B extends A {} class C extends B {} class D extends B implements A {} class M {} class E extends A with M {} class F implements A {} '''); var classA = findElement.class_('A'); var classB = findElement.class_('B'); var classC = findElement.class_('C'); var classD = findElement.class_('D'); var classE = findElement.class_('E'); var classF = findElement.class_('F'); var objectElement = classA.supertype!.element; // Object { var supers = getSuperClasses(objectElement); expect(supers, isEmpty); } // A { var supers = getSuperClasses(classA); expect(supers, unorderedEquals([objectElement])); } // B { var supers = getSuperClasses(classB); expect(supers, unorderedEquals([objectElement, classA])); } // C { var supers = getSuperClasses(classC); expect(supers, unorderedEquals([objectElement, classA, classB])); } // D { var supers = getSuperClasses(classD); expect(supers, unorderedEquals([objectElement, classA, classB])); } // E { var supers = getSuperClasses(classE); expect(supers, unorderedEquals([objectElement, classA])); } // F { var supers = getSuperClasses(classF); expect(supers, unorderedEquals([objectElement, classA])); } } Future test_getSuperClasses_superclassConstraints() async { await _indexTestUnit(''' class A {} class B extends A {} class C {} mixin M1 on A {} mixin M2 on B {} mixin M3 on M1 {} mixin M4 on M2 {} mixin M5 on A, C {} '''); var a = findElement.class_('A'); var b = findElement.class_('B'); var c = findElement.class_('C'); var m1 = findElement.mixin('M1'); var m2 = findElement.mixin('M2'); var m3 = findElement.mixin('M3'); var m4 = findElement.mixin('M4'); var m5 = findElement.mixin('M5'); var object = a.supertype!.element; _assertSuperClasses(object, []); _assertSuperClasses(a, [object]); _assertSuperClasses(b, [object, a]); _assertSuperClasses(c, [object]); _assertSuperClasses(m1, [object, a]); _assertSuperClasses(m2, [object, a, b]); _assertSuperClasses(m3, [object, a, m1]); _assertSuperClasses(m4, [object, a, b, m2]); _assertSuperClasses(m5, [object, a, c]); } void _assertSuperClasses(ClassElement element, List expected) { var supers = getSuperClasses(element); expect(supers, unorderedEquals(expected)); } Future _indexTestUnit(String code) async { await resolveTestCode(code); } }