blob: c8b6de55cc199e800517a0eb73d0c2b270986d36 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 Red Hat Inc. 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:
* - Mickael Istria (Red Hat Inc.) - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.text.tests.codemining;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.LongSupplier;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.eclipse.jdt.testplugin.JavaProjectHelper;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.codemining.ICodeMiningProvider;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.text.tests.util.DisplayHelper;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.intro.IIntroManager;
import org.eclipse.ui.intro.IIntroPart;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaCodeMiningReconciler;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer;
import org.eclipse.jdt.internal.ui.javaeditor.codemining.JavaMethodParameterCodeMiningProvider;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class ParameterNamesCodeMiningTest extends TestCase {
private IJavaProject fProject;
private IPackageFragment fPackage;
private JavaMethodParameterCodeMiningProvider fParameterNameCodeMiningProvider;
private boolean wasCodeMiningEnabled;
public static Test suite() {
return new TestSuite(ParameterNamesCodeMiningTest.class);
}
@Override
@Before
protected void setUp() throws Exception {
super.setUp();
if(!welcomeClosed) {
closeIntro(PlatformUI.getWorkbench());
}
fProject= JavaProjectHelper.createJavaProject(getClass().getName(), "bin");
JavaProjectHelper.addRTJar(fProject);
IPackageFragmentRoot root= JavaProjectHelper.addSourceContainer(fProject, "src");
fPackage= root.getPackageFragment("");
fParameterNameCodeMiningProvider= new JavaMethodParameterCodeMiningProvider();
wasCodeMiningEnabled= PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CODEMINING_ENABLED);
PreferenceConstants.getPreferenceStore().setValue(PreferenceConstants.EDITOR_CODEMINING_ENABLED, true);
}
@Override
@After
protected void tearDown() throws Exception {
super.tearDown();
PreferenceConstants.getPreferenceStore().setValue(PreferenceConstants.EDITOR_CODEMINING_ENABLED, wasCodeMiningEnabled);
IWorkbenchPage workbenchPage= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
for (IEditorReference ref : workbenchPage.getEditorReferences()) {
workbenchPage.closeEditor(ref.getEditor(false), false);
}
}
private void waitReconciled(JavaSourceViewer viewer) {
assertTrue("Editor not reconciled", new DisplayHelper() {
@Override
protected boolean condition() {
return JavaCodeMiningReconciler.isReconciled(viewer);
}
}.waitForCondition(viewer.getTextWidget().getDisplay(), 2000));
}
public void testParameterNamesOK() throws Exception {
String contents= "public class Foo {\n" +
" int n= Math.max(1, 2);\n" +
"}\n";
ICompilationUnit compilationUnit= fPackage.createCompilationUnit("Foo.java", contents, true, new NullProgressMonitor());
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
public void testVarargs() throws Exception {
String contents= "public class Foo {\n" +
" String s= String.format(\"%d %d\", 1, 2);\n" +
"}\n";
ICompilationUnit compilationUnit= fPackage.createCompilationUnit("Foo.java", contents, true, new NullProgressMonitor());
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
public void testMultiLines() throws Exception {
String contents =
"class Foo {\n" +
" long n= Math.max(System.currentTimeMillis(\n" +
" ), 0);\n" +
"}";
ICompilationUnit compilationUnit= fPackage.createCompilationUnit("Foo.java", contents, true, new NullProgressMonitor());
CompilationUnitEditor editor= (CompilationUnitEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
viewer.setCodeMiningProviders(new ICodeMiningProvider[] {
fParameterNameCodeMiningProvider
});
waitReconciled(viewer);
StyledText widget= viewer.getTextWidget();
//
assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
//
int charWidth= widget.getTextBounds(0, 1).width;
LongSupplier drawnCodeMiningsCount= () -> Arrays.stream(widget.getStyleRanges()).filter(style ->
style.metrics != null && style.metrics.width > charWidth).count();
new DisplayHelper() {
@Override
protected boolean condition() {
return drawnCodeMiningsCount.getAsLong() == 2;
}
}.waitForCondition(widget.getDisplay(), 500);
assertEquals(2, drawnCodeMiningsCount.getAsLong());
}
public void testUnresolvedMethodBinding() throws Exception {
String contents= "public class Foo {\n" +
" public void mehod() {\n" +
" List<String> list= Arrays.asList(\"foo\", \"bar\");\n" +
" System.out.printf(\"%s %s\", list.get(0), list.get(1));\n" +
" }\n" +
"}";
ICompilationUnit compilationUnit= fPackage.createCompilationUnit("Foo.java", contents, true, new NullProgressMonitor());
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
waitReconciled(viewer);
// Only code mining on "printf" parameters
assertEquals(2, fParameterNameCodeMiningProvider.provideCodeMinings(viewer, new NullProgressMonitor()).get().size());
}
public void testCollapsedFolding() throws Exception {
String contents= "/**\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
" */" +
"public class Foo {\n" +
" int n= Math.max(1, 2);\n" +
"}";
ICompilationUnit compilationUnit= fPackage.createCompilationUnit("Foo.java", contents, true, new NullProgressMonitor());
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
viewer.doOperation(ProjectionViewer.COLLAPSE_ALL);
viewer.setCodeMiningProviders(new ICodeMiningProvider[] {
fParameterNameCodeMiningProvider
});
waitReconciled(viewer);
//
ILog log= WorkbenchPlugin.getDefault().getLog();
AtomicReference<IStatus> errorInLog= new AtomicReference<>();
ILogListener logListener= (status, plugin) -> {
if (status.getSeverity() == IStatus.ERROR) {
errorInLog.set(status);
}
};
try {
log.addLogListener(logListener);
DisplayHelper.sleep(editor.getViewer().getTextWidget().getDisplay(), 1000);
Assert.assertNull(errorInLog.get());
} finally {
log.removeLogListener(logListener);
}
}
public void testCollapsedFoldingAndToggleHighlight() throws Exception {
String contents= "/**\n" +
" *\n" +
" */" +
"public class Foo {\n" +
" int n= Math.max(1, 2);\n" +
"}";
ICompilationUnit compilationUnit= fPackage.createCompilationUnit("Foo.java", contents, true, new NullProgressMonitor());
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
fParameterNameCodeMiningProvider.setContext(editor);
JavaSourceViewer viewer= (JavaSourceViewer)editor.getViewer();
viewer.setCodeMiningProviders(new ICodeMiningProvider[] {
fParameterNameCodeMiningProvider
});
waitReconciled(viewer);
//
StyledText widget= viewer.getTextWidget();
int charWidth= widget.getTextBounds(0, 1).width;
assertTrue("Code mining not available on expected chars", new DisplayHelper() {
@Override
protected boolean condition() {
return Arrays.stream(widget.getStyleRanges(widget.getText().indexOf(", 2"), 3)).anyMatch(style ->
style.metrics != null && style.metrics.width > charWidth);
}
}.waitForCondition(widget.getDisplay(), 2000));
//
viewer.doOperation(ProjectionViewer.COLLAPSE_ALL);
assertTrue("Code mining not available on expected chars after collapsing", new DisplayHelper() {
@Override
protected boolean condition() {
return Arrays.stream(widget.getStyleRanges(widget.getText().indexOf(", 2"), 3)).anyMatch(style ->
style.metrics != null && style.metrics.width > charWidth);
}
}.waitForCondition(widget.getDisplay(), 2000));
//
viewer.setSelectedRange(viewer.getDocument().get().indexOf("max") + 1, 0);
IPreferenceStore preferenceStore= JavaPlugin.getDefault().getPreferenceStore();
boolean initial= preferenceStore.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES);
try {
preferenceStore.setValue(PreferenceConstants.EDITOR_MARK_OCCURRENCES, true);
assertTrue("Occurence annotation not added", new org.eclipse.jdt.text.tests.performance.DisplayHelper() {
@Override
protected boolean condition() {
AtomicInteger annotationCount= new AtomicInteger();
viewer.getAnnotationModel().getAnnotationIterator().forEachRemaining(annotation -> {
if (annotation.getType().contains("occurrence")) {
annotationCount.incrementAndGet();
}
});
return annotationCount.get() != 0;
}
}.waitForCondition(widget.getDisplay(), 2000));
assertTrue("Code mining space at undesired offset after collapsing", new DisplayHelper() {
@Override
protected boolean condition() {
return Arrays.stream(widget.getStyleRanges())
.filter(range -> range.metrics != null && range.metrics.width > charWidth)
.allMatch(style -> {
char c= widget.getText().charAt(style.start + 1);
return c == '1' || c == '2';
});
}
}.waitForCondition(widget.getDisplay(), 2000));
} finally {
preferenceStore.setValue(PreferenceConstants.EDITOR_MARK_OCCURRENCES, initial);
}
}
private static boolean welcomeClosed;
private static void closeIntro(final IWorkbench wb) {
IWorkbenchWindow window= wb.getActiveWorkbenchWindow();
if (window != null) {
IIntroManager im= wb.getIntroManager();
IIntroPart intro= im.getIntro();
if (intro != null) {
welcomeClosed= im.closeIntro(intro);
}
}
}
}