mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-08 21:14:41 -04:00
Add back "invokeTestMethod" function to allow control over calling the test method. (#4474)
* Add back "invokeTestMethod" function to allow custom logic before and after tests. * Improve TestAnnotationLocator.validateMethod
This commit is contained in:
parent
4e7a6c5738
commit
81c4afbc1a
4 changed files with 110 additions and 7 deletions
fabric-gametest-api-v1/src
main/java/net/fabricmc/fabric
testmod
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.gametest.v1;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import net.minecraft.test.TestContext;
|
||||
|
||||
/**
|
||||
* Implement this interface on test suites to provide custom logic for invoking {@link GameTest} test methods.
|
||||
*/
|
||||
public interface CustomTestMethodInvoker {
|
||||
/**
|
||||
* Implement this method to provide custom logic used to invoke the test method.
|
||||
* This can be used to run code before or after each test.
|
||||
* You can also pass in custom parameters into the test method if desired.
|
||||
* The structure will have been placed in the world before this method is invoked.
|
||||
*
|
||||
* @param context The vanilla test context
|
||||
* @param method The test method to invoke
|
||||
*/
|
||||
void invokeTestMethod(TestContext context, Method method) throws ReflectiveOperationException;
|
||||
}
|
|
@ -37,6 +37,7 @@ import net.minecraft.test.TestEnvironmentDefinition;
|
|||
import net.minecraft.test.TestInstance;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.gametest.v1.CustomTestMethodInvoker;
|
||||
import net.fabricmc.fabric.api.gametest.v1.GameTest;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.entrypoint.EntrypointContainer;
|
||||
|
@ -72,7 +73,7 @@ final class TestAnnotationLocator {
|
|||
findMagicMethods(entrypoint, testClass, methods);
|
||||
|
||||
if (methods.isEmpty()) {
|
||||
LOGGER.warn("No methods with the FabricGameTest annotation were found in {}", testClass.getName());
|
||||
LOGGER.warn("No methods with the GameTest annotation were found in {}", testClass.getName());
|
||||
}
|
||||
|
||||
return methods;
|
||||
|
@ -82,7 +83,11 @@ final class TestAnnotationLocator {
|
|||
private void findMagicMethods(EntrypointContainer<Object> entrypoint, Class<?> testClass, List<TestMethod> methods) {
|
||||
for (Method method : testClass.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(GameTest.class)) {
|
||||
validateMethod(method);
|
||||
if (!CustomTestMethodInvoker.class.isAssignableFrom(testClass)) {
|
||||
// Only validate the test method when using the default reflection invoker
|
||||
validateMethod(method);
|
||||
}
|
||||
|
||||
methods.add(new TestMethod(method, method.getAnnotation(GameTest.class), entrypoint));
|
||||
}
|
||||
}
|
||||
|
@ -93,21 +98,30 @@ final class TestAnnotationLocator {
|
|||
}
|
||||
|
||||
private void validateMethod(Method method) {
|
||||
List<String> issues = new ArrayList<>();
|
||||
|
||||
if (method.getParameterCount() != 1 || method.getParameterTypes()[0] != TestContext.class) {
|
||||
throw new UnsupportedOperationException("Method %s must have a single parameter of type TestContext".formatted(method.getName()));
|
||||
issues.add("must have a single parameter of type TestContext");
|
||||
}
|
||||
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
throw new UnsupportedOperationException("Method %s must be public".formatted(method.getName()));
|
||||
issues.add("must be public");
|
||||
}
|
||||
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new UnsupportedOperationException("Method %s must not be static".formatted(method.getName()));
|
||||
issues.add("must not be static");
|
||||
}
|
||||
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new UnsupportedOperationException("Method %s must return void".formatted(method.getName()));
|
||||
issues.add("must return void");
|
||||
}
|
||||
|
||||
if (issues.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String methodName = method.getDeclaringClass().getName() + "#" + method.getName();
|
||||
throw new UnsupportedOperationException("Test method (%s) has the following issues: %s".formatted(methodName, String.join(", ", issues)));
|
||||
}
|
||||
|
||||
public record TestMethod(Method method, GameTest gameTest, EntrypointContainer<Object> entrypoint) {
|
||||
|
@ -118,8 +132,15 @@ final class TestAnnotationLocator {
|
|||
|
||||
Consumer<TestContext> testFunction() {
|
||||
return context -> {
|
||||
Object instance = entrypoint.getEntrypoint();
|
||||
|
||||
try {
|
||||
method.invoke(entrypoint.getEntrypoint(), context);
|
||||
if (instance instanceof CustomTestMethodInvoker customTestMethodInvoker) {
|
||||
customTestMethodInvoker.invokeTestMethod(context, method);
|
||||
return;
|
||||
}
|
||||
|
||||
method.invoke(instance, context);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Failed to invoke test method", e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.gametest;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.test.TestContext;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.fabricmc.fabric.api.gametest.v1.CustomTestMethodInvoker;
|
||||
import net.fabricmc.fabric.api.gametest.v1.GameTest;
|
||||
|
||||
public class CustomTestInvokerTest implements CustomTestMethodInvoker {
|
||||
@Override
|
||||
public void invokeTestMethod(TestContext context, Method method) throws ReflectiveOperationException {
|
||||
context.setBlockState(0, 1, 0, Blocks.DIAMOND_BLOCK);
|
||||
|
||||
method.invoke(this, context, Blocks.DIAMOND_BLOCK);
|
||||
}
|
||||
|
||||
@GameTest
|
||||
public void testCustomInvoker(TestContext context, Block testBlock) {
|
||||
context.addInstantFinalTask(() ->
|
||||
context.checkBlock(new BlockPos(0, 1, 0), (block) -> block == testBlock, (b) -> Text.literal("Expect block to be diamond"))
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
"license": "Apache-2.0",
|
||||
"entrypoints": {
|
||||
"fabric-gametest" : [
|
||||
"net.fabricmc.fabric.test.gametest.CustomTestInvokerTest",
|
||||
"net.fabricmc.fabric.test.gametest.ExampleFabricTestSuite"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue