Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#3007] Content Assistant test infrastructure improvements. #3024

Merged
merged 1 commit into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2013, 2020 itemis AG (http://www.itemis.eu) and others.
* Copyright (c) 2013, 2024 itemis AG (http://www.itemis.eu) and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
Expand All @@ -10,10 +10,12 @@

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
Expand All @@ -26,8 +28,11 @@
import org.eclipse.xtext.resource.FileExtensionProvider;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.eclipse.xtext.ui.XtextProjectHelper;
import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil;
import org.eclipse.xtext.ui.testing.util.JavaProjectSetupUtil;
import org.eclipse.xtext.ui.testing.util.ResourceLoadHelper;
import org.eclipse.xtext.util.Strings;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.jupiter.api.AfterAll;
Expand All @@ -53,11 +58,18 @@ public abstract class AbstractContentAssistTest implements ResourceLoadHelper, I
private Injector injector;

private static IJavaProject javaProject;

/**
* cursor position marker
* @since 2.35
*/
protected String c = "<|>";

@BeforeClass
@BeforeAll
public static void setUp() throws CoreException {
javaProject = JavaProjectSetupUtil.createJavaProject("contentAssistTest");
IResourcesSetupUtil.addNature(javaProject.getProject(), XtextProjectHelper.NATURE_ID);
}

@AfterClass
Expand All @@ -72,15 +84,35 @@ public XtextResource getResourceFor(InputStream stream) {
XtextResourceSet resourceSet = resourceSetProvider.get();
initializeTypeProvider(resourceSet);
try {
URI resourceUri = URI.createURI("Test." + fileExtensionProvider.getPrimaryFileExtension());
Resource resource = resourceSet.createResource(resourceUri);
String projectFullPath = javaProject.getProject().getFullPath().toString();
URI resourceUri = URI.createPlatformResourceURI(projectFullPath + "/" + getProjectRelativePath() + "/" + "Test." + fileExtensionProvider.getPrimaryFileExtension(), true);

/*
* Avoid the following java.lang.IllegalStateException:
* A different resource with the URI 'platform:/resource/contentAssistTest/Test....' was already registered.
*/
Resource resource = resourceSet.getResource(resourceUri, false);
if (resource == null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if the resource is not null, i.e., it exists, the passed input stream is not used to populate it, is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Exactly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I still don't understand... I was expecting the specified input stream to be taken into consideration and in case replace the current resource... maybe I'm still missing something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LorenzoBettini : The method getResourceFor(InputStream stream) will be called twice within each test case execution, in both cases the passed stream is created from the currentModelToParse variable. So basically it does not matter if we use the first call and ingore the second call or if we create the resource on the first call and overwrite it with the same content in the second call.

I modified the PR so that in the second call the current resource content will be replaced, as requested.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@miklossy but the question now is why is it called twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a good question, but currently I am not sure if we could fix that without any breaking change. Let's analyse it in a follow up issue :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a good question, but currently I am not sure if we could fix that without any breaking change. Let's analyse it in a follow up issue :-)

OK, if it's always been like that :)

resource = resourceSet.createResource(resourceUri);
}
resource.load(stream, null);
return (XtextResource) resource;
} catch (IOException e) {
throw new RuntimeException(e);
}
}

/**
* Returns the project relative path where the files should be created.
* The default implementation creates them directly in the src folder.
* Clients may override.
*
* @since 2.35
*/
protected String getProjectRelativePath() {
return "src";
}

@Override
public IJavaProject getJavaProject(ResourceSet resourceSet) {
return javaProject;
Expand All @@ -104,4 +136,135 @@ protected void initializeTypeProvider(XtextResourceSet resourceSet) {
resourceSet.setClasspathURIContext(getJavaProject(resourceSet));
}

/**
* Creates a dsl file.
*
* @param fileName
* The name of the file (without the file extension).
* It is also possible to customize the project relative path, see {@link #getProjectRelativePath()}.
* To use workspace relative path, use {@link IResourcesSetupUtil#createFile(String, String)} instead.
*
* @param content
* The content of the file.
*
* @since 2.35
*/
protected IFile createDslFile(String fileName, CharSequence content) {
return createDslFile(fileName, fileExtensionProvider.getPrimaryFileExtension(), content);
}

/**
* Creates a dsl file.
*
* @param fileName
* The name of the file (without the file extension).
* It is also possible to customize the project relative path, see {@link #getProjectRelativePath()}.
* To use workspace relative path, use {@link IResourcesSetupUtil#createFile(String, String)} instead.
*
* @param fileExtension
* The extension of the file.
*
* @param content
* The content of the file.
*
* @since 2.35
*/
protected IFile createDslFile(String fileName, String fileExtension, CharSequence content) {
try {
return IResourcesSetupUtil.createFile(javaProject.getElementName(), getProjectRelativePath() + "/" + fileName, fileExtension, content.toString());
} catch (InvocationTargetException | CoreException | InterruptedException e) {
throw new RuntimeException(e);
}
}

/**
* Verifies whether the content assistant provides the expected proposals on the given cursor position.
*
* @param text
* The editor's input text. The text must contain the {@link #c} special symbol indicating the current cursor position.
*
* @param expectedProposals
* The proposals (separated by new lines) that are expected to be offered whenever the content assistant is triggered on the given cursor position.
*
* @since 2.35
*/
protected void assertContentAssistant(CharSequence text, CharSequence expectedProposals) {
assertContentAssistant(text, expectedProposals, null, null);
}

/**
* Verifies whether the content assistant provides the expected proposals on the given cursor position.
*
* @param text
* The editor's input text. The text must contain the {@link #c} special symbol indicating the current cursor position.
*
* @param expectedProposals
* The proposals that are expected to be offered whenever the content assistant is triggered on the given cursor position.
*
* @since 2.35
*/
protected void assertContentAssistant(CharSequence text, String[] expectedProposals) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you removed the version with List?

That could have been useful in Xtend with #[ ... ]. Or would it work anyway thanks to conversion?

Moreover, if we want to use arrays, why not using String... expectedProposals, which would not require the creation of an array when calling this method? Would it conflict with the one accepting a String?

assertContentAssistant(text, expectedProposals, null, null);
}

/**
* Verifies whether the content assistant provides the expected proposals on the given cursor position.
* Furthermore, it applies the proposalToApply - if it is given - and verifies the expected content afterwards.
*
* @param text
* The editor's input text. The text must contain the {@link #c} special symbol indicating the current cursor position.
*
* @param expectedProposals
* The proposals (separated by new lines) that are expected to be offered whenever the content assistant is triggered on the given cursor position.
*
* @param proposalToApply
* The proposal to apply from the list of the expected proposals.
*
* @param expectedContent
* The expected editor content after the given proposal has been applied.
*
* @since 2.35
*/
protected void assertContentAssistant(CharSequence text, CharSequence expectedProposals, String proposalToApply, String expectedContent) {
String[] expectedProposalsArray = Strings.toUnixLineSeparator(expectedProposals.toString()).split("\n");
assertContentAssistant(text, expectedProposalsArray, proposalToApply, expectedContent);
}

/**
* Verifies whether the content assistant provides the expected proposals on the given cursor position.
* Furthermore, it applies the proposalToApply - if it is given - and verifies the expected content afterwards.
*
* @param text
* The editor's input text. The text must contain the {@link #c} special symbol indicating the current cursor position.
*
* @param expectedProposals
* The proposals that are expected to be offered whenever the content assistant is triggered on the given cursor position.
*
* @param proposalToApply
* The proposal to apply from the list of the expected proposals.
*
* @param expectedContent
* The expected editor content after the given proposal has been applied.
*
* @since 2.35
*/
protected void assertContentAssistant(CharSequence text, String[] expectedProposals, String proposalToApply, String expectedContent) {

int cursorPosition = text.toString().indexOf(c);
if (cursorPosition == -1) {
throw new RuntimeException("Can't locate cursor position symbols '" + c + "' in the input text.");
}

String content = text.toString().replace(c, "");

try {
ContentAssistProcessorTestBuilder builder = newBuilder().append(content).assertTextAtCursorPosition(cursorPosition, expectedProposals);

if (proposalToApply != null) {
builder.applyProposal(cursorPosition, proposalToApply).expectContent(expectedContent);
}
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright (c) 2024 itemis AG (http://www.itemis.eu) and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.xtext.ui.tests.editor.contentassist;

import org.eclipse.xtext.testing.InjectWith;
import org.eclipse.xtext.testing.XtextRunner;
import org.eclipse.xtext.ui.testing.AbstractContentAssistTest;
import org.eclipse.xtext.ui.testing.util.IResourcesSetupUtil;
import org.eclipse.xtext.ui.tests.linking.ui.tests.ImportUriUiTestLanguageUiInjectorProvider;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
* @author miklossy - Initial contribution and API
*/
@RunWith(XtextRunner.class)
@InjectWith(ImportUriUiTestLanguageUiInjectorProvider.class)
public class ContentAssistWithSeveralResourcesTest extends AbstractContentAssistTest {

@Test public void test_with_one_resource() {
assertContentAssistant("type A extends " + c, new String[]{("A")});
}

@Test public void test_with_two_resources() {
createDslFile("types", "type A extends A");
IResourcesSetupUtil.waitForBuild();
assertContentAssistant("import \"types.importuriuitestlanguage\" type B extends " + c, "A\nB");
}

@Test public void test_with_three_resources() {
createDslFile("types1", "type A extends A");
createDslFile("types2", "type B extends B");
IResourcesSetupUtil.waitForBuild();
assertContentAssistant("import \"types1.importuriuitestlanguage\" import \"types2.importuriuitestlanguage\" type C extends " + c, new String[]{"A", "B", "C"});
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012, 2019 itemis AG (http://www.itemis.eu) and others.
* Copyright (c) 2012, 2024 itemis AG (http://www.itemis.eu) and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
Expand All @@ -8,7 +8,6 @@
*******************************************************************************/
package org.eclipse.xtext.example.domainmodel.ui.tests

import java.util.List
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.XtextRunner
import org.eclipse.xtext.ui.testing.AbstractContentAssistTest
Expand All @@ -22,9 +21,6 @@ import org.junit.runner.RunWith
@InjectWith(DomainmodelUiInjectorProvider)
class ContentAssistTest extends AbstractContentAssistTest {

// cursor position marker
val c = '''<|>'''

@Test def void testImportCompletion() throws Exception {
newBuilder.append('import java.util.Da').assertText('java.util.Date')
}
Expand Down Expand Up @@ -56,7 +52,7 @@ class ContentAssistTest extends AbstractContentAssistTest {
entity E {
«c»
}
'''.testContentAssistant(#[
'''.assertContentAssistant(#[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so, concerning my comment above about String[] instead of List, this seems to work out of the box with Xtend, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Xtend automatically converts the actual parameter from array to list (and vice versa) if the formal parameter is a list/array.

'Operation - template for an Operation',
'Property - template for a Property',
'op'
Expand All @@ -72,7 +68,7 @@ class ContentAssistTest extends AbstractContentAssistTest {
entity E {
«c»
}
'''.testContentAssistant(#[
'''.assertContentAssistant(#[
'Operation - template for an Operation',
'Property - template for a Property',
'op'
Expand All @@ -84,15 +80,4 @@ class ContentAssistTest extends AbstractContentAssistTest {
}
''')
}

private def void testContentAssistant(CharSequence text, List<String> expectedProposals, String proposalToApply, String expectedContent) throws Exception {

val cursorPosition = text.toString.indexOf(c)
val content = text.toString.replace(c, "")

newBuilder.append(content).
assertTextAtCursorPosition(cursorPosition, expectedProposals).
applyProposal(cursorPosition, proposalToApply).
expectContent(expectedContent)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2012, 2019 itemis AG (http://www.itemis.eu) and others.
* Copyright (c) 2012, 2024 itemis AG (http://www.itemis.eu) and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
Expand All @@ -8,16 +8,11 @@
*/
package org.eclipse.xtext.example.domainmodel.ui.tests;

import java.util.Collections;
import java.util.List;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.testing.InjectWith;
import org.eclipse.xtext.testing.XtextRunner;
import org.eclipse.xtext.ui.testing.AbstractContentAssistTest;
import org.eclipse.xtext.ui.testing.ContentAssistProcessorTestBuilder;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.Conversions;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
import org.junit.Test;
import org.junit.runner.RunWith;

Expand All @@ -28,15 +23,6 @@
@InjectWith(DomainmodelUiInjectorProvider.class)
@SuppressWarnings("all")
public class ContentAssistTest extends AbstractContentAssistTest {
private final String c = new Function0<String>() {
@Override
public String apply() {
StringConcatenation _builder = new StringConcatenation();
_builder.append("<|>");
return _builder.toString();
}
}.apply();

@Test
public void testImportCompletion() throws Exception {
this.newBuilder().append("import java.util.Da").assertText("java.util.Date");
Expand Down Expand Up @@ -94,8 +80,8 @@ public void testPropertyTemplateProposal() throws Exception {
_builder_1.newLine();
_builder_1.append("}");
_builder_1.newLine();
this.testContentAssistant(_builder,
Collections.<String>unmodifiableList(CollectionLiterals.<String>newArrayList("Operation - template for an Operation", "Property - template for a Property", "op")), "Property - template for a Property", _builder_1.toString());
this.assertContentAssistant(_builder,
new String[] { "Operation - template for an Operation", "Property - template for a Property", "op" }, "Property - template for a Property", _builder_1.toString());
}

@Test
Expand All @@ -121,13 +107,7 @@ public void testOperationTemplateProposal() throws Exception {
_builder_1.newLine();
_builder_1.append("}");
_builder_1.newLine();
this.testContentAssistant(_builder,
Collections.<String>unmodifiableList(CollectionLiterals.<String>newArrayList("Operation - template for an Operation", "Property - template for a Property", "op")), "Operation - template for an Operation", _builder_1.toString());
}

private void testContentAssistant(final CharSequence text, final List<String> expectedProposals, final String proposalToApply, final String expectedContent) throws Exception {
final int cursorPosition = text.toString().indexOf(this.c);
final String content = text.toString().replace(this.c, "");
this.newBuilder().append(content).assertTextAtCursorPosition(cursorPosition, ((String[])Conversions.unwrapArray(expectedProposals, String.class))).applyProposal(cursorPosition, proposalToApply).expectContent(expectedContent);
this.assertContentAssistant(_builder,
new String[] { "Operation - template for an Operation", "Property - template for a Property", "op" }, "Operation - template for an Operation", _builder_1.toString());
}
}