| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library test.edit.refactoring; | 5 library test.edit.refactoring; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/edit/edit_domain.dart'; | 9 import 'package:analysis_server/src/edit/edit_domain.dart'; |
| 10 import 'package:analysis_server/src/protocol.dart'; | 10 import 'package:analysis_server/src/protocol.dart'; |
| 11 import 'package:analysis_server/src/protocol2.dart' show | 11 import 'package:analysis_server/src/protocol2.dart' show |
| 12 EditGetAvailableRefactoringsParams, EditGetAvailableRefactoringsResult, | 12 EditGetAvailableRefactoringsParams, EditGetAvailableRefactoringsResult, |
| 13 RefactoringKind; | 13 EditGetRefactoringParams, EditGetRefactoringResult, RefactoringKind, |
| 14 RefactoringProblem, RefactoringProblemSeverity, RenameOptions, SourceChange, |
| 15 SourceEdit, SourceFileEdit; |
| 16 import 'package:analysis_server/src/services/index/index.dart'; |
| 17 import 'package:analysis_server/src/services/index/local_memory_index.dart'; |
| 14 import 'package:analysis_testing/reflective_tests.dart'; | 18 import 'package:analysis_testing/reflective_tests.dart'; |
| 15 import 'package:unittest/unittest.dart' hide ERROR; | 19 import 'package:unittest/unittest.dart' hide ERROR; |
| 16 | 20 |
| 17 import '../analysis_abstract.dart'; | 21 import '../analysis_abstract.dart'; |
| 18 | 22 |
| 19 | 23 |
| 20 main() { | 24 main() { |
| 21 groupSep = ' | '; | 25 groupSep = ' | '; |
| 22 runReflectiveTests(GetAvailableRefactoringsTest); | 26 runReflectiveTests(GetAvailableRefactoringsTest); |
| 27 runReflectiveTests(GetRefactoring_Rename_Test); |
| 23 } | 28 } |
| 24 | 29 |
| 25 | 30 |
| 26 @ReflectiveTestCase() | 31 @ReflectiveTestCase() |
| 27 class GetAvailableRefactoringsTest extends AbstractAnalysisTest { | 32 class GetAvailableRefactoringsTest extends AbstractAnalysisTest { |
| 28 /** | 33 /** |
| 29 * Tests that there is a RENAME refactoring available at the [search] offset. | 34 * Tests that there is a RENAME refactoring available at the [search] offset. |
| 30 */ | 35 */ |
| 31 Future assertHasRenameRefactoring(String code, String search) { | 36 Future assertHasRenameRefactoring(String code, String search) { |
| 32 addTestFile(code); | 37 addTestFile(code); |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 // not an element | 200 // not an element |
| 196 } | 201 } |
| 197 '''); | 202 '''); |
| 198 return waitForTasksFinished().then((_) { | 203 return waitForTasksFinished().then((_) { |
| 199 List<RefactoringKind> kinds = | 204 List<RefactoringKind> kinds = |
| 200 getRefactoringsAtString('// not an element'); | 205 getRefactoringsAtString('// not an element'); |
| 201 expect(kinds, isNot(contains(RefactoringKind.RENAME))); | 206 expect(kinds, isNot(contains(RefactoringKind.RENAME))); |
| 202 }); | 207 }); |
| 203 } | 208 } |
| 204 } | 209 } |
| 210 |
| 211 |
| 212 @ReflectiveTestCase() |
| 213 class GetRefactoring_Rename_Test extends _AbstractGetRefactoring_Test { |
| 214 test_class() { |
| 215 addTestFile(''' |
| 216 class Test {} |
| 217 main() { |
| 218 Test v; |
| 219 } |
| 220 '''); |
| 221 String search = 'Test {}'; |
| 222 String newName = 'NewName'; |
| 223 return assertSuccessfulRefactoring(search, newName, ''' |
| 224 class NewName {} |
| 225 main() { |
| 226 NewName v; |
| 227 } |
| 228 '''); |
| 229 } |
| 230 |
| 231 test_classMember_field() { |
| 232 addTestFile(''' |
| 233 class A { |
| 234 var test = 0; |
| 235 main() { |
| 236 print(test); |
| 237 } |
| 238 } |
| 239 '''); |
| 240 String search = 'test = 0'; |
| 241 String newName = 'newName'; |
| 242 return assertSuccessfulRefactoring(search, newName, ''' |
| 243 class A { |
| 244 var newName = 0; |
| 245 main() { |
| 246 print(newName); |
| 247 } |
| 248 } |
| 249 '''); |
| 250 } |
| 251 |
| 252 test_classMember_getter() { |
| 253 addTestFile(''' |
| 254 class A { |
| 255 get test => 0; |
| 256 main() { |
| 257 print(test); |
| 258 } |
| 259 } |
| 260 '''); |
| 261 String search = 'test =>'; |
| 262 String newName = 'newName'; |
| 263 return assertSuccessfulRefactoring(search, newName, ''' |
| 264 class A { |
| 265 get newName => 0; |
| 266 main() { |
| 267 print(newName); |
| 268 } |
| 269 } |
| 270 '''); |
| 271 } |
| 272 |
| 273 test_classMember_setter() { |
| 274 addTestFile(''' |
| 275 class A { |
| 276 set test(x) {} |
| 277 main() { |
| 278 test = 0; |
| 279 } |
| 280 } |
| 281 '''); |
| 282 String search = 'test = 0'; |
| 283 String newName = 'newName'; |
| 284 return assertSuccessfulRefactoring(search, newName, ''' |
| 285 class A { |
| 286 set newName(x) {} |
| 287 main() { |
| 288 newName = 0; |
| 289 } |
| 290 } |
| 291 '''); |
| 292 } |
| 293 |
| 294 test_class_options_fatalError() { |
| 295 addTestFile(''' |
| 296 class Test {} |
| 297 main() { |
| 298 Test v; |
| 299 } |
| 300 '''); |
| 301 return waitForTasksFinished().then((_) { |
| 302 String search = 'Test {}'; |
| 303 return sendRenameRequest(search, '').then((Response response) { |
| 304 var result = new EditGetRefactoringResult.fromResponse(response); |
| 305 assertResultProblemsFatal(result, 'Class name must not be empty.'); |
| 306 // ...there is no any change |
| 307 expect(result.change, isNull); |
| 308 }); |
| 309 }); |
| 310 } |
| 311 |
| 312 test_class_validateOnly() { |
| 313 addTestFile(''' |
| 314 class Test {} |
| 315 main() { |
| 316 Test v; |
| 317 } |
| 318 '''); |
| 319 String search = 'Test {}'; |
| 320 String newName = 'NewName'; |
| 321 return getRefactoringResult( |
| 322 search, |
| 323 newName, |
| 324 validateOnly: true).then((result) { |
| 325 assertResultProblemsOK(result); |
| 326 expect(result.change, isNull); |
| 327 }); |
| 328 } |
| 329 |
| 330 test_class_warning() { |
| 331 addTestFile(''' |
| 332 class Test {} |
| 333 main() { |
| 334 Test v; |
| 335 } |
| 336 '''); |
| 337 return waitForTasksFinished().then((_) { |
| 338 String search = 'Test {}'; |
| 339 return sendRenameRequest(search, 'newName').then((Response response) { |
| 340 var result = new EditGetRefactoringResult.fromResponse(response); |
| 341 assertResultProblemsWarning( |
| 342 result, |
| 343 'Class name should start with an uppercase letter.'); |
| 344 // ...but there is still a change |
| 345 assertTestRefactoringResult(result, ''' |
| 346 class newName {} |
| 347 main() { |
| 348 newName v; |
| 349 } |
| 350 '''); |
| 351 }).then((_) { |
| 352 return sendRenameRequest(search, 'NewName').then((Response response) { |
| 353 var result = new EditGetRefactoringResult.fromResponse(response); |
| 354 // OK |
| 355 assertResultProblemsOK(result); |
| 356 }); |
| 357 }); |
| 358 }); |
| 359 } |
| 360 |
| 361 test_constructor() { |
| 362 addTestFile(''' |
| 363 class A { |
| 364 A.test() {} |
| 365 } |
| 366 main() { |
| 367 new A.test(); |
| 368 } |
| 369 '''); |
| 370 String search = 'test();'; |
| 371 String newName = 'newName'; |
| 372 return assertSuccessfulRefactoring(search, newName, ''' |
| 373 class A { |
| 374 A.newName() {} |
| 375 } |
| 376 main() { |
| 377 new A.newName(); |
| 378 } |
| 379 '''); |
| 380 } |
| 381 |
| 382 test_function() { |
| 383 addTestFile(''' |
| 384 test() {} |
| 385 main() { |
| 386 test(); |
| 387 print(test); |
| 388 } |
| 389 '''); |
| 390 String search = 'test() {}'; |
| 391 String newName = 'newName'; |
| 392 return assertSuccessfulRefactoring(search, newName, ''' |
| 393 newName() {} |
| 394 main() { |
| 395 newName(); |
| 396 print(newName); |
| 397 } |
| 398 '''); |
| 399 } |
| 400 |
| 401 test_init_fatalError_noElement() { |
| 402 addTestFile('// nothing to rename'); |
| 403 String search = '// nothing'; |
| 404 return getRefactoringResult(search, null).then((result) { |
| 405 assertResultProblemsFatal(result, 'Unable to create a refactoring'); |
| 406 // ...there is no any change |
| 407 expect(result.change, isNull); |
| 408 }); |
| 409 } |
| 410 |
| 411 test_localVariable() { |
| 412 addTestFile(''' |
| 413 main() { |
| 414 int test = 0; |
| 415 test = 1; |
| 416 test += 2; |
| 417 print(test); |
| 418 } |
| 419 '''); |
| 420 String search = 'test = 1'; |
| 421 String newName = 'newName'; |
| 422 return assertSuccessfulRefactoring(search, newName, ''' |
| 423 main() { |
| 424 int newName = 0; |
| 425 newName = 1; |
| 426 newName += 2; |
| 427 print(newName); |
| 428 } |
| 429 '''); |
| 430 } |
| 431 |
| 432 test_localVariable_finalCheck_shadowError() { |
| 433 addTestFile(''' |
| 434 main() { |
| 435 var newName; |
| 436 int test = 0; |
| 437 print(test); |
| 438 } |
| 439 '''); |
| 440 String search = 'test = 0'; |
| 441 String newName = 'newName'; |
| 442 return getRefactoringResult(search, newName).then((result) { |
| 443 assertResultProblemsError(result, "Duplicate local variable 'newName'."); |
| 444 }); |
| 445 } |
| 446 } |
| 447 |
| 448 |
| 449 @ReflectiveTestCase() |
| 450 class _AbstractGetRefactoring_Test extends AbstractAnalysisTest { |
| 451 /** |
| 452 * Asserts that [result] has a single ERROR problem. |
| 453 */ |
| 454 void assertResultProblemsError(EditGetRefactoringResult result, |
| 455 [String message]) { |
| 456 List<RefactoringProblem> problems = result.problems; |
| 457 RefactoringProblem problem = problems[0]; |
| 458 expect(problems, hasLength(1)); |
| 459 expect( |
| 460 problem.severity, |
| 461 RefactoringProblemSeverity.ERROR, |
| 462 reason: problem.toString()); |
| 463 if (message != null) { |
| 464 expect(problem.message, message); |
| 465 } |
| 466 } |
| 467 |
| 468 /** |
| 469 * Asserts that [result] has a single FATAL problem. |
| 470 */ |
| 471 void assertResultProblemsFatal(EditGetRefactoringResult result, |
| 472 [String message]) { |
| 473 List<RefactoringProblem> problems = result.problems; |
| 474 RefactoringProblem problem = problems[0]; |
| 475 expect(problems, hasLength(1)); |
| 476 expect( |
| 477 problem.severity, |
| 478 RefactoringProblemSeverity.FATAL, |
| 479 reason: problem.toString()); |
| 480 if (message != null) { |
| 481 expect(problem.message, message); |
| 482 } |
| 483 } |
| 484 |
| 485 /** |
| 486 * Asserts that [result] has no problems at all. |
| 487 */ |
| 488 void assertResultProblemsOK(EditGetRefactoringResult result) { |
| 489 expect(result.problems, isEmpty); |
| 490 } |
| 491 |
| 492 /** |
| 493 * Asserts that [result] has a single WARNING problem. |
| 494 */ |
| 495 void assertResultProblemsWarning(EditGetRefactoringResult result, |
| 496 [String message]) { |
| 497 List<RefactoringProblem> problems = result.problems; |
| 498 RefactoringProblem problem = problems[0]; |
| 499 expect(problems, hasLength(1)); |
| 500 expect( |
| 501 problem.severity, |
| 502 RefactoringProblemSeverity.WARNING, |
| 503 reason: problem.toString()); |
| 504 if (message != null) { |
| 505 expect(problem.message, message); |
| 506 } |
| 507 } |
| 508 |
| 509 Future assertSuccessfulRefactoring(String search, String newName, |
| 510 String expectedCode) { |
| 511 return getRefactoringResult(search, newName).then((result) { |
| 512 assertResultProblemsOK(result); |
| 513 assertTestRefactoringResult(result, expectedCode); |
| 514 }); |
| 515 } |
| 516 |
| 517 /** |
| 518 * Asserts that the given [EditGetRefactoringResult] has a [testFile] change |
| 519 * which results in the [expectedCode]. |
| 520 */ |
| 521 void assertTestRefactoringResult(EditGetRefactoringResult result, |
| 522 String expectedCode) { |
| 523 SourceChange change = result.change; |
| 524 expect(change, isNotNull); |
| 525 for (SourceFileEdit fileEdit in change.edits) { |
| 526 if (fileEdit.file == testFile) { |
| 527 String actualCode = SourceEdit.applySequence(testCode, fileEdit.edits); |
| 528 expect(actualCode, expectedCode); |
| 529 return; |
| 530 } |
| 531 } |
| 532 fail('No SourceFileEdit for $testFile in $change'); |
| 533 } |
| 534 |
| 535 @override |
| 536 Index createIndex() { |
| 537 return createLocalMemoryIndex(); |
| 538 } |
| 539 |
| 540 Future<EditGetRefactoringResult> getRefactoringResult(String search, |
| 541 String newName, {bool validateOnly: false}) { |
| 542 return waitForTasksFinished().then((_) { |
| 543 return sendRenameRequest( |
| 544 search, |
| 545 newName, |
| 546 validateOnly: validateOnly).then((Response response) { |
| 547 return new EditGetRefactoringResult.fromResponse(response); |
| 548 }); |
| 549 }); |
| 550 } |
| 551 |
| 552 Future sendRenameRequest(String search, String newName, {bool validateOnly: |
| 553 false}) { |
| 554 Request request = new EditGetRefactoringParams( |
| 555 RefactoringKind.RENAME, |
| 556 testFile, |
| 557 findOffset(search), |
| 558 0, |
| 559 validateOnly, |
| 560 options: new RenameOptions(newName)).toRequest('0'); |
| 561 return serverChannel.sendRequest(request); |
| 562 } |
| 563 |
| 564 @override |
| 565 void setUp() { |
| 566 super.setUp(); |
| 567 server.handlers = [new EditDomainHandler(server),]; |
| 568 createProject(); |
| 569 handler = new EditDomainHandler(server); |
| 570 } |
| 571 } |
| OLD | NEW |