Skip to content

Commit

Permalink
testing JUnit 5 equivalent of XpectRunner
Browse files Browse the repository at this point in the history
  • Loading branch information
trancexpress committed May 23, 2024
1 parent e27f2f2 commit 25adb74
Show file tree
Hide file tree
Showing 12 changed files with 562 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.eclipse.xpect.XpectFile;
import org.eclipse.xpect.registry.ILanguageInfo;
import org.eclipse.xpect.runner.XpectRunner;
import org.eclipse.xpect.runner.XpectTestGlobalState;

import com.google.inject.Injector;

Expand Down Expand Up @@ -67,8 +68,8 @@ protected static ResourceSet cloneResourceSet(ResourceSet rs) {
// need delegation or nothing because of "java" protocol
// result.setResourceFactoryRegistry(rs.getResourceFactoryRegistry());
result.setURIConverter(rs.getURIConverter());
if (XpectRunner.testClassloader != null) {
result.setClasspathURIContext(XpectRunner.testClassloader);
if (XpectTestGlobalState.INSTANCE.testClass() != null) {
result.setClasspathURIContext(XpectTestGlobalState.INSTANCE.testClass().getClassLoader());
result.setClasspathUriResolver(new ClassloaderClasspathUriResolver());
} else if (rs instanceof XtextResourceSet) {
XtextResourceSet xrs = (XtextResourceSet) rs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.xpect.XpectFile;
import org.eclipse.xpect.XpectJavaModel;
import org.eclipse.xpect.runner.XpectRunner;
import org.eclipse.xpect.runner.XpectTestGlobalState;
import org.eclipse.xpect.ui.internal.XpectActivator;

import com.google.inject.Injector;
Expand All @@ -40,8 +41,8 @@ public static XpectFile loadFile(IFile file) {
Injector injector = XpectActivator.getInstance().getInjector(XpectActivator.ORG_ECLIPSE_XPECT_XPECT);
XtextResourceSet rs = new XtextResourceSet();
IJavaProject javaProject = JavaCore.create(file.getProject());
if (XpectRunner.testClassloader != null) {
rs.setClasspathURIContext(XpectRunner.testClassloader);
if (XpectTestGlobalState.INSTANCE.testClass() != null) {
rs.setClasspathURIContext(XpectTestGlobalState.INSTANCE.testClass().getClassLoader());
rs.setClasspathUriResolver(new ClassloaderClasspathUriResolver());
} else if (javaProject != null && javaProject.exists()) {
rs.setClasspathURIContext(javaProject);
Expand Down
2 changes: 2 additions & 0 deletions org.eclipse.xpect/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ Require-Bundle: org.eclipse.xtext,
org.antlr.runtime;bundle-version="[3.2.0,3.2.1)",
org.apache.log4j;bundle-version="1.2.24",
org.junit;bundle-version="4.11.0";visibility:=reexport,
junit-jupiter-api;bundle-version="5.10.2";visibility:=reexport,
org.eclipse.xtext.common.types;visibility:=reexport,
org.apache.log4j;bundle-version="1.2.0";visibility:=reexport,
org.objectweb.asm;bundle-version="[9.5.0,10.0.0)";resolution:=optional
Bundle-RequiredExecutionEnvironment: JavaSE-11
Export-Package: org.eclipse.xpect,
org.eclipse.xpect.dynamic,
org.eclipse.xpect.expectation,
org.eclipse.xpect.expectation.impl;
x-friends:="org.eclipse.xpect.xtext.lib,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.eclipse.xpect.dynamic;

import java.util.stream.Stream;

import org.eclipse.xpect.XpectImport;
import org.eclipse.xpect.runner.TestTitleProvider;
import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.TestFactory;

@XpectImport(TestTitleProvider.class)
public interface IXpectDynamicTestFactory {

@TestFactory
default Stream<DynamicContainer> generateTests() {
return XpectDynamicTestFactory.xpectTests(getClass());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.eclipse.xpect.dynamic;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.xpect.XjmTestMethod;
import org.eclipse.xpect.runner.ValidatingSetup;
import org.eclipse.xpect.runner.XpectTestGlobalState;
import org.eclipse.xpect.setup.ThisTestObject;
import org.eclipse.xpect.state.Creates;
import org.eclipse.xpect.state.StateContainer;
import org.junit.jupiter.api.DynamicTest;

import com.google.common.base.Preconditions;

public class XpectDynamicTest {

private final String className;
private XjmTestMethod method;
private final StateContainer state;

public XpectDynamicTest(StateContainer state, XjmTestMethod method) {
Preconditions.checkNotNull(method);
this.className = XpectTestGlobalState.INSTANCE.testClass().getName();
this.method = method;
this.state = state;
}

@Creates
public XpectDynamicTest create() {
return this;
}

public XjmTestMethod getMethod() {
return method;
}

public StateContainer getState() {
return state;
}

public DynamicTest test() {
String testName = getName();
return DynamicTest.dynamicTest(testName, () -> runInternal());
}

public String getName() {
String testName = formatDisplayName(method.getName(), className);
return testName;
}

protected void runInternal() throws Throwable {
Object test = state.get(Object.class, ThisTestObject.class).get();
try {
try {
state.get(ValidatingSetup.class).get().validate();
} catch (Throwable e) {
throw new AssertionError("Setup validation failed", e);
}
method.getJavaMethod().invoke(test);
} catch (InvocationTargetException e) {
throw e.getCause();
} finally {
state.invalidate();
}
}

private static String formatDisplayName(String name, String className) {
return String.format("%s(%s)", name, className);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package org.eclipse.xpect.dynamic;

import java.util.List;
import java.util.stream.Stream;

import org.eclipse.emf.common.util.URI;
import org.eclipse.xpect.XjmMethod;
import org.eclipse.xpect.XjmTestMethod;
import org.eclipse.xpect.XpectFile;
import org.eclipse.xpect.XpectInvocation;
import org.eclipse.xpect.XpectJavaModel;
import org.eclipse.xpect.runner.IXpectURIProvider;
import org.eclipse.xpect.runner.TestExecutor;
import org.eclipse.xpect.setup.ThisRootTestClass;
import org.eclipse.xpect.state.Creates;
import org.eclipse.xpect.state.StateContainer;
import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicTest;

import com.google.common.collect.Lists;

public class XpectDynamicTestCase {
private Stream<DynamicTest> children;
private final StateContainer state;
private final XpectFile xpectFile;

public XpectDynamicTestCase(StateContainer state, XpectFile file) {
this.xpectFile = file;
this.state = state;
}

@Creates
public XpectDynamicTestCase create() {
return this;
}

/**
* <p>
* To run code before an Xpect test begins, extend this class and annotate the extending class with:
* {@code @org.eclipse.xpect.XpectReplace(org.eclipse.xpect.dynamic.XpectDynamicTestCase)}
* </p>
* <p>
* The extended class must then be included in the values of the annotation of the test case:
* {@code @org.eclipse.xpect.XpectImport({...class})}
* </p>
*/
public void setUp() throws Throwable {
// nothing to set up
}

/**
* <p>
* To run code after an Xpect test finishes, extend this class and annotate the extending class with:
* {@code @org.eclipse.xpect.XpectReplace(org.eclipse.xpect.dynamic.XpectDynamicTestCase)}
* </p>
* <p>
* The extended class must then be included in the values of the annotation of the test case:
* {@code @org.eclipse.xpect.XpectImport({...class})}
* </p>
*/
public void tearDown() throws Throwable {
// nothing to tear down
}

public DynamicContainer dynamicContainer() {
return DynamicContainer.dynamicContainer(getName(), getChildren());
}

protected Stream<DynamicTest> createChildren() {
List<DynamicTest> children = Lists.newArrayList();
if (xpectFile != null) {
XpectJavaModel xjm = xpectFile.getJavaModel();
for (XjmMethod method : xjm.getMethods().values())
if (method instanceof XjmTestMethod) {
DynamicTest test = createDynamicTest((XjmTestMethod) method);
if (test != null)
children.add(test);
}
for (XpectInvocation inv : xpectFile.getInvocations()) {
DynamicTest test = createDynamicTest(inv);
if (test != null)
children.add(test);
}
}
return children.stream().map(test -> wrapTest(test));
}

protected DynamicTest createDynamicTest(XjmTestMethod method) {
StateContainer childState = TestExecutor.createState(state, TestExecutor.createTestConfiguration(method));
return childState.get(XpectDynamicTest.class).get().test();
}

protected DynamicTest createDynamicTest(XpectInvocation invocation) {
StateContainer childState = TestExecutor.createState(state, TestExecutor.createXpectConfiguration(invocation));
DynamicTest test = childState.get(XpectInvocationDynamicTest.class).get().test();
return wrapTest(test);
}

protected DynamicTest wrapTest(DynamicTest test) {
return DynamicTest.dynamicTest(test.getDisplayName(), () -> {
setUp();
try {
test.getExecutable().execute();
} finally {
try {
state.invalidate();
} finally {
tearDown();
}
}
});
}

protected Stream<DynamicTest> getChildren() {
if (children == null)
children = createChildren();
return children;
}

public Class<?> getJavaTestClass() {
return state.get(Class.class, ThisRootTestClass.class).get();
}

public IXpectURIProvider getURIProvider() {
return state.get(IXpectURIProvider.class).get();
}

public StateContainer getState() {
return state;
}

public URI getUri() {
return xpectFile.eResource().getURI();
}

public XpectFile getXpectFile() {
return xpectFile;
}

public String getName() {
IXpectURIProvider uriProvider = getURIProvider();
URI uri = getUri();
URI deresolved = uriProvider.deresolveToProject(uri);
String pathInProject = deresolved.trimSegments(1).toString();
String fileName = deresolved.lastSegment();
return fileName + ": " + pathInProject;
}
}
Loading

0 comments on commit 25adb74

Please sign in to comment.