Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(503)

Unified Diff: pkg/analysis_server/test/domain_analysis_test.dart

Issue 314493002: Navigation computer and two variants of tests for it. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analysis_server/test/domain_analysis_test.dart
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 8efd2e40f1e19f749d99342982bc6d6c924f8091..aa113258612e4ab6e2333f02a47195e60a2d88bc 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -174,6 +174,7 @@ class AnalysisTestHelper {
Map<String, List<AnalysisError>> filesErrors = {};
Map<String, List<Map<String, Object>>> filesHighlights = {};
+ Map<String, List<Map<String, Object>>> filesNavigation = {};
String testFile = '/project/bin/test.dart';
String testCode;
@@ -195,6 +196,10 @@ class AnalysisTestHelper {
String file = notification.getParameter(FILE);
filesHighlights[file] = notification.getParameter(REGIONS);
}
+ if (notification.event == NOTIFICATION_NAVIGATION) {
+ String file = notification.getParameter(FILE);
+ filesNavigation[file] = notification.getParameter(REGIONS);
+ }
});
}
@@ -222,6 +227,16 @@ class AnalysisTestHelper {
}
/**
+ * Returns the offset of [search] in [testCode].
+ * Fails if not found.
+ */
+ int findOffset(String search) {
+ int offset = testCode.indexOf(search);
+ expect(offset, isNot(-1));
+ return offset;
+ }
+
+ /**
* Returns [AnalysisError]s recorded for the given [file].
* May be empty, but not `null`.
*/
@@ -246,6 +261,18 @@ class AnalysisTestHelper {
}
/**
+ * Returns navigation regions recorded for the given [file].
+ * May be empty, but not `null`.
+ */
+ List<Map<String, Object>> getNavigation(String file) {
+ List<Map<String, Object>> navigation = filesNavigation[file];
+ if (navigation != null) {
+ return navigation;
+ }
+ return [];
+ }
+
+ /**
* Returns [AnalysisError]s recorded for the [testFile].
* May be empty, but not `null`.
*/
@@ -262,6 +289,14 @@ class AnalysisTestHelper {
}
/**
+ * Returns navigation information recorded for the given [testFile].
+ * May be empty, but not `null`.
+ */
+ List<Map<String, Object>> getTestNavigation() {
+ return getNavigation(testFile);
+ }
+
+ /**
* Creates an empty project `/project`.
*/
void createEmptyProject() {
@@ -1084,6 +1119,411 @@ class A<T> {
}
+
+
+class NotificationNavigationHelper extends AnalysisTestHelper {
+ List<Map<String, Object>> regions;
+
+ Future prepareRegions(then()) {
+ // TODO(scheglov) add subscription
+// addAnalysisSubscriptionHighlight(testFile);
+ return waitForOperationsFinished().then((_) {
+ regions = getTestNavigation();
+ then();
+ });
+ }
+
+ void assertHasRegion(String regionSearch, String targetSearch) {
+ var regionOffset = findOffset(regionSearch);
+ int regionLength = findIdentifierLength(regionSearch);
+ var targetOffset = findOffset(targetSearch);
+ var targetLength = findIdentifierLength(targetSearch);
+ asserHasRegionInts(regionOffset, regionLength, targetOffset, targetLength);
+ }
+
+ void asserHasOperatorRegion(String search, int regionLength, int targetLength) {
+ var regionOffset = findOffset(search);
+ var region = asserHasRegionInts(regionOffset, regionLength, -1, 0);
+ if (targetLength != -1) {
+ expect(region['targets'][0]['length'], targetLength);
+ }
+ }
+
+ asserHasRegionInts(int regionOffset, int regionLength,
+ int targetOffset, int targetLength) {
+ Map<String, Object> region = findRegion(regionOffset, regionLength);
+ if (region != null) {
+ List<Map<String, Object>> targets = region['targets'];
+ if (targetOffset == -1) {
+ return region;
+ }
+ var target = findTarget(targets, testFile, targetOffset, targetLength);
+ if (target != null) {
+ return target;
+ }
+ }
+ fail('Expected to find (offset=$regionOffset; length=$regionLength) => '
+ '(offset=$targetOffset; length=$targetLength) in\n'
+ '${regions.join('\n')}');
+ }
+
+ Map<String, Object> findRegionString(String search, [bool notNull]) {
+ int offset = findOffset(search);
+ int length = search.length;
+ return findRegion(offset, length, notNull);
+ }
+
+ Map<String, Object> findRegionAt(String search, [bool notNull]) {
+ int offset = findOffset(search);
+ for (Map<String, Object> region in regions) {
+ if (region['offset'] == offset) {
+ if (notNull == false) {
+ fail('Not expected to find at offset=$offset in\n'
+ '${regions.join('\n')}');
+ }
+ return region;
+ }
+ }
+ if (notNull == true) {
+ fail('Expected to find at offset=$offset in\n'
+ '${regions.join('\n')}');
+ }
+ return null;
+ }
+
+ Map<String, Object> findRegionIdentifier(String search, [bool notNull]) {
+ int offset = findOffset(search);
+ int length = findIdentifierLength(search);
+ return findRegion(offset, length, notNull);
+ }
+
+ Map<String, Object> findRegion(int offset, int length, [bool notNull]) {
+ for (Map<String, Object> region in regions) {
+ if (region['offset'] == offset && region['length'] == length) {
+ if (notNull == false) {
+ fail('Not expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
+ }
+ return region;
+ }
+ }
+ if (notNull == true) {
+ fail('Expected to find (offset=$offset; length=$length) in\n'
+ '${regions.join('\n')}');
+ }
+ return null;
+ }
+
+ Map<String, Object> findTarget(List<Map<String, Object>> targets,
+ String file, int offset, int length) {
+ for (Map<String, Object> target in targets) {
+ if (target['file'] == file &&
+ target['offset'] == offset &&
+ target['length'] == length) {
+ return target;
+ }
+ }
+ return null;
+ }
+
+ void assertNoRegion(String regionSearch) {
+ var regionOffset = findOffset(regionSearch);
+ var regionLength = findIdentifierLength(regionSearch);
+ for (Map<String, Object> region in regions) {
+ if (region['offset'] == regionOffset && region['length'] == regionLength) {
+ fail('Unexpected (offset=$regionOffset; length=$regionLength) in\n'
+ '${regions.join('\n')}');
+ }
+ }
+ }
+}
+
+
+int findIdentifierLength(String search) {
+ int length = 0;
+ while (length < search.length) {
+ int c = search.codeUnitAt(length);
+ if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
+ c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
+ c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
+ break;
+ }
+ length++;
+ }
+ return length;
+}
+
+
+testNotificationNavigation() {
+ Future testNavigation(String code, then(NotificationNavigationHelper helper)) {
+ var helper = new NotificationNavigationHelper();
+ helper.createSingleFileProject(code);
+ return helper.prepareRegions(() {
+ then(helper);
+ });
+ }
+
+ group('constructor', () {
+ test('named', () {
+ var code = '''
+class A {
+ A.named(int p) {}
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ // has region for complete "A.named"
+ helper.asserHasRegionInts(
+ helper.findOffset('A.named'), 'A.named'.length,
+ helper.findOffset('named(int'), 'named'.length);
+ // no separate regions for "A" and "named"
+ helper.assertNoRegion('A.named(');
+ helper.assertNoRegion('named(');
+ // validate that we don't forget to resolve parameters
+ helper.asserHasRegionInts(
+ helper.findOffset('int p'), 'int'.length,
+ -1, 0);
+ });
+ });
+
+ test('unnamed', () {
+ var code = '''
+class A {
+ A(int p) {}
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ // has constructor region for "A()"
+ helper.asserHasRegionInts(
+ helper.findOffset('A(int p)'), 'A'.length,
+ helper.findOffset('A(int p)'), 0);
+ // validate that we don't forget to resolve parameters
+ helper.asserHasRegionInts(
+ helper.findOffset('int p'), 'int'.length,
+ -1, 0);
+ });
+ });
+ });
+
+ group('identifier', () {
+ test('resolved', () {
+ var code = '''
+class AAA {}
+main() {
+ AAA aaa = null;
+ print(aaa);
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.assertHasRegion('AAA aaa', 'AAA {}');
+ helper.assertHasRegion('aaa);', 'aaa = null');
+ helper.assertHasRegion('main() {', 'main() {');
+ });
+ });
+
+ test('unresolved', () {
+ var code = '''
+main() {
+ print(noo);
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.assertNoRegion('noo);');
+ });
+ });
+ });
+
+ test('fieldFormalParameter', () {
+ var code = '''
+class A {
+ int fff = 123;
+ A(this.fff);
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.assertHasRegion('fff);', 'fff = 123');
+ });
+ });
+
+ group('instanceCreation', () {
+ test('named', () {
+ var code = '''
+class A {
+ A.named() {}
+}
+main() {
+ new A.named();
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.asserHasRegionInts(
+ helper.findOffset('new A.named'), 'new A.named'.length,
+ helper.findOffset('named()'), 'named'.length);
+ });
+ });
+
+ test('unnamed', () {
+ var code = '''
+class A {
+ A() {}
+}
+main() {
+ new A();
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.asserHasRegionInts(
+ helper.findOffset('new A'), 'new A'.length,
+ helper.findOffset('A()'), ''.length);
+ });
+ });
+ });
+
+ group('operator', () {
+ test('int', () {
+ var code = '''
+main() {
+ var v = 0;
+ v - 1;
+ v + 2;
+ -v; // unary
+ --v;
+ ++v;
+ v--; // mm
+ v++; // pp
+ v -= 3;
+ v += 4;
+ v *= 5;
+ v /= 6;
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.asserHasOperatorRegion('- 1;', 1, 1);
+ helper.asserHasOperatorRegion('+ 2;', 1, 1);
+ helper.asserHasOperatorRegion('-v; // unary', 1, -1);
+ helper.asserHasOperatorRegion('--v;', 2, 1);
+ helper.asserHasOperatorRegion('++v;', 2, 1);
+ helper.asserHasOperatorRegion('--; // mm', 2, 1);
+ helper.asserHasOperatorRegion('++; // pp', 2, 1);
+ helper.asserHasOperatorRegion('-= 3;', 2, 1);
+ helper.asserHasOperatorRegion('+= 4;', 2, 1);
+ helper.asserHasOperatorRegion('*= 5;', 2, 1);
+ helper.asserHasOperatorRegion('/= 6;', 2, 1);
+ });
+ });
+
+ test('list', () {
+ var code = '''
+main() {
+ List<int> v = [1, 2, 3];
+ v[0]; // []
+ v[1] = 1; // []=
+ v[2] += 2;
+}
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.asserHasOperatorRegion(']; // []', 1, 2);
+ helper.asserHasOperatorRegion('] = 1', 1, 3);
+ helper.asserHasOperatorRegion('] += 2', 1, 3);
+ helper.asserHasOperatorRegion('+= 2', 2, 1);
+ });
+ });
+ });
+
+ test('partOf', () {
+ var helper = new NotificationNavigationHelper();
+ var code = '''
+part of lib;
+''';
+ helper.createSingleFileProject(code);
+ var libPath = helper.setFileContent('/project/bin/lib.dart', '''
+library lib;
+part 'test.dart';
+''');
+ return helper.prepareRegions(() {
+ var region = helper.findRegionString('part of lib', true);
+ var target = region['targets'][0];
+ expect(target['file'], libPath);
+ });
+ });
+
+ group('string', () {
+ test('export', () {
+ var code = '''
+export "dart:math";
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.findRegionString('export "dart:math"', true);
+ });
+ });
+
+ test('export unresolved URI', () {
+ var code = '''
+export 'no.dart';
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.findRegionAt('export ', false);
+ });
+ });
+
+ test('import', () {
+ var code = '''
+import "dart:math" as m;
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.findRegionString('import "dart:math"', true);
+ });
+ });
+
+ test('import no URI', () {
+ var code = '''
+import ;
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.findRegionAt('import ', false);
+ });
+ });
+
+ test('import unresolved URI', () {
+ var code = '''
+import 'no.dart';
+''';
+ return testNavigation(code, (NotificationNavigationHelper helper) {
+ helper.findRegionAt('import ', false);
+ });
+ });
+
+ test('part', () {
+ var helper = new NotificationNavigationHelper();
+ var code = '''
+library lib;
+part "my_part.dart";
+''';
+ helper.createSingleFileProject(code);
+ var unitPath = helper.setFileContent('/project/bin/my_part.dart', '''
+part of lib;
+''');
+ return helper.prepareRegions(() {
+ var region = helper.findRegionString('part "my_part.dart"', true);
+ var target = region['targets'][0];
+ expect(target['file'], unitPath);
+ });
+ });
+
+ test('part unresolved URI', () {
+ var helper = new NotificationNavigationHelper();
+ var code = '''
+library lib;
+part "my_part.dart";
+''';
+ helper.createSingleFileProject(code);
+ return helper.prepareRegions(() {
+ helper.findRegionAt('part ', false);
+ });
+ });
+ });
+}
+
+
testUpdateContent() {
test('full content', () {
AnalysisTestHelper helper = new AnalysisTestHelper();

Powered by Google App Engine
This is Rietveld 408576698