Skip to content

Commit

Permalink
Move common Command logic to AbstractCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
JacksonBailey committed Jun 29, 2024
1 parent e0fdb58 commit 7a0cd00
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.hooks.EventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -22,11 +20,8 @@ public class TerraConfig {

@Bean
@Scope("prototype")
public JDABuilder jdaBuilder(TerraConfigProps terraConfigProps,
ObjectProvider<EventListener> listenerProvider) {
JDABuilder builder = JDABuilder.createDefault(terraConfigProps.token());
listenerProvider.orderedStream().forEach(builder::addEventListeners);
return builder;
public JDABuilder jdaBuilder(TerraConfigProps terraConfigProps) {
return JDABuilder.createDefault(terraConfigProps.token());
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
package dev.jacksonbailey.wheel.terra.service;

import jakarta.annotation.PostConstruct;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractCommand extends ListenerAdapter {

private static final Logger log = LoggerFactory.getLogger(AbstractCommand.class);
protected final JDA jda;

public AbstractCommand(JDA jda) {
this.jda = jda;
}

public abstract CommandData getCommandData();

@PostConstruct
public void registerCommand() {
jda.addEventListener(this);
jda.upsertCommand(getCommandData())
.queue(this::onUpsertCommandSuccess, onUpsertCommandFailure());
}

public abstract MessageCreateData doCommand(@NotNull SlashCommandInteractionEvent event);

Expand All @@ -32,6 +47,15 @@ public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent even
}
}

protected void onUpsertCommandSuccess(Command command) {

}

// It seems like JDA logs errors by default
protected Consumer<? super Throwable> onUpsertCommandFailure() {
return null;
}

protected void onDeferReplySuccess(InteractionHook hook,
Future<MessageCreateData> messageFuture) {
MessageCreateData messageCreateData;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
package dev.jacksonbailey.wheel.terra.service;

import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

@Service
public class EchoListener extends AbstractCommand {
public class EchoCommand extends AbstractCommand {

public static final String ECHO_COMMAND_NAME = "echo";
public static final String ECHO_PARAM_NAME = "message";

public EchoCommand(JDA jda) {
super(jda);
}

@Override
public CommandData getCommandData() {
return Commands.slash(ECHO_COMMAND_NAME, "Says it right back")
.addOption(OptionType.STRING, ECHO_PARAM_NAME, "The thing to say");
}

@Override
public MessageCreateData doCommand(@NotNull SlashCommandInteractionEvent event) {
var builder = new MessageCreateBuilder();
Expand Down
39 changes: 0 additions & 39 deletions terra/src/main/java/dev/jacksonbailey/wheel/terra/service/Foo.java

This file was deleted.

20 changes: 20 additions & 0 deletions terra/src/test/java/dev/jacksonbailey/wheel/terra/TestUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dev.jacksonbailey.wheel.terra;

import static org.mockito.ArgumentMatchers.any;

import java.util.function.Consumer;

public final class TestUtils {

private TestUtils() {
throw new AssertionError();
}

public static <T> Consumer<T> anyConsumerOf(T t) {
@SuppressWarnings("unchecked")
Consumer<T> toReturn = any(Consumer.class);
return toReturn;
}


}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package dev.jacksonbailey.wheel.terra.config;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.requests.RestAction;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
Expand All @@ -13,7 +18,11 @@ public class TerraTestConfig {
@Bean
@Profile("!live")
public JDA jda() {
return mock(JDA.class);
JDA jda = mock(JDA.class);
@SuppressWarnings("unchecked")
RestAction<Command> restAction = mock(RestAction.class);
given(jda.upsertCommand(any(CommandData.class))).willReturn(restAction);
return jda;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package dev.jacksonbailey.wheel.terra.service;

import static dev.jacksonbailey.wheel.terra.TestUtils.anyConsumerOf;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;

import java.util.function.Consumer;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class AbstractCommandTest {

@Mock
private CommandData commandData;

@Mock
private JDA jda;

@InjectMocks
private AbstractCommandStub abstractCommandStub;

@Mock
RestAction<Command> upsertRestAction;

@Mock
Consumer<Throwable> upsertCommandFailure;

private static class AbstractCommandStub extends AbstractCommand {

private final CommandData commandData;

private final Consumer<Throwable> upsertCommandFailure;

public AbstractCommandStub(JDA jda, CommandData commandData,
Consumer<Throwable> upsertCommandFailure) {
super(jda);
this.commandData = commandData;
this.upsertCommandFailure = upsertCommandFailure;
}

@Override
public CommandData getCommandData() {
return commandData;
}

@Override
public MessageCreateData doCommand(@NotNull SlashCommandInteractionEvent event) {
return null;
}

@Override
public String getCommandName() {
return "stub";
}

@Override
public boolean isEphemeral() {
return false;
}

protected Consumer<? super Throwable> onUpsertCommandFailure() {
return upsertCommandFailure;
}
}

@BeforeEach
void beforeEach() {
given(jda.upsertCommand(any(CommandData.class))).willReturn(upsertRestAction);
}

@Test
void registerCommandAddsListener() {
abstractCommandStub.registerCommand();
verify(jda).addEventListener(abstractCommandStub);
}

@Test
void registerCommandUpsertsCommand() {
abstractCommandStub.registerCommand();
verify(jda).upsertCommand(commandData);
verify(upsertRestAction).queue(anyConsumerOf(Command.class), eq(upsertCommandFailure));
}

// TODO Add more unit tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.jacksonbailey.wheel.terra.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class EchoCommandTest {

@Mock
private JDA jda;

@InjectMocks
private EchoCommand echoCommand;

@Test
void echoReturnsInput() {
var event = mock(SlashCommandInteractionEvent.class);
var optionMapping = mock(OptionMapping.class);
given(event.getOption(EchoCommand.ECHO_PARAM_NAME)).willReturn(optionMapping);
var input = "Hello, World!";
given(optionMapping.getAsString()).willReturn(input);

try (var messageCreateData = echoCommand.doCommand(event)) {
assertEquals(input, messageCreateData.getContent());
}
}

}

0 comments on commit 7a0cd00

Please sign in to comment.