| 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_test.dart'; |
| 14 import 'reflective_tests.dart'; |
| 15 |
| 16 |
| 17 @ReflectiveTestCase() |
| 18 class AnalysisNotificationNavigationTest extends AbstractAnalysisTest { |
| 19 List<Map<String, Object>> regions; |
| 20 Map<String, Object> testRegion; |
| 21 List<Map<String, Object>> testTargets; |
| 22 |
| 23 void processNotification(Notification notification) { |
| 24 if (notification.event == NOTIFICATION_NAVIGATION) { |
| 25 String file = notification.getParameter(FILE); |
| 26 if (file == testFile) { |
| 27 regions = notification.getParameter(REGIONS); |
| 28 } |
| 29 } |
| 30 } |
| 31 |
| 32 Future prepareNavigation(then()) { |
| 33 // TODO(scheglov) add subscription |
| 34 // addAnalysisSubscriptionHighlight(testFile); |
| 35 return waitForTasksFinished().then((_) { |
| 36 then(); |
| 37 }); |
| 38 } |
| 39 |
| 40 /** |
| 41 * Finds the navigation region with the given [offset] and [length]. |
| 42 * If [length] is `-1`, then it is ignored. |
| 43 * |
| 44 * If [exists] is `true`, then fails if such region does not exist. |
| 45 * Otherwise remembers this it into [testRegion]. |
| 46 * Also fills [testTargets] with its targets. |
| 47 * |
| 48 * If [exists] is `false`, then fails if such region exists. |
| 49 */ |
| 50 void findRegion(int offset, int length, [bool exists]) { |
| 51 for (Map<String, Object> region in regions) { |
| 52 if (region['offset'] == offset && |
| 53 (length == -1 || region['length'] == length)) { |
| 54 if (exists == false) { |
| 55 fail('Not expected to find (offset=$offset; length=$length) in\n' |
| 56 '${regions.join('\n')}'); |
| 57 } |
| 58 testRegion = region; |
| 59 testTargets = region['targets']; |
| 60 return; |
| 61 } |
| 62 } |
| 63 if (exists == true) { |
| 64 fail('Expected to find (offset=$offset; length=$length) in\n' |
| 65 '${regions.join('\n')}'); |
| 66 } |
| 67 } |
| 68 |
| 69 /** |
| 70 * Validates that there is a region at the offset of [search] in [testFile]. |
| 71 * If [length] is not specified explicitly, then length of an identifier |
| 72 * from [search] is used. |
| 73 */ |
| 74 void assertHasRegion(String search, [int length = -1]) { |
| 75 int offset = findOffset(search); |
| 76 if (length == -1) { |
| 77 length = findIdentifierLength(search); |
| 78 } |
| 79 findRegion(offset, length, true); |
| 80 } |
| 81 |
| 82 /** |
| 83 * Validates that there is a region at the offset of [search] in [testFile] |
| 84 * with the length of [search]. |
| 85 */ |
| 86 void assertHasRegionString(String search) { |
| 87 int offset = findOffset(search); |
| 88 int length = search.length; |
| 89 findRegion(offset, length, true); |
| 90 } |
| 91 |
| 92 /** |
| 93 * Validates that there is a target in [testTargets] with [testFile], at the |
| 94 * offset of [search] in [testFile], and with the given [length] or the length |
| 95 * of an leading identifier in [search]. |
| 96 */ |
| 97 void assertHasTarget(String search, [int length = -1]) { |
| 98 int offset = findOffset(search); |
| 99 if (length == -1) { |
| 100 length = findIdentifierLength(search); |
| 101 } |
| 102 for (Map<String, Object> target in testTargets) { |
| 103 if (target['file'] == testFile && |
| 104 target['offset'] == offset && |
| 105 target['length'] == length) { |
| 106 return; |
| 107 } |
| 108 } |
| 109 fail('Expected to find target (offset=$offset; length=$length) in\n' |
| 110 '${testRegion} in\n' |
| 111 '${regions.join('\n')}'); |
| 112 } |
| 113 |
| 114 /** |
| 115 * Validates that there is a target in [testTargets] with [file], at [offset] |
| 116 * and with the given [length]. |
| 117 */ |
| 118 void assertHasFileTarget(String file, int offset, int length) { |
| 119 for (Map<String, Object> target in testTargets) { |
| 120 if (target['file'] == file && |
| 121 target['offset'] == offset && |
| 122 target['length'] == length) { |
| 123 return; |
| 124 } |
| 125 } |
| 126 fail('Expected to find target (file=$file; offset=$offset; length=$length) i
n\n' |
| 127 '${testRegion} in\n' |
| 128 '${regions.join('\n')}'); |
| 129 } |
| 130 |
| 131 /** |
| 132 * Validates that there is an identifier region at [regionSearch] with target |
| 133 * at [targetSearch]. |
| 134 */ |
| 135 void assertHasRegionTarget(String regionSearch, String targetSearch) { |
| 136 assertHasRegion(regionSearch); |
| 137 assertHasTarget(targetSearch); |
| 138 } |
| 139 |
| 140 void assertHasOperatorRegion(String regionSearch, int regionLength, |
| 141 String targetSearch, int targetLength) { |
| 142 assertHasRegion(regionSearch, regionLength); |
| 143 assertHasTarget(targetSearch, targetLength); |
| 144 } |
| 145 |
| 146 /** |
| 147 * Validates that there is no a region at [search] and with the given |
| 148 * [length]. |
| 149 */ |
| 150 void assertNoRegion(String search, int length) { |
| 151 int offset = findOffset(search); |
| 152 findRegion(offset, length, false); |
| 153 } |
| 154 |
| 155 /** |
| 156 * Validates that there is no a region at [search] with any length. |
| 157 */ |
| 158 void assertNoRegionAt(String search) { |
| 159 int offset = findOffset(search); |
| 160 findRegion(offset, -1, false); |
| 161 } |
| 162 |
| 163 /** |
| 164 * Validates that there is no a region for [search] string. |
| 165 */ |
| 166 void assertNoRegionString(String search) { |
| 167 int offset = findOffset(search); |
| 168 int length = search.length; |
| 169 findRegion(offset, length, false); |
| 170 } |
| 171 |
| 172 test_constructor_named() { |
| 173 addTestFile(''' |
| 174 class A { |
| 175 A.named(BBB p) {} |
| 176 } |
| 177 class BBB {} |
| 178 '''); |
| 179 return prepareNavigation(() { |
| 180 // has region for complete "A.named" |
| 181 assertHasRegionString('A.named'); |
| 182 assertHasTarget('named(BBB'); |
| 183 // no separate regions for "A" and "named" |
| 184 assertNoRegion('A.named(', 'A'.length); |
| 185 assertNoRegion('named(', 'named'.length); |
| 186 // validate that we don't forget to resolve parameters |
| 187 assertHasRegionTarget('BBB p', 'BBB {}'); |
| 188 }); |
| 189 } |
| 190 |
| 191 test_constructor_unnamed() { |
| 192 addTestFile(''' |
| 193 class A { |
| 194 A(BBB p) {} |
| 195 } |
| 196 class BBB {} |
| 197 '''); |
| 198 return prepareNavigation(() { |
| 199 // has region for complete "A.named" |
| 200 assertHasRegion("A(BBB"); |
| 201 assertHasTarget("A(BBB", 0); |
| 202 // validate that we don't forget to resolve parameters |
| 203 assertHasRegionTarget('BBB p', 'BBB {}'); |
| 204 }); |
| 205 } |
| 206 |
| 207 test_fieldFormalParameter() { |
| 208 addTestFile(''' |
| 209 class AAA { |
| 210 int fff = 123; |
| 211 AAA(this.fff); |
| 212 } |
| 213 '''); |
| 214 return prepareNavigation(() { |
| 215 assertHasRegionTarget('fff);', 'fff = 123'); |
| 216 }); |
| 217 } |
| 218 |
| 219 test_identifier_resolved() { |
| 220 addTestFile(''' |
| 221 class AAA {} |
| 222 main() { |
| 223 AAA aaa = null; |
| 224 print(aaa); |
| 225 } |
| 226 '''); |
| 227 return prepareNavigation(() { |
| 228 assertHasRegionTarget('AAA aaa', 'AAA {}'); |
| 229 assertHasRegionTarget('aaa);', 'aaa = null'); |
| 230 assertHasRegionTarget('main() {', 'main() {'); |
| 231 }); |
| 232 } |
| 233 |
| 234 test_identifier_unresolved() { |
| 235 addTestFile(''' |
| 236 main() { |
| 237 print(vvv); |
| 238 } |
| 239 '''); |
| 240 return prepareNavigation(() { |
| 241 assertNoRegionString('vvv'); |
| 242 }); |
| 243 } |
| 244 |
| 245 test_instanceCreation_named() { |
| 246 addTestFile(''' |
| 247 class A { |
| 248 A.named() {} |
| 249 } |
| 250 main() { |
| 251 new A.named(); |
| 252 } |
| 253 '''); |
| 254 return prepareNavigation(() { |
| 255 assertHasRegionString('new A.named'); |
| 256 assertHasTarget('named() {}'); |
| 257 }); |
| 258 } |
| 259 |
| 260 test_instanceCreation_unnamed() { |
| 261 addTestFile(''' |
| 262 class A { |
| 263 A() {} |
| 264 } |
| 265 main() { |
| 266 new A(); |
| 267 } |
| 268 '''); |
| 269 return prepareNavigation(() { |
| 270 assertHasRegionString('new A'); |
| 271 assertHasTarget("A() {}", 0); |
| 272 }); |
| 273 } |
| 274 |
| 275 test_operator_arithmetic() { |
| 276 addTestFile(''' |
| 277 class A { |
| 278 A operator +(other) => null; |
| 279 A operator -() => null; |
| 280 A operator -(other) => null; |
| 281 A operator *(other) => null; |
| 282 A operator /(other) => null; |
| 283 } |
| 284 main() { |
| 285 var a = new A(); |
| 286 a - 1; |
| 287 a + 2; |
| 288 -a; // unary |
| 289 --a; |
| 290 ++a; |
| 291 a--; // mm |
| 292 a++; // pp |
| 293 a -= 3; |
| 294 a += 4; |
| 295 a *= 5; |
| 296 a /= 6; |
| 297 } |
| 298 '''); |
| 299 return prepareNavigation(() { |
| 300 assertHasOperatorRegion('- 1', 1, '-(other) => null', 1); |
| 301 assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1); |
| 302 assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1); |
| 303 assertHasOperatorRegion('--a;', 2, '-(other) => null', 1); |
| 304 assertHasOperatorRegion('++a;', 2, '+(other) => null', 1); |
| 305 assertHasOperatorRegion('--; // mm', 2, '-(other) => null', 1); |
| 306 assertHasOperatorRegion('++; // pp', 2, '+(other) => null', 1); |
| 307 assertHasOperatorRegion('-= 3', 2, '-(other) => null', 1); |
| 308 assertHasOperatorRegion('+= 4', 2, '+(other) => null', 1); |
| 309 assertHasOperatorRegion('*= 5', 2, '*(other) => null', 1); |
| 310 assertHasOperatorRegion('/= 6', 2, '/(other) => null', 1); |
| 311 }); |
| 312 } |
| 313 |
| 314 test_operator_index() { |
| 315 addTestFile(''' |
| 316 class A { |
| 317 A operator +(other) => null; |
| 318 } |
| 319 class B { |
| 320 A operator [](index) => null; |
| 321 operator []=(index, A value) {} |
| 322 } |
| 323 main() { |
| 324 var b = new B(); |
| 325 b[0] // []; |
| 326 b[1] = 1; // []=; |
| 327 b[2] += 2; |
| 328 } |
| 329 '''); |
| 330 return prepareNavigation(() { |
| 331 assertHasOperatorRegion('] // []', 1, '[](index)', 2); |
| 332 assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3); |
| 333 assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3); |
| 334 assertHasOperatorRegion('+= 2;', 2, '+(other)', 1); |
| 335 }); |
| 336 } |
| 337 |
| 338 test_partOf() { |
| 339 var libCode = 'library lib; part "test.dart";'; |
| 340 var libFile = addFile('$projectPath/bin/lib.dart', libCode); |
| 341 addTestFile('part of lib;'); |
| 342 return prepareNavigation(() { |
| 343 assertHasRegionString('part of lib'); |
| 344 assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length); |
| 345 }); |
| 346 } |
| 347 |
| 348 test_string_export() { |
| 349 var libCode = 'library lib;'; |
| 350 var libFile = addFile('$projectPath/bin/lib.dart', libCode); |
| 351 addTestFile('export "lib.dart";'); |
| 352 return prepareNavigation(() { |
| 353 assertHasRegionString('export "lib.dart"'); |
| 354 assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length); |
| 355 }); |
| 356 } |
| 357 |
| 358 test_string_export_unresolvedUri() { |
| 359 addTestFile('export "no.dart";'); |
| 360 return prepareNavigation(() { |
| 361 assertNoRegionString('export "no.dart"'); |
| 362 }); |
| 363 } |
| 364 |
| 365 test_string_import() { |
| 366 var libCode = 'library lib;'; |
| 367 var libFile = addFile('$projectPath/bin/lib.dart', libCode); |
| 368 addTestFile('import "lib.dart";'); |
| 369 return prepareNavigation(() { |
| 370 assertHasRegionString('import "lib.dart"'); |
| 371 assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length); |
| 372 }); |
| 373 } |
| 374 |
| 375 test_string_import_noUri() { |
| 376 addTestFile('import ;'); |
| 377 return prepareNavigation(() { |
| 378 assertNoRegionAt('import ;'); |
| 379 }); |
| 380 } |
| 381 |
| 382 test_string_import_unresolvedUri() { |
| 383 addTestFile('import "no.dart";'); |
| 384 return prepareNavigation(() { |
| 385 assertNoRegionString('import "no.dart"'); |
| 386 }); |
| 387 } |
| 388 |
| 389 test_string_part() { |
| 390 var unitCode = 'part of lib; f() {}'; |
| 391 var unitFile = addFile('$projectPath/bin/test_unit.dart', unitCode); |
| 392 addTestFile(''' |
| 393 library lib; |
| 394 part "test_unit.dart"; |
| 395 '''); |
| 396 return prepareNavigation(() { |
| 397 assertHasRegionString('part "test_unit.dart"'); |
| 398 assertHasFileTarget(unitFile, 0, 0); |
| 399 }); |
| 400 } |
| 401 |
| 402 test_string_part_unresolvedUri() { |
| 403 // TODO(scheglov) why do we throw MemoryResourceException here? |
| 404 // This Source/File does not exist. |
| 405 // addTestFile(''' |
| 406 //library lib; |
| 407 //part "test_unit.dart"; |
| 408 //'''); |
| 409 // return prepareNavigation(() { |
| 410 // assertNoRegionString('part "test_unit.dart"'); |
| 411 // }); |
| 412 } |
| 413 } |
| 414 |
| 415 |
| 416 main() { |
| 417 group('notification.navigation', () { |
| 418 runReflectiveTests(AnalysisNotificationNavigationTest); |
| 419 }); |
| 420 } |
| OLD | NEW |