diff --git a/modules/Gem/pom.xml b/modules/Gem/pom.xml index 6476837..013d68c 100644 --- a/modules/Gem/pom.xml +++ b/modules/Gem/pom.xml @@ -66,6 +66,10 @@ placeholderapi https://repo.extendedclip.com/content/repositories/placeholderapi/ + + helpch + https://repo.helpch.at/releases/ + @@ -78,8 +82,32 @@ me.clip placeholderapi - 2.11.1 + 2.11.5 provided + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + 5.11.0 + test + + + org.mockito + mockito-inline + 5.2.0 + test + + + net.bytebuddy + byte-buddy + 1.14.17 + test + diff --git a/modules/Gem/src/main/java/com/mcatk/gem/command/CommandGem.java b/modules/Gem/src/main/java/com/mcatk/gem/command/CommandGem.java index ee7c43e..b549756 100644 --- a/modules/Gem/src/main/java/com/mcatk/gem/command/CommandGem.java +++ b/modules/Gem/src/main/java/com/mcatk/gem/command/CommandGem.java @@ -41,7 +41,7 @@ public void run() { } switch (args[0].toLowerCase()) { case "set": - set(); + set(sender, args); break; case "check": check(); @@ -60,13 +60,20 @@ public void run() { return true; } - private void set() { + private void set(CommandSender sender, String[] args) { if (args.length != 3) { sendParameterError(); } else { try { - Gem.getPlugin().getGemExecutor().setGems(args[1], Integer.parseInt(args[2])); - sender.sendMessage(Message.INFO + args[1] + " 的宝石设置为: " + args[2]); + final String playerName = args[1]; + final int gems = Integer.parseInt(args[2]); + new BukkitRunnable() { + @Override + public void run() { + Gem.getPlugin().getGemExecutor().setGems(playerName, gems); + sender.sendMessage(Message.INFO + playerName + " 的宝石设置为: " + gems); + } + }.runTaskAsynchronously(Gem.getPlugin()); } catch (NumberFormatException e) { sender.sendMessage(Message.ERROR + "宝石必须是整数"); } diff --git a/modules/Gem/src/test/java/com/mcatk/gem/command/CommandGemBenchmarkTest.java b/modules/Gem/src/test/java/com/mcatk/gem/command/CommandGemBenchmarkTest.java new file mode 100644 index 0000000..417de7b --- /dev/null +++ b/modules/Gem/src/test/java/com/mcatk/gem/command/CommandGemBenchmarkTest.java @@ -0,0 +1,94 @@ +package com.mcatk.gem.command; + +import com.mcatk.gem.Gem; +import com.mcatk.gem.GemExecutor; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.junit.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.logging.Logger; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class CommandGemBenchmarkTest { + + private Gem gemMock; + private GemExecutor gemExecutorMock; + private CommandSender senderMock; + private Command commandMock; + private Server serverMock; + private BukkitScheduler schedulerMock; + + @Before + public void setUp() throws Exception { + // Mock Gem.plugin (static field) + gemMock = mock(Gem.class); + Field pluginField = Gem.class.getDeclaredField("plugin"); + pluginField.setAccessible(true); + pluginField.set(null, gemMock); + + // Mock GemExecutor + gemExecutorMock = mock(GemExecutor.class); + lenient().when(gemMock.getGemExecutor()).thenReturn(gemExecutorMock); + lenient().when(gemMock.getLogger()).thenReturn(Logger.getLogger("GemTest")); + + // Mock Bukkit.server (static) + serverMock = mock(Server.class); + Field serverField = Bukkit.class.getDeclaredField("server"); + serverField.setAccessible(true); + serverField.set(null, serverMock); + + // Mock Scheduler + schedulerMock = mock(BukkitScheduler.class); + lenient().when(serverMock.getScheduler()).thenReturn(schedulerMock); + + // Mock generic runTaskAsynchronously + lenient().when(schedulerMock.runTaskAsynchronously(any(Plugin.class), any(Runnable.class))) + .thenReturn(mock(BukkitTask.class)); + + // Mock CommandSender + senderMock = mock(CommandSender.class); + when(senderMock.isOp()).thenReturn(true); + + // Mock Command + commandMock = mock(Command.class); + } + + @Test + public void testSetGemsAsync() { + CommandGem commandGem = new CommandGem(); + String[] args = new String[]{"set", "player", "100"}; + + long startTime = System.currentTimeMillis(); + commandGem.onCommand(senderMock, commandMock, "gem", args); + long endTime = System.currentTimeMillis(); + + long duration = endTime - startTime; + System.out.println("Execution time: " + duration + "ms"); + + // Assert that it returns immediately (non-blocking) + assertTrue("Execution should be async and take < 50ms, but took " + duration + "ms", duration < 50); + + // Capture and run the task + ArgumentCaptor runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(schedulerMock).runTaskAsynchronously(any(Plugin.class), runnableCaptor.capture()); + + runnableCaptor.getValue().run(); + + // Verify logic executed + verify(gemExecutorMock).setGems("player", 100); + verify(senderMock).sendMessage(contains("100")); + } +}