/* * $Id$ * * SARL is an general-purpose agent programming language. * More details on http://www.sarl.io * * Copyright (C) 2014-2017 the original authors or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.sarl.lang.ui.tests.contentassist; import static org.junit.Assert.assertEquals; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.google.common.collect.Lists; import com.google.inject.Binder; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.name.Named; import org.eclipse.core.resources.IFile; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.xtext.Constants; import org.eclipse.xtext.IGrammarAccess; import org.eclipse.xtext.junit4.internal.LineDelimiters; import org.eclipse.xtext.junit4.ui.ContentAssistProcessorTestBuilder; import org.eclipse.xtext.junit4.util.ResourceLoadHelper; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal; import org.eclipse.xtext.ui.editor.contentassist.ReplacementTextApplier; import org.eclipse.xtext.ui.editor.model.IXtextDocument; import org.eclipse.xtext.util.StringInputStream; import org.junit.Assert; import org.junit.ComparisonFailure; import io.sarl.lang.sarl.SarlScript; import io.sarl.tests.api.AbstractSarlUiTest; import io.sarl.tests.api.WorkbenchTestHelper; @SuppressWarnings("all") public abstract class AbstractContentAssistTest extends AbstractSarlUiTest implements ResourceLoadHelper { @Inject private IGrammarAccess access; @Override protected Module[] getInjectionModules() { final Module[] originals = super.getInjectionModules(); final Module[] newModules = Arrays.copyOf(originals, originals.length + 1); newModules[newModules.length - 1] = new Module() { @Override public void configure(Binder binder) { binder.bind(ContentAssistProcessorTestBuilder.Factory.class).to(ProcessorTestBuilderFactory.class); } }; return newModules; } @Override public final XtextResource getResourceFor(InputStream stream) { try { final StringBuilder content = new StringBuilder(); try (final InputStreamReader reader = new InputStreamReader(stream)) { final BufferedReader breader = new BufferedReader(reader); String line = breader.readLine(); while (line != null) { content.append(line); content.append(getLineSeparator()); line = breader.readLine(); } } final WorkbenchTestHelper helper = helper(); final String strContent = content.toString(); final IFile file = helper.createFile(helper.generateFilename(), strContent); final XtextResource resource = (XtextResource) helper.getResourceSet().createResource(helper.uri(file)); try (InputStream is = new StringInputStream(strContent)) { resource.load(is, null); } return resource; } catch(Exception e) { throw new RuntimeException(e); } } /** Replies the default prefix. * * <p>The prefix is appended when calling {@link #newBuilder()}. * * @return the default prefix. */ protected String getPrefix() { return ""; } /** Replies the default suffix. * * <p>The suffix is appended when calling {@link #newBuilder()}. * * @return the default suffix. */ protected String getSuffix() { return ""; } /** Create a builder for content assist tests. * * @return the builder. * @throws Exception if the builder cannot be created. */ protected final ContentAssistProcessorTestBuilder newBuilder() throws Exception { ContentAssistProcessorTestBuilder builder = new ContentAssistProcessorTestBuilder(getInjectedInjector(), this); String prefix = getPrefix(); if (prefix.length() > 0) { builder = builder.appendNl(prefix); } String suffix = getSuffix(); if (suffix.length() > 0) { builder = builder.appendSuffix(suffix); } return builder; } /** Flattening the arrays. * * @param arrays the arrays to be flattened. * @return the content of the arrays. */ protected static String[] expect(String[]... arrays) { List<String> expectation = Lists.newArrayList(); for(String[] array: arrays) { expectation.addAll(Arrays.asList(array)); } return expectation.toArray(new String[expectation.size()]); } /** Assert that all the given texts are not in the proposal. * * @param builder the proposal builder. * @param notExpectations the texts to not be proposed. * @return the builder. * @throws Exception */ protected static ContentAssistProcessorTestBuilder assertNoText(ContentAssistProcessorTestBuilder builder, String... notExpectations) throws Exception { ICompletionProposal[] computeCompletionProposals = builder.computeCompletionProposals(); if (computeCompletionProposals == null) { computeCompletionProposals = new ICompletionProposal[0]; } Arrays.sort(notExpectations); List<String> sortedNotExpectations = Lists.newArrayList(); for (String expectation : notExpectations) { sortedNotExpectations.add(LineDelimiters.toPlatform(expectation)); } for (final ICompletionProposal completionProposal : computeCompletionProposals) { String proposedText = getProposedText(completionProposal); Assert.assertFalse("Unexpected proposal '" + proposedText + "'", sortedNotExpectations.contains(proposedText)); } return builder; } /** Assert that all the given texts are in the proposal. * * <p>In opposite to {@link ContentAssistProcessorTestBuilder#assertText(String...)}, this function * is not failing if the more text than the given ones are proposed. * * @param builder the proposal builder. * @param expectations the texts to be proposed. * @return the builder. * @throws Exception */ protected static ContentAssistProcessorTestBuilder assertTextInsideProposals(ContentAssistProcessorTestBuilder builder, String... expectations) throws Exception { ICompletionProposal[] computeCompletionProposals = builder.computeCompletionProposals(); if (computeCompletionProposals == null) { computeCompletionProposals = new ICompletionProposal[0]; } Arrays.sort(expectations); final List<String> sortedExpectations = Lists.newArrayList(); for (String expectation : expectations) { sortedExpectations.add(LineDelimiters.toPlatform(expectation)); } for (final ICompletionProposal completionProposal : computeCompletionProposals) { String proposedText = getProposedText(completionProposal); sortedExpectations.remove(proposedText); } if (!sortedExpectations.isEmpty()) { String[] actual = new String[computeCompletionProposals.length]; int i = 0; for (final ICompletionProposal completionProposal : computeCompletionProposals) { String proposedText = getProposedText(completionProposal); actual[i] = proposedText; ++i; } Arrays.sort(actual); throw new ComparisonFailure("Expecting text: " + sortedExpectations.toString(), toString(expectations), toString(actual)); } return builder; } private static String toString(Object[] array) { StringBuilder buf = new StringBuilder(); if (array != null) { for (Object obj : array) { if (obj != null) { buf.append(obj); } buf.append(getLineSeparator()); } } return buf.toString(); } private static String getProposedText(ICompletionProposal completionProposal) { String proposedText = completionProposal.getDisplayString(); if (completionProposal instanceof ConfigurableCompletionProposal) { ConfigurableCompletionProposal configurableProposal = (ConfigurableCompletionProposal) completionProposal; proposedText = configurableProposal.getReplacementString(); if (configurableProposal.getTextApplier() instanceof ReplacementTextApplier) { proposedText = ((ReplacementTextApplier) configurableProposal.getTextApplier()) .getActualReplacementString(configurableProposal); } } return proposedText; } /** * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public static class ProcessorTestBuilderFactory extends ContentAssistProcessorTestBuilder.Factory { private final Injector injector; @Inject public ProcessorTestBuilderFactory(Injector injector) { super(injector); this.injector = injector; } public ContentAssistProcessorTestBuilder create(ResourceLoadHelper resourceLoadHelper) throws Exception { final ProcessorTestBuilder builder = new ProcessorTestBuilder(this.injector, resourceLoadHelper); this.injector.injectMembers(builder); return builder; } } /** * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ private static class ProcessorTestBuilder extends ContentAssistProcessorTestBuilder { @Inject private IWorkbench workbench; public ProcessorTestBuilder(Injector injector, ResourceLoadHelper helper) throws Exception { super(injector, helper); } protected Shell getShell() { if (this.workbench != null) { final IWorkbenchWindow window = this.workbench.getActiveWorkbenchWindow(); if (window != null) { return window.getShell(); } else { for (final IWorkbenchWindow window1 : this.workbench.getWorkbenchWindows()) { Shell shell = window.getShell(); if (shell != null) { return shell; } } } } return null; } private Shell ensureShell() { Shell shell; if (isEclipseRuntimeEnvironment()) { shell = getShell(); if (shell == null) { shell = new Shell(); } } else { shell = new Shell(); } return shell; } @Override protected ICompletionProposal[] computeCompletionProposals(IXtextDocument xtextDocument, int cursorPosition) throws BadLocationException { if (isEclipseRuntimeEnvironment()) { Shell shell = getShell(); if (shell != null) { return computeCompletionProposals(xtextDocument, cursorPosition, shell); } } final Display display = Display.getDefault(); final List<ICompletionProposal[]> resultBuffer = new ArrayList<>(1); final List<BadLocationException> exceptionBuffer = new ArrayList<>(1); display.syncExec(() -> { final Shell asyncShell = new Shell(display); try { final ICompletionProposal[] result = computeCompletionProposals(xtextDocument, cursorPosition, asyncShell); resultBuffer.add(result); } catch (BadLocationException exception) { exceptionBuffer.add(exception); } finally { asyncShell.dispose(); } }); if (!exceptionBuffer.isEmpty()) { throw exceptionBuffer.get(0); } return resultBuffer.get(0); } @Override public ContentAssistProcessorTestBuilder applyProposal(int position, String proposalString) throws Exception { throw new UnsupportedOperationException("must be overriden for Shell access"); } @Override public ContentAssistProcessorTestBuilder appendAndApplyProposal(String model, int position, String proposalString) throws Exception { throw new UnsupportedOperationException("must be overriden for Shell access"); } public ContentAssistProcessorTestBuilder assertMatchString(String matchString) throws Exception { throw new UnsupportedOperationException("must be overriden for Shell access"); } } }