diff options
author | Stephan Wahlbrink | 2019-12-02 14:31:12 +0000 |
---|---|---|
committer | Mickael Istria | 2019-12-03 16:34:17 +0000 |
commit | ba8184ce0177f0bd80b2c7c049df6b5eb2ff91c6 (patch) | |
tree | 27efc955c66875af9b30cb74fecab52980ba4427 | |
parent | 6b2a33e6a69a6661649601cc07e72e2ceb494ca7 (diff) | |
download | eclipse.platform.text-ba8184ce0177f0bd80b2c7c049df6b5eb2ff91c6.tar.gz eclipse.platform.text-ba8184ce0177f0bd80b2c7c049df6b5eb2ff91c6.tar.xz eclipse.platform.text-ba8184ce0177f0bd80b2c7c049df6b5eb2ff91c6.zip |
Bug 553622: Add tests for context information to jface.text.tests
Change-Id: I35d5ee744a0df394dfa8288b40e6d5b8a3c633fb
Signed-off-by: Stephan Wahlbrink <sw@wahlbrink.eu>
5 files changed, 591 insertions, 0 deletions
diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java index 1a315f14078..08104d53c8b 100644 --- a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java @@ -20,6 +20,8 @@ import org.junit.runners.Suite.SuiteClasses; import org.eclipse.jface.text.tests.codemining.CodeMiningProjectionViewerTest; import org.eclipse.jface.text.tests.codemining.CodeMiningTest; import org.eclipse.jface.text.tests.contentassist.AsyncContentAssistTest; +import org.eclipse.jface.text.tests.contentassist.ContextInformationPresenterTest; +import org.eclipse.jface.text.tests.contentassist.ContextInformationTest; import org.eclipse.jface.text.tests.contentassist.FilteringAsyncContentAssistTests; import org.eclipse.jface.text.tests.reconciler.AbstractReconcilerTest; import org.eclipse.jface.text.tests.rules.DefaultPartitionerTest; @@ -51,6 +53,8 @@ import org.eclipse.jface.text.tests.templates.persistence.TemplatePersistenceDat DefaultPairMatcherTest2.class, AsyncContentAssistTest.class, FilteringAsyncContentAssistTests.class, + ContextInformationTest.class, + ContextInformationPresenterTest.class, AbstractReconcilerTest.class, diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/AbstractContentAssistTest.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/AbstractContentAssistTest.java new file mode 100644 index 00000000000..c6692817b12 --- /dev/null +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/AbstractContentAssistTest.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2019 Stephan Wahlbrink 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: + * Stephan Wahlbrink <sw@wahlbrink.eu> + *******************************************************************************/ + +package org.eclipse.jface.text.tests.contentassist; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.After; +import org.junit.Assert; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.contentassist.ContentAssistant; +import org.eclipse.jface.text.contentassist.IContentAssistant; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.text.source.SourceViewerConfiguration; +import org.eclipse.jface.text.tests.util.DisplayHelper; + + +public class AbstractContentAssistTest { + + + private Shell shell; + private SourceViewer viewer; + private ContentAssistant assistant; + private Document document; + + + public AbstractContentAssistTest() { + } + + + @After + public void close() { + if (shell != null && !shell.isDisposed()) { + shell.close(); + } + } + + + protected void setupSourceViewer(ContentAssistant contentAssistant, String initialText) { + shell= new Shell(); + shell.setSize(500, 240); + shell.setLayout(new FillLayout()); + + viewer= new SourceViewer(shell, null, SWT.NONE); + assistant= contentAssistant; + viewer.configure(createSourceViewerConfiguration()); + + document= new Document(); + if (initialText != null) { + document.set(initialText); + } + viewer.setDocument(document); + + shell.open(); + Assert.assertTrue(new DisplayHelper() { + @Override + protected boolean condition() { + return viewer.getTextWidget().isVisible(); + } + }.waitForCondition(shell.getDisplay(), 3000)); + } + + protected SourceViewerConfiguration createSourceViewerConfiguration() { + return new SourceViewerConfiguration() { + @Override + public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { + return AbstractContentAssistTest.this.getContentAssistant(); + } + }; + } + + protected SourceViewer getSourceViewer() { + return viewer; + } + + protected Document getDocument() { + return document; + } + + protected ContentAssistant getContentAssistant() { + return assistant; + } + + protected void selectAndReveal(int selectionStart, int selectionLength) { + StyledText widget= viewer.getTextWidget(); + widget.setRedraw(false); + + viewer.revealRange(selectionStart, selectionLength); + viewer.setSelectedRange(selectionStart, selectionLength); + + widget.setRedraw(true); + } + + protected void postSourceViewerKeyEvent(int keyCode, int stateMask, int type) { + processEvents(); + Event event= new Event(); + event.type= type; + event.widget= viewer.getTextWidget(); + event.display= viewer.getTextWidget().getDisplay(); + event.keyCode= keyCode; + event.stateMask= stateMask; + event.doit= true; + viewer.getTextWidget().notifyListeners(type, event); + processEvents(); + } + + protected void runTextOperation(int operation) { + ITextOperationTarget textOperationTarget= viewer.getTextOperationTarget(); + + assertTrue(textOperationTarget.canDoOperation(operation)); + textOperationTarget.doOperation(operation); + } + + protected void triggerContextInformation() { + runTextOperation(ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); + } + + + protected void processEvents() { + DisplayHelper.driveEventQueue(shell.getDisplay()); + } + + protected List<Shell> getCurrentShells() { + return Arrays.stream(shell.getDisplay().getShells()) + .filter(Shell::isVisible) + .collect(Collectors.toList()); + } + + protected List<Shell> findNewShells(Collection<Shell> beforeShells) { + return Arrays.stream(shell.getDisplay().getShells()) + .filter(Shell::isVisible) + .filter(shell -> !beforeShells.contains(shell)) + .collect(Collectors.toList()); + } + + protected Shell findNewShell(Collection<Shell> beforeShells) { + DisplayHelper.sleep(shell.getDisplay(), 100); + List<Shell> afterShells= findNewShells(beforeShells); + if (afterShells.isEmpty()) { + DisplayHelper.sleep(shell.getDisplay(), 1000); + } + afterShells= findNewShells(beforeShells); + assertEquals("No new shell found", 1, afterShells.size()); + return afterShells.get(0); + } + +} diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/BarContentAssistProcessor.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/BarContentAssistProcessor.java new file mode 100644 index 00000000000..0cced65d683 --- /dev/null +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/BarContentAssistProcessor.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2016, 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.) + * Stephan Wahlbrink <sw@wahlbrink.eu> - Bug 512251 - Fix IllegalArgumentException in ContextInformationPopup + *******************************************************************************/ + +package org.eclipse.jface.text.tests.contentassist; + +import java.util.Arrays; + +import org.eclipse.swt.graphics.Image; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.CompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.IContentAssistProcessor; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformationExtension; +import org.eclipse.jface.text.contentassist.IContextInformationValidator; + + +public class BarContentAssistProcessor implements IContentAssistProcessor { + + public static final String PROPOSAL= "bars are good for a beer."; + + protected static class BarContextInformation implements IContextInformation, IContextInformationExtension { + + private String contextDisplayString; + + private String informationDisplayString; + + private int offset; + + public BarContextInformation(String contextDisplayString, String informationDisplayString, int offset) { + this.contextDisplayString= contextDisplayString; + this.informationDisplayString= informationDisplayString; + this.offset= offset; + } + + @Override + public String getContextDisplayString() { + return contextDisplayString; + } + + @Override + public Image getImage() { + return null; + } + + @Override + public String getInformationDisplayString() { + return informationDisplayString; + } + + @Override + public int getContextInformationPosition() { + return offset; + } + + } + + protected static class ContextInformationValidator implements IContextInformationValidator { + + protected BarContextInformation info; + + protected ITextViewer viewer; + + protected int offset; + + @Override + public void install(IContextInformation info, ITextViewer viewer, int offset) { + if (info instanceof BarContextInformation) { + this.info= (BarContextInformation) info; + } + this.viewer= viewer; + this.offset= offset; + } + + @Override + public boolean isContextInformationValid(int offset) { + if (this.info == null) { + return false; + } + try { + IDocument document= viewer.getDocument(); + IRegion line= document.getLineInformationOfOffset(this.offset); + int end= line.getOffset() + line.getLength(); + return (offset >= this.offset && offset < end); + } catch (BadLocationException e) { + return false; + } + } + } + + + private final String completeString; + + public BarContentAssistProcessor() { + this(PROPOSAL); + } + + public BarContentAssistProcessor(String completeString) { + this.completeString= completeString; + } + + @Override + public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { + for (int offsetInProposal= Math.min(this.completeString.length(), viewer.getDocument().getLength()); offsetInProposal > 0; offsetInProposal--) { + String maybeMatchingString= this.completeString.substring(0, offsetInProposal); + try { + int lastIndex= offset - offsetInProposal + this.completeString.length(); + if (offset >= offsetInProposal && viewer.getDocument().get(offset - offsetInProposal, maybeMatchingString.length()).equals(maybeMatchingString)) { + CompletionProposal proposal= new CompletionProposal(this.completeString.substring(offsetInProposal), offset, 0, lastIndex); + return new ICompletionProposal[] { proposal }; + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + return new ICompletionProposal[0]; + } + + @Override + public char[] getCompletionProposalAutoActivationCharacters() { + return null; + } + + @Override + public char[] getContextInformationAutoActivationCharacters() { + return null; + } + + /** + * Creates context info "idx= <word index in #PROPOSAL>" at the end of a word. + **/ + @Override + public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { + try { + IDocument document= viewer.getDocument(); + int wordBegin= offset; + while (wordBegin > 0 && Character.isLetterOrDigit(document.getChar(wordBegin - 1))) { + wordBegin--; + } + if (wordBegin < offset) { + String word= document.get(wordBegin, offset - wordBegin); + int wordIdx= Arrays.asList(completeString.split("\\W")).indexOf(word); + if (wordIdx >= 0) { + return new IContextInformation[] { + new BarContextInformation(word, "idx= " + wordIdx, wordBegin) + }; + } + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public IContextInformationValidator getContextInformationValidator() { + return new ContextInformationValidator(); + } + + @Override + public String getErrorMessage() { + return null; + } + +} diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/ContextInformationPresenterTest.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/ContextInformationPresenterTest.java new file mode 100644 index 00000000000..80b8cefc0d1 --- /dev/null +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/ContextInformationPresenterTest.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2017, 2019 Stephan Wahlbrink 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: + * Stephan Wahlbrink <sw@wahlbrink.eu> + *******************************************************************************/ +package org.eclipse.jface.text.tests.contentassist; + +import static org.eclipse.jface.text.tests.contentassist.ContextInformationTest.getInfoText; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.contentassist.ContentAssistant; +import org.eclipse.jface.text.contentassist.IContextInformationPresenter; +import org.eclipse.jface.text.contentassist.IContextInformationValidator; + + +public class ContextInformationPresenterTest extends AbstractContentAssistTest { + + private static class ValidatorWithPresenter extends BarContentAssistProcessor.ContextInformationValidator + implements IContextInformationPresenter { + + private boolean isStyled; + + /** + * Hightlight (bold) "idx" if caret is inside the word (including end) + */ + @Override + public boolean updatePresentation(int offset, TextPresentation presentation) { + if (info == null) { // Ignore unknown information + return false; + } + + int begin= info.getContextInformationPosition(); + int end= begin + info.getContextDisplayString().length(); + boolean style= (offset >= begin && offset <= end); + if (style == isStyled) { + return false; + } + if (style) { + presentation.clear(); + presentation.addStyleRange(new StyleRange(0, 3, null, null, SWT.BOLD)); + } else { + presentation.clear(); + } + isStyled= style; + return true; + } + + } + + + private Shell infoShell; + + + private ContentAssistant createBarContentAssist() { + ContentAssistant contentAssistant= new ContentAssistant(); + contentAssistant.setContentAssistProcessor(new BarContentAssistProcessor() { + @Override + public IContextInformationValidator getContextInformationValidator() { + return new ValidatorWithPresenter(); + } + }, IDocument.DEFAULT_CONTENT_TYPE); + return contentAssistant; + } + + @Test + public void testContextInfo_withStyledTextPresentation() throws Exception { + setupSourceViewer(createBarContentAssist(), BarContentAssistProcessor.PROPOSAL); + + final List<Shell> beforeShells= getCurrentShells(); + + postSourceViewerKeyEvent(SWT.ARROW_RIGHT, 0, SWT.KeyDown); + selectAndReveal(4, 0); + processEvents(); + + triggerContextInformation(); + this.infoShell= findNewShell(beforeShells); + assertEquals("idx= 0", getInfoText(this.infoShell)); + assertArrayEquals(new StyleRange[] { + new StyleRange(0, 3, null, null, SWT.BOLD) + }, getInfoStyleRanges(this.infoShell)); + + postSourceViewerKeyEvent(SWT.ARROW_RIGHT, 0, SWT.KeyDown); + + assertEquals("idx= 0", getInfoText(this.infoShell)); + assertArrayEquals(new StyleRange[] { + }, getInfoStyleRanges(this.infoShell)); + } + + + static StyleRange[] getInfoStyleRanges(final Shell shell) { + assertTrue(shell.isVisible()); + Control[] children= shell.getChildren(); + for (Control child : children) { + if (child instanceof Text) { + return null; + } + if (child instanceof StyledText) { + return ((StyledText) child).getStyleRanges(); + } + } + return null; + } + +} diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/ContextInformationTest.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/ContextInformationTest.java new file mode 100644 index 00000000000..1d5d6afa85e --- /dev/null +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/contentassist/ContextInformationTest.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2017, 2019 Stephan Wahlbrink 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: + * Stephan Wahlbrink <sw@wahlbrink.eu> + *******************************************************************************/ +package org.eclipse.jface.text.tests.contentassist; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import org.eclipse.text.tests.Accessor; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.contentassist.ContentAssistant; + + +public class ContextInformationTest extends AbstractContentAssistTest { + + + private Shell infoShell; + + + private ContentAssistant createBarContentAssist() { + ContentAssistant contentAssistant= new ContentAssistant(); + contentAssistant.setContentAssistProcessor(new BarContentAssistProcessor(), IDocument.DEFAULT_CONTENT_TYPE); + return contentAssistant; + } + + @Test + public void testContextInfo() throws Exception { + setupSourceViewer(createBarContentAssist(), BarContentAssistProcessor.PROPOSAL); + + final List<Shell> beforeShells= getCurrentShells(); + + selectAndReveal(4, 0); + processEvents(); + + triggerContextInformation(); + this.infoShell= findNewShell(beforeShells); + assertEquals("idx= 0", getInfoText(this.infoShell)); + + selectAndReveal(8, 0); + processEvents(); + + triggerContextInformation(); + this.infoShell= findNewShell(beforeShells); + assertEquals("idx= 1", getInfoText(this.infoShell)); + } + + @Test + public void testContextInfo_hide_Bug512251() throws Exception { + setupSourceViewer(createBarContentAssist(), BarContentAssistProcessor.PROPOSAL); + + final List<Shell> beforeShells= getCurrentShells(); + + selectAndReveal(4, 0); + processEvents(); + + triggerContextInformation(); + this.infoShell= findNewShell(beforeShells); + + selectAndReveal(8, 0); + processEvents(); + + triggerContextInformation(); + this.infoShell= findNewShell(beforeShells); + + // ITextEditorActionConstants.DELETE_LINE + getDocument().set(""); + + new Accessor(getContentAssistant(), ContentAssistant.class).invoke("hide", new Object[0]); + } + + + static String getInfoText(final Shell shell) { + assertTrue(shell.isVisible()); + Control[] children= shell.getChildren(); + for (Control child : children) { + if (child instanceof Text) { + return ((Text) child).getText(); + } + if (child instanceof StyledText) { + return ((StyledText) child).getText(); + } + } + return null; + } + +} |