From 38a30eb50270568aabc56d551d75d98755bd7312 Mon Sep 17 00:00:00 2001 From: SchnTgaiSpock Date: Tue, 5 Nov 2024 00:18:19 -0500 Subject: [PATCH] more unit tests --- .../slimefun4/api/recipes/Recipe.java | 20 ++-- .../slimefun4/api/recipes/RecipeOutput.java | 42 +++++-- .../api/recipes/items/RecipeOutputItem.java | 12 +- .../core/services/RecipeService.java | 4 + .../slimefun4/api/recipes/TestRecipes.java | 52 ++++----- .../core/services/TestSFRecipeService.java | 105 ++++++++++++++++++ 6 files changed, 192 insertions(+), 43 deletions(-) create mode 100644 src/test/java/io/github/thebusybiscuit/slimefun4/core/services/TestSFRecipeService.java diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/Recipe.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/Recipe.java index 9677b5b925..52219c82a9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/Recipe.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/Recipe.java @@ -14,7 +14,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; -import io.github.thebusybiscuit.slimefun4.api.recipes.items.RecipeOutputItemStack; import io.github.thebusybiscuit.slimefun4.api.recipes.matching.InputMatchResult; import io.github.thebusybiscuit.slimefun4.api.recipes.matching.MatchProcedure; import io.github.thebusybiscuit.slimefun4.api.recipes.matching.RecipeMatchResult; @@ -47,12 +46,12 @@ public Recipe(Optional id, String filename, AbstractRecipeInput input, A } } - public static Recipe fromItemStacks(String id, ItemStack[] inputs, ItemStack output, RecipeType type) { + public static Recipe fromItemStacks(String id, ItemStack[] inputs, ItemStack[] outputs, RecipeType type, MatchProcedure match) { return new Recipe( Optional.of(id), id.toLowerCase(), - RecipeInput.fromItemStacks(inputs, type.getDefaultMatchProcedure()), - new RecipeOutput(List.of(new RecipeOutputItemStack(output))), + RecipeInput.fromItemStacks(inputs, match), + RecipeOutput.fromItemStacks(outputs), List.of(type), Optional.empty(), Optional.empty(), @@ -60,12 +59,16 @@ public static Recipe fromItemStacks(String id, ItemStack[] inputs, ItemStack out ); } - public static Recipe fromItemStacks(ItemStack[] inputs, ItemStack output, RecipeType type, MatchProcedure match) { + public static Recipe fromItemStacks(String id, ItemStack[] inputs, ItemStack[] outputs, RecipeType type) { + return fromItemStacks(id, inputs, outputs, type, type.getDefaultMatchProcedure()); + } + + public static Recipe fromItemStacks(ItemStack[] inputs, ItemStack[] outputs, RecipeType type, MatchProcedure match) { return new Recipe( Optional.empty(), "other_recipes", RecipeInput.fromItemStacks(inputs, match), - new RecipeOutput(List.of(new RecipeOutputItemStack(output))), + RecipeOutput.fromItemStacks(outputs), List.of(type), Optional.empty(), Optional.empty(), @@ -73,11 +76,10 @@ public static Recipe fromItemStacks(ItemStack[] inputs, ItemStack output, Recipe ); } - public static Recipe fromItemStacks(ItemStack[] inputs, ItemStack output, RecipeType type) { - return fromItemStacks(inputs, output, type, type.getDefaultMatchProcedure()); + public static Recipe fromItemStacks(ItemStack[] inputs, ItemStack[] outputs, RecipeType type) { + return fromItemStacks(inputs, outputs, type, type.getDefaultMatchProcedure()); } - public Optional getId() { return id; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/RecipeOutput.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/RecipeOutput.java index 5f1766c789..35c4affffe 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/RecipeOutput.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/RecipeOutput.java @@ -14,9 +14,14 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.api.recipes.items.AbstractRecipeOutputItem; import io.github.thebusybiscuit.slimefun4.api.recipes.items.AbstractRecipeOutputItem.SpaceRequirement; +import io.github.thebusybiscuit.slimefun4.api.recipes.items.RecipeOutputItem; +import io.github.thebusybiscuit.slimefun4.api.recipes.items.RecipeOutputItemStack; +import io.github.thebusybiscuit.slimefun4.api.recipes.items.RecipeOutputSlimefunItem; import io.github.thebusybiscuit.slimefun4.api.recipes.matching.RecipeMatchResult; +import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; public class RecipeOutput extends AbstractRecipeOutput { @@ -60,6 +65,25 @@ public RecipeOutput(List items) { this.items = items; } + public static RecipeOutput fromItemStacks(ItemStack[] items) { + List outputItems = new ArrayList<>(); + for (ItemStack item : items) { + if (item == null || item.getType().isAir()) { + outputItems.add(RecipeOutputItem.EMPTY); + continue; + } + + SlimefunItem sfItem = SlimefunItem.getByItem(item); + + if (sfItem != null) { + outputItems.add(new RecipeOutputSlimefunItem(sfItem.getId(), item.getAmount())); + } else { + outputItems.add(new RecipeOutputItemStack(item)); + } + } + return new RecipeOutput(outputItems); + } + public List getItems() { return this.items; } @@ -102,19 +126,23 @@ public Inserter checkSpace(RecipeMatchResult result, Inventory inventory, int[] // Search for matching item int amount = outputStack.getAmount(); int stackSize = outputStack.getType().getMaxStackSize(); // TODO item components - for (int i = 0; i < filledSlots.size(); i++) { + for (int i : filledSlots) { if (amount <= 0) break; ItemStack filledItem = inventory.getItem(i); + if (!SlimefunUtils.isItemSimilar(filledItem, outputStack, true, false)) { + continue; + } int filledAmount = filledItem.getAmount(); - if (filledAmount >= stackSize) { + int currentAdd = addToStacks.getOrDefault(i, 0); + if (filledAmount + currentAdd >= stackSize) { continue; - } else if (filledAmount + amount > stackSize) { - int diff = stackSize - filledAmount; + } else if (filledAmount + currentAdd + amount > stackSize) { + int diff = stackSize - filledAmount - currentAdd; amount -= diff; - addToStacks.put(i, diff); - } else if (filledAmount + amount == stackSize) { + addToStacks.put(i, diff + currentAdd); + } else { + addToStacks.put(i, amount + currentAdd); amount = 0; - addToStacks.put(i, amount); } } if (amount > 0) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/items/RecipeOutputItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/items/RecipeOutputItem.java index e03141b2ac..88a7fcd6e9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/items/RecipeOutputItem.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/recipes/items/RecipeOutputItem.java @@ -16,7 +16,7 @@ public abstract class RecipeOutputItem extends AbstractRecipeOutputItem { /** - * Should not be used in recipes unless as a default. + * Should not be used in recipes. * If you need an empty recipe output, use RecipeOutput.EMPTY instead */ public static final AbstractRecipeOutputItem EMPTY = new AbstractRecipeOutputItem() { @@ -25,6 +25,11 @@ public boolean matchItem(ItemStack item) { return item == null || item.getType().isAir(); } + @Override + public SpaceRequirement getSpaceRequirement() { + return SpaceRequirement.MATCHING_ITEM; + } + @Override public ItemStack generateOutput(RecipeMatchResult result) { return new ItemStack(Material.AIR); @@ -59,6 +64,11 @@ public RecipeOutputItem(int amount) { public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } + @Override + public SpaceRequirement getSpaceRequirement() { + return SpaceRequirement.MATCHING_ITEM; + } + /** * Converts a string into a RecipeSingleItem * @param string A namespace string in the format diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/RecipeService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/RecipeService.java index 29ff930173..c9b5a1979b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/RecipeService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/RecipeService.java @@ -165,6 +165,10 @@ public RecipeSearchResult searchRecipes(RecipeType type, Function givenItems, MatchProcedure matchAs) { + return searchRecipes(type, recipe -> recipe.matchAs(matchAs, givenItems), recipe -> RecipeUtils.hashItemsIgnoreAmount(givenItems)); + } + public RecipeSearchResult searchRecipes(RecipeType type, List givenItems) { return searchRecipes(type, recipe -> recipe.match(givenItems), recipe -> RecipeUtils.hashItemsIgnoreAmount(givenItems)); } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/api/recipes/TestRecipes.java b/src/test/java/io/github/thebusybiscuit/slimefun4/api/recipes/TestRecipes.java index 00a5bf9839..cfcefe9937 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/api/recipes/TestRecipes.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/api/recipes/TestRecipes.java @@ -333,27 +333,27 @@ void testShapedRecipeMatching() { null, null, null, new ItemStack(Material.SUGAR, 10), new ItemStack(Material.APPLE, 2), null, null, new ItemStack(Material.STICK, 3), null, - }, new ItemStack(Material.STICK), RecipeType.NULL); + }, new ItemStack[] { new ItemStack(Material.STICK) }, RecipeType.NULL); ItemStack sticks = new ItemStack(Material.STICK, 64); ItemStack apples = new ItemStack(Material.APPLE, 64); ItemStack sugar = new ItemStack(Material.SUGAR, 64); - var falseResult = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList(new ItemStack[] { + var falseResult = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList( sugar, apples, null, null, new ItemStack(Material.ACACIA_BOAT), null, - null, null, null, - })); + null, null, null + )); Assertions.assertFalse(falseResult.itemsMatch()); - falseResult = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList(new ItemStack[] { + falseResult = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList( sugar, apples, null, null, new ItemStack(Material.STICK, 1), null, - null, null, null, - })); + null, null, null + )); Assertions.assertFalse(falseResult.itemsMatch()); - var result = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList(new ItemStack[] { + var result = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList( sugar, apples, null, null, sticks, null, - null, null, null, - })); + null, null, null + )); Assertions.assertTrue(result.itemsMatch()); Assertions.assertEquals(3, result.getInputMatchResult().consumeItems(3)); Assertions.assertEquals(55, sticks.getAmount()); @@ -371,17 +371,17 @@ null, new ItemStack(Material.STICK, 1), null, sticks = new ItemStack(Material.STICK, 64); apples = new ItemStack(Material.APPLE, 64); sugar = new ItemStack(Material.SUGAR, 64); - falseResult = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList(new ItemStack[] { + falseResult = recipe.matchAs(MatchProcedure.SHAPED, Arrays.asList( null, null, null, null, apples, sugar, - null, sticks, null, - })); + null, sticks, null + )); Assertions.assertFalse(falseResult.itemsMatch()); - result = recipe.matchAs(MatchProcedure.SHAPED_FLIPPABLE, Arrays.asList(new ItemStack[] { + result = recipe.matchAs(MatchProcedure.SHAPED_FLIPPABLE, Arrays.asList( null, null, null, null, apples, sugar, - null, sticks, null, - })); + null, sticks, null + )); Assertions.assertTrue(result.itemsMatch()); Assertions.assertEquals(3, result.getInputMatchResult().consumeItems(3)); Assertions.assertEquals(55, sticks.getAmount()); @@ -404,28 +404,28 @@ void testShapelessRecipeMatching() { null, null, new ItemStack(Material.BLAZE_POWDER, 4), new ItemStack(Material.GUNPOWDER, 3), new ItemStack(Material.COAL, 7), null, null, null, null, - }, new ItemStack(Material.STICK), RecipeType.NULL); + }, new ItemStack[] { new ItemStack(Material.STICK) }, RecipeType.NULL); ItemStack blazePowder = new ItemStack(Material.BLAZE_POWDER, 64); ItemStack gunpowder = new ItemStack(Material.GUNPOWDER, 64); ItemStack coal = new ItemStack(Material.COAL, 64); ItemStack sticks = new ItemStack(Material.STICK, 64); // If subset is false, then shapeless will also be false - var falseResult = recipe.matchAs(MatchProcedure.SUBSET, Arrays.asList(new ItemStack[] { + var falseResult = recipe.matchAs(MatchProcedure.SUBSET, Arrays.asList( null, coal, null, null, null, gunpowder - })); + )); Assertions.assertFalse(falseResult.itemsMatch()); - falseResult = recipe.matchAs(MatchProcedure.SHAPELESS, Arrays.asList(new ItemStack[] { + falseResult = recipe.matchAs(MatchProcedure.SHAPELESS, Arrays.asList( null, coal, null, null, null, gunpowder, blazePowder, sticks - })); + )); Assertions.assertFalse(falseResult.itemsMatch()); - var result = recipe.matchAs(MatchProcedure.SHAPELESS, Arrays.asList(new ItemStack[] { + var result = recipe.matchAs(MatchProcedure.SHAPELESS, Arrays.asList( null, coal, null, null, null, gunpowder, blazePowder - })); + )); Assertions.assertTrue(result.itemsMatch()); - result = recipe.matchAs(MatchProcedure.SUBSET, Arrays.asList(new ItemStack[] { - null, coal, null, null, null, gunpowder, blazePowder, sticks, - })); + result = recipe.matchAs(MatchProcedure.SUBSET, Arrays.asList( + null, coal, null, null, null, gunpowder, blazePowder, sticks + )); Assertions.assertTrue(result.itemsMatch()); Assertions.assertEquals(9, result.getInputMatchResult().consumeItems(9)); Assertions.assertEquals(28, blazePowder.getAmount()); diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/TestSFRecipeService.java b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/TestSFRecipeService.java new file mode 100644 index 0000000000..7bb43062cf --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/TestSFRecipeService.java @@ -0,0 +1,105 @@ +package io.github.thebusybiscuit.slimefun4.core.services; + +import java.util.Arrays; + +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import io.github.bakedlibs.dough.items.CustomItemStack; +import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; +import io.github.thebusybiscuit.slimefun4.api.recipes.Recipe; +import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.api.recipes.matching.MatchProcedure; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.test.mocks.MockSlimefunItem; +import be.seeseemelk.mockbukkit.MockBukkit; + +class TestSFRecipeService { + + private static Slimefun sf; + private static ItemGroup itemGroup; + private static MockSlimefunItem testItem1; + private static MockSlimefunItem testItem2; + private static MockSlimefunItem testItem3; + private static MockSlimefunItem testItem4; + private static MockSlimefunItem testItem5; + + @BeforeAll + public static void load() { + MockBukkit.mock(); + sf = MockBukkit.load(Slimefun.class); + itemGroup = new ItemGroup(new NamespacedKey(sf, "test_group"), new CustomItemStack(Material.DIAMOND_AXE, "Test Group")); + testItem1 = new MockSlimefunItem(itemGroup, new ItemStack(Material.IRON_INGOT), "TEST_ITEM_1"); + testItem2 = new MockSlimefunItem(itemGroup, new ItemStack(Material.IRON_INGOT), "TEST_ITEM_2"); + testItem3 = new MockSlimefunItem(itemGroup, new ItemStack(Material.IRON_INGOT), "TEST_ITEM_3"); + testItem4 = new MockSlimefunItem(itemGroup, new ItemStack(Material.IRON_INGOT), "TEST_ITEM_4"); + testItem5 = new MockSlimefunItem(itemGroup, new ItemStack(Material.IRON_INGOT), "TEST_ITEM_5"); + testItem1.register(sf); + testItem2.register(sf); + testItem3.register(sf); + testItem4.register(sf); + testItem5.register(sf); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + @Test + @DisplayName("Test adding recipes") + void testRecipe() { + RecipeService service = new RecipeService(sf); + + Recipe recipe1 = Recipe.fromItemStacks("TEST_ITEM_1", new ItemStack[] { + null, null, null, + null, null, testItem1.getItem(), + null, null, null, + }, new ItemStack[] { testItem1.getItem() }, RecipeType.NULL); + Recipe recipe2 = Recipe.fromItemStacks("TEST_ITEM_2", new ItemStack[] { + null, null, null, + null, null, testItem1.getItem(), + testItem2.getItem(), null, null, + }, new ItemStack[] { testItem2.getItem() }, RecipeType.NULL); + Recipe recipe3 = Recipe.fromItemStacks("TEST_ITEM_3", new ItemStack[] { + null, testItem3.getItem(), null, + null, null, testItem1.getItem(), + testItem2.getItem(), null, null, + }, new ItemStack[] { testItem3.getItem() }, RecipeType.NULL); + Recipe recipe4 = Recipe.fromItemStacks("TEST_ITEM_4", new ItemStack[] { + null, testItem3.getItem(), null, + null, null, testItem1.getItem(), + testItem2.getItem(), null, null, + }, new ItemStack[] { testItem4.getItem() }, RecipeType.NULL); + + service.addRecipe(recipe1); + service.addRecipe(recipe2); + service.addRecipe(recipe3); + service.addRecipe(recipe4); + + Assertions.assertEquals(recipe1, service.getRecipe("TEST_ITEM_1")); + Assertions.assertEquals(recipe2, service.getRecipe("TEST_ITEM_2")); + Assertions.assertEquals(recipe3, service.getRecipe("TEST_ITEM_3")); + Assertions.assertEquals(recipe4, service.getRecipe("TEST_ITEM_4")); + + ItemStack sfItem = testItem1.getItem().clone(); + var search = service.searchRecipes(RecipeType.NULL, Arrays.asList( + null, null, null, + null, sfItem, null, + null, null, null + ), MatchProcedure.SHAPED); + Assertions.assertTrue(search.matchFound()); + var result = search.getResult().get(); + Assertions.assertTrue(result.itemsMatch()); + var recipe = search.getRecipe().get(); + Assertions.assertEquals(recipe1, recipe); + + } + +}