/*******************************************************************************
 * Copyright (c) 2000, 2017 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Vladimir Piskarev <pisv@1c.ru> - F_CONTENT sometimes lost when merging deltas - https://bugs.eclipse.org/520336
 *******************************************************************************/
package org.eclipse.jdt.core.tests.model;

import junit.framework.Test;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;

import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;

public class RenameTests extends CopyMoveTests {
	ICompilationUnit cu;
public RenameTests(String name) {
	super(name);
}
/**
 * Attempts to rename the elements with optional
 * forcing. The operation should fail with the failure code.
 */
public void renameNegative(IJavaElement[] elements ,String[] renamings, boolean force, int failureCode) {
	try {
		//rename
	 	getJavaModel().rename(elements, new IJavaElement[]{elements[0].getParent()}, renamings, force, null);
	} catch (JavaModelException jme) {
		assertTrue("Code not correct for JavaModelException: "  + jme, jme.getStatus().getCode() == failureCode);
		return;
	}
	assertTrue("The rename should have failed for multiple renaming", false);
	return;
}
/**
 * Attempts to rename the element with optional
 * forcing. The operation should fail with the failure code.
 */
public void renameNegative(IJavaElement element, String rename, boolean force, int failureCode) {
	try {
		//rename
		getJavaModel().rename(new IJavaElement[] {element}, new IJavaElement[] {element.getParent()}, new String[] {rename}, force, null);
	} catch (JavaModelException jme) {
		assertTrue("Code not correct for JavaModelException: " + jme, jme.getStatus().getCode() == failureCode);
		return;
	}
	assertTrue("The rename should have failed for: " + element, false);
	return;
}
/**
 * Renames the element to the container with optional
 * forcing. The operation should succeed, so any exceptions
 * encountered are thrown.
 */
public void renamePositive(IJavaElement[] elements, String[] names, boolean force) throws JavaModelException {
	renamePositive(elements, new IJavaElement[]{elements[0].getParent()}, names, force);
}
/**
 * Renames the element to the container with optional
 * forcing. The operation should succeed, so any exceptions
 * encountered are thrown.
 */
public void renamePositive(IJavaElement[] elements, IJavaElement[] destinations, String[] names, boolean force) throws JavaModelException {
	renamePositive(elements, destinations, names, force, false);
}
/**
 * Renames the element to the container with optional
 * forcing. The operation should succeed, so any exceptions
 * encountered are thrown.
 */
public void renamePositive(IJavaElement[] elements, IJavaElement[] destinations, String[] names, boolean force, boolean originalShouldExist) throws JavaModelException {
	renamePositive(elements, destinations, names, force, originalShouldExist, null);
}
/**
 * Renames the element to the container with optional
 * forcing. The operation should succeed, so any exceptions
 * encountered are thrown.
 */
public void renamePositive(IJavaElement[] elements, IJavaElement[] destinations, String[] names, boolean force, boolean originalShouldExist, IProgressMonitor monitor) throws JavaModelException {
	// if forcing, ensure that a name collision exists
	int i;
	if (force) {
		for (i = 0; i < elements.length; i++) {
			IJavaElement e = elements[i];
			IJavaElement collision = generateHandle(e, names[i], e.getParent());
			assertTrue("Collision does not exist", collision.exists());
		}
	}

	// rename
	getJavaModel().rename(elements, destinations, names, force, monitor);
	for (i = 0; i < elements.length; i++) {
		// generate the new element	handle
		IJavaElement e = elements[i];
		IJavaElement renamed = generateHandle(e, names[i], e.getParent());
		assertTrue("Renamed element should exist", renamed.exists());
		if (!originalShouldExist) {
			assertTrue("Original element should not exist", !e.exists());
		}
		IJavaElementDelta destDelta = this.deltaListener.getDeltaFor(renamed.getParent());
		if (isMainType(e, e.getParent())) {
			assertTrue("Renamed compilation unit as result of main type not added", destDelta != null && destDelta.getKind() == IJavaElementDelta.ADDED);
			assertTrue("Added children not correct for element copy", destDelta.getElement().equals(renamed.getParent()));
			assertTrue("flag should be F_MOVED_FROM", (destDelta.getFlags() & IJavaElementDelta.F_MOVED_FROM) > 0);
			assertTrue("moved from handle should be original", destDelta.getMovedFromElement().equals(e.getParent()));
		} else {
			assertTrue("Destination container not changed", destDelta != null && deltaChildrenChanged(destDelta));
			IJavaElementDelta[] deltas = force ? destDelta.getChangedChildren() : destDelta.getAddedChildren();
			assertTrue("Added children not correct for element rename", deltas.length > i && deltas[i].getElement().equals(renamed));
			assertTrue("kind should be K_ADDED", deltas[i].getKind() == (force? IJavaElementDelta.CHANGED : IJavaElementDelta.ADDED));
			deltas = destDelta.getRemovedChildren();
			assertTrue("Removed children not correct for element rename", deltas.length > i && deltas[i].getElement().equals(e));
			assertTrue("kind should be K_REMOVED", deltas[i].getKind() == IJavaElementDelta.REMOVED);
		}
	}
}
/**
 * Renames the element to the container with optional
 * forcing. The operation should succeed, so any exceptions
 * encountered are thrown.
 */
public void renamePositive(IJavaElement element, String rename, boolean force) throws JavaModelException {
	renamePositive(new IJavaElement[] {element}, new String[] {rename}, force);
}
/**
 * Setup for the next test.
 */
@Override
public void setUp() throws Exception {
	super.setUp();

	this.createJavaProject("P", new String[] {"src"}, "bin");
	this.createFile(
		"/P/src/X.java",
		"public class X {\n" +
		"  boolean other;\n" +
		"  int bar;\n" +
		"  {\n" +
		"    bar = 1;\n" +
		"  }\n" +
		"  X(int i) {\n" +
		"  }\n" +
		"  void otherMethod(String s) {\n" +
		"  }\n" +
		"  void foo(String s) {\n" +
		"  }\n" +
		"}"
	);
	this.cu = getCompilationUnit("/P/src/X.java");

	startDeltas();
}
@Override
public void setUpSuite() throws Exception {
	super.setUpSuite();

	IJavaProject project = this.createJavaProject("BinaryProject", new String[] {"src"}, new String[] {"JCL_LIB"}, "lib");
	this.createFile(
		"/BinaryProject/src/X.java",
		"public class X {\n" +
		"  int bar;\n" +
		"  public void foo() {\n" +
		"  }\n" +
		"}"
	);
	project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
	waitForAutoBuild();
	project.setRawClasspath(
		new IClasspathEntry[] {
			JavaCore.newLibraryEntry(new Path("/BinaryProject/lib"), null, null)
		},
		null
	);
}
// Use this static initializer to specify subset for tests
// All specified tests which do not belong to the class are skipped...
static {
	// Names of tests to run: can be "testBugXXXX" or "BugXXXX")
//		TESTS_PREFIX = "testCombineAccessRestrictions";
//		TESTS_NAMES = new String[] {"testRenameFieldFragment"};
//		TESTS_NUMBERS = new int[] { 5, 6 };
//		TESTS_RANGE = new int[] { 21, 38 };
}
public static Test suite() {
	return buildModelTestSuite(RenameTests.class);
}
/**
 * Cleanup after the previous test.
 */
@Override
public void tearDown() throws Exception {
	stopDeltas();
	this.deleteProject("P");

	super.tearDown();
}
@Override
public void tearDownSuite() throws Exception {
	this.deleteProject("BinaryProject");
	super.tearDownSuite();
}
/**
 * Ensures that a binary field cannot be renamed.
 */
public void testRenameBinaryField() throws JavaModelException {
	IOrdinaryClassFile cf = getClassFile("BinaryProject", "lib", "", "X.class");
	IField binaryField = cf.getType().getField("bar");
	renameNegative(binaryField, "fred", false, IJavaModelStatusConstants.READ_ONLY);
}
/**
 * Ensures that a binary method cannot be renamed.
 */
public void testRenameBinaryMethod() throws JavaModelException {
	IOrdinaryClassFile cf = getClassFile("BinaryProject", "lib", "", "X.class");
	IMethod binaryMethod = cf.getType().getMethods()[0];
	renameNegative(binaryMethod, "fred", false, IJavaModelStatusConstants.READ_ONLY);
}
/**
 * Ensures that a binary type cannot be renamed.
 */
public void testRenameBinaryType() throws JavaModelException {
	IOrdinaryClassFile cf = getClassFile("BinaryProject", "lib", "", "X.class");
	IType binaryType = cf.getType();
	renameNegative(binaryType, "Y", false, IJavaModelStatusConstants.READ_ONLY);
}

/**
 * This operation should fail as renaming a CU and a CU member at the
 * same time is not supported.
 */
public void testRenameCompilationUnitAndType() {
	renameNegative(
		new IJavaElement[] {this.cu, this.cu.getType("X")},
		new String[]{"Y.java", "Y"},
		false,
		IJavaModelStatusConstants.INVALID_ELEMENT_TYPES);
}
/**
 * Ensures that compilation units cannot be renamed to an existing cu name
 * unless the force flag is set.
 */
public void testRenameCompilationUnitResultingInCollision() throws CoreException{
	this.createFile(
		"/P/src/Y.java",
		"public class Y {\n" +
		"}"
	);

	renameNegative(this.cu, "Y.java", false, IJavaModelStatusConstants.NAME_COLLISION);
	renamePositive(this.cu, "Y.java", true);
}
/**
 * Ensures that compilation units can be renamed.
 * Verifies that the proper change deltas are generated as a side effect
 * of running the operation.
 */
public void testRenameCompilationUnitsCheckingDeltas() throws CoreException{
	this.createFile(
		"/P/src/Y.java",
		"public class Y {\n" +
		"}"
	);
	ICompilationUnit cu2 = this.getCompilationUnit("/P/src/Y.java");

	clearDeltas();
	renamePositive(
		new ICompilationUnit[] {this.cu, cu2},
		new String[] {"NewX.java", "NewY.java"},
		false);

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		<default>[*]: {CHILDREN}\n" +
		"			NewX.java[+]: {MOVED_FROM(X.java [in <default> [in src [in P]]])}\n" +
		"			NewY.java[+]: {MOVED_FROM(Y.java [in <default> [in src [in P]]])}\n" +
		"			X.java[-]: {MOVED_TO(NewX.java [in <default> [in src [in P]]])}\n" +
		"			Y.java[-]: {MOVED_TO(NewY.java [in <default> [in src [in P]]])}"
	);
}
/**
 * Ensures that a compilation unit cannot be renamed to an invalid name.
 * The new name for a cu must end in .java and be a valid Java identifier.
 */
public void testRenameCompilationUnitWithInvalidName() {
	renameNegative(this.cu, "NewX", false, IJavaModelStatusConstants.INVALID_NAME);
	renameNegative(this.cu, "New X.java", false, IJavaModelStatusConstants.INVALID_NAME);
}
/**
 * This operation should fail as renaming a CU with a null name should throw
 * an <code>IllegalArgumentException</code>
 */
public void testRenameCompilationUnitWithNull() throws JavaModelException {
	try {
		this.cu.rename(null, false, null);
	} catch (IllegalArgumentException iae) {
		return;
	}
	assertTrue("Should not be able to rename a cu with a null name", false);
}
/**
 * Ensures that a construtor cannot be renamed using the
 * <code>RenameElementsOperation</code>.
 */
public void testRenameConstructor() {
	IMethod constructor = this.cu.getType("X").getMethod("X",  new String[] {"I"});
	renameNegative(constructor, "newName", false, IJavaModelStatusConstants.NAME_COLLISION);
}

public void testRenameCU1() throws CoreException {
	this.cu.rename("NewX.java", false, null);
	assertTrue("Original CU should not exist", !this.cu.exists());

	ICompilationUnit newCU = getCompilationUnit("/P/src/NewX.java");
	assertTrue("New CU should exist", newCU.exists());

	assertTypesEqual(
		"Unexpected types",
		"NewX\n",
		newCU.getAllTypes());

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		<default>[*]: {CHILDREN}\n" +
		"			NewX.java[+]: {MOVED_FROM(X.java [in <default> [in src [in P]]])}\n" +
		"			X.java[-]: {MOVED_TO(NewX.java [in <default> [in src [in P]]])}"
	);
}
public void testRenameCU2() throws CoreException {
	this.createFile(
		"/P/src/Y.java",
		"public class Y {\n" +
		"}"
	);

	clearDeltas();
	this.cu.rename("Y.java", true, null);

	IFile file = (IFile)this.cu.getResource();
	ICompilationUnit destCU = getCompilationUnit("/P/src/Y.java");
	IFile destFile = (IFile)destCU.getResource();

	assertTrue("Original CU should not exist", !this.cu.exists());
	assertTrue("Original file should not exist", !file.exists());
	assertTrue("Destination CU should exist", destCU.exists());
	assertTrue("Destination file should exist", destFile.exists());

	assertTypesEqual(
		"Unexpected types",
		"Y\n",
		destCU.getAllTypes());

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
				"	src[*]: {CHILDREN}\n" +
				"		<default>[*]: {CHILDREN}\n" +
				"			X.java[-]: {MOVED_TO(Y.java [in <default> [in src [in P]]])}\n" +
				"			Y.java[*]: {CHILDREN | CONTENT | FINE GRAINED | PRIMARY RESOURCE}\n" +
				"				Y[+]: {MOVED_FROM(X [in X.java [in <default> [in src [in P]]]])}"
	);
}
/*
 * Ensures that the correct scheduling rule is used when running ICompilationUnit.rename(...)
 * (regression test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=142990 )
 */
public void testRenameCU3() throws Exception {
	IWorkspaceRunnable runnable = new IWorkspaceRunnable(){
		public void run(IProgressMonitor monitor) throws CoreException {
			RenameTests.this.cu.rename("NewX.java", false, null);
			assertTrue("Original CU should not exist", !RenameTests.this.cu.exists());
		}
	};
	getWorkspace().run(runnable, getFolder("/P/src"), IResource.NONE, null);
}
/*
 * Ensures that the correct scheduling rule is used when running ICompilationUnit.rename(...)
 * (regression test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=142990 )
 */
public void testRenameCU4() throws Exception {
	createFolder("/P/src/p1");
	createFile("/P/src/p1/X.java", "package p1; public class X {}");
	IWorkspaceRunnable runnable = new IWorkspaceRunnable(){
		public void run(IProgressMonitor monitor) throws CoreException {
			ICompilationUnit x = getCompilationUnit("/P/src/p1/X.java");
			x.rename("NewX.java", false, null);
			assertTrue("Original CU should not exist", !x.exists());
		}
	};
	getWorkspace().run(runnable, getFolder("/P/src/p1"), IResource.NONE, null);
}
/*
 * Ensures that renaming an empty package fragment doesn't make it disappear
 * (regression test for bug 24505 Refactoring an empty package makes it disappears)
 */
public void testRenameEmptyPF() throws CoreException {
	this.createFolder("/P/src/x/y/z");

	clearDeltas();
	getPackage("/P/src/x/y/z").rename("x.y", false, null);

	IPackageFragment newFrag = getPackage("/P/src/x/y");
	assertTrue("New package should exist", newFrag.exists());
	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		x.y.z[-]: {MOVED_TO(x.y [in src [in P]])}\n" +
		"		x.y[+]: {MOVED_FROM(x.y.z [in src [in P]])}"
	);
}
/*
 * Ensures that renaming an enum also renames the constructors of this enum.
 * (regression test for bug 83593 Rename of enum type does not update constructor / throws ClassCastException)
 */
public void testRenameEnum() throws CoreException {
	try {
		createJavaProject("P15", new String[] {""}, new String[] {"JCL15_LIB"}, "", "1.5");
		createFile(
			"/P15/En.java",
			"public enum En {\n" +
			"  ;\n" +
			"  En() {\n" +
			"  }\n" +
			"}"
		);
		ICompilationUnit enumCU = getCompilationUnit("/P15/En.java");
		enumCU.rename("OtherEnum.java", false, null);
		ICompilationUnit renamedCu = getCompilationUnit("/P15/OtherEnum.java");
		assertSourceEquals(
			"Unexpected source after rename",
			"public enum OtherEnum {\n" +
			"  ;\n" +
			"  OtherEnum() {\n" +
			"  }\n" +
			"}",
			renamedCu.getSource()
		);
	} finally {
		deleteProject("P15");
	}
}
/*
 * Ensures that renaming an enum that contain an enum constant with a body doesn't throw a ClassCastExeption.
 * (regression test for bug 83593 Rename of enum type does not update constructor / throws ClassCastException)
 */
public void testRenameEnum2() throws CoreException {
	try {
		createJavaProject("P15", new String[] {""}, new String[] {"JCL15_LIB"}, "", "1.5");
		createFile(
			"/P15/En.java",
			"public enum En {\n" +
			"  CONST() {\n" +
			"  }\n" +
			"}"
		);
		ICompilationUnit enumCU = getCompilationUnit("/P15/En.java");
		enumCU.rename("OtherEnum.java", false, null);
		ICompilationUnit renamedCu = getCompilationUnit("/P15/OtherEnum.java");
		assertSourceEquals(
			"Unexpected source after rename",
			"public enum OtherEnum {\n" +
			"  CONST() {\n" +
			"  }\n" +
			"}",
			renamedCu.getSource()
		);
	} finally {
		deleteProject("P15");
	}
}
/**
 * Ensures that fields can be renamed.
 * Verifies that the proper change deltas are generated as a side effect
 * of running the operation. As well ensures that the fields are
 * positioned in the same location as before the rename.
 */
public void testRenameFieldsCheckingDeltasAndPositions() throws JavaModelException {
	IType type = this.cu.getType("X");
	IField field = type.getField("bar");
	renamePositive(field, "fred", false);

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		<default>[*]: {CHILDREN}\n" +
		"			X.java[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
		"				X[*]: {CHILDREN | FINE GRAINED}\n" +
		"					bar[-]: {}\n" +
		"					fred[+]: {}"
	);
	ensureCorrectPositioning(type, type.getField("fred"), type.getField("other"));
}
/*
 * Ensures that renaming a field fragment renames the right fragment
 * (regression test for bug 121076 Wrong field gets renamed)
 */
public void testRenameFieldFragment() throws Exception {
     this.createFile(
            "/P/src/Y.java",
            "public class Y {\n" +
            "  int int1, int2, int3;\n" +
            "}"
    );
    ICompilationUnit c = getCompilationUnit("/P/src/Y.java");
    IType type = c.getType("Y");
    IField field = type.getField("int2");
    renamePositive(field, "int2_renamed", false);
}
/**
 * Ensures that fields can be renamed even if one of the renamings fails.
 */
public void testRenameFieldsMultiStatus() throws CoreException {
	String addition = "multiStatus";
	IType type = this.cu.getType("X");
	IField[] iFields = type.getFields();
	String[] newNames = new String[iFields.length];
	int i;
	for (i = 0; i < iFields.length; i++) {
		IField f = iFields[i];
		newNames[i] = addition + f.getElementName();
	}
	newNames[1] = ";"; //invalid name

	boolean e = false;
	try {
		type.getJavaModel().rename(iFields, new IJavaElement[] {type}, newNames, false, null);
	} catch (JavaModelException jme) {
		assertTrue("Should not be multistatus (only one failure)", !jme.getStatus().isMultiStatus());
		assertTrue("Should be an invalid destination", jme.getStatus().getCode() == IJavaModelStatusConstants.INVALID_NAME);
		e = true;
	}
	assertTrue("Should have been an exception", e);

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		<default>[*]: {CHILDREN}\n" +
		"			X.java[*]: {CHILDREN | FINE GRAINED | PRIMARY RESOURCE}\n" +
		"				X[*]: {CHILDREN | FINE GRAINED}\n" +
		"					multiStatusother[+]: {}\n" +
		"					other[-]: {}"
	);

	IJavaElement copy = generateHandle(iFields[0], newNames[0], type);
	assertTrue("Copy should exist", copy.exists());
}
/**
 * Ensures that fields cannot be renamed to the same name.
 */
public void testRenameFieldsResultingInCollision() throws JavaModelException {
	String addition = "new";
	IType type= this.cu.getType("X");
	IField[] iFields = type.getFields();
	String[] newNames = new String[iFields.length];
	int i;
	for (i = 0; i < iFields.length; i++) {
		IField f = iFields[i];
		newNames[i] = addition + f.getElementName();
	}
	//set two fields to have the same new name
	newNames[i-1]= newNames[i-2];

	renameNegative(iFields, newNames, false, IJavaModelStatusConstants.NAME_COLLISION);
}
/**
 * Ensures that renaming can be canceled.
 */
public void testRenameFieldsWithCancel() throws CoreException {
	boolean isCanceled = false;
	String addition = "new1";
	IType type = RenameTests.this.cu.getType("X");
	IField[] iFields = type.getFields();
	String[] newNames = new String[iFields.length];
	int i;
	for (i = 0; i < iFields.length; i++) {
		IField f = iFields[i];
		newNames[i] = addition + f.getElementName();
	}
	try {
		TestProgressMonitor monitor = TestProgressMonitor.getInstance();
		monitor.setCancelledCounter(1);
		renamePositive(iFields, new IJavaElement[] {type}, newNames, false, false, monitor);
	} catch (OperationCanceledException e) {
		isCanceled = true;
	}
	assertTrue("Operation should have thrown an operation canceled exception", isCanceled);
}
/**
 * Ensures that an initializer cannot be renamed.
 */
public void testRenameInitializer() {
	IType typeSource= this.cu.getType("X");
	IInitializer initializerSource= typeSource.getInitializer(1);

	renameNegative(initializerSource, "someName", false, IJavaModelStatusConstants.INVALID_ELEMENT_TYPES);
}
/**
 * Ensures that main types can be renamed. As a side effect
 * of renaming the main types, the types' enclosing compilation unit
 * are renamed as well.
 */
public void testRenameMainTypes() throws CoreException {
	this.createFile(
		"/P/src/Y.java",
		"public class Y {\n" +
		"  public Y() {\n" +
		"  }\n" +
		"}"
	);
	ICompilationUnit cu2 = getCompilationUnit("/P/src/Y.java");
	IPackageFragment pkg = (IPackageFragment) this.cu.getParent();

	IJavaElement[] types = new IJavaElement[] {
		this.cu.getType("X"),
		cu2.getType("Y")
	};
	String[] newNames = new String[] {"NewX", "NewY"};
	renamePositive(
		new IJavaElement[] {
			this.cu.getType("X"),
			cu2.getType("Y")
		},
		new IJavaElement[] {
			types[0].getParent(),
			types[1].getParent()},
		newNames,
		false);

	//test that both the compilation unit, main type and constructors have been renamed.
	ICompilationUnit renamedCU1= pkg.getCompilationUnit("NewX.java");
	ICompilationUnit renamedCU2= pkg.getCompilationUnit("NewY.java");
	IType newType1 = renamedCU1.getType("NewX");
	IType newType2 = renamedCU2.getType("NewY");
	assertTrue("NewX should be present", newType1.exists());
	assertTrue("NewY should be present", newType2.exists());

	IMethod constructor1 = newType1.getMethod("NewX", new String[] {"I"});
	IMethod constructor2 = newType2.getMethod("NewY", new String[] {});
	assertTrue("NewX(int) should be present", constructor1.exists());
	assertTrue("NewY() should be present", constructor2.exists());
}
/**
 * Ensures that main types can be renamed as well as a child of a main type. As a side effect
 * of renaming the main types, the types enclosing compilation unit
 * are renamed as well.
 * @see "1FTKMBD: ITPJCORE:ALL - JM- Cannot rename parent and child with the same operation"
 */
public void testRenameMainTypesAndAChild() throws CoreException {
	this.createFile(
		"/P/src/Y.java",
		"public class Y {\n" +
		"  public Y() {\n" +
		"  }\n" +
		"}"
	);
	ICompilationUnit cu2 = getCompilationUnit("/P/src/Y.java");

	String[] newNames = new String[] {
		"newBar",
		"NewX",
		"NewY"
	};
	IJavaElement[] elements = new IJavaElement[] {
		this.cu.getType("X").getField("bar"),
		this.cu.getType("X"),
		cu2.getType("Y")
	};
	IJavaElement[] destinations = new IJavaElement[elements.length];
	for (int i = 0; i < elements.length; i++) {
		destinations[i] = elements[i].getParent();
	}

	getJavaModel().rename(elements, destinations, newNames, false, null);

	//test that both the compilation unit and the main type have been renamed.
	IPackageFragment pkg = (IPackageFragment) this.cu.getParent();
	ICompilationUnit renamedCU1= pkg.getCompilationUnit("NewX.java");
	IType newX = renamedCU1.getType("NewX");
	assertTrue("NewX should be present", newX.exists());

	ICompilationUnit renamedCU2= pkg.getCompilationUnit("NewY.java");
	IType newY = renamedCU2.getType("NewY");
	assertTrue("NewY should be present", newY.exists());

	IField newBar = newX.getField("newBar");
	assertTrue("Renamed field should exist", newBar.exists());
}
/**
 * Ensures that a method can be renamed.
 */
public void testRenameMethod() throws JavaModelException {
	IType type = this.cu.getType("X");
	IMethod method = type.getMethod("foo", new String[] {"QString;"});
	renamePositive(method, "newFoo", false);

	//ensure that the method did not move as a result of the rename
	ensureCorrectPositioning(
		type,
		type.getMethod("newFoo", new String[] {"QString;"}),
		type.getMethod("otherMethod", new String[] {"QString;"}));
}
/**
 * Ensures that a method cannot be renamed to an existing method name.
 */
public void testRenameMethodResultingInCollision() {
	IType type = this.cu.getType("X");
	IMethod method = type.getMethod("foo", new String[] {"QString;"});
	renameNegative(method, "otherMethod", false, IJavaModelStatusConstants.NAME_COLLISION);
}
/**
 * Ensures that a method cannot be renamed to an invalid method name
 */
public void testRenameMethodsWithInvalidName() {
	IMethod method = this.cu.getType("X").getMethod("foo", new String[] {"QString;"});
	renameNegative(method, "%%someInvalidName", false, IJavaModelStatusConstants.INVALID_NAME);
}
public void testRenamePF() throws CoreException {
	this.createFolder("/P/src/x/y/z");
	this.createFile(
		"/P/src/x/y/z/A.java",
		"package x.y.z;\n" +
		"public class A {\n" +
		"}"
	);

	IPackageFragment frag = getPackage("/P/src/x/y/z");
	clearDeltas();
	frag.rename("x.y.newZ", false, null);

	IPackageFragment newFrag = getPackage("/P/src/x/y/newZ");
	assertTrue("Old package should not exist", !frag.exists());
	assertTrue("New package should exist", newFrag.exists());

	ICompilationUnit compilationUnit = newFrag.getCompilationUnit("A.java");
	assertTrue("A.java should exits in new package", compilationUnit.exists());

	IType[] types = compilationUnit.getTypes();
	assertTrue(types != null && types.length == 1);
	IType mainType = types[0];
	assertEquals(
		"Unexpected A.java's main type'",
		"x.y.newZ.A",
		mainType.getFullyQualifiedName());

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		x.y.newZ[+]: {MOVED_FROM(x.y.z [in src [in P]])}\n" +
		"		x.y.z[-]: {MOVED_TO(x.y.newZ [in src [in P]])}"
	);
}
/*
 * Ensures that renaming to a name containing spaces works
 * (regression test for bug 21957 'refactor rename' allows subpackage name to start with a space)
 */
public void testRenamePF2() throws CoreException {
	this.createFolder("/P/src/x/y/z");
	this.createFile(
		"/P/src/x/y/z/A.java",
		"package x.y.z;\n" +
		"public class A {\n" +
		"}"
	);

	IPackageFragment frag = getPackage("/P/src/x/y/z");
	clearDeltas();
	frag.rename("x.y. z2", false, null);

	IPackageFragment newFrag = getPackage("/P/src/x/y/z2");
	assertTrue("Old package should not exist", !frag.exists());
	assertTrue("New package should exist", newFrag.exists());

	ICompilationUnit compilationUnit = newFrag.getCompilationUnit("A.java");
	assertTrue("A.java should exits in new package", compilationUnit.exists());

	IType[] types = compilationUnit.getTypes();
	assertTrue(types != null && types.length == 1);
	IType mainType = types[0];
	assertEquals(
		"Unexpected A.java's main type'",
		"x.y.z2.A",
		mainType.getFullyQualifiedName());

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		x.y.z2[+]: {MOVED_FROM(x.y.z [in src [in P]])}\n" +
		"		x.y.z[-]: {MOVED_TO(x.y.z2 [in src [in P]])}"
	);
}
/*
 * Ensure that renaming a package to a sub package and using IJavaProject#findType(...) in a IWorskpaceRunnable
 * finds the right type
 * (regression test for bug 83646 NPE renaming package)
 */
public void testRenamePF3() throws CoreException {
	createFolder("/P/src/x");
	createFile(
		"/P/src/x/A.java",
		"package x;\n" +
		"public class A {\n" +
		"}"
	);
	IWorkspaceRunnable runnable = new IWorkspaceRunnable(){
		public void run(IProgressMonitor monitor) throws CoreException {
			getPackage("/P/src/x").rename("x.y", false, null);
			IType type = getJavaProject("P").findType("x.y.A");
			assertTypesEqual(
				"Unepected type",
				"x.y.A\n",
				new IType[] {type});
		}
	};
	getWorkspace().run(runnable, null);
}
public void testRenamePFWithSubPackages() throws CoreException {
	this.createFolder("/P/src/x/y/z");
	this.createFile(
		"/P/src/x/y/z/A.java",
		"package x.y.z;\n" +
		"public class A {\n" +
		"}"
	);

	clearDeltas();
	getPackage("/P/src/x").rename("newX", false, null);

	IPackageFragment oldFrag = getPackage("/P/src/x/y/z");
	assertTrue("Old inner package should still exist", oldFrag.exists());

	IPackageFragment newFrag = getPackage("/P/src/newX");
	assertTrue("New package should exist", newFrag.exists());

	ICompilationUnit compilationUnit = oldFrag.getCompilationUnit("A.java");
	assertTrue("A.java should exits in old inner package", compilationUnit.exists());

	assertDeltas(
		"Unexpected deltas",
		"P[*]: {CHILDREN}\n" +
		"	src[*]: {CHILDREN}\n" +
		"		newX[+]: {}"
	);
}
/**
 * Ensures that a method can be renamed if it contains syntax errors.
 */
public void testRenameSyntaxErrorMethod() throws CoreException {
	this.createFile(
		"/P/src/Y.java",
		"public class Y {\n" +
		"  void foo( {\n" + // syntax error
		"  }\n" +
		"}"
	);
	IMethod method = getCompilationUnit("/P/src/Y.java").getType("Y").getMethod("foo", null);
	renamePositive(method, "newFoo", false);
}
/**
 * Ensures that attempting to rename with an incorrect number of renamings fails
 */
public void testRenameWithInvalidRenamings() {
	IMethod method = getCompilationUnit("/P/src/X.java").getType("X").getMethod("foo", null);

	renameNegative(
		new IJavaElement[] {method},
		new String[]{"", ""},
		false,
		IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);

	renameNegative(
		new IJavaElement[] {method},
		null,
		false,
		IJavaModelStatusConstants.NULL_NAME);
}
/**
 * Ensures that a working copy cannot be renamed.
 */
public void testRenameWorkingCopy() throws JavaModelException {
	ICompilationUnit copy = null;
	try {
		copy = this.cu.getWorkingCopy(null);
		renameNegative(copy, "NewX", false, IJavaModelStatusConstants.INVALID_ELEMENT_TYPES);
	} finally {
		if (copy != null) copy.discardWorkingCopy();
	}
}

}
