blob: 1e11ea39556c10b7d0e70937c5b2cf918e09ab5d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019, 2020 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
*******************************************************************************/
package org.eclipse.jdt.text.tests.contentassist;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.junit.After;
import org.junit.Test;
import org.eclipse.jdt.testplugin.JavaProjectHelper;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.ui.texteditor.ContentAssistAction;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
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.JavaUI;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProcessor;
public class ContentAssistAndThreadsTest extends AbstractCompletionTest {
@After
public void resetPreference() {
JavaPlugin.getDefault().getPreferenceStore().setToDefault(PreferenceConstants.CODEASSIST_NONUITHREAD_COMPUTATION);
}
@Test
public void testComputeCompletionInNonUIThread() throws Exception {
IJavaProject fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin");
JavaProjectHelper.addRTJar(fJProject1);
IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
IPackageFragment pack1= sourceFolder.createPackageFragment("test1", false, null);
ICompilationUnit cu= pack1.createCompilationUnit("Blah.java", "", true, new NullProgressMonitor());
JavaEditor part= (JavaEditor) JavaUI.openInEditor(cu);
ContentAssistant assistant= new ContentAssistant();
assistant.setDocumentPartitioning(IJavaPartitions.JAVA_PARTITIONING);
JavaCompletionProcessor javaProcessor= new JavaCompletionProcessor(part, assistant, getContentType());
AtomicReference<Throwable> exception = new AtomicReference<>();
List<IStatus> errors = new ArrayList<>();
JavaPlugin.getDefault().getLog().addLogListener((status, plugin) -> {
if (status.getSeverity() >= IStatus.WARNING) {
errors.add(status);
}
});
Thread thread = new Thread(() -> {
try {
javaProcessor.computeCompletionProposals(part.getViewer(), 0);
// a popup can be shown and block the thread in case of error
} catch (Exception e) {
exception.set(e);
}
});
thread.start();
thread.join();
if (exception.get() != null) {
exception.get().printStackTrace();
}
assertNull(exception.get());
assertEquals(Collections.emptyList(), errors);
}
@Test
public void testLongNonUIThreadContentAssistDoesntFreezeUI() throws Exception {
JavaPlugin.getDefault().getPreferenceStore().setValue(PreferenceConstants.CODEASSIST_NONUITHREAD_COMPUTATION, true);
IJavaProject fJProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin");
JavaProjectHelper.addRTJar(fJProject1);
IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
IPackageFragment pack1= sourceFolder.createPackageFragment("test1", false, null);
ICompilationUnit cu= pack1.createCompilationUnit("Blah.java", LongCompletionProposalComputer.CONTENT_TRIGGER_STRING, true, new NullProgressMonitor());
JavaEditor part= (JavaEditor) JavaUI.openInEditor(cu);
final Set<Shell> beforeShells = Arrays.stream(part.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet());
Display display= part.getViewer().getTextWidget().getDisplay();
ContentAssistAction action = (ContentAssistAction) part.getAction(ITextEditorActionConstants.CONTENT_ASSIST);
action.update();
CheckUIThreadReactivityThread thread = new CheckUIThreadReactivityThread(display);
thread.start();
display.asyncExec(() -> action.run()); // mustn't be synchronous or CheckUIThreadReactivityTest can miss it.
try {
assertTrue("Missing completion proposal", new org.eclipse.jdt.text.tests.performance.DisplayHelper() {
@Override
protected boolean condition() {
Set<Shell> newShells = Arrays.stream(part.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet());
newShells.removeAll(beforeShells);
if (!newShells.isEmpty()) {
Table completionTable = findCompletionSelectionControl(newShells.iterator().next());
return Arrays.stream(completionTable.getItems()).map(TableItem::getText).anyMatch(LongCompletionProposalComputer.CONTENT_TRIGGER_STRING::equals);
}
return false;
}
}.waitForCondition(display, 3000));
} finally {
thread.interrupt();
}
assertTrue("UI was frozen for " + thread.getMaxDuration(), thread.getMaxDuration() < 1000);
}
private Table findCompletionSelectionControl(Widget control) {
if (control instanceof Table) {
return (Table)control;
} else if (control instanceof Composite) {
for (Widget child : ((Composite)control).getChildren()) {
Table res = findCompletionSelectionControl(child);
if (res != null) {
return res;
}
}
}
return null;
}
}