Skip to content

Commit

Permalink
Validate KitchenSinkExtension for completeness
Browse files Browse the repository at this point in the history
  • Loading branch information
marcphilipp committed Jul 31, 2024
1 parent 2cdd597 commit e5f9509
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,22 @@
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.DynamicContainer.dynamicContainer;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import static org.junit.platform.commons.util.FunctionUtils.where;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.platform.commons.support.ModifierSupport;
import org.junit.platform.commons.util.ClassUtils;
import org.junit.platform.commons.util.ReflectionUtils;

Expand All @@ -43,8 +50,7 @@ class ExtensionComposabilityTests {
void ensureJupiterExtensionApisAreComposable() {

// 1) Find all existing top-level Extension APIs
List<Class<?>> extensionApis = ReflectionUtils.findAllClassesInPackage(Extension.class.getPackage().getName(),
this::isExtensionApi, name -> true);
List<Class<?>> extensionApis = findExtensionApis();

// 2) Determine which methods we expect the kitchen sink to implement...

Expand Down Expand Up @@ -110,6 +116,34 @@ void ensureJupiterExtensionApisAreComposable() {
// @formatter:on
}

@TestFactory
Stream<DynamicContainer> kitchenSinkExtensionImplementsAllExtensionApis() {
var declaredMethods = List.of(KitchenSinkExtension.class.getDeclaredMethods());
return findExtensionApis().stream() //
.map(c -> dynamicContainer( //
c.getSimpleName(), //
Stream.concat( //
Stream.of(
dynamicTest("implements interface", () -> c.isAssignableFrom(KitchenSinkExtension.class))), //
Arrays.stream(c.getMethods()) //
.filter(ModifierSupport::isNotStatic).map(m -> dynamicTest( //
"overrides " + m.getName(), //
() -> assertTrue( //
declaredMethods.stream().anyMatch(it -> //
it.getName().equals(m.getName()) //
&& it.getReturnType().equals(m.getReturnType()) //
&& Arrays.equals(it.getParameterTypes(), m.getParameterTypes()) //
))) //
) //
) //
));
}

private List<Class<?>> findExtensionApis() {
return ReflectionUtils.findAllClassesInPackage(Extension.class.getPackage().getName(), this::isExtensionApi,
name -> true);
}

private boolean isExtensionApi(Class<?> candidate) {
return candidate.isInterface() && (candidate != Extension.class) && Extension.class.isAssignableFrom(candidate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

package org.junit.jupiter.api.extension;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.stream.Stream;

Expand Down Expand Up @@ -177,4 +179,67 @@ public void testAborted(ExtensionContext context, Throwable cause) {
public void testFailed(ExtensionContext context, Throwable cause) {
}

// --- InvocationInterceptor -----------------------------------------------

@Override
public <T> T interceptTestClassConstructor(Invocation<T> invocation,
ReflectiveInvocationContext<Constructor<T>> invocationContext, ExtensionContext extensionContext)
throws Throwable {
return InvocationInterceptor.super.interceptTestClassConstructor(invocation, invocationContext,
extensionContext);
}

@Override
public void interceptBeforeAllMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptBeforeAllMethod(invocation, invocationContext, extensionContext);
}

@Override
public void interceptBeforeEachMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptBeforeEachMethod(invocation, invocationContext, extensionContext);
}

@Override
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptTestMethod(invocation, invocationContext, extensionContext);
}

@Override
public <T> T interceptTestFactoryMethod(Invocation<T> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
return InvocationInterceptor.super.interceptTestFactoryMethod(invocation, invocationContext, extensionContext);
}

@Override
public void interceptTestTemplateMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptTestTemplateMethod(invocation, invocationContext, extensionContext);
}

@SuppressWarnings("deprecation")
@Override
public void interceptDynamicTest(Invocation<Void> invocation, ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptDynamicTest(invocation, extensionContext);
}

@Override
public void interceptDynamicTest(Invocation<Void> invocation, DynamicTestInvocationContext invocationContext,
ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptDynamicTest(invocation, invocationContext, extensionContext);
}

@Override
public void interceptAfterEachMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptAfterEachMethod(invocation, invocationContext, extensionContext);
}

@Override
public void interceptAfterAllMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
InvocationInterceptor.super.interceptAfterAllMethod(invocation, invocationContext, extensionContext);
}
}

0 comments on commit e5f9509

Please sign in to comment.