/*******************************************************************************
* Copyright (c) 2015 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.base.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.MoveArguments;
import org.eclipse.ltk.core.refactoring.participants.MoveParticipant;
import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.DocumentProviderRegistry;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.jboss.tools.common.EclipseUtil;
import org.jboss.tools.common.util.FileUtil;
import org.jboss.tools.test.util.JobUtils;
import org.junit.Assert;
public class RenameParticipantTestUtil {
public static void checkRenameParticipant(IJavaElement element, RenameProcessor renameProcessor,
RefactoringParticipant participant, String newName, List<TestChangeStructure> changeList)
throws CoreException, BadLocationException {
processTestChanges(changeList);
JobUtils.waitForIdle();
participant.initialize(renameProcessor, element, new RenameArguments(newName, true));
RefactoringStatus status = participant.checkConditions(new NullProgressMonitor(), null);
Assert.assertNotNull("Rename participant returned null status", status);
Assert.assertFalse("There is fatal errors in rename participant", status.hasFatalError());
CompositeChange rootChange = (CompositeChange) participant.createChange(new NullProgressMonitor());
checkChanges(rootChange, changeList);
}
public static void checkRenameProcessor(RenameProcessor processor, List<TestChangeStructure> changeList)
throws CoreException, BadLocationException {
processTestChanges(changeList);
JobUtils.waitForIdle();
// Test before renaming
checkBeforeRefactoring(changeList);
// Rename
RefactoringStatus status = processor.checkInitialConditions(new NullProgressMonitor());
RefactoringStatusEntry[] entries = status.getEntries();
for (RefactoringStatusEntry entry : entries) {
System.out.println("Refactor status - " + entry.getMessage());
}
Assert.assertNull("Rename processor returns fatal error",
status.getEntryMatchingSeverity(RefactoringStatus.FATAL));
status = processor.checkFinalConditions(new NullProgressMonitor(), null);
entries = status.getEntries();
for (RefactoringStatusEntry entry : entries) {
System.out.println("Refactor status - " + entry.getMessage());
}
Assert.assertNull("Rename processor returns fatal error",
status.getEntryMatchingSeverity(RefactoringStatus.FATAL));
CompositeChange rootChange = (CompositeChange) processor.createChange(new NullProgressMonitor());
checkChanges(rootChange, changeList);
}
public static void checkMoveParticipant(RefactoringProcessor processor, IResource oldObject,
IResource destinationObject, MoveParticipant participant, List<TestChangeStructure> changeList)
throws CoreException, BadLocationException {
processTestChanges(changeList);
JobUtils.waitForIdle();
// Test before moving
checkBeforeRefactoring(changeList);
// Move
MoveArguments arguments = new MoveArguments(destinationObject, true);
boolean initialized = participant.initialize(processor, oldObject, arguments);
Assert.assertTrue("Participant has not been initialized", initialized);
RefactoringStatus status = participant.checkConditions(new NullProgressMonitor(), null);
RefactoringStatusEntry[] entries = status.getEntries();
for (RefactoringStatusEntry entry : entries) {
System.out.println("Refactor status - " + entry.getMessage());
}
Assert.assertNull("Move processor returns fatal error",
status.getEntryMatchingSeverity(RefactoringStatus.FATAL));
CompositeChange rootChange = (CompositeChange) participant.createChange(new NullProgressMonitor());
Change mainChange = processor.createChange(new NullProgressMonitor());
mainChange.perform(new NullProgressMonitor());
checkChanges(rootChange, changeList);
}
public static void checkRenameParticipant(RefactoringProcessor processor, IResource oldObject,
String newName, RenameParticipant participant, List<TestChangeStructure> changeList)
throws CoreException, BadLocationException {
processTestChanges(changeList);
JobUtils.waitForIdle(2000);
// Test before renaming
checkBeforeRefactoring(changeList);
// Rename
RenameArguments arguments = new RenameArguments(newName, true);
boolean initialized = participant.initialize(processor, oldObject, arguments);
Assert.assertTrue("Participant has not been initialized", initialized);
RefactoringStatus status = participant.checkConditions(new NullProgressMonitor(), null);
RefactoringStatusEntry[] entries = status.getEntries();
for (RefactoringStatusEntry entry : entries) {
System.out.println("Refactor status - " + entry.getMessage());
}
Assert.assertNull("Rename processor returns fatal error",
status.getEntryMatchingSeverity(RefactoringStatus.FATAL));
CompositeChange rootChange = (CompositeChange) participant.createChange(new NullProgressMonitor());
Change mainChange = processor.createChange(new NullProgressMonitor());
mainChange.perform(new NullProgressMonitor());
checkChanges(rootChange, changeList);
}
private static void processTestChanges(List<TestChangeStructure> structureList) throws CoreException, BadLocationException {
// int offset = 0;
// for (TestChangeStructure tStructure : structureList) {
// IFile file = tStructure.getProject().getFile(tStructure.getFileName());
// String fileContent = FileUtil.readStream(file);
// for (TestTextChange tChange : tStructure.getTextChanges()) {
// if (tChange.getOffset() == -1) {
// offset = fileContent.indexOf(tChange.getSearchText(), offset+1);
// tChange.setOffset(offset);
// }
// }
// }
int offset = 0;
for (TestChangeStructure tStructure : structureList) {
IFile file = tStructure.getProject().getFile(tStructure.getFileName());
FileEditorInput editorInput = new FileEditorInput(file);
IDocumentProvider documentProvider = null;
documentProvider = DocumentProviderRegistry.getDefault().getDocumentProvider(editorInput);
Assert.assertNotNull("The document provider for the file \"" + file.getFullPath() + "\" is not loaded", documentProvider); //$NON-NLS-1$ //$NON-NLS-2$
documentProvider.connect(editorInput);
IDocument document = documentProvider.getDocument(editorInput);
FindReplaceDocumentAdapter adapter = new FindReplaceDocumentAdapter(document);
IRegion region = new Region(0,0);
for (TestTextChange tChange : tStructure.getTextChanges()) {
if (tChange.getOffset() == -1) {
IRegion newRegion = adapter.find(region.getOffset()+region.getLength(), tChange.getSearchText(), true, true, false, false);
if(newRegion != null){
tChange.setOffset(newRegion.getOffset());
region = newRegion;
}else
Assert.fail("Can not find string - "+tChange.getSearchText()); //$NON-NLS-1$
}
}
documentProvider.disconnect(editorInput);
}
}
private static void checkBeforeRefactoring(List<TestChangeStructure> changeList) {
for (TestChangeStructure changeStructure : changeList) {
IFile file = changeStructure.getProject().getFile(changeStructure.getFileName());
String content = null;
try {
content = readStream(file);
} catch (CoreException e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
for (TestTextChange change : changeStructure.getTextChanges()) {
Assert.assertNotSame(change.getText(),
content.substring(change.getOffset(), change.getOffset() + change.getLength()));
}
}
}
private static void checkChanges(CompositeChange rootChange, List<TestChangeStructure> changeList)
throws CoreException {
Assert.assertNotNull("Root change is null", rootChange);
int numberOfChanges = rootChange.getChildren().length;
for (int i = 0; i < rootChange.getChildren().length; i++) {
Change fileChange = rootChange.getChildren()[i];
MultiTextEdit edit = null;
IFile file = null;
if (fileChange instanceof TextFileChange) {
edit = (MultiTextEdit) ((TextFileChange) fileChange).getEdit();
file = ((TextFileChange) fileChange).getFile();
} else{
Assert.fail("fileChange must be instance of TextFileChange but was - "+fileChange.getClass());
}
TestChangeStructure change = findChange(changeList, file);
Assert.assertNotNull("Change not found for file - "+file.getFullPath(), change);
Assert.assertEquals(change.size(), edit.getChildrenSize());
for(TextEdit te : edit.getChildren()){
checkEdit(change, (ReplaceEdit)te);
}
}
}
public static TestChangeStructure findChange(List<TestChangeStructure> changeList, IFile file) {
for (TestChangeStructure tcs : changeList) {
if (tcs.getFileName().endsWith(file.getFullPath().removeFirstSegments(1).toString()))
return tcs;
}
return null;
}
private static void checkEdit(TestChangeStructure change, ReplaceEdit edit) throws CoreException{
IFile file = change.getProject().getFile(change.getFileName());
String fileContent = FileUtil.readStream(file);
String newText = edit.getText();
String editText = fileContent.substring(edit.getOffset(),edit.getOffset()+edit.getLength());
for (TestTextChange ttc : change.getTextChanges()) {
if(ttc.getOffset() == edit.getOffset()){
Assert.assertEquals("Wrong length of TextEdit file - "+file.getFullPath()+" editText - "+editText+" newText - "+newText, ttc.getLength(), newText.length());
Assert.assertEquals("Wrong text of TextEdit file - "+file.getFullPath()+" editText - "+editText, ttc.getText(), newText);
return;
}
}
Assert.fail("Unexpected edit file - "+file.getFullPath()+" offset - "+edit.getOffset()+" length - "+edit.getLength()+" text - "+editText+" newText - "+newText);
}
public static IType getJavaType(IProject project, String className) {
IJavaProject javaProject = EclipseUtil.getJavaProject(project);
if (javaProject != null) {
try {
return javaProject.findType(className);
} catch (JavaModelException ex) {
Assert.fail(ex.getMessage());
}
}
return null;
}
public static IMethod getJavaMethod(IProject project, String className, String methodName) {
IType type = getJavaType(project, className);
if (type != null) {
return type.getMethod(methodName, new String[0]);
}
return null;
}
public static IField getJavaField(IProject project, String className, String fieldName) {
IType type = getJavaType(project, className);
if (type != null) {
return type.getField(fieldName);
}
return null;
}
public static class TestChangeStructure {
private IProject project;
private String fileName;
ArrayList<TestTextChange> textChanges = new ArrayList<TestTextChange>();
public TestChangeStructure(IProject project, String fileName) {
this.project = project;
this.fileName = fileName;
}
public IProject getProject() {
return project;
}
public String getFileName() {
return fileName;
}
public ArrayList<TestTextChange> getTextChanges() {
return textChanges;
}
public void addTextChange(TestTextChange change) {
textChanges.add(change);
}
public int size() {
return textChanges.size();
}
}
public static class TestTextChange {
private String searchText;
private int offset;
private int length;
private String text;
public TestTextChange(int offset, int length, String text) {
this.offset = offset;
this.length = length;
this.text = text;
}
public TestTextChange(String searchText, int length, String text) {
this.offset = -1;
this.searchText = searchText;
this.length = length;
this.text = text;
}
public void setOffset(int offset) {
this.offset = offset;
}
public String getSearchText() {
return searchText;
}
public int getOffset() {
return offset;
}
public int getLength() {
return length;
}
public String getText() {
return text;
}
}
public static String readStream(IFile file) throws CoreException {
String content = null;
InputStream in = null;
try {
in = file.getContents();
content = readStream(in);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
}
return content;
}
public static String readStream(InputStream is) {
StringBuffer sb = new StringBuffer(""); //$NON-NLS-1$
try {
byte[] b = new byte[4096];
while (true) {
int l = is.read(b, 0, b.length);
if (l < 0)
break;
sb.append(new String(b, 0, l));
}
} catch (IOException e) {
e.printStackTrace();
Assert.fail(e.getMessage());
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
return sb.toString();
}
}