mirror of
https://github.com/FancyInnovations/FancyPlugins.git
synced 2025-12-06 07:43:36 +00:00
Refactor packet tests and update dependencies
This commit is contained in:
@@ -1,243 +0,0 @@
|
||||
package de.oliver.fancylib.tests;
|
||||
|
||||
/**
|
||||
* A generic class for making assertions on the expected values.
|
||||
*
|
||||
* @param <T> the type of the value to be asserted.
|
||||
*/
|
||||
public class Expectable<T> {
|
||||
|
||||
/**
|
||||
* The value that is being wrapped by this Expectable instance.
|
||||
* This is the object against which all expectations will be verified.
|
||||
*/
|
||||
private final T t;
|
||||
|
||||
private Expectable(T t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of Expectable for the given value.
|
||||
*
|
||||
* @param <T> the type of the value being tested
|
||||
* @param t the actual value to create an expectation for
|
||||
* @return a new Expectable instance for the given value
|
||||
*/
|
||||
public static <T> Expectable<T> expect(T t) {
|
||||
return new Expectable<>(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the actual value is not null.
|
||||
* <p>
|
||||
* Throws an AssertionError if the value of the field 't' is null,
|
||||
* indicating that the actual value is expected to be non-null.
|
||||
*
|
||||
* @throws AssertionError if the value of the field 't' is null
|
||||
*/
|
||||
public void toBeDefined() {
|
||||
if (t == null) {
|
||||
throw new AssertionError("Expected not null but got null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the value of the field 't' is null.
|
||||
* <p>
|
||||
* Throws an AssertionError if the value of 't' is not null,
|
||||
* indicating the expectation that the value should be null.
|
||||
*
|
||||
* @throws AssertionError if the value of 't' is not null
|
||||
*/
|
||||
public void toBeNull() {
|
||||
if (t != null) {
|
||||
throw new AssertionError("Expected null but got not null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is equal to the expected value.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be equal to
|
||||
* @throws AssertionError if the actual value is not equal to the expected value
|
||||
*/
|
||||
public void toBe(T expected) {
|
||||
if (t != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is equal to the expected value using the {@code equals} method.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be equal to
|
||||
* @throws AssertionError if the actual value is not equal to the expected value
|
||||
*/
|
||||
public void toEqual(T expected) {
|
||||
if (!t.equals(expected)) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is greater than the expected value.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be greater than
|
||||
* @throws AssertionError if the actual value is not greater than the expected value,
|
||||
* or if the type of the actual value is not one of Integer, Long, Float, or Double
|
||||
*/
|
||||
public void toBeGreaterThan(T expected) {
|
||||
if (t instanceof Integer) {
|
||||
if ((Integer) t <= (Integer) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Long) {
|
||||
if ((Long) t <= (Long) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Float) {
|
||||
if ((Float) t <= (Float) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Double) {
|
||||
if ((Double) t <= (Double) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("toBeGreaterThan can only be used on Integers, Longs, Floats, and Doubles");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is less than the expected value.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be less than
|
||||
* @throws AssertionError if the actual value is not less than the expected value,
|
||||
* or if the type of the actual value is not one of Integer, Long, Float, or Double
|
||||
*/
|
||||
public void toBeLessThan(T expected) {
|
||||
if (t instanceof Integer) {
|
||||
if ((Integer) t >= (Integer) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Long) {
|
||||
if ((Long) t >= (Long) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Float) {
|
||||
if ((Float) t >= (Float) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Double) {
|
||||
if ((Double) t >= (Double) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("toBeLessThan can only be used on Integers, Longs, Floats, and Doubles");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is an instance of the expected class.
|
||||
* This method checks whether the value held in the field 't' is an instance of the provided Class.
|
||||
*
|
||||
* @param expected the Class object that the actual value is expected to be an instance of
|
||||
* @throws AssertionError if the actual value is not an instance of the expected class
|
||||
*/
|
||||
public void toBeInstanceOf(Class<?> expected) {
|
||||
if (!expected.isInstance(t)) {
|
||||
throw new AssertionError("Expected " + t + " to be an instance of " + expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given expected value is contained within the actual value.
|
||||
* <p>
|
||||
* This method checks if the expected value is present in a String, Iterable, or Array.
|
||||
* If the actual value is a String, it uses the contains method to check if the expected value
|
||||
* is a substring. If the actual value is an Iterable, it checks if the expected value is an element.
|
||||
* If the actual value is an Array, it checks if the expected value is present in the array.
|
||||
*
|
||||
* @param expected the value that is expected to be contained within the actual value
|
||||
* @throws AssertionError if the expected value is not contained within the actual value
|
||||
*/
|
||||
public void toContain(Object expected) {
|
||||
if (t instanceof String) {
|
||||
if (!((String) t).contains((String) expected)) {
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Iterable) {
|
||||
if (!((Iterable<?>) t).spliterator().tryAdvance(o -> {
|
||||
if (o.equals(expected)) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
})) {
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Object[]) {
|
||||
for (Object o : (Object[]) t) {
|
||||
if (o.equals(expected)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
}
|
||||
|
||||
throw new AssertionError("toContain can only be used on Strings, Iterables and Arrays");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value has the expected length.
|
||||
* This method checks if the actual value is a String, Iterable, or Array,
|
||||
* and compares their length or size to the given expected length.
|
||||
*
|
||||
* @param expected the expected length of the actual value
|
||||
* @throws AssertionError if the actual value does not have the expected length,
|
||||
* or if the actual value is not of type String, Iterable, or Array
|
||||
*/
|
||||
public void toHaveLength(int expected) {
|
||||
if (t instanceof String) {
|
||||
if (((String) t).length() != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + ((String) t).length());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Iterable) {
|
||||
if (((Iterable<?>) t).spliterator().getExactSizeIfKnown() != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + ((Iterable<?>) t).spliterator().getExactSizeIfKnown());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Object[]) {
|
||||
if (((Object[]) t).length != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + ((Object[]) t).length);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("toHaveLength can only be used on Strings");
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package de.oliver.fancylib.tests;
|
||||
|
||||
import de.oliver.fancylib.tests.annotations.FPAfterEach;
|
||||
import de.oliver.fancylib.tests.annotations.FPBeforeEach;
|
||||
import de.oliver.fancylib.tests.annotations.FPTest;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* FPTestClass is a record that encapsulates information about a test class and its associated test methods.
|
||||
* This class supports running tests annotated with {@link FPTest}.
|
||||
*
|
||||
* @param testClass the test class to run tests for (must be annotated with {@link FPTest})
|
||||
* @param beforeEach the method annotated with {@link FPBeforeEach} to run before each test
|
||||
* @param afterEach the method annotated with {@link FPAfterEach} to run after each test
|
||||
* @param testMethods the list of test methods annotated with {@link FPTest}
|
||||
*/
|
||||
public record FPTestClass(
|
||||
Class<?> testClass,
|
||||
Method beforeEach,
|
||||
Method afterEach,
|
||||
List<Method> testMethods
|
||||
) {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FPTestClass.class.getName());
|
||||
|
||||
/**
|
||||
* Creates an instance of FPTestClass by inspecting the provided test class for methods annotated
|
||||
* with FPTest, FPBeforeEach, and FPAfterEach annotations.
|
||||
* These methods are used to define the setup, teardown, and test methods for the class.
|
||||
*
|
||||
* @param testClass the class to be inspected for annotated methods
|
||||
* @return an instance of FPTestClass containing the test class and its annotated methods
|
||||
*/
|
||||
public static FPTestClass fromClass(Class<?> testClass) {
|
||||
Method beforeEach = null;
|
||||
Method afterEach = null;
|
||||
List<Method> testMethods = new ArrayList<>();
|
||||
|
||||
for (Method method : testClass.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(FPTest.class)) {
|
||||
if (method.getParameterCount() != 1) continue;
|
||||
if (method.getParameterTypes()[0] != Player.class) continue;
|
||||
|
||||
testMethods.add(method);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(FPBeforeEach.class)) {
|
||||
if (method.getParameterCount() != 1) continue;
|
||||
if (method.getParameterTypes()[0] != Player.class) continue;
|
||||
|
||||
beforeEach = method;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(FPAfterEach.class)) {
|
||||
if (method.getParameterCount() != 1) continue;
|
||||
if (method.getParameterTypes()[0] != Player.class) continue;
|
||||
|
||||
afterEach = method;
|
||||
}
|
||||
}
|
||||
|
||||
return new FPTestClass(testClass, beforeEach, afterEach, testMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the test methods belonging to the test class, performing any necessary setup and teardown operations.
|
||||
*
|
||||
* @param player The player context to pass to the test methods.
|
||||
* @return true if all tests completed successfully, false if any test failed or an unexpected exception occurred.
|
||||
*/
|
||||
public boolean runTests(Player player) {
|
||||
logger.info("Running tests for " + testClass.getSimpleName());
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<green>Running tests for " + testClass.getSimpleName()));
|
||||
|
||||
for (Method testMethod : testMethods) {
|
||||
Object testClassObj;
|
||||
try {
|
||||
testClassObj = testClass.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
logger.warning("Failed to create test class instance: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
FPTest fpTest = testMethod.getAnnotation(FPTest.class);
|
||||
if (fpTest.skip()) {
|
||||
logger.info("Skipping test " + displayName(testMethod));
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<gold>Skipping test " + displayName(testMethod)));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
long testStart = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
if (beforeEach != null) beforeEach.invoke(testClassObj, player);
|
||||
|
||||
testMethod.invoke(testClassObj, player);
|
||||
|
||||
if (afterEach != null) afterEach.invoke(testClassObj, player);
|
||||
} catch (InvocationTargetException e) {
|
||||
logger.warning("Test " + displayName(testMethod) + " failed with exception: " + e.getCause().getMessage());
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<red>Test " + displayName(testMethod) + " failed with exception: " + e.getCause().getMessage()));
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
logger.warning("Unexpected exception in test " + fpTest.name() + ": " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
long testEnd = System.currentTimeMillis();
|
||||
logger.info("Test " + displayName(testMethod) + " took " + (testEnd - testStart) + "ms");
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<green>Test " + displayName(testMethod) + " took " + (testEnd - testStart) + "ms"));
|
||||
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
logger.warning("Thread interrupted while waiting between tests: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a display name for a given test method, incorporating annotation details if present.
|
||||
*
|
||||
* @param m the method for which to generate the display name
|
||||
* @return a display name that includes the test class and method name, and optionally the value of the FPTest annotation's name attribute if the annotation is present
|
||||
*/
|
||||
public String displayName(Method m) {
|
||||
if (!m.isAnnotationPresent(FPTest.class)) {
|
||||
return testClass.getSimpleName() + "#" + m.getName();
|
||||
}
|
||||
|
||||
FPTest fpTest = m.getAnnotation(FPTest.class);
|
||||
return testClass.getSimpleName() + "#" + m.getName() + " (" + fpTest.name() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package de.oliver.fancylib.tests.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to mark a method that should be executed after each test case in a test class.
|
||||
* This annotation is used to identify methods that perform teardown operations, ensuring
|
||||
* that the test environment is cleaned up and reset after each individual test method is executed.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FPAfterEach {
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package de.oliver.fancylib.tests.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* FPBeforeEach is a custom annotation designed to be used on methods that should be executed before each test method.
|
||||
* Methods annotated with FPBeforeEach are typically used to perform setup operations needed before executing each test case.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FPBeforeEach {
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package de.oliver.fancylib.tests.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* FPTest is a custom annotation designed to be used on methods for marking them as test cases.
|
||||
* It helps to identify methods that should be treated as test cases in the testing framework.
|
||||
* The annotation's attributes allow for providing a human-readable test name and an optional flag to skip the test.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FPTest {
|
||||
|
||||
/**
|
||||
* Specifies the name of the test case. This name is used to identify the test case
|
||||
* in reports, logs, and other contexts where the test case is referenced.
|
||||
*
|
||||
* @return the name of the test case
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Indicates whether the annotated test case should be skipped during test execution.
|
||||
*
|
||||
* @return true if the test case should be skipped, false otherwise
|
||||
*/
|
||||
boolean skip() default false;
|
||||
}
|
||||
Reference in New Issue
Block a user