| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library test.domain.analysis.notification.navigation; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 | |
| 9 import 'package:analysis_server/src/constants.dart'; | |
| 10 import 'package:analysis_server/src/protocol.dart'; | |
| 11 import 'package:unittest/unittest.dart'; | |
| 12 | |
| 13 import 'analysis_abstract.dart'; | |
| 14 import 'reflective_tests.dart'; | |
| 15 | |
| 16 | |
| 17 main() { | |
| 18 groupSep = ' | '; | |
| 19 runReflectiveTests(AnalysisNotificationNavigationTest); | |
| 20 } | |
| 21 | |
| 22 | |
| 23 @ReflectiveTestCase() | |
| 24 class AnalysisNotificationNavigationTest extends AbstractAnalysisTest { | |
| 25 List<NavigationRegion> regions; | |
| 26 NavigationRegion testRegion; | |
| 27 List<Element> testTargets; | |
| 28 Element testTarget; | |
| 29 | |
| 30 /** | |
| 31 * Validates that there is a target in [testTargets] with [file], at [offset] | |
| 32 * and with the given [length]. | |
| 33 */ | |
| 34 void assertHasFileTarget(String file, int offset, int length) { | |
| 35 for (Element target in testTargets) { | |
| 36 Location location = target.location; | |
| 37 if (location.file == file && | |
| 38 location.offset == offset && | |
| 39 location.length == length) { | |
| 40 testTarget = target; | |
| 41 return; | |
| 42 } | |
| 43 } | |
| 44 fail( | |
| 45 'Expected to find target (file=$file; offset=$offset; length=$length) in
\n' | |
| 46 '${testRegion} in\n' '${testTargets.join('\n')}'); | |
| 47 } | |
| 48 | |
| 49 void assertHasOperatorRegion(String regionSearch, int regionLength, | |
| 50 String targetSearch, int targetLength) { | |
| 51 assertHasRegion(regionSearch, regionLength); | |
| 52 assertHasTarget(targetSearch, targetLength); | |
| 53 } | |
| 54 | |
| 55 /** | |
| 56 * Validates that there is a region at the offset of [search] in [testFile]. | |
| 57 * If [length] is not specified explicitly, then length of an identifier | |
| 58 * from [search] is used. | |
| 59 */ | |
| 60 void assertHasRegion(String search, [int length = -1]) { | |
| 61 int offset = findOffset(search); | |
| 62 if (length == -1) { | |
| 63 length = findIdentifierLength(search); | |
| 64 } | |
| 65 findRegion(offset, length, true); | |
| 66 } | |
| 67 | |
| 68 /** | |
| 69 * Validates that there is a region at the offset of [search] in [testFile] | |
| 70 * with the length of [search]. | |
| 71 */ | |
| 72 void assertHasRegionString(String search) { | |
| 73 int offset = findOffset(search); | |
| 74 int length = search.length; | |
| 75 findRegion(offset, length, true); | |
| 76 } | |
| 77 | |
| 78 /** | |
| 79 * Validates that there is an identifier region at [regionSearch] with target | |
| 80 * at [targetSearch]. | |
| 81 */ | |
| 82 void assertHasRegionTarget(String regionSearch, String targetSearch) { | |
| 83 assertHasRegion(regionSearch); | |
| 84 assertHasTarget(targetSearch); | |
| 85 } | |
| 86 | |
| 87 /** | |
| 88 * Validates that there is a target in [testTargets] with [testFile], at the | |
| 89 * offset of [search] in [testFile], and with the given [length] or the length | |
| 90 * of an leading identifier in [search]. | |
| 91 */ | |
| 92 void assertHasTarget(String search, [int length = -1]) { | |
| 93 int offset = findOffset(search); | |
| 94 if (length == -1) { | |
| 95 length = findIdentifierLength(search); | |
| 96 } | |
| 97 assertHasFileTarget(testFile, offset, length); | |
| 98 } | |
| 99 | |
| 100 /** | |
| 101 * Validates that there is no a region at [search] and with the given | |
| 102 * [length]. | |
| 103 */ | |
| 104 void assertNoRegion(String search, int length) { | |
| 105 int offset = findOffset(search); | |
| 106 findRegion(offset, length, false); | |
| 107 } | |
| 108 | |
| 109 /** | |
| 110 * Validates that there is no a region at [search] with any length. | |
| 111 */ | |
| 112 void assertNoRegionAt(String search) { | |
| 113 int offset = findOffset(search); | |
| 114 findRegion(offset, -1, false); | |
| 115 } | |
| 116 | |
| 117 /** | |
| 118 * Validates that there is no a region for [search] string. | |
| 119 */ | |
| 120 void assertNoRegionString(String search) { | |
| 121 int offset = findOffset(search); | |
| 122 int length = search.length; | |
| 123 findRegion(offset, length, false); | |
| 124 } | |
| 125 | |
| 126 /** | |
| 127 * Finds the navigation region with the given [offset] and [length]. | |
| 128 * If [length] is `-1`, then it is ignored. | |
| 129 * | |
| 130 * If [exists] is `true`, then fails if such region does not exist. | |
| 131 * Otherwise remembers this it into [testRegion]. | |
| 132 * Also fills [testTargets] with its targets. | |
| 133 * | |
| 134 * If [exists] is `false`, then fails if such region exists. | |
| 135 */ | |
| 136 void findRegion(int offset, int length, [bool exists]) { | |
| 137 for (NavigationRegion region in regions) { | |
| 138 if (region.offset == offset && | |
| 139 (length == -1 || region.length == length)) { | |
| 140 if (exists == false) { | |
| 141 fail( | |
| 142 'Not expected to find (offset=$offset; length=$length) in\n' | |
| 143 '${regions.join('\n')}'); | |
| 144 } | |
| 145 testRegion = region; | |
| 146 testTargets = region.targets; | |
| 147 return; | |
| 148 } | |
| 149 } | |
| 150 if (exists == true) { | |
| 151 fail( | |
| 152 'Expected to find (offset=$offset; length=$length) in\n' | |
| 153 '${regions.join('\n')}'); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 Future prepareNavigation() { | |
| 158 addAnalysisSubscription(AnalysisService.NAVIGATION, testFile); | |
| 159 return waitForTasksFinished(); | |
| 160 } | |
| 161 | |
| 162 void processNotification(Notification notification) { | |
| 163 if (notification.event == ANALYSIS_NAVIGATION) { | |
| 164 var params = new AnalysisNavigationParams.fromNotification(notification); | |
| 165 if (params.file == testFile) { | |
| 166 regions = params.regions; | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 @override | |
| 172 void setUp() { | |
| 173 super.setUp(); | |
| 174 createProject(); | |
| 175 } | |
| 176 | |
| 177 test_afterAnalysis() { | |
| 178 addTestFile(''' | |
| 179 class AAA {} | |
| 180 AAA aaa; | |
| 181 '''); | |
| 182 return waitForTasksFinished().then((_) { | |
| 183 return prepareNavigation().then((_) { | |
| 184 assertHasRegionTarget('AAA aaa;', 'AAA {}'); | |
| 185 }); | |
| 186 }); | |
| 187 } | |
| 188 | |
| 189 test_constructor_named() { | |
| 190 addTestFile(''' | |
| 191 class A { | |
| 192 A.named(BBB p) {} | |
| 193 } | |
| 194 class BBB {} | |
| 195 '''); | |
| 196 return prepareNavigation().then((_) { | |
| 197 // has region for complete "A.named" | |
| 198 assertHasRegionString('A.named'); | |
| 199 assertHasTarget('named(BBB'); | |
| 200 // no separate regions for "A" and "named" | |
| 201 assertNoRegion('A.named(', 'A'.length); | |
| 202 assertNoRegion('named(', 'named'.length); | |
| 203 // validate that we don't forget to resolve parameters | |
| 204 assertHasRegionTarget('BBB p', 'BBB {}'); | |
| 205 }); | |
| 206 } | |
| 207 | |
| 208 test_constructor_unnamed() { | |
| 209 addTestFile(''' | |
| 210 class A { | |
| 211 A(BBB p) {} | |
| 212 } | |
| 213 class BBB {} | |
| 214 '''); | |
| 215 return prepareNavigation().then((_) { | |
| 216 // has region for complete "A.named" | |
| 217 assertHasRegion("A(BBB"); | |
| 218 assertHasTarget("A(BBB", 0); | |
| 219 // validate that we don't forget to resolve parameters | |
| 220 assertHasRegionTarget('BBB p', 'BBB {}'); | |
| 221 }); | |
| 222 } | |
| 223 | |
| 224 test_fieldFormalParameter() { | |
| 225 addTestFile(''' | |
| 226 class AAA { | |
| 227 int fff = 123; | |
| 228 AAA(this.fff); | |
| 229 } | |
| 230 '''); | |
| 231 return prepareNavigation().then((_) { | |
| 232 assertHasRegionTarget('fff);', 'fff = 123'); | |
| 233 }); | |
| 234 } | |
| 235 | |
| 236 test_identifier_resolved() { | |
| 237 addTestFile(''' | |
| 238 class AAA {} | |
| 239 main() { | |
| 240 AAA aaa = null; | |
| 241 print(aaa); | |
| 242 } | |
| 243 '''); | |
| 244 return prepareNavigation().then((_) { | |
| 245 assertHasRegionTarget('AAA aaa', 'AAA {}'); | |
| 246 assertHasRegionTarget('aaa);', 'aaa = null'); | |
| 247 assertHasRegionTarget('main() {', 'main() {'); | |
| 248 }); | |
| 249 } | |
| 250 | |
| 251 test_identifier_unresolved() { | |
| 252 addTestFile(''' | |
| 253 main() { | |
| 254 print(vvv); | |
| 255 } | |
| 256 '''); | |
| 257 return prepareNavigation().then((_) { | |
| 258 assertNoRegionString('vvv'); | |
| 259 }); | |
| 260 } | |
| 261 | |
| 262 test_instanceCreation_implicit() { | |
| 263 addTestFile(''' | |
| 264 class A { | |
| 265 } | |
| 266 main() { | |
| 267 new A(); | |
| 268 } | |
| 269 '''); | |
| 270 return prepareNavigation().then((_) { | |
| 271 findRegion(findOffset('new A'), 'new A'.length, true); | |
| 272 assertHasTarget('A {'); | |
| 273 }); | |
| 274 } | |
| 275 | |
| 276 test_instanceCreation_named() { | |
| 277 addTestFile(''' | |
| 278 class A { | |
| 279 A.named() {} | |
| 280 } | |
| 281 main() { | |
| 282 new A.named(); | |
| 283 } | |
| 284 '''); | |
| 285 return prepareNavigation().then((_) { | |
| 286 { | |
| 287 findRegion(findOffset('new '), 'new '.length, true); | |
| 288 assertHasTarget('named() {}'); | |
| 289 } | |
| 290 { | |
| 291 findRegion(findOffset('A.named();'), 'A'.length, true); | |
| 292 assertHasTarget('A {'); | |
| 293 } | |
| 294 { | |
| 295 findRegion(findOffset('.named();'), '.named'.length, true); | |
| 296 assertHasTarget('named() {}'); | |
| 297 } | |
| 298 }); | |
| 299 } | |
| 300 | |
| 301 test_instanceCreation_unnamed() { | |
| 302 addTestFile(''' | |
| 303 class A { | |
| 304 A() {} | |
| 305 } | |
| 306 main() { | |
| 307 new A(); | |
| 308 } | |
| 309 '''); | |
| 310 return prepareNavigation().then((_) { | |
| 311 { | |
| 312 findRegion(findOffset('new '), 'new '.length, true); | |
| 313 assertHasTarget('A() {}', 0); | |
| 314 } | |
| 315 { | |
| 316 findRegion(findOffset('A();'), 'A'.length, true); | |
| 317 assertHasTarget('A {'); | |
| 318 } | |
| 319 }); | |
| 320 } | |
| 321 | |
| 322 test_operator_arithmetic() { | |
| 323 addTestFile(''' | |
| 324 class A { | |
| 325 A operator +(other) => null; | |
| 326 A operator -() => null; | |
| 327 A operator -(other) => null; | |
| 328 A operator *(other) => null; | |
| 329 A operator /(other) => null; | |
| 330 } | |
| 331 main() { | |
| 332 var a = new A(); | |
| 333 a - 1; | |
| 334 a + 2; | |
| 335 -a; // unary | |
| 336 --a; | |
| 337 ++a; | |
| 338 a--; // mm | |
| 339 a++; // pp | |
| 340 a -= 3; | |
| 341 a += 4; | |
| 342 a *= 5; | |
| 343 a /= 6; | |
| 344 } | |
| 345 '''); | |
| 346 return prepareNavigation().then((_) { | |
| 347 assertHasOperatorRegion('- 1', 1, '-(other) => null', 1); | |
| 348 assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1); | |
| 349 assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1); | |
| 350 assertHasOperatorRegion('--a;', 2, '-(other) => null', 1); | |
| 351 assertHasOperatorRegion('++a;', 2, '+(other) => null', 1); | |
| 352 assertHasOperatorRegion('--; // mm', 2, '-(other) => null', 1); | |
| 353 assertHasOperatorRegion('++; // pp', 2, '+(other) => null', 1); | |
| 354 assertHasOperatorRegion('-= 3', 2, '-(other) => null', 1); | |
| 355 assertHasOperatorRegion('+= 4', 2, '+(other) => null', 1); | |
| 356 assertHasOperatorRegion('*= 5', 2, '*(other) => null', 1); | |
| 357 assertHasOperatorRegion('/= 6', 2, '/(other) => null', 1); | |
| 358 }); | |
| 359 } | |
| 360 | |
| 361 test_operator_index() { | |
| 362 addTestFile(''' | |
| 363 class A { | |
| 364 A operator +(other) => null; | |
| 365 } | |
| 366 class B { | |
| 367 A operator [](index) => null; | |
| 368 operator []=(index, A value) {} | |
| 369 } | |
| 370 main() { | |
| 371 var b = new B(); | |
| 372 b[0] // []; | |
| 373 b[1] = 1; // []=; | |
| 374 b[2] += 2; | |
| 375 } | |
| 376 '''); | |
| 377 return prepareNavigation().then((_) { | |
| 378 assertHasOperatorRegion('] // []', 1, '[](index)', 2); | |
| 379 assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3); | |
| 380 assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3); | |
| 381 assertHasOperatorRegion('+= 2;', 2, '+(other)', 1); | |
| 382 }); | |
| 383 } | |
| 384 | |
| 385 test_partOf() { | |
| 386 var libCode = 'library lib; part "test.dart";'; | |
| 387 var libFile = addFile('$projectPath/bin/lib.dart', libCode); | |
| 388 addTestFile('part of lib;'); | |
| 389 return prepareNavigation().then((_) { | |
| 390 assertHasRegionString('part of lib'); | |
| 391 assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length); | |
| 392 }); | |
| 393 } | |
| 394 | |
| 395 test_string_export() { | |
| 396 var libCode = 'library lib;'; | |
| 397 var libFile = addFile('$projectPath/bin/lib.dart', libCode); | |
| 398 addTestFile('export "lib.dart";'); | |
| 399 return prepareNavigation().then((_) { | |
| 400 assertHasRegionString('export "lib.dart"'); | |
| 401 assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length); | |
| 402 }); | |
| 403 } | |
| 404 | |
| 405 test_string_export_unresolvedUri() { | |
| 406 addTestFile('export "no.dart";'); | |
| 407 return prepareNavigation().then((_) { | |
| 408 assertNoRegionString('export "no.dart"'); | |
| 409 }); | |
| 410 } | |
| 411 | |
| 412 test_string_import() { | |
| 413 var libCode = 'library lib;'; | |
| 414 var libFile = addFile('$projectPath/bin/lib.dart', libCode); | |
| 415 addTestFile('import "lib.dart";'); | |
| 416 return prepareNavigation().then((_) { | |
| 417 assertHasRegionString('import "lib.dart"'); | |
| 418 assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length); | |
| 419 }); | |
| 420 } | |
| 421 | |
| 422 test_string_import_noUri() { | |
| 423 addTestFile('import ;'); | |
| 424 return prepareNavigation().then((_) { | |
| 425 assertNoRegionAt('import ;'); | |
| 426 }); | |
| 427 } | |
| 428 | |
| 429 test_string_import_unresolvedUri() { | |
| 430 addTestFile('import "no.dart";'); | |
| 431 return prepareNavigation().then((_) { | |
| 432 assertNoRegionString('import "no.dart"'); | |
| 433 }); | |
| 434 } | |
| 435 | |
| 436 test_string_part() { | |
| 437 var unitCode = 'part of lib; f() {}'; | |
| 438 var unitFile = addFile('$projectPath/bin/test_unit.dart', unitCode); | |
| 439 addTestFile(''' | |
| 440 library lib; | |
| 441 part "test_unit.dart"; | |
| 442 '''); | |
| 443 return prepareNavigation().then((_) { | |
| 444 assertHasRegionString('part "test_unit.dart"'); | |
| 445 assertHasFileTarget(unitFile, 0, 0); | |
| 446 }); | |
| 447 } | |
| 448 | |
| 449 test_string_part_unresolvedUri() { | |
| 450 addTestFile(''' | |
| 451 library lib; | |
| 452 part "test_unit.dart"; | |
| 453 '''); | |
| 454 return prepareNavigation().then((_) { | |
| 455 assertNoRegionString('part "test_unit.dart"'); | |
| 456 }); | |
| 457 } | |
| 458 | |
| 459 test_targetElement() { | |
| 460 addTestFile(''' | |
| 461 class AAA {} | |
| 462 main() { | |
| 463 AAA aaa = null; | |
| 464 } | |
| 465 '''); | |
| 466 return prepareNavigation().then((_) { | |
| 467 assertHasRegionTarget('AAA aaa', 'AAA {}'); | |
| 468 expect(testTarget.kind, ElementKind.CLASS); | |
| 469 expect(testTarget.name, 'AAA'); | |
| 470 expect(testTarget.isAbstract, false); | |
| 471 expect(testTarget.parameters, isNull); | |
| 472 expect(testTarget.returnType, isNull); | |
| 473 }); | |
| 474 } | |
| 475 | |
| 476 test_type_dynamic() { | |
| 477 addTestFile(''' | |
| 478 main() { | |
| 479 dynamic v = null; | |
| 480 } | |
| 481 '''); | |
| 482 return prepareNavigation().then((_) { | |
| 483 assertNoRegionAt('dynamic'); | |
| 484 }); | |
| 485 } | |
| 486 | |
| 487 test_type_void() { | |
| 488 addTestFile(''' | |
| 489 void main() { | |
| 490 } | |
| 491 '''); | |
| 492 return prepareNavigation().then((_) { | |
| 493 assertNoRegionAt('void'); | |
| 494 }); | |
| 495 } | |
| 496 } | |
| OLD | NEW |