/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.engine.services.internal.refactoring;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.context.AnalysisContextHelper;
import com.google.dart.engine.services.change.Change;
import com.google.dart.engine.services.status.RefactoringStatusSeverity;
import com.google.dart.engine.source.FileBasedSource;
import com.google.dart.engine.source.Source;
import java.io.File;
/**
* Test for {@link RenameUnitMemberRefactoringImpl}.
*/
public class RenameUnitMemberRefactoringImplTest extends RenameRefactoringImplTest {
public void fail_createChange_sharedBetweenTwoLibraries() throws Exception {
// TODO(scheglov) This test fails with new split index.
// Problem is that we rename for element "A" with location "libA.dart ; test.dart; A".
// So, we search using this location. But in "libB.dart" class "A" from "test.dart" has a
// different location.
Source libSourceA = addSource(
"/libA.dart",
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"library lib;",
"part 'test.dart';",
"A f() {}"));
Source libSourceB = addSource(
"/libB.dart",
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"library lib;",
"part 'test.dart';",
"A f() {}"));
testCode = makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"part of lib;",
"class A {}");
testSource = addSource("/test.dart", testCode);
// index unit in libraries A and B
analysisContext.computeLibraryElement(libSourceA);
analysisContext.computeLibraryElement(libSourceB);
CompilationUnit libUnitA = analysisContext.getResolvedCompilationUnit(libSourceA, libSourceA);
CompilationUnit libUnitB = analysisContext.getResolvedCompilationUnit(libSourceB, libSourceB);
CompilationUnit unitA = analysisContext.getResolvedCompilationUnit(testSource, libSourceA);
CompilationUnit unitB = analysisContext.getResolvedCompilationUnit(testSource, libSourceB);
index.indexUnit(analysisContext, libUnitA);
index.indexUnit(analysisContext, libUnitB);
index.indexUnit(analysisContext, unitA);
index.indexUnit(analysisContext, unitB);
// Set "testUnit" to "unitA", which was indexed before "unitB" with the same Source.
// So, if index does not support separate information for the same Source in different
// libraries, then information about "testSource" in "A" was removed, and this test will fail.
testUnit = unitA;
// configure refactoring
createRenameRefactoring("A {}");
assertEquals("Rename Class", refactoring.getRefactoringName());
refactoring.setNewName("NewName");
// perform refactoring
assertRefactoringStatusOK();
refactoringChange = refactoring.createChange(pm);
// validate change
assertChangeResult(
refactoringChange,
testSource,
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"part of lib;",
"class NewName {}"));
assertChangeResult(
refactoringChange,
libSourceA,
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"library lib;",
"part 'test.dart';",
"NewName f() {}"));
assertChangeResult(
refactoringChange,
libSourceB,
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"library lib;",
"part 'test.dart';",
"NewName f() {}"));
}
public void test_checkFinalConditions_hasTopLevel_ClassElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}",
"class NewName {} // existing");
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatus(
refactoring.checkFinalConditions(pm),
RefactoringStatusSeverity.ERROR,
"Library already declares class with name 'NewName'.",
findRangeIdentifier("NewName {} // existing"));
}
public void test_checkFinalConditions_hasTopLevel_FunctionTypeAliasElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}",
"typedef NewName(); // existing");
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatus(
refactoring.checkFinalConditions(pm),
RefactoringStatusSeverity.ERROR,
"Library already declares function type alias with name 'NewName'.",
findRangeIdentifier("NewName(); // existing"));
}
public void test_checkFinalConditions_shadowedBy_MethodElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}",
"class A {",
" NewName() {}",
" main() {",
" new Test();",
" }",
"}");
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatus(
refactoring.checkFinalConditions(pm),
RefactoringStatusSeverity.ERROR,
"Reference to renamed class will shadowed by method 'A.NewName'.",
findRangeIdentifier("NewName() {}"));
}
public void test_checkFinalConditions_shadowsInSubClass_importedLib() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"library test;",
"class Test {}");
String libCode = makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"library my.lib;",
"import 'Test.dart';",
"class A {",
" NewName() {}",
"}",
"class B extends A {",
" main() {",
" NewName(); // super-ref",
" }",
"}");
indexUnit("/lib.dart", libCode);
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatus(
refactoring.checkFinalConditions(pm),
RefactoringStatusSeverity.ERROR,
"Renamed class will shadow method 'A.NewName'.",
findRangeIdentifier(libCode, "NewName(); // super-ref"));
}
public void test_checkFinalConditions_shadowsInSubClass_importedLib_hideCombinator()
throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}");
indexUnit(
"/lib.dart",
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"import 'Test.dart' hide Test;",
"class A {",
" NewName() {}",
"}",
"class B extends A {",
" main() {",
" NewName(); // super-ref",
" }",
"}"));
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatusOK(refactoring.checkFinalConditions(pm));
}
public void test_checkFinalConditions_shadowsInSubClass_MethodElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}",
"class A {",
" NewName() {}",
"}",
"class B extends A {",
" main() {",
" NewName(); // super-ref",
" }",
"}");
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatus(
refactoring.checkFinalConditions(pm),
RefactoringStatusSeverity.ERROR,
"Renamed class will shadow method 'A.NewName'.",
findRangeIdentifier("NewName(); // super-ref"));
}
public void test_checkFinalConditions_shadowsInSubClass_notImportedLib() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}");
indexUnit(
"/lib.dart",
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"class A {",
" NewName() {}",
"}",
"class B extends A {",
" main() {",
" NewName(); // super-ref",
" }",
"}"));
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatusOK(refactoring.checkFinalConditions(pm));
}
public void test_checkFinalConditions_shadowsInSubClass_notSubClass() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}",
"class A {",
" NewName() {}",
"}",
"class B {",
" main(A a) {",
" a.NewName();",
" }",
"}");
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatusOK(refactoring.checkFinalConditions(pm));
}
public void test_checkFinalConditionsOK_qualifiedSuper_MethodElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}",
"class A {",
" NewName() {}",
"}",
"class B extends A {",
" main() {",
" super.NewName(); // super-ref",
" }",
"}");
createRenameRefactoring("Test {}");
// check status
refactoring.setNewName("NewName");
assertRefactoringStatusOK(refactoring.checkFinalConditions(pm));
}
public void test_checkNewName_ClassElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {}");
createRenameRefactoring("Test {}");
// null
assertRefactoringStatus(
refactoring.checkNewName(null),
RefactoringStatusSeverity.ERROR,
"Class name must not be null.");
// empty
refactoring.setNewName("");
assertRefactoringStatus(
refactoring.checkNewName(""),
RefactoringStatusSeverity.ERROR,
"Class name must not be empty.");
// same name
assertRefactoringStatus(
refactoring.checkNewName("Test"),
RefactoringStatusSeverity.FATAL,
"Choose another name.");
}
public void test_checkNewName_FunctionElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"test() {}");
createRenameRefactoring("test() {");
// null
assertRefactoringStatus(
refactoring.checkNewName(null),
RefactoringStatusSeverity.ERROR,
"Function name must not be null.");
// empty
assertRefactoringStatus(
refactoring.checkNewName(""),
RefactoringStatusSeverity.ERROR,
"Function name must not be empty.");
// same name
assertRefactoringStatus(
refactoring.checkNewName("test"),
RefactoringStatusSeverity.FATAL,
"Choose another name.");
}
public void test_checkNewName_TopLevelVariableElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"var test;");
createRenameRefactoring("test;");
// null
assertRefactoringStatus(
refactoring.checkNewName(null),
RefactoringStatusSeverity.ERROR,
"Variable name must not be null.");
// empty
assertRefactoringStatus(
refactoring.checkNewName(""),
RefactoringStatusSeverity.ERROR,
"Variable name must not be empty.");
// same name
assertRefactoringStatus(
refactoring.checkNewName("test"),
RefactoringStatusSeverity.FATAL,
"Choose another name.");
}
public void test_checkNewName_TypeAliasElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"typedef Test();");
createRenameRefactoring("Test();");
// null
assertRefactoringStatus(
refactoring.checkNewName(null),
RefactoringStatusSeverity.ERROR,
"Function type alias name must not be null.");
// empty
assertRefactoringStatus(
refactoring.checkNewName(""),
RefactoringStatusSeverity.ERROR,
"Function type alias name must not be empty.");
// same name
assertRefactoringStatus(
refactoring.checkNewName("Test"),
RefactoringStatusSeverity.FATAL,
"Choose another name.");
}
public void test_createChange_ClassElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test implements Other {",
" Test() {}",
" Test.named() {}",
"}",
"class Other {",
" factory Other.a() = Test;",
" factory Other.b() = Test.named;",
"}",
"main() {",
" Test t1 = new Test();",
" Test t2 = new Test.named();",
"}");
// configure refactoring
createRenameRefactoring("Test implements");
assertEquals("Rename Class", refactoring.getRefactoringName());
refactoring.setNewName("NewName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"class NewName implements Other {",
" NewName() {}",
" NewName.named() {}",
"}",
"class Other {",
" factory Other.a() = NewName;",
" factory Other.b() = NewName.named;",
"}",
"main() {",
" NewName t1 = new NewName();",
" NewName t2 = new NewName.named();",
"}");
}
public void test_createChange_ClassElement_multipleUnits() throws Exception {
testCode = makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"library libA;",
"class Test implements Other {",
" Test() {}",
" Test.named() {}",
"}",
"class Other {",
" factory Other.a() = Test;",
" factory Other.b() = Test.named;",
"}",
"main() {",
" Test t1 = new Test();",
" Test t2 = new Test.named();",
"}");
Source libA = addSource(testCode);
Source sourceB = addSource(
"/B.dart",
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"import 'test.dart';",
"main() {",
" Test t = new Test();",
"}"));
indexTestUnit(libA);
indexUnit(sourceB);
// configure refactoring
createRenameRefactoring("Test implements");
assertEquals("Rename Class", refactoring.getRefactoringName());
refactoring.setNewName("NewName");
// validate change
assertRefactoringStatusOK();
Change refactoringChange = refactoring.createChange(pm);
assertChangeResult(
refactoringChange,
testSource,
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"library libA;",
"class NewName implements Other {",
" NewName() {}",
" NewName.named() {}",
"}",
"class Other {",
" factory Other.a() = NewName;",
" factory Other.b() = NewName.named;",
"}",
"main() {",
" NewName t1 = new NewName();",
" NewName t2 = new NewName.named();",
"}"));
assertChangeResult(
refactoringChange,
sourceB,
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"import 'test.dart';",
"main() {",
" NewName t = new NewName();",
"}"));
}
public void test_createChange_ClassElement_parameterTypeNested() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class Test {",
"}",
"method(f(Test p)) {",
"}");
// configure refactoring
createRenameRefactoring("Test {");
assertEquals("Rename Class", refactoring.getRefactoringName());
refactoring.setNewName("NewName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"class NewName {",
"}",
"method(f(NewName p)) {",
"}");
}
public void test_createChange_ClassElement_typeAlias() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class A {}",
"class Test = Object with A;",
"f(Test t) {",
"}");
// configure refactoring
createRenameRefactoring("Test =");
assertEquals("Rename Class", refactoring.getRefactoringName());
refactoring.setNewName("NewName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"class A {}",
"class NewName = Object with A;",
"f(NewName t) {",
"}");
}
public void test_createChange_FunctionElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"test() {}",
"main() {",
" print(test);",
" print(test());",
"}");
// configure refactoring
createRenameRefactoring("test() {}");
assertEquals("Rename Top-Level Function", refactoring.getRefactoringName());
refactoring.setNewName("newName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"newName() {}",
"main() {",
" print(newName);",
" print(newName());",
"}");
}
public void test_createChange_oneUnitInTwoContexts() throws Exception {
String code = makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"main() {",
" main();",
"}");
// index unit in separate context
{
AnalysisContextHelper helper = new AnalysisContextHelper();
Source source = helper.addSource("/Test.dart", code);
CompilationUnit unit = helper.resolveDefiningUnit(source);
index.indexUnit(helper.context, unit);
}
// index same unit as "test"
indexTestUnit(code);
// configure refactoring
createRenameRefactoring("main() {");
assertEquals("Rename Top-Level Function", refactoring.getRefactoringName());
refactoring.setNewName("newName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"newName() {",
" newName();",
"}");
}
public void test_createChange_PropertyAccessorElement_getter_declaration() throws Exception {
check_createChange_PropertyAccessorElement("test {}");
}
public void test_createChange_PropertyAccessorElement_getter_usage() throws Exception {
check_createChange_PropertyAccessorElement("test)");
}
public void test_createChange_PropertyAccessorElement_mix() throws Exception {
check_createChange_PropertyAccessorElement("test += 2");
}
public void test_createChange_PropertyAccessorElement_setter_declaration() throws Exception {
check_createChange_PropertyAccessorElement("test(x) {}");
}
public void test_createChange_PropertyAccessorElement_setter_usage() throws Exception {
check_createChange_PropertyAccessorElement("test = 1");
}
public void test_createChange_TopLevelVariableElement_field() throws Exception {
check_createChange_TopLevelVariableElement("test = 42;");
}
public void test_createChange_TopLevelVariableElement_getter() throws Exception {
check_createChange_TopLevelVariableElement("test);");
}
public void test_createChange_TopLevelVariableElement_mix() throws Exception {
check_createChange_TopLevelVariableElement("test += 2;");
}
public void test_createChange_TopLevelVariableElement_setter() throws Exception {
check_createChange_TopLevelVariableElement("test = 1;");
}
public void test_createChange_TypeAliasElement() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"typedef Test();",
"main2(Test t) {",
"}");
// configure refactoring
createRenameRefactoring("Test();");
assertEquals("Rename Function Type Alias", refactoring.getRefactoringName());
refactoring.setNewName("NewName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"typedef NewName();",
"main2(NewName t) {",
"}");
}
public void test_shouldReportUnsafeRefactoringSource() throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"class MyPublic {}",
"class _MyPrivate {}");
Source externalSource = new FileBasedSource(new File("other.dart"));
// check public
createRenameRefactoring("MyPublic {}");
assertTrue(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, testSource));
assertTrue(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, externalSource));
assertFalse(refactoring.shouldReportUnsafeRefactoringSource(null, testSource));
// check private
createRenameRefactoring("_MyPrivate {}");
assertTrue(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, testSource));
assertFalse(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, externalSource));
}
public void xtest_createChange_oneLibInTwoContexts() throws Exception {
String libCode = "test() {}";
String code = makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"import 'Lib.dart';",
"main() {",
" test();",
"}");
// index unit in separate context
Source source2;
{
AnalysisContextHelper helper = new AnalysisContextHelper();
helper.addSource("/Lib.dart", libCode);
source2 = helper.addSource("/Test2.dart", code);
CompilationUnit unit = helper.resolveDefiningUnit(source2);
index.indexUnit(helper.context, unit);
}
// index unit Lib.dart in "test"
addSource("/Lib.dart", libCode);
indexTestUnit(code);
// configure refactoring
createRenameRefactoring("test()");
assertEquals("Rename Top-Level Function", refactoring.getRefactoringName());
refactoring.setNewName("newName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"import 'Lib.dart';",
"main() {",
" newName();",
"}");
assertChangeResult(
refactoringChange,
source2,
makeSource(
"// filler filler filler filler filler filler filler filler filler filler",
"import 'Lib.dart';",
"main() {",
" newName();",
"}"));
}
private void check_createChange_PropertyAccessorElement(String search) throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"get test {}",
"set test(x) {}",
"main() {",
" print(test);",
" test = 1;",
" test += 2;",
"}");
// configure refactoring
createRenameRefactoring(search);
assertEquals("Rename Top-Level Variable", refactoring.getRefactoringName());
refactoring.setNewName("newName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"get newName {}",
"set newName(x) {}",
"main() {",
" print(newName);",
" newName = 1;",
" newName += 2;",
"}");
}
private void check_createChange_TopLevelVariableElement(String search) throws Exception {
indexTestUnit(
"// filler filler filler filler filler filler filler filler filler filler",
"int test = 42;",
"main() {",
" print(test);",
" test = 1;",
" test += 2;",
"}");
// configure refactoring
createRenameRefactoring(search);
assertEquals("Rename Top-Level Variable", refactoring.getRefactoringName());
refactoring.setNewName("newName");
// validate change
assertSuccessfulRename(
"// filler filler filler filler filler filler filler filler filler filler",
"int newName = 42;",
"main() {",
" print(newName);",
" newName = 1;",
" newName += 2;",
"}");
}
}