Added JUnit5 framework.
This commit is contained in:
parent
eb4552fa83
commit
1dc418ae84
10
.travis.yml
Normal file
10
.travis.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
language: java
|
||||||
|
jdk:
|
||||||
|
- openjdk11
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- chmod +x gradlew
|
||||||
|
- chmod +x gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
script:
|
||||||
|
- ./gradlew clean test jacocoTestReport coveralls
|
@ -0,0 +1,141 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
|
||||||
|
import com.intellij.openapi.Disposable;
|
||||||
|
import com.intellij.openapi.util.Disposer;
|
||||||
|
import com.intellij.testFramework.EdtTestUtilKt;
|
||||||
|
import com.intellij.testFramework.TestLoggerFactory;
|
||||||
|
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
|
||||||
|
import com.intellij.testFramework.fixtures.CodeInsightTestFixture;
|
||||||
|
import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.junit.jupiter.api.extension.*;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class LightCodeInsightExtension implements ParameterResolver, AfterTestExecutionCallback, InvocationInterceptor {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(LightCodeInsightExtension.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||||
|
Parameter parameter = parameterContext.getParameter();
|
||||||
|
return parameter.isAnnotationPresent(MyFixture.class)
|
||||||
|
|| parameter.isAnnotationPresent(MyTestCase.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||||
|
LightCodeInsightFixtureTestCaseWrapper testCase = getWrapper(extensionContext);
|
||||||
|
Parameter parameter = parameterContext.getParameter();
|
||||||
|
if (parameter.isAnnotationPresent(MyFixture.class)) return testCase.getMyFixture();
|
||||||
|
else if (parameter.isAnnotationPresent(MyTestCase.class)) return testCase;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LightCodeInsightFixtureTestCaseWrapper getWrapper(ExtensionContext extensionContext) {
|
||||||
|
Store store = getStore(extensionContext);
|
||||||
|
return (LightCodeInsightFixtureTestCaseWrapper) store.getOrComputeIfAbsent("testCase",
|
||||||
|
key -> {
|
||||||
|
LightCodeInsightFixtureTestCaseWrapper wrapper = new LightCodeInsightFixtureTestCaseWrapper(extensionContext);
|
||||||
|
try {
|
||||||
|
wrapper.setUp();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.severe("Exception during setUp(): " + e);
|
||||||
|
throw new IllegalStateException("Exception during setUp()", e);
|
||||||
|
}
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTestExecution(ExtensionContext context) throws Exception {
|
||||||
|
Store store = getStore(context);
|
||||||
|
LightCodeInsightFixtureTestCaseWrapper testCase = (LightCodeInsightFixtureTestCaseWrapper) store.get("testCase");
|
||||||
|
if (testCase != null) testCase.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Store getStore(ExtensionContext context) {
|
||||||
|
return context.getStore(Namespace.create(LightCodeInsightExtension.class, context.getRequiredTestMethod()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
|
||||||
|
Throwable[] throwables = new Throwable[1];
|
||||||
|
|
||||||
|
Runnable runnable = () -> {
|
||||||
|
try {
|
||||||
|
TestLoggerFactory.onTestStarted();
|
||||||
|
invocation.proceed();
|
||||||
|
TestLoggerFactory.onTestFinished(true);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
TestLoggerFactory.onTestFinished(false);
|
||||||
|
throwables[0] = e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
invokeTestRunnable(runnable);
|
||||||
|
|
||||||
|
if (throwables[0] != null) throw throwables[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void invokeTestRunnable(@NotNull Runnable runnable) {
|
||||||
|
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
|
||||||
|
if (policy != null && !policy.runInDispatchThread()) runnable.run();
|
||||||
|
else EdtTestUtilKt.runInEdtAndWait(() -> {
|
||||||
|
runnable.run();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LightCodeInsightFixtureTestCaseWrapper extends BasePlatformTestCase {
|
||||||
|
private final ExtensionContext extensionContext;
|
||||||
|
|
||||||
|
private LightCodeInsightFixtureTestCaseWrapper(ExtensionContext extensionContext) {
|
||||||
|
this.extensionContext = extensionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
Store store = getStore(extensionContext);
|
||||||
|
store.put("disposable", Disposer.newDisposable("LightCodeInsightFixtureTestCaseWrapper"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
Store store = getStore(extensionContext);
|
||||||
|
Disposable disposable = (Disposable) store.get("disposable");
|
||||||
|
if (myFixture != null && disposable != null) {
|
||||||
|
Disposer.dispose(disposable);
|
||||||
|
store.remove("disposable");
|
||||||
|
}
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTestDataPath() {
|
||||||
|
TestDataPath testDataPath = getMethodOrClassAnnotation(TestDataPath.class);
|
||||||
|
if (testDataPath == null) return super.getTestDataPath();
|
||||||
|
TestDataSubPath testDataSubPath = getMethodOrClassAnnotation(TestDataSubPath.class);
|
||||||
|
if (testDataSubPath == null) return testDataPath.value();
|
||||||
|
return Paths.get(testDataPath.value(), testDataSubPath.value()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CodeInsightTestFixture getMyFixture() {
|
||||||
|
return myFixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Annotation> T getMethodOrClassAnnotation(Class<T> clazz) {
|
||||||
|
T annotation = extensionContext.getRequiredTestMethod().getAnnotation(clazz);
|
||||||
|
if (annotation == null) annotation = extensionContext.getRequiredTestClass().getAnnotation(clazz);
|
||||||
|
return annotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/test/java/de/platon42/intellij/jupiter/MyFixture.java
Normal file
11
src/test/java/de/platon42/intellij/jupiter/MyFixture.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.PARAMETER)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface MyFixture {
|
||||||
|
}
|
14
src/test/java/de/platon42/intellij/jupiter/MyParser.java
Normal file
14
src/test/java/de/platon42/intellij/jupiter/MyParser.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
import com.intellij.lang.ParserDefinition;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
public @interface MyParser {
|
||||||
|
Class<? extends ParserDefinition> value();
|
||||||
|
|
||||||
|
String extension();
|
||||||
|
}
|
11
src/test/java/de/platon42/intellij/jupiter/MyTestCase.java
Normal file
11
src/test/java/de/platon42/intellij/jupiter/MyTestCase.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.PARAMETER)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface MyTestCase {
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
public @interface ParserResultFile {
|
||||||
|
String value();
|
||||||
|
}
|
@ -0,0 +1,232 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
|
||||||
|
import com.intellij.lang.ParserDefinition;
|
||||||
|
import com.intellij.openapi.Disposable;
|
||||||
|
import com.intellij.openapi.util.Disposer;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import com.intellij.testFramework.EdtTestUtilKt;
|
||||||
|
import com.intellij.testFramework.ParsingTestCase;
|
||||||
|
import com.intellij.testFramework.TestLoggerFactory;
|
||||||
|
import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.junit.jupiter.api.extension.*;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class ParsingTestExtension implements ParameterResolver, AfterTestExecutionCallback, InvocationInterceptor {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(ParsingTestExtension.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||||
|
Parameter parameter = parameterContext.getParameter();
|
||||||
|
return parameter.isAnnotationPresent(MyTestCase.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||||
|
ParsingTestCaseWrapper testCase = getWrapper(extensionContext);
|
||||||
|
Parameter parameter = parameterContext.getParameter();
|
||||||
|
if (parameter.isAnnotationPresent(MyTestCase.class)) {
|
||||||
|
return testCase;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParsingTestCaseWrapper getWrapper(ExtensionContext extensionContext) {
|
||||||
|
Store store = getStore(extensionContext);
|
||||||
|
return (ParsingTestCaseWrapper) store.getOrComputeIfAbsent("testCase",
|
||||||
|
key -> {
|
||||||
|
MyParser myParser = extensionContext.getRequiredTestClass().getAnnotation(MyParser.class);
|
||||||
|
ParserDefinition parserDefinition;
|
||||||
|
try {
|
||||||
|
parserDefinition = myParser.value().getDeclaredConstructor().newInstance();
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) {
|
||||||
|
throw new RuntimeException("Could not instantiate ParserDefinition!", ex);
|
||||||
|
}
|
||||||
|
ParsingTestCaseWrapper wrapper = new ParsingTestCaseWrapper(extensionContext, myParser.extension(), parserDefinition);
|
||||||
|
try {
|
||||||
|
wrapper.setUp();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.severe("Exception during setUp(): " + e);
|
||||||
|
throw new IllegalStateException("Exception during setUp()", e);
|
||||||
|
}
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTestExecution(ExtensionContext context) throws Exception {
|
||||||
|
Store store = getStore(context);
|
||||||
|
ParsingTestCaseWrapper testCase = (ParsingTestCaseWrapper) store.get("testCase");
|
||||||
|
if (testCase != null) {
|
||||||
|
testCase.tearDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Store getStore(ExtensionContext context) {
|
||||||
|
return context.getStore(Namespace.create(ParsingTestExtension.class, context.getRequiredTestMethod()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
|
||||||
|
Throwable[] throwables = new Throwable[1];
|
||||||
|
|
||||||
|
Runnable runnable = () -> {
|
||||||
|
try {
|
||||||
|
TestLoggerFactory.onTestStarted();
|
||||||
|
invocation.proceed();
|
||||||
|
TestLoggerFactory.onTestFinished(true);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
TestLoggerFactory.onTestFinished(false);
|
||||||
|
throwables[0] = e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
invokeTestRunnable(runnable);
|
||||||
|
|
||||||
|
if (throwables[0] != null) {
|
||||||
|
throw throwables[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void invokeTestRunnable(@NotNull Runnable runnable) {
|
||||||
|
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
|
||||||
|
if (policy != null && !policy.runInDispatchThread()) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
EdtTestUtilKt.runInEdtAndWait(() -> {
|
||||||
|
runnable.run();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IParsingTestCase {
|
||||||
|
void ensureNoErrorElements();
|
||||||
|
|
||||||
|
void doTest(boolean checkResult);
|
||||||
|
|
||||||
|
void doTest(boolean checkResult, boolean ensureNoErrorElements);
|
||||||
|
|
||||||
|
PsiFile parseFile(String name, String text);
|
||||||
|
|
||||||
|
void doCodeTest(@NotNull String code) throws IOException;
|
||||||
|
|
||||||
|
PsiFile getFile();
|
||||||
|
|
||||||
|
void ensureCorrectReparse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ParsingTestCaseWrapper extends ParsingTestCase implements IParsingTestCase {
|
||||||
|
private ExtensionContext extensionContext;
|
||||||
|
private static ExtensionContext extensionContextHack;
|
||||||
|
|
||||||
|
private ParsingTestCaseWrapper(ExtensionContext extensionContext, String extension, ParserDefinition parserDefinition) {
|
||||||
|
super(passthroughInitHack(extensionContext), extension, parserDefinition);
|
||||||
|
this.extensionContext = extensionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String passthroughInitHack(ExtensionContext extensionContext) {
|
||||||
|
extensionContextHack = extensionContext;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
Store store = getStore(extensionContext);
|
||||||
|
store.put("disposable", Disposer.newDisposable("ParsingTestCaseWrapper"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
Store store = getStore(extensionContext);
|
||||||
|
Disposable disposable = (Disposable) store.get("disposable");
|
||||||
|
if (disposable != null) {
|
||||||
|
Disposer.dispose(disposable);
|
||||||
|
store.remove("disposable");
|
||||||
|
}
|
||||||
|
super.tearDown(); // Clears fields!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
String testname = extensionContext.getDisplayName().replace(" ", "_");
|
||||||
|
ParserResultFile parserResultFile = extensionContext.getRequiredTestMethod().getAnnotation(ParserResultFile.class);
|
||||||
|
if (parserResultFile != null) {
|
||||||
|
testname = parserResultFile.value();
|
||||||
|
}
|
||||||
|
return testname;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTestDataPath() {
|
||||||
|
if (extensionContext == null) // Method is called by super-constructor, damnit!
|
||||||
|
{
|
||||||
|
extensionContext = extensionContextHack;
|
||||||
|
}
|
||||||
|
TestDataPath testDataPath = getMethodOrClassAnnotation(TestDataPath.class);
|
||||||
|
if (testDataPath == null) {
|
||||||
|
return super.getTestDataPath();
|
||||||
|
}
|
||||||
|
TestDataSubPath testDataSubPath = getMethodOrClassAnnotation(TestDataSubPath.class);
|
||||||
|
if (testDataSubPath == null) {
|
||||||
|
return testDataPath.value();
|
||||||
|
}
|
||||||
|
return Paths.get(testDataPath.value(), testDataSubPath.value()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Annotation> T getMethodOrClassAnnotation(Class<T> clazz) {
|
||||||
|
T annotation = extensionContext.getRequiredTestMethod().getAnnotation(clazz);
|
||||||
|
if (annotation == null) {
|
||||||
|
annotation = extensionContext.getRequiredTestClass().getAnnotation(clazz);
|
||||||
|
}
|
||||||
|
return annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ensureNoErrorElements() {
|
||||||
|
super.ensureNoErrorElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doTest(boolean checkResult) {
|
||||||
|
super.doTest(checkResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doTest(boolean checkResult, boolean ensureNoErrorElements) {
|
||||||
|
super.doTest(checkResult, ensureNoErrorElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiFile parseFile(String name, String text) {
|
||||||
|
return super.parseFile(name, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doCodeTest(@NotNull String code) throws IOException {
|
||||||
|
super.doCodeTest(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiFile getFile() {
|
||||||
|
return myFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ensureCorrectReparse() {
|
||||||
|
ensureCorrectReparse(myFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/test/java/de/platon42/intellij/jupiter/TestDataPath.java
Normal file
10
src/test/java/de/platon42/intellij/jupiter/TestDataPath.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
public @interface TestDataPath {
|
||||||
|
String value();
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package de.platon42.intellij.jupiter;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
public @interface TestDataSubPath {
|
||||||
|
String value();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user