blob: 513a88427e41013d425b2024f307d5a652fdfd4a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018, 2020 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.text.tests.codemining;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.eclipse.jdt.testplugin.JavaProjectHelper;
import org.eclipse.jdt.text.tests.performance.DisplayHelper;
import org.eclipse.swt.widgets.Display;
import org.eclipse.core.expressions.PropertyTester;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.internal.text.codemining.CodeMiningLineHeaderAnnotation;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.codemining.ICodeMining;
import org.eclipse.jface.text.codemining.ICodeMiningProvider;
import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.ISourceViewerExtension5;
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.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
@SuppressWarnings("unchecked")
public class CodeMiningTriggerTest {
private IPreferenceStore fPreferenceStore;
private boolean wasCodeMiningEnabled;
private IJavaProject fJavaProject;
private IPackageFragment pack;
public static class TestCodeMiningProvider implements ICodeMiningProvider {
static boolean isOn = false;
@Override
public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) {
try {
TestCodeMining cm = new TestCodeMining(0, viewer.getDocument(), this);
return CompletableFuture.completedFuture(Collections.singletonList(cm));
} catch (BadLocationException e) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
}
@Override
public void dispose() {
// nothing
}
}
static class TestCodeMining extends LineHeaderCodeMining {
static String codeMiningText = "Default Code Mining";
public TestCodeMining(int beforeLineNumber, IDocument document, ICodeMiningProvider provider) throws BadLocationException {
super(beforeLineNumber, document, provider);
setLabel(codeMiningText);
}
}
public static class TestCodeMiningProviderPropertyTester extends PropertyTester {
@Override
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
if ("isOn".equals(property)) {
return TestCodeMiningProvider.isOn;
}
return false;
}
}
@Before
public void setUp() throws CoreException {
fPreferenceStore= JavaPlugin.getDefault().getPreferenceStore();
this.wasCodeMiningEnabled = fPreferenceStore.getBoolean(PreferenceConstants.EDITOR_CODEMINING_ENABLED);
fPreferenceStore.setValue(PreferenceConstants.EDITOR_CODEMINING_ENABLED, true);
fJavaProject= JavaProjectHelper.createJavaProject(getClass().getName(), "bin");
IPackageFragmentRoot root= JavaProjectHelper.addSourceContainer(fJavaProject, "src");
pack= root.createPackageFragment("testA.testB", true, null);
TestCodeMiningProvider.isOn = true;
}
@After
public void tearDown() {
TestCodeMiningProvider.isOn = false;
this.fPreferenceStore.setValue(PreferenceConstants.EDITOR_CODEMINING_ENABLED, wasCodeMiningEnabled);
}
@Test
public void testPullCodeMining() throws Exception {
String contents= "public class Foo {\n" +
" int ab, ba;\n" +
" void m() {\n" +
" }\n" +
"}\n";
ICompilationUnit compilationUnit= pack.createCompilationUnit("Foo.java", contents, true, new NullProgressMonitor());
JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(compilationUnit);
disableCodeMiningReconciler(editor);
assertCodeMiningAnnotation(editor.getViewer(), TestCodeMining.codeMiningText, 1000);
TestCodeMining.codeMiningText = "Some other code mining";
((ISourceViewerExtension5)editor.getViewer()).updateCodeMinings();
assertCodeMiningAnnotation(editor.getViewer(), TestCodeMining.codeMiningText, 1000);
}
/**
* Disables Java reconciler (after AST is parsed) but keeps the default code mining
* mechanics working.
* @param editor
* @throws NoSuchMethodException
* @throws IllegalAccessException
* @throws InvocationTargetException
*
*/
private void disableCodeMiningReconciler(JavaEditor editor) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Method method = JavaEditor.class.getDeclaredMethod("uninstallJavaCodeMining");
method.setAccessible(true);
method.invoke(editor);
}
private void assertCodeMiningAnnotation(ISourceViewer viewer, String message, int timeout) throws Exception {
assertTrue("Cannot find CodeMining header line annotation with text `" + message + "`",
new DisplayHelper() {
@Override
protected boolean condition() {
for (Iterator<Annotation> itr = viewer.getAnnotationModel().getAnnotationIterator(); itr.hasNext();) {
Annotation a = itr.next();
if (a instanceof CodeMiningLineHeaderAnnotation) {
Field f;
try {
f= CodeMiningLineHeaderAnnotation.class.getDeclaredField("fMinings");
f.setAccessible(true);
List<ICodeMining> minings = (List<ICodeMining>)f.get(a);
for (ICodeMining m : minings) {
if (m instanceof TestCodeMining) {
if (message.equals(m.getLabel())) {
return true;
}
}
}
} catch (Exception e) {
Platform.getLog(Platform.getBundle("org.eclipse.jdt.text.tests")).log(
new Status(IStatus.ERROR, "org.eclipse.jdt.text.tests", e.getMessage(), e)
);
return false;
}
}
}
return false;
}
}.waitForCondition(Display.getDefault(), timeout));
}
}