Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing documentation to the test module #100

Merged
merged 9 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions testing/src/main/java/net/minestom/testing/Collector.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,70 @@
import java.util.List;
import java.util.function.Consumer;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.*;

/**
* The {@link Collector} is a utility class to collect elements and apply assertions to them.
*
* @param <T> the type for the elements
* @version 1.0.0
* @since 1.0.0
TheMeinerLP marked this conversation as resolved.
Show resolved Hide resolved
*/
public interface Collector<T> {

/**
* Collects a list of elements
*
* @return the list of elements
*/
@NotNull List<@NotNull T> collect();

default <P extends T> void assertSingle(@NotNull Class<P> type, @NotNull Consumer<P> consumer) {
/**
* Asserts that the collector contains exactly one element of the given type and applies the consumer to it.
*
* @param type the type of the element
* @param consumer the consumer to apply to the element
*/
default <P extends T> void assertSingle(@NotNull Class<P> type, @NotNull Consumer<P> consumer) {
List<T> elements = collect();
assertEquals(1, elements.size(), "Expected 1 element, got " + elements);
var element = elements.get(0);
var element = elements.getFirst();
assertInstanceOf(type, element, "Expected type " + type.getSimpleName() + ", got " + element.getClass().getSimpleName());
consumer.accept((P) element);
}

/**
* Asserts that the collector contains exactly one element and applies the consumer to it.
* The consumer can be sued to inject own assertions to the element.
*
* @param consumer the consumer to apply to the element
*/
default void assertSingle(@NotNull Consumer<T> consumer) {
List<T> elements = collect();
assertEquals(1, elements.size(), "Expected 1 element, got " + elements);
consumer.accept(elements.get(0));
consumer.accept(elements.getFirst());
}

/**
* Asserts that the collector contains the given amount of elements.
*
* @param count the expected amount of elements
*/
default void assertCount(int count) {
List<T> elements = collect();
assertEquals(count, elements.size(), "Expected " + count + " element(s), got " + elements.size() + ": " + elements);
}

/**
* Asserts that the collector contains exactly one element.
*/
default void assertSingle() {
assertCount(1);
}

/**
* Asserts that the collector is empty.
*/
default void assertEmpty() {
assertCount(0);
}
Expand Down
92 changes: 89 additions & 3 deletions testing/src/main/java/net/minestom/testing/EnvImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,71 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

/**
* The {@link EnvImpl} is the implementation of the {@link Env} interface.
* It is used to create connections and more for the testing environment.
*
* @version 1.0.0
* @since 1.0.0
TheMeinerLP marked this conversation as resolved.
Show resolved Hide resolved
*/
final class EnvImpl implements Env {

private final ServerProcess process;
private final List<FlexibleListenerImpl<?>> listeners = new CopyOnWriteArrayList<>();

public EnvImpl(ServerProcess process) {
/**
* Creates a new instance of {@link EnvImpl} with the given {@link ServerProcess}.
*
* @param process the process to use
*/
public EnvImpl(@NotNull ServerProcess process) {
this.process = process;
}

/**
* Gets the {@link ServerProcess} used by this environment.
*
* @return the server process
*/
@Override
public @NotNull ServerProcess process() {
return process;
}

/**
* Creates a new connection.
*
* @return the created connection
*/
@Override
public @NotNull TestConnection createConnection() {
return new TestConnectionImpl(this);
}

/**
* Tracks a specific event type in the test environment.
*
* @param eventType the event type to track
* @param filter the filter to apply
* @param actor the actor to use
* @param <E> the event type
* @param <H> the actor type
* @return the {@link Collector} instance to use
*/
@Override
public @NotNull <E extends Event, H> Collector<E> trackEvent(@NotNull Class<E> eventType, @NotNull EventFilter<? super E, H> filter, @NotNull H actor) {
var tracker = new EventCollector<E>(actor);
this.process.eventHandler().map(actor, filter).addListener(eventType, tracker.events::add);
return tracker;
}

/**
* Listens for a specific event type in the test environment.
*
* @param eventType the event type to listen for
* @param <E> the event type
* @return the {@link FlexibleListener} instance from the event type
*/
@Override
public @NotNull <E extends Event> FlexibleListener<E> listen(@NotNull Class<E> eventType) {
var handler = process.eventHandler();
Expand All @@ -48,48 +88,91 @@ public EnvImpl(ServerProcess process) {
return flexible;
}

/**
* Removes all listener which are currently registered in the test environment.
*/
@Override
public void cleanup() {
this.listeners.forEach(FlexibleListenerImpl::check);
this.process.stop();
}

/**
* The class is the implementation of the {@link Collector} interface.
*
* @param <E> the event type
*/
final class EventCollector<E extends Event> implements Collector<E> {

private final Object handler;
private final List<E> events = new CopyOnWriteArrayList<>();

public EventCollector(Object handler) {
/**
* Creates a new instance of an event collector with the given handler.
*
* @param handler the handler to use
*/
public EventCollector(@NotNull Object handler) {
this.handler = handler;
}

/**
* Returns a list of all collected events.
*
* @return the list of events
*/
@Override
public @NotNull List<E> collect() {
process.eventHandler().unmap(handler);
return List.copyOf(events);
}
}

/**
* The class is the implementation of the {@link FlexibleListener} interface.
*
* @param <E> the event type
*/
static final class FlexibleListenerImpl<E extends Event> implements FlexibleListener<E> {

private final Class<E> eventType;
private Consumer<E> handler = e -> {
};
private boolean initialized;
private boolean called;

FlexibleListenerImpl(Class<E> eventType) {
/**
* Creates a new instance of a flexible listener with the given event type.
*
* @param eventType the event type
*/
FlexibleListenerImpl(@NotNull Class<E> eventType) {
this.eventType = eventType;
}

/**
* Updates the current handler reference.
*
* @param handler the handler to update
*/
@Override
public void followup(@NotNull Consumer<E> handler) {
updateHandler(handler);
}

/**
* Calls a fail assertions if the event can't be followed up.
*/
@Override
public void failFollowup() {
updateHandler(e -> fail("Event " + e.getClass().getSimpleName() + " was not expected"));
}

/**
* Updates the {@link Consumer} which acts as the handler.
*
* @param handler the handler to update
*/
void updateHandler(@NotNull Consumer<E> handler) {
check();
this.initialized = true;
Expand All @@ -100,6 +183,9 @@ void updateHandler(@NotNull Consumer<E> handler) {
};
}

/**
* Checks if the last listener has been called.
*/
void check() {
assertTrue(!initialized || called, "Last listener has not been called: " + eventType.getSimpleName());
}
Expand Down
57 changes: 0 additions & 57 deletions testing/src/main/java/net/minestom/testing/EnvTest.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,23 @@

import java.util.function.Consumer;

/**
* A FlexibleListener is a listener construct which works different from the normal listener code from Minestom.
* The use case is to follow listener during a test and can be used that the event was called or not
*
* @param <E> the event type
* @version 1.0.0
* @since 1.0.0
TheMeinerLP marked this conversation as resolved.
Show resolved Hide resolved
*/
public interface FlexibleListener<E extends Event> {
/**
* Updates the handler. Fails if the previous followup has not been called.
*/
void followup(@NotNull Consumer<E> handler);

/**
* Default followup which does nothing.
*/
default void followup() {
followup(event -> {
// Empty
Expand Down
Loading
Loading