| 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.services.completion.dart.keyword; | |
| 6 | |
| 7 import 'package:analysis_server/src/protocol.dart'; | |
| 8 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; | |
| 9 import 'package:analysis_server/src/services/completion/keyword_computer.dart'; | |
| 10 import 'package:analyzer/src/generated/scanner.dart'; | |
| 11 import 'package:unittest/unittest.dart'; | |
| 12 | |
| 13 import '../../reflective_tests.dart'; | |
| 14 import 'completion_test_util.dart'; | |
| 15 | |
| 16 main() { | |
| 17 groupSep = ' | '; | |
| 18 runReflectiveTests(KeywordContributorTest); | |
| 19 } | |
| 20 | |
| 21 @reflectiveTest | |
| 22 class KeywordContributorTest extends AbstractCompletionTest { | |
| 23 static const List<Keyword> CLASS_BODY_KEYWORDS = const [ | |
| 24 Keyword.CONST, | |
| 25 Keyword.DYNAMIC, | |
| 26 Keyword.FACTORY, | |
| 27 Keyword.FINAL, | |
| 28 Keyword.GET, | |
| 29 Keyword.OPERATOR, | |
| 30 Keyword.SET, | |
| 31 Keyword.STATIC, | |
| 32 Keyword.VAR, | |
| 33 Keyword.VOID | |
| 34 ]; | |
| 35 | |
| 36 static const List<Keyword> DECLARATION_KEYWORDS = const [ | |
| 37 Keyword.ABSTRACT, | |
| 38 Keyword.CLASS, | |
| 39 Keyword.CONST, | |
| 40 Keyword.DYNAMIC, | |
| 41 Keyword.FINAL, | |
| 42 Keyword.TYPEDEF, | |
| 43 Keyword.VAR, | |
| 44 Keyword.VOID | |
| 45 ]; | |
| 46 | |
| 47 static const List<Keyword> DIRECTIVE_AND_DECLARATION_KEYWORDS = const [ | |
| 48 Keyword.ABSTRACT, | |
| 49 Keyword.CLASS, | |
| 50 Keyword.CONST, | |
| 51 Keyword.DYNAMIC, | |
| 52 Keyword.EXPORT, | |
| 53 Keyword.FINAL, | |
| 54 Keyword.IMPORT, | |
| 55 Keyword.PART, | |
| 56 Keyword.TYPEDEF, | |
| 57 Keyword.VAR, | |
| 58 Keyword.VOID | |
| 59 ]; | |
| 60 | |
| 61 static const List<Keyword> DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS = | |
| 62 const [ | |
| 63 Keyword.ABSTRACT, | |
| 64 Keyword.CLASS, | |
| 65 Keyword.CONST, | |
| 66 Keyword.DYNAMIC, | |
| 67 Keyword.EXPORT, | |
| 68 Keyword.FINAL, | |
| 69 Keyword.IMPORT, | |
| 70 Keyword.LIBRARY, | |
| 71 Keyword.PART, | |
| 72 Keyword.TYPEDEF, | |
| 73 Keyword.VAR, | |
| 74 Keyword.VOID | |
| 75 ]; | |
| 76 | |
| 77 static const List<Keyword> IN_BLOCK_IN_CLASS = const [ | |
| 78 Keyword.ASSERT, | |
| 79 Keyword.CASE, | |
| 80 Keyword.CONTINUE, | |
| 81 Keyword.DO, | |
| 82 Keyword.FINAL, | |
| 83 Keyword.FOR, | |
| 84 Keyword.IF, | |
| 85 Keyword.NEW, | |
| 86 Keyword.RETHROW, | |
| 87 Keyword.RETURN, | |
| 88 Keyword.SUPER, | |
| 89 Keyword.SWITCH, | |
| 90 Keyword.THIS, | |
| 91 Keyword.THROW, | |
| 92 Keyword.TRY, | |
| 93 Keyword.VAR, | |
| 94 Keyword.VOID, | |
| 95 Keyword.WHILE | |
| 96 ]; | |
| 97 | |
| 98 static const List<Keyword> IN_BLOCK_NOT_IN_CLASS = const [ | |
| 99 Keyword.ASSERT, | |
| 100 Keyword.CASE, | |
| 101 Keyword.CONTINUE, | |
| 102 Keyword.DO, | |
| 103 Keyword.FINAL, | |
| 104 Keyword.FOR, | |
| 105 Keyword.IF, | |
| 106 Keyword.NEW, | |
| 107 Keyword.RETHROW, | |
| 108 Keyword.RETURN, | |
| 109 Keyword.SWITCH, | |
| 110 Keyword.THROW, | |
| 111 Keyword.TRY, | |
| 112 Keyword.VAR, | |
| 113 Keyword.VOID, | |
| 114 Keyword.WHILE | |
| 115 ]; | |
| 116 | |
| 117 void assertSuggestKeywords(Iterable<Keyword> expectedKeywords, | |
| 118 [int relevance = DART_RELEVANCE_KEYWORD]) { | |
| 119 Set<Keyword> actualKeywords = new Set<Keyword>(); | |
| 120 for (CompletionSuggestion s in request.suggestions) { | |
| 121 if (s.kind == CompletionSuggestionKind.KEYWORD) { | |
| 122 Keyword k = Keyword.keywords[s.completion]; | |
| 123 if (k == null) { | |
| 124 fail('Invalid keyword suggested: ${s.completion}'); | |
| 125 } else { | |
| 126 if (!actualKeywords.add(k)) { | |
| 127 fail('Duplicate keyword suggested: ${s.completion}'); | |
| 128 } | |
| 129 } | |
| 130 } | |
| 131 } | |
| 132 if (expectedKeywords.any((k) => k is String)) { | |
| 133 StringBuffer msg = new StringBuffer(); | |
| 134 msg.writeln('Expected set should be:'); | |
| 135 expectedKeywords.forEach((n) { | |
| 136 Keyword k = Keyword.keywords[n]; | |
| 137 msg.writeln(' Keyword.${k.name},'); | |
| 138 }); | |
| 139 fail(msg.toString()); | |
| 140 } | |
| 141 if (!_equalSets(expectedKeywords, actualKeywords)) { | |
| 142 StringBuffer msg = new StringBuffer(); | |
| 143 msg.writeln('Expected:'); | |
| 144 _appendKeywords(msg, expectedKeywords); | |
| 145 msg.writeln('but found:'); | |
| 146 _appendKeywords(msg, actualKeywords); | |
| 147 fail(msg.toString()); | |
| 148 } | |
| 149 for (CompletionSuggestion s in request.suggestions) { | |
| 150 if (s.kind == CompletionSuggestionKind.KEYWORD) { | |
| 151 Keyword k = Keyword.keywords[s.completion]; | |
| 152 expect(s.relevance, equals(relevance), reason: k.toString()); | |
| 153 expect(s.selectionOffset, equals(s.completion.length)); | |
| 154 expect(s.selectionLength, equals(0)); | |
| 155 expect(s.isDeprecated, equals(false)); | |
| 156 expect(s.isPotential, equals(false)); | |
| 157 } | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 @override | |
| 162 void setUpContributor() { | |
| 163 contributor = new KeywordContributor(); | |
| 164 } | |
| 165 | |
| 166 test_after_class() { | |
| 167 addTestSource('class A {} ^'); | |
| 168 expect(computeFast(), isTrue); | |
| 169 assertSuggestKeywords(DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 170 } | |
| 171 | |
| 172 test_after_class2() { | |
| 173 addTestSource('class A {} c^'); | |
| 174 expect(computeFast(), isTrue); | |
| 175 assertSuggestKeywords(DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 176 } | |
| 177 | |
| 178 test_after_import() { | |
| 179 addTestSource('import foo; ^'); | |
| 180 expect(computeFast(), isTrue); | |
| 181 assertSuggestKeywords( | |
| 182 DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 183 } | |
| 184 | |
| 185 test_after_import2() { | |
| 186 addTestSource('import foo; c^'); | |
| 187 expect(computeFast(), isTrue); | |
| 188 assertSuggestKeywords( | |
| 189 DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 190 } | |
| 191 | |
| 192 test_before_import() { | |
| 193 addTestSource('^ import foo;'); | |
| 194 expect(computeFast(), isTrue); | |
| 195 assertSuggestKeywords([ | |
| 196 Keyword.EXPORT, | |
| 197 Keyword.IMPORT, | |
| 198 Keyword.LIBRARY, | |
| 199 Keyword.PART | |
| 200 ], DART_RELEVANCE_HIGH); | |
| 201 } | |
| 202 | |
| 203 test_class() { | |
| 204 addTestSource('class A e^ { }'); | |
| 205 expect(computeFast(), isTrue); | |
| 206 assertSuggestKeywords( | |
| 207 [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 208 } | |
| 209 | |
| 210 test_class_body() { | |
| 211 addTestSource('class A {^}'); | |
| 212 expect(computeFast(), isTrue); | |
| 213 assertSuggestKeywords(CLASS_BODY_KEYWORDS); | |
| 214 } | |
| 215 | |
| 216 test_class_body_beginning() { | |
| 217 addTestSource('class A {^ var foo;}'); | |
| 218 expect(computeFast(), isTrue); | |
| 219 assertSuggestKeywords(CLASS_BODY_KEYWORDS); | |
| 220 } | |
| 221 | |
| 222 test_class_body_between() { | |
| 223 addTestSource('class A {var bar; ^ var foo;}'); | |
| 224 expect(computeFast(), isTrue); | |
| 225 assertSuggestKeywords(CLASS_BODY_KEYWORDS); | |
| 226 } | |
| 227 | |
| 228 test_class_body_end() { | |
| 229 addTestSource('class A {var foo; ^}'); | |
| 230 expect(computeFast(), isTrue); | |
| 231 assertSuggestKeywords(CLASS_BODY_KEYWORDS); | |
| 232 } | |
| 233 | |
| 234 test_class_extends() { | |
| 235 addTestSource('class A extends foo ^'); | |
| 236 expect(computeFast(), isTrue); | |
| 237 assertSuggestKeywords( | |
| 238 [Keyword.IMPLEMENTS, Keyword.WITH], DART_RELEVANCE_HIGH); | |
| 239 } | |
| 240 | |
| 241 test_class_extends2() { | |
| 242 addTestSource('class A extends foo i^'); | |
| 243 expect(computeFast(), isTrue); | |
| 244 assertSuggestKeywords( | |
| 245 [Keyword.IMPLEMENTS, Keyword.WITH], DART_RELEVANCE_HIGH); | |
| 246 } | |
| 247 | |
| 248 test_class_extends3() { | |
| 249 addTestSource('class A extends foo i^ { }'); | |
| 250 expect(computeFast(), isTrue); | |
| 251 assertSuggestKeywords( | |
| 252 [Keyword.IMPLEMENTS, Keyword.WITH], DART_RELEVANCE_HIGH); | |
| 253 } | |
| 254 | |
| 255 test_class_extends_name() { | |
| 256 addTestSource('class A extends ^'); | |
| 257 expect(computeFast(), isTrue); | |
| 258 assertSuggestKeywords([]); | |
| 259 } | |
| 260 | |
| 261 test_class_implements() { | |
| 262 addTestSource('class A ^ implements foo'); | |
| 263 expect(computeFast(), isTrue); | |
| 264 assertSuggestKeywords([Keyword.EXTENDS], DART_RELEVANCE_HIGH); | |
| 265 } | |
| 266 | |
| 267 test_class_implements2() { | |
| 268 addTestSource('class A e^ implements foo'); | |
| 269 expect(computeFast(), isTrue); | |
| 270 // TODO (danrubel) refinement: don't suggest implements | |
| 271 assertSuggestKeywords( | |
| 272 [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 273 } | |
| 274 | |
| 275 test_class_implements3() { | |
| 276 addTestSource('class A e^ implements foo { }'); | |
| 277 expect(computeFast(), isTrue); | |
| 278 // TODO (danrubel) refinement: don't suggest implements | |
| 279 assertSuggestKeywords( | |
| 280 [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 281 } | |
| 282 | |
| 283 test_class_implements_name() { | |
| 284 addTestSource('class A implements ^'); | |
| 285 expect(computeFast(), isTrue); | |
| 286 assertSuggestKeywords([]); | |
| 287 } | |
| 288 | |
| 289 test_class_name() { | |
| 290 addTestSource('class ^'); | |
| 291 expect(computeFast(), isTrue); | |
| 292 assertSuggestKeywords([]); | |
| 293 } | |
| 294 | |
| 295 test_class_noBody() { | |
| 296 addTestSource('class A ^'); | |
| 297 expect(computeFast(), isTrue); | |
| 298 assertSuggestKeywords( | |
| 299 [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 300 } | |
| 301 | |
| 302 test_class_noBody2() { | |
| 303 addTestSource('class A e^'); | |
| 304 expect(computeFast(), isTrue); | |
| 305 assertSuggestKeywords( | |
| 306 [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 307 } | |
| 308 | |
| 309 test_class_noBody3() { | |
| 310 addTestSource('class A e^ String foo;'); | |
| 311 expect(computeFast(), isTrue); | |
| 312 assertSuggestKeywords( | |
| 313 [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 314 } | |
| 315 | |
| 316 test_class_with() { | |
| 317 addTestSource('class A extends foo with bar ^'); | |
| 318 expect(computeFast(), isTrue); | |
| 319 assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 320 } | |
| 321 | |
| 322 test_class_with2() { | |
| 323 addTestSource('class A extends foo with bar i^'); | |
| 324 expect(computeFast(), isTrue); | |
| 325 assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 326 } | |
| 327 | |
| 328 test_class_with3() { | |
| 329 addTestSource('class A extends foo with bar i^ { }'); | |
| 330 expect(computeFast(), isTrue); | |
| 331 assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH); | |
| 332 } | |
| 333 | |
| 334 test_class_with_name() { | |
| 335 addTestSource('class A extends foo with ^'); | |
| 336 expect(computeFast(), isTrue); | |
| 337 assertSuggestKeywords([]); | |
| 338 } | |
| 339 | |
| 340 test_empty() { | |
| 341 addTestSource('^'); | |
| 342 expect(computeFast(), isTrue); | |
| 343 assertSuggestKeywords( | |
| 344 DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 345 } | |
| 346 | |
| 347 test_function_body_inClass_constructorInitializer() { | |
| 348 addTestSource(r''' | |
| 349 foo(p) {} | |
| 350 class A { | |
| 351 final f; | |
| 352 A() : f = foo(() {^}); | |
| 353 } | |
| 354 '''); | |
| 355 expect(computeFast(), isTrue); | |
| 356 assertSuggestKeywords(IN_BLOCK_NOT_IN_CLASS); | |
| 357 } | |
| 358 | |
| 359 test_function_body_inClass_field() { | |
| 360 addTestSource(r''' | |
| 361 class A { | |
| 362 var f = () {^}; | |
| 363 } | |
| 364 '''); | |
| 365 expect(computeFast(), isTrue); | |
| 366 assertSuggestKeywords(IN_BLOCK_NOT_IN_CLASS); | |
| 367 } | |
| 368 | |
| 369 test_function_body_inClass_methodBody() { | |
| 370 addTestSource(r''' | |
| 371 class A { | |
| 372 m() { | |
| 373 f() {^}; | |
| 374 } | |
| 375 } | |
| 376 '''); | |
| 377 expect(computeFast(), isTrue); | |
| 378 assertSuggestKeywords(IN_BLOCK_IN_CLASS); | |
| 379 } | |
| 380 | |
| 381 test_function_body_inClass_methodBody_inFunction() { | |
| 382 addTestSource(r''' | |
| 383 class A { | |
| 384 m() { | |
| 385 f() { | |
| 386 f2() {^}; | |
| 387 }; | |
| 388 } | |
| 389 } | |
| 390 '''); | |
| 391 expect(computeFast(), isTrue); | |
| 392 assertSuggestKeywords(IN_BLOCK_IN_CLASS); | |
| 393 } | |
| 394 | |
| 395 test_function_body_inUnit() { | |
| 396 addTestSource('main() {^}'); | |
| 397 expect(computeFast(), isTrue); | |
| 398 assertSuggestKeywords(IN_BLOCK_NOT_IN_CLASS); | |
| 399 } | |
| 400 | |
| 401 test_function_body_inUnit_afterBlock() { | |
| 402 addTestSource('main() {{}^}'); | |
| 403 expect(computeFast(), isTrue); | |
| 404 assertSuggestKeywords(IN_BLOCK_NOT_IN_CLASS); | |
| 405 } | |
| 406 | |
| 407 test_library() { | |
| 408 addTestSource('library foo;^'); | |
| 409 expect(computeFast(), isTrue); | |
| 410 assertSuggestKeywords( | |
| 411 DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 412 } | |
| 413 | |
| 414 test_library_name() { | |
| 415 addTestSource('library ^'); | |
| 416 expect(computeFast(), isTrue); | |
| 417 assertSuggestKeywords([]); | |
| 418 } | |
| 419 | |
| 420 test_method_body() { | |
| 421 addTestSource('class A { foo() {^}}'); | |
| 422 expect(computeFast(), isTrue); | |
| 423 assertSuggestKeywords(IN_BLOCK_IN_CLASS); | |
| 424 } | |
| 425 | |
| 426 test_named_constructor_invocation() { | |
| 427 addTestSource('void main() {new Future.^}'); | |
| 428 expect(computeFast(), isTrue); | |
| 429 assertSuggestKeywords([]); | |
| 430 } | |
| 431 | |
| 432 test_part_of() { | |
| 433 addTestSource('part of foo;^'); | |
| 434 expect(computeFast(), isTrue); | |
| 435 assertSuggestKeywords( | |
| 436 DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 437 } | |
| 438 | |
| 439 test_partial_class() { | |
| 440 addTestSource('cl^'); | |
| 441 expect(computeFast(), isTrue); | |
| 442 assertSuggestKeywords( | |
| 443 DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 444 } | |
| 445 | |
| 446 test_partial_class2() { | |
| 447 addTestSource('library a; cl^'); | |
| 448 expect(computeFast(), isTrue); | |
| 449 assertSuggestKeywords( | |
| 450 DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH); | |
| 451 } | |
| 452 | |
| 453 void _appendKeywords(StringBuffer msg, Iterable<Keyword> keywords) { | |
| 454 List<Keyword> sorted = keywords.toList(); | |
| 455 sorted.sort((k1, k2) => k1.name.compareTo(k2.name)); | |
| 456 sorted.forEach((k) => msg.writeln(' Keyword.${k.name},')); | |
| 457 } | |
| 458 | |
| 459 bool _equalSets(Iterable<Keyword> iter1, Iterable<Keyword> iter2) { | |
| 460 if (iter1.length != iter2.length) return false; | |
| 461 if (iter1.any((k) => !iter2.contains(k))) return false; | |
| 462 if (iter2.any((k) => !iter1.contains(k))) return false; | |
| 463 return true; | |
| 464 } | |
| 465 } | |
| OLD | NEW |