-
Notifications
You must be signed in to change notification settings - Fork 317
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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. | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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 | ||
|
@@ -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) { | ||
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; | ||
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 Moreover, if we want to use arrays, why not using |
||
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. | ||
|
@@ -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 | ||
|
@@ -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') | ||
} | ||
|
@@ -56,7 +52,7 @@ class ContentAssistTest extends AbstractContentAssistTest { | |
entity E { | ||
«c» | ||
} | ||
'''.testContentAssistant(#[ | ||
'''.assertContentAssistant(#[ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, so, concerning my comment above about There was a problem hiding this comment. Choose a reason for hiding this commentThe 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' | ||
|
@@ -72,7 +68,7 @@ class ContentAssistTest extends AbstractContentAssistTest { | |
entity E { | ||
«c» | ||
} | ||
'''.testContentAssistant(#[ | ||
'''.assertContentAssistant(#[ | ||
'Operation - template for an Operation', | ||
'Property - template for a Property', | ||
'op' | ||
|
@@ -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) | ||
} | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Exactly.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 thecurrentModelToParse
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, if it's always been like that :)