blob: a24dd4773d3a8f2d5d4438f221d780ccd7bebe56 [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.
library test.analysis.get_type_hierarhy;
import 'dart:async';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/search/search_domain.dart';
import 'package:analysis_services/constants.dart';
import 'package:analysis_services/index/index.dart';
import 'package:analysis_services/index/local_memory_index.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:unittest/unittest.dart';
import '../analysis_abstract.dart';
main() {
groupSep = ' | ';
runReflectiveTests(GetTypeHierarchyTest);
}
@ReflectiveTestCase()
class GetTypeHierarchyTest extends AbstractAnalysisTest {
static const String requestId = 'test-getTypeHierarchy';
@override
Index createIndex() {
return createLocalMemoryIndex();
}
@override
void setUp() {
super.setUp();
server.handlers = [new SearchDomainHandler(server),];
createProject();
}
test_bad_function() {
addTestFile('''
main() {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('main() {').then((jsons) {
expect(jsons, isNull);
});
});
}
test_bad_recursion() {
addTestFile('''
class A extends B {
}
class B extends A {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('B extends A').then((jsons) {
expect(jsons, [{
'classElement': {
'kind': 'CLASS',
'name': 'B',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'A',
'location': anything,
'flags': 0
},
'superclass': 0,
'interfaces': [],
'mixins': [],
'subclasses': [1]
}]);
});
});
}
test_class_displayName() {
addTestFile('''
class A<T> {
}
class B extends A<int> {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('B extends').then((jsons) {
var jsonB = jsons[0];
var jsonA = jsons[jsonB[SUPERCLASS]];
expect(jsonA[CLASS_ELEMENT][NAME], 'A');
expect(jsonB[CLASS_ELEMENT][NAME], 'B');
expect(jsonA[DISPLAY_NAME], 'A<int>');
});
});
}
test_class_extendsTypeA() {
addTestFile('''
class A {}
class B extends A {
}
class C extends B {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('A {}').then((jsons) {
expect(jsons, [{
'classElement': {
'kind': 'CLASS',
'name': 'A',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': [2]
}, {
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'B',
'location': anything,
'flags': 0
},
'superclass': 0,
'interfaces': [],
'mixins': [],
'subclasses': [3]
}, {
'classElement': {
'kind': 'CLASS',
'name': 'C',
'location': anything,
'flags': 0
},
'superclass': 2,
'interfaces': [],
'mixins': [],
'subclasses': []
}]);
});
});
}
test_class_extendsTypeB() {
addTestFile('''
class A {
}
class B extends A {
}
class C extends B {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('B extends').then((jsons) {
expect(jsons, [{
'classElement': {
'kind': 'CLASS',
'name': 'B',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': [3]
}, {
'classElement': {
'kind': 'CLASS',
'name': 'A',
'location': anything,
'flags': 0
},
'superclass': 2,
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'C',
'location': anything,
'flags': 0
},
'superclass': 0,
'interfaces': [],
'mixins': [],
'subclasses': []
}]);
});
});
}
test_class_extendsTypeC() {
addTestFile('''
class A {
}
class B extends A {
}
class C extends B {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('C extends').then((jsons) {
expect(jsons, [{
'classElement': {
'kind': 'CLASS',
'name': 'C',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'B',
'location': anything,
'flags': 0
},
'superclass': 2,
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'A',
'location': anything,
'flags': 0
},
'superclass': 3,
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
}]);
});
});
}
test_class_implementsTypes() {
addTestFile('''
class MA {}
class MB {}
class B extends A {
}
class T implements MA, MB {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('T implements').then((jsons) {
expect(jsons, [{
'classElement': {
'kind': 'CLASS',
'name': 'T',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [2, 3],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'MA',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'MB',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': []
}]);
});
});
}
test_class_withTypes() {
addTestFile('''
class MA {}
class MB {}
class B extends A {
}
class T extends Object with MA, MB {
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('T extends Object').then((jsons) {
expect(jsons, [{
'classElement': {
'kind': 'CLASS',
'name': 'T',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [2, 3],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'MA',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': []
}, {
'classElement': {
'kind': 'CLASS',
'name': 'MB',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': []
}]);
});
});
}
test_member_getter() {
addTestFile('''
class A {
get test => null; // in A
}
class B extends A {
get test => null; // in B
}
class C extends B {
}
class D extends C {
get test => null; // in D
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('test => null; // in B').then((jsons) {
Map jsonB = jsons[0];
Map jsonA = jsons[jsonB[SUPERCLASS]];
Map jsonC = jsons[jsonB[SUBCLASSES][0]];
Map jsonD = jsons[jsonC[SUBCLASSES][0]];
expect(jsonA[CLASS_ELEMENT][NAME], 'A');
expect(jsonB[CLASS_ELEMENT][NAME], 'B');
expect(jsonC[CLASS_ELEMENT][NAME], 'C');
expect(jsonD[CLASS_ELEMENT][NAME], 'D');
expect(
jsonA[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test => null; // in A'));
expect(
jsonB[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test => null; // in B'));
expect(jsonC['memberElement'], isNull);
expect(
jsonD[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test => null; // in D'));
});
});
}
test_member_method() {
addTestFile('''
class A {
test() {} // in A
}
class B extends A {
test() {} // in B
}
class C extends B {
}
class D extends C {
test() {} // in D
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('test() {} // in B').then((jsons) {
var jsonB = jsons[0];
var jsonA = jsons[jsonB[SUPERCLASS]];
var jsonC = jsons[jsonB[SUBCLASSES][0]];
var jsonD = jsons[jsonC[SUBCLASSES][0]];
expect(jsonA[CLASS_ELEMENT][NAME], 'A');
expect(jsonB[CLASS_ELEMENT][NAME], 'B');
expect(jsonC[CLASS_ELEMENT][NAME], 'C');
expect(jsonD[CLASS_ELEMENT][NAME], 'D');
expect(
jsonA[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test() {} // in A'));
expect(
jsonB[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test() {} // in B'));
expect(jsonC['memberElement'], isNull);
expect(
jsonD[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test() {} // in D'));
});
});
}
test_member_operator() {
addTestFile('''
class A {
operator ==(x) => null; // in A
}
class B extends A {
operator ==(x) => null; // in B
}
class C extends B {
}
class D extends C {
operator ==(x) => null; // in D
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('==(x) => null; // in B').then((jsons) {
var jsonB = jsons[0];
var jsonA = jsons[jsonB[SUPERCLASS]];
var jsonC = jsons[jsonB[SUBCLASSES][0]];
var jsonD = jsons[jsonC[SUBCLASSES][0]];
expect(jsonA[CLASS_ELEMENT][NAME], 'A');
expect(jsonB[CLASS_ELEMENT][NAME], 'B');
expect(jsonC[CLASS_ELEMENT][NAME], 'C');
expect(jsonD[CLASS_ELEMENT][NAME], 'D');
expect(
jsonA[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('==(x) => null; // in A'));
expect(
jsonB[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('==(x) => null; // in B'));
expect(jsonC['memberElement'], isNull);
expect(
jsonD[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('==(x) => null; // in D'));
});
});
}
test_member_setter() {
addTestFile('''
class A {
set test(x) {} // in A
}
class B extends A {
set test(x) {} // in B
}
class C extends B {
}
class D extends C {
set test(x) {} // in D
}
''');
return waitForTasksFinished().then((_) {
return _getTypeHierarchy('test(x) {} // in B').then((jsons) {
var jsonB = jsons[0];
var jsonA = jsons[jsonB[SUPERCLASS]];
var jsonC = jsons[jsonB[SUBCLASSES][0]];
var jsonD = jsons[jsonC[SUBCLASSES][0]];
expect(jsonA[CLASS_ELEMENT][NAME], 'A');
expect(jsonB[CLASS_ELEMENT][NAME], 'B');
expect(jsonC[CLASS_ELEMENT][NAME], 'C');
expect(jsonD[CLASS_ELEMENT][NAME], 'D');
expect(
jsonA[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test(x) {} // in A'));
expect(
jsonB[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test(x) {} // in B'));
expect(jsonC['memberElement'], isNull);
expect(
jsonD[MEMBER_ELEMENT][LOCATION][OFFSET],
findOffset('test(x) {} // in D'));
});
});
}
Request _createGetTypeHierarchyRequest(String search) {
int offset = findOffset(search);
Request request = new Request(requestId, SEARCH_GET_TYPE_HIERARCHY);
request.setParameter(FILE, testFile);
request.setParameter(OFFSET, offset);
return request;
}
Future<List<Map<String, Object>>> _getTypeHierarchy(String search) {
Request request = _createGetTypeHierarchyRequest(search);
return serverChannel.sendRequest(request).then((Response response) {
return response.getResult(HIERARCHY_ITEMS) as List<Map<String, Object>>;
});
}
}