/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are 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
*
* Contributors:
* IBM Corporation - initial API and implementation
* Sebastian Davids <sdavids@gmx.de> - testInvertEquals1-23
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.ui.tests.quickfix;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
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.source.IAnnotationModel;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.ui.PartInitException;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.testplugin.EditorTestHelper;
import org.eclipse.cdt.ui.tests.BaseUITestCase;
import org.eclipse.cdt.ui.text.ICCompletionProposal;
import org.eclipse.cdt.ui.text.IInvocationContext;
import org.eclipse.cdt.ui.text.IProblemLocation;
import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.text.correction.CCorrectionProcessor;
import org.eclipse.cdt.internal.ui.text.correction.CorrectionContext;
import org.eclipse.cdt.internal.ui.text.correction.ProblemLocation;
import org.eclipse.cdt.internal.ui.text.correction.proposals.LinkedNamesAssistProposal;
import org.eclipse.cdt.internal.ui.text.correction.proposals.RenameRefactoringProposal;
import org.eclipse.cdt.internal.ui.text.correction.proposals.TUCorrectionProposal;
public class AssistQuickFixTest extends BaseUITestCase {
private static final Class<AssistQuickFixTest> THIS = AssistQuickFixTest.class;
private static final String PROJECT = "AssistQuickFixTest";
private ICProject fCProject;
private CEditor fEditor;
private IDocument fDocument;
private FindReplaceDocumentAdapter fFindReplaceDocumentAdapter;
private final IProblem[] fProblems;
private IAnnotationModel fAnnotationModel;
private IRegion fMatch;
private StyledText fTextWidget;
private ProjectTestSetup fProjectSetup;
protected static class ProjectTestSetup extends TestSetup {
private ICProject fCProject;
public ProjectTestSetup(Test test) {
super(test);
}
@Override
protected void setUp() throws Exception {
super.setUp();
fCProject= EditorTestHelper.createCProject(PROJECT, "resources/quickFix", false, true);
}
@Override
protected void tearDown() throws Exception {
if (fCProject != null)
CProjectHelper.delete(fCProject);
super.tearDown();
}
}
public AssistQuickFixTest(String name) {
super(name);
fProblems = new IProblem[0];
}
public static Test setUpTest(Test someTest) {
return new ProjectTestSetup(someTest);
}
public static Test suite() {
return setUpTest(new TestSuite(THIS));
}
@Override
protected void setUp() throws Exception {
if (!ResourcesPlugin.getWorkspace().getRoot().exists(new Path(PROJECT))) {
fProjectSetup= new ProjectTestSetup(this);
fProjectSetup.setUp();
}
fEditor= openCEditor(new Path("/" + PROJECT + "/src/RenameInFile.cpp"));
assertNotNull(fEditor);
fTextWidget= fEditor.getViewer().getTextWidget();
assertNotNull(fTextWidget);
boolean ok= EditorTestHelper.joinReconciler((SourceViewer) fEditor.getViewer(), 10, 500, 20);
assertTrue("Reconciler did not finish in time", ok);
fDocument= fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
assertNotNull(fDocument);
fFindReplaceDocumentAdapter= new FindReplaceDocumentAdapter(fDocument);
fAnnotationModel= fEditor.getDocumentProvider().getAnnotationModel(fEditor.getEditorInput());
fMatch= null;
}
/*
* @see junit.framework.TestCase#tearDown()
*/
@Override
protected void tearDown() throws Exception {
EditorTestHelper.closeAllEditors();
if (fProjectSetup != null) {
fProjectSetup.tearDown();
}
}
private CEditor openCEditor(IPath path) {
IFile file= ResourcesPlugin.getWorkspace().getRoot().getFile(path);
assertTrue(file != null && file.exists());
try {
return (CEditor) EditorTestHelper.openInEditor(file, true);
} catch (PartInitException e) {
fail();
return null;
}
}
private static final List<ICCompletionProposal> collectCorrections(CorrectionContext context, Class<?>[] filteredTypes) throws CoreException {
List<ICCompletionProposal> proposals= new ArrayList<ICCompletionProposal>();
IStatus status= CCorrectionProcessor.collectCorrections(context, new IProblemLocation[0], proposals);
assertStatusOk(status);
if (!proposals.isEmpty()) {
assertTrue("should be marked as 'has assist'", CCorrectionProcessor.hasAssists(context));
}
if (filteredTypes != null && filteredTypes.length > 0) {
for (Iterator<ICCompletionProposal> iter= proposals.iterator(); iter.hasNext(); ) {
if (isFiltered(iter.next(), filteredTypes)) {
iter.remove();
}
}
}
return proposals;
}
private static boolean isFiltered(Object curr, Class<?>[] filteredTypes) {
for (int k = 0; k < filteredTypes.length; k++) {
if (filteredTypes[k].isInstance(curr)) {
return true;
}
}
return false;
}
private CorrectionContext getCorrectionContext(int offset, int length) {
ITranslationUnit tu= CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(fEditor.getEditorInput());
return new CorrectionContext(tu, offset, length);
}
private static final ArrayList<ICCompletionProposal> collectAssists(CorrectionContext context, Class<?>[] filteredTypes) throws CoreException {
ArrayList<ICCompletionProposal> proposals= new ArrayList<ICCompletionProposal>();
IStatus status= CCorrectionProcessor.collectAssists(context, new IProblemLocation[0], proposals);
assertStatusOk(status);
if (!proposals.isEmpty()) {
assertTrue("should be marked as 'has assist'", CCorrectionProcessor.hasAssists(context));
}
if (filteredTypes != null && filteredTypes.length > 0) {
for (Iterator<ICCompletionProposal> iter= proposals.iterator(); iter.hasNext(); ) {
if (isFiltered(iter.next(), filteredTypes)) {
iter.remove();
}
}
}
return proposals;
}
private static void assertStatusOk(IStatus status) throws CoreException {
if (!status.isOK() && status.getException() == null) {
// Find a status with an exception
for (IStatus child : status.getChildren()) {
if (child.getException() != null) {
throw new CoreException(child);
}
}
}
}
private static void assertCorrectContext(IInvocationContext context, ProblemLocation problem) {
if (problem.getProblemId() != 0) {
if (!CCorrectionProcessor.hasCorrections(context.getTranslationUnit(), problem.getProblemId(), problem.getMarkerType())) {
assertTrue("Problem type not marked with light bulb: " + problem, false);
}
}
}
private static void assertNumberOfProposals(List<ICCompletionProposal> proposals, int expectedProposals) {
if (proposals.size() != expectedProposals) {
StringBuilder buf= new StringBuilder();
buf.append("Wrong number of proposals, is: ").append(proposals.size()). append(", expected: ").append(expectedProposals).append('\n');
for (ICCompletionProposal proposal : proposals) {
buf.append(" - ").append(proposal.getDisplayString()).append('\n');
if (proposal instanceof TUCorrectionProposal) {
try {
buf.append(((TUCorrectionProposal) proposal).getPreviewContent());
} catch (CoreException e) {
// ignore
}
}
}
assertTrue(buf.toString(), false);
}
}
private static void assertCorrectLabels(List<ICCompletionProposal> proposals) {
for (ICCompletionProposal proposal : proposals) {
String name= proposal.getDisplayString();
if (name == null || name.length() == 0 || name.charAt(0) == '!' || name.indexOf("{0}") != -1 || name.indexOf("{1}") != -1) {
assertTrue("wrong proposal label: " + name, false);
}
if (proposal.getImage() == null) {
assertTrue("wrong proposal image", false);
}
}
}
private static void assertCorrectContext(CorrectionContext context, ProblemLocation problem) {
if (problem.getProblemId() != 0) {
if (!CCorrectionProcessor.hasCorrections(context.getTranslationUnit(), problem.getProblemId(), problem.getMarkerType())) {
assertTrue("Problem type not marked with light bulb: " + problem, false);
}
}
}
public void testLocalRenameClass() throws Exception {
final String name = "Base2";
try {
fMatch= fFindReplaceDocumentAdapter.find(0, name, true, true, true, false);
} catch (BadLocationException e) {
fail();
}
assertNotNull(fMatch);
CorrectionContext context= getCorrectionContext(fMatch.getOffset(), 0);
List<ICCompletionProposal> proposals= collectAssists(context, null);
assertNumberOfProposals(proposals, 2);
assertCorrectLabels(proposals);
assertTrue(proposals.get(0) instanceof LinkedNamesAssistProposal);
assertTrue(proposals.get(1) instanceof RenameRefactoringProposal);
}
public void testLocalRenameMacro() throws Exception {
final String name = "INT";
try {
fMatch= fFindReplaceDocumentAdapter.find(0, name, true, true, true, false);
} catch (BadLocationException e) {
fail();
}
assertNotNull(fMatch);
CorrectionContext context= getCorrectionContext(fMatch.getOffset(), 0);
List<ICCompletionProposal> proposals= collectAssists(context, null);
assertNumberOfProposals(proposals, 2);
assertCorrectLabels(proposals);
assertTrue(proposals.get(0) instanceof LinkedNamesAssistProposal);
assertTrue(proposals.get(1) instanceof RenameRefactoringProposal);
}
public void testLocalRenameLanguageKeyword() throws Exception {
final String name = "int";
try {
fMatch= fFindReplaceDocumentAdapter.find(0, name, true, true, true, false);
} catch (BadLocationException e) {
fail();
}
assertNotNull(fMatch);
CorrectionContext context= getCorrectionContext(fMatch.getOffset(), 0);
List<ICCompletionProposal> proposals= collectAssists(context, null);
assertNumberOfProposals(proposals, 0);
}
}