package net.minestom.testing; import net.minestom.server.ServerProcess; import net.minestom.server.event.Event; import net.minestom.server.event.EventFilter; import net.minestom.server.event.EventListener; import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; final class EnvImpl implements Env { private final ServerProcess process; private final List> listeners = new CopyOnWriteArrayList<>(); public EnvImpl(ServerProcess process) { this.process = process; } @Override public @NotNull ServerProcess process() { return process; } @Override public @NotNull TestConnection createConnection() { return new TestConnectionImpl(this); } @Override public @NotNull Collector trackEvent(@NotNull Class eventType, @NotNull EventFilter filter, @NotNull H actor) { var tracker = new EventCollector(actor); this.process.eventHandler().map(actor, filter).addListener(eventType, tracker.events::add); return tracker; } @Override public @NotNull FlexibleListener listen(@NotNull Class eventType) { var handler = process.eventHandler(); var flexible = new FlexibleListenerImpl<>(eventType); var listener = EventListener.of(eventType, e -> flexible.handler.accept(e)); handler.addListener(listener); this.listeners.add(flexible); return flexible; } void cleanup() { this.listeners.forEach(FlexibleListenerImpl::check); } final class EventCollector implements Collector { private final Object handler; private final List events = new CopyOnWriteArrayList<>(); public EventCollector(Object handler) { this.handler = handler; } @Override public @NotNull List collect() { process.eventHandler().unmap(handler); return List.copyOf(events); } } static final class FlexibleListenerImpl implements FlexibleListener { private final Class eventType; private Consumer handler = e -> { }; private boolean initialized; private boolean called; FlexibleListenerImpl(Class eventType) { this.eventType = eventType; } @Override public void followup(@NotNull Consumer handler) { updateHandler(handler); } @Override public void failFollowup() { updateHandler(e -> fail("Event " + e.getClass().getSimpleName() + " was not expected")); } void updateHandler(@NotNull Consumer handler) { check(); this.initialized = true; this.called = false; this.handler = e -> { handler.accept(e); this.called = true; }; } void check() { assertTrue(!initialized || called, "Last listener has not been called: " + eventType.getSimpleName()); } } }