aboutsummaryrefslogtreecommitdiff
path: root/src/functionalTest/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/functionalTest/java')
-rw-r--r--src/functionalTest/java/gregtech/test/GT5TestMod.java86
-rw-r--r--src/functionalTest/java/gregtech/test/GTParallelHelperTest.java122
-rw-r--r--src/functionalTest/java/gregtech/test/GTRecipeTest.java264
-rw-r--r--src/functionalTest/java/gregtech/test/mock/MockIVoidableMachine.java55
-rw-r--r--src/functionalTest/java/kubatech/test/EIGTests.java342
-rw-r--r--src/functionalTest/java/kubatech/test/kubatechTestMod.java101
6 files changed, 970 insertions, 0 deletions
diff --git a/src/functionalTest/java/gregtech/test/GT5TestMod.java b/src/functionalTest/java/gregtech/test/GT5TestMod.java
new file mode 100644
index 0000000000..88029f641d
--- /dev/null
+++ b/src/functionalTest/java/gregtech/test/GT5TestMod.java
@@ -0,0 +1,86 @@
+package gregtech.test;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.ChatComponentText;
+
+import org.apache.commons.io.output.CloseShieldOutputStream;
+import org.junit.platform.engine.discovery.DiscoverySelectors;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.LauncherSession;
+import org.junit.platform.launcher.TestPlan;
+import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
+import org.junit.platform.launcher.core.LauncherFactory;
+import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
+import org.junit.platform.launcher.listeners.TestExecutionSummary;
+import org.junit.platform.reporting.legacy.xml.LegacyXmlReportGeneratingListener;
+
+import cpw.mods.fml.common.FMLCommonHandler;
+import cpw.mods.fml.common.Mod;
+import cpw.mods.fml.common.event.FMLServerStartedEvent;
+
+@Mod(modid = "gt5-tests", name = "GT5 Dev Tests", version = "1.0", dependencies = "required-after:gregtech")
+public class GT5TestMod {
+
+ @Mod.EventHandler
+ public void onServerStarted(FMLServerStartedEvent event) {
+ MinecraftServer.getServer()
+ .addChatMessage(new ChatComponentText("Running GT5 unit tests..."));
+ runTests();
+ MinecraftServer.getServer()
+ .addChatMessage(new ChatComponentText("Running GT5 unit tests finished"));
+ }
+
+ private void runTests() {
+ // https://junit.org/junit5/docs/current/user-guide/#launcher-api
+ System.setProperty("junit.platform.reporting.open.xml.enabled", "false");
+ final Path testsXmlOutDir = FileSystems.getDefault()
+ .getPath("./junit-out/")
+ .toAbsolutePath();
+ final File testsXmlOutDirFile = testsXmlOutDir.toFile();
+ testsXmlOutDirFile.mkdirs();
+ {
+ File[] fileList = testsXmlOutDirFile.listFiles();
+ if (fileList != null) {
+ for (File child : fileList) {
+ if (child.isFile() && child.getName()
+ .endsWith(".xml")) {
+ child.delete();
+ }
+ }
+ }
+ }
+ final LauncherDiscoveryRequest discovery = LauncherDiscoveryRequestBuilder.request()
+ .selectors(DiscoverySelectors.selectPackage("gregtech.test"))
+ .build();
+ final SummaryGeneratingListener summaryGenerator = new SummaryGeneratingListener();
+ final TestExecutionSummary summary;
+ try (PrintWriter stderrWriter = new PrintWriter(new CloseShieldOutputStream(System.err), true)) {
+ final LegacyXmlReportGeneratingListener xmlGenerator = new LegacyXmlReportGeneratingListener(
+ testsXmlOutDir,
+ stderrWriter);
+ try (LauncherSession session = LauncherFactory.openSession()) {
+ final Launcher launcher = session.getLauncher();
+ final TestPlan plan = launcher.discover(discovery);
+ launcher.registerTestExecutionListeners(summaryGenerator, xmlGenerator);
+ launcher.execute(plan);
+ }
+ summary = summaryGenerator.getSummary();
+
+ summary.printFailuresTo(stderrWriter, 32);
+ summary.printTo(stderrWriter);
+ stderrWriter.flush();
+ }
+ // Throw an exception if running via `runServer`
+ if (summary.getTotalFailureCount() > 0 && FMLCommonHandler.instance()
+ .getSide()
+ .isServer()) {
+ throw new RuntimeException("Some of the unit tests failed to execute, check the log for details");
+ }
+ }
+}
diff --git a/src/functionalTest/java/gregtech/test/GTParallelHelperTest.java b/src/functionalTest/java/gregtech/test/GTParallelHelperTest.java
new file mode 100644
index 0000000000..67abe8a5bd
--- /dev/null
+++ b/src/functionalTest/java/gregtech/test/GTParallelHelperTest.java
@@ -0,0 +1,122 @@
+package gregtech.test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import gregtech.api.enums.Materials;
+import gregtech.api.enums.TierEU;
+import gregtech.api.util.GT_ParallelHelper;
+import gregtech.api.util.GT_Recipe;
+import gregtech.api.util.GT_Utility;
+import gregtech.test.mock.MockIVoidableMachine;
+
+public class GTParallelHelperTest {
+
+ static GT_Recipe rubberRecipe;
+ static ItemStack[] inputItems;
+ static MockIVoidableMachine machine;
+
+ @BeforeAll
+ static void setup() {
+ machine = new MockIVoidableMachine();
+ ItemStack rubberDust = Materials.RawRubber.getDust(1);
+ ItemStack sulfurDust = Materials.Sulfur.getDust(1);
+ rubberRecipe = new GT_Recipe(
+ new ItemStack[] { rubberDust.copy(), sulfurDust.copy() },
+ new ItemStack[] { Materials.Rubber.getDust(1), Materials.Rubber.getDustTiny(1) },
+ null,
+ new int[] { 10000, 6667 },
+ null,
+ new FluidStack[] { Materials.Rubber.getMolten(1000) },
+ 1,
+ 1,
+ 0);
+
+ inputItems = new ItemStack[] { GT_Utility.copyAmountUnsafe(Integer.MAX_VALUE, rubberDust),
+ GT_Utility.copyAmountUnsafe(Integer.MAX_VALUE, rubberDust),
+ GT_Utility.copyAmountUnsafe(Integer.MAX_VALUE, sulfurDust),
+ GT_Utility.copyAmountUnsafe(Integer.MAX_VALUE, sulfurDust) };
+ }
+
+ @Test
+ void OutputsIntegerOverflow() {
+ GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(rubberRecipe)
+ .setMachine(machine, false, false)
+ .setItemInputs(inputItems)
+ .setMaxParallel(4_000_000)
+ .setAvailableEUt(4_000_000)
+ .setOutputCalculation(true)
+ .setConsumption(false);
+ helper.build();
+ FluidStack[] fluidStacks = helper.getFluidOutputs();
+
+ assertEquals(2, fluidStacks.length);
+ assertEquals(Integer.MAX_VALUE, fluidStacks[0].amount);
+ assertEquals(4_000_000L * 1000 - Integer.MAX_VALUE, fluidStacks[1].amount);
+ }
+
+ @Test
+ void parallelIntegerOverflow() {
+ // Without batch mode
+ GT_ParallelHelper helperWithoutBatchMode = new GT_ParallelHelper().setRecipe(rubberRecipe)
+ .setMachine(machine, false, false)
+ .setItemInputs(inputItems)
+ .setMaxParallel(Integer.MAX_VALUE)
+ .setAvailableEUt(TierEU.MAX * 16)
+ .setConsumption(false)
+ .build();
+ assertEquals(Integer.MAX_VALUE, helperWithoutBatchMode.getCurrentParallel());
+
+ // With batch mode
+ GT_ParallelHelper helperWithBatchMode = new GT_ParallelHelper().setRecipe(rubberRecipe)
+ .setMachine(machine, false, false)
+ .setItemInputs(inputItems)
+ .setMaxParallel(Integer.MAX_VALUE / 50)
+ .setAvailableEUt(TierEU.MAX * 16)
+ .enableBatchMode(128)
+ .setConsumption(false)
+ .build();
+ assertEquals(Integer.MAX_VALUE, helperWithBatchMode.getCurrentParallel());
+ }
+
+ @Test
+ void chanceMultiplier() {
+ GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(rubberRecipe)
+ .setMachine(machine, false, false)
+ .setItemInputs(inputItems)
+ .setMaxParallel(10)
+ .setAvailableEUt(10)
+ .setConsumption(false)
+ .setOutputCalculation(true)
+ .setChanceMultiplier(10)
+ .build();
+
+ int rubberDustAmount = helper.getItemOutputs()[0].stackSize;
+ int rubberDustTinyAmount = helper.getItemOutputs()[1].stackSize;
+
+ assertEquals(100, rubberDustAmount);
+ assertTrue(rubberDustTinyAmount >= 60 && rubberDustTinyAmount <= 70);
+ }
+
+ @Test
+ void outputMultiplier() {
+ GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(rubberRecipe)
+ .setMachine(machine, false, false)
+ .setItemInputs(inputItems)
+ .setMaxParallel(1)
+ .setAvailableEUt(1)
+ .setConsumption(false)
+ .setOutputCalculation(true)
+ .setOutputMultiplier(2)
+ .build();
+
+ assertEquals(2000, helper.getFluidOutputs()[0].amount);
+ assertEquals(2, helper.getItemOutputs()[0].stackSize);
+ }
+}
diff --git a/src/functionalTest/java/gregtech/test/GTRecipeTest.java b/src/functionalTest/java/gregtech/test/GTRecipeTest.java
new file mode 100644
index 0000000000..c54fb0a7c8
--- /dev/null
+++ b/src/functionalTest/java/gregtech/test/GTRecipeTest.java
@@ -0,0 +1,264 @@
+package gregtech.test;
+
+import static gregtech.api.enums.GT_Values.RA;
+import static gregtech.api.enums.ItemList.Circuit_Advanced;
+import static gregtech.api.enums.ItemList.Circuit_Nanoprocessor;
+import static gregtech.api.enums.ItemList.Circuit_Parts_Crystal_Chip_Master;
+import static gregtech.api.enums.ItemList.IC2_LapotronCrystal;
+import static gregtech.api.enums.Materials.Advanced;
+import static gregtech.api.enums.Materials.BlueTopaz;
+import static gregtech.api.enums.Mods.GregTech;
+import static gregtech.api.enums.OrePrefixes.circuit;
+import static gregtech.api.enums.OrePrefixes.lens;
+import static gregtech.api.util.GT_ModHandler.getModItem;
+import static gregtech.api.util.GT_OreDictUnificator.get;
+import static gregtech.api.util.GT_OreDictUnificator.isItemStackInstanceOf;
+import static gregtech.api.util.GT_Utility.copyAmount;
+import static net.minecraft.init.Blocks.chest;
+import static net.minecraft.init.Blocks.iron_ore;
+import static net.minecraft.init.Blocks.lapis_block;
+import static net.minecraft.init.Blocks.log;
+import static net.minecraft.init.Blocks.planks;
+import static net.minecraft.init.Blocks.stone;
+import static net.minecraft.init.Blocks.stone_slab;
+import static net.minecraft.init.Items.glass_bottle;
+import static net.minecraft.init.Items.iron_ingot;
+import static net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import gregtech.api.enums.ItemList;
+import gregtech.api.recipe.RecipeMap;
+import gregtech.api.recipe.RecipeMapBuilder;
+import gregtech.api.util.GT_Recipe;
+
+class GTRecipeTest {
+
+ static RecipeMap<?> recipeMap;
+ static GT_Recipe lapotronChipRecipe;
+
+ @BeforeAll
+ static void setup() {
+ recipeMap = RecipeMapBuilder.of("__test__")
+ .maxIO(9, 1, 1, 0)
+ .build();
+
+ RA.stdBuilder()
+ .itemInputs(new ItemStack(log, 2, WILDCARD_VALUE), new ItemStack(planks, 2, WILDCARD_VALUE))
+ .itemOutputs(new ItemStack(chest, 1))
+ .duration(0)
+ .eut(0)
+ .addTo(recipeMap);
+
+ RA.stdBuilder()
+ .itemInputs(new ItemStack(lapis_block, 1), get(circuit, Advanced, 1))
+ .itemOutputs(IC2_LapotronCrystal.get(1))
+ .duration(0)
+ .eut(0)
+ .addTo(recipeMap);
+
+ lapotronChipRecipe = RA.stdBuilder()
+ .itemInputs(IC2_LapotronCrystal.getWildcard(1), copyAmount(0, get(lens, BlueTopaz, 1)))
+ .itemOutputs(Circuit_Parts_Crystal_Chip_Master.get(3))
+ .duration(0)
+ .eut(0)
+ .addTo(recipeMap)
+ .toArray(new GT_Recipe[0])[0];
+
+ RA.stdBuilder()
+ .itemInputs(getModItem(GregTech.ID, "gt.blockores", 1, 32))
+ .itemOutputs(new ItemStack(iron_ingot, 1))
+ .duration(0)
+ .eut(0)
+ .addTo(recipeMap);
+
+ RA.stdBuilder()
+ .itemInputs(new ItemStack(stone_slab, 64), new ItemStack(stone_slab, 64))
+ .itemOutputs(new ItemStack(stone, 2))
+ .duration(0)
+ .eut(0)
+ .addTo(recipeMap);
+
+ ItemStack dataStick = ItemList.Tool_DataStick.get(0);
+ NBTTagCompound dataStickTag = new NBTTagCompound();
+ dataStickTag.setInteger("integer", 123456);
+ dataStick.setTagCompound(dataStickTag);
+ RA.stdBuilder()
+ .itemInputs(dataStick)
+ .itemOutputs(new ItemStack(chest, 1))
+ .duration(0)
+ .eut(0)
+ .addTo(recipeMap);
+
+ ItemStack glass = new ItemStack(glass_bottle, 2);
+ NBTTagCompound glassTag = new NBTTagCompound();
+ glassTag.setInteger("integer", 123456);
+ glass.setTagCompound(glassTag);
+ RA.stdBuilder()
+ .itemInputs(glass)
+ .itemOutputs(new ItemStack(chest, 1))
+ .duration(0)
+ .eut(0)
+ .nbtSensitive()
+ .addTo(recipeMap);
+ }
+
+ @Test
+ void ensureRecipesAdded() {
+ assertEquals(
+ recipeMap.getAllRecipes()
+ .size(),
+ 7);
+ }
+
+ @Test
+ void findWithExactSameInputs() {
+ GT_Recipe recipe = recipeMap.findRecipeQuery()
+ .items(new ItemStack(lapis_block, 1), get(circuit, Advanced, 1))
+ .find();
+ assertNotNull(recipe);
+
+ GT_Recipe stoneRecipe = recipeMap.findRecipeQuery()
+ .items(new ItemStack(stone_slab, 128))
+ .find();
+ assertNotNull(stoneRecipe);
+ }
+
+ @Test
+ void findWildcardWithExactSameInputs() {
+ GT_Recipe chestRecipe = recipeMap.findRecipeQuery()
+ .items(new ItemStack(log, 2, WILDCARD_VALUE), new ItemStack(planks, 2, WILDCARD_VALUE))
+ .find();
+ assertNotNull(chestRecipe);
+
+ GT_Recipe lapotronChipRecipe = recipeMap.findRecipeQuery()
+ .items(IC2_LapotronCrystal.getWildcard(1), copyAmount(0, get(lens, BlueTopaz, 1)))
+ .find();
+ assertNotNull(lapotronChipRecipe);
+ }
+
+ @Test
+ void findWildcardWithDifferentMeta() {
+ // https://github.com/GTNewHorizons/GT5-Unofficial/pull/2364/commits/e7112fce5f24431f3a4ad19288d662b93cbb91f2
+ GT_Recipe recipe = recipeMap.findRecipeQuery()
+ .items(new ItemStack(log, 2, 0), new ItemStack(planks, 2, 1))
+ .find();
+ assertNotNull(recipe);
+ }
+
+ @Test
+ void findWithNBT() {
+ // https://github.com/GTNewHorizons/GT5-Unofficial/pull/2364/commits/844a38662b05494b42a4439bbc0e6d4d7df1a683
+ ItemStack lapisBlock = new ItemStack(lapis_block, 1);
+ NBTTagCompound tag = new NBTTagCompound();
+ tag.setFloat("charge", 123456);
+ lapisBlock.stackTagCompound = tag;
+ GT_Recipe recipe = recipeMap.findRecipeQuery()
+ .items(lapisBlock, get(circuit, Advanced, 1))
+ .find();
+ assertNotNull(recipe);
+
+ // For NBT sensitive recipes
+ ItemStack glass = new ItemStack(glass_bottle, 2);
+ NBTTagCompound glassTag = new NBTTagCompound();
+ glassTag.setInteger("integer", 123456);
+ glass.setTagCompound(glassTag);
+ GT_Recipe nbtSensitiveRecipe = recipeMap.findRecipeQuery()
+ .items(glass)
+ .find();
+ assertNotNull(nbtSensitiveRecipe);
+
+ // For items that need to check NBT, e.g. data sticks
+ ItemStack dataStick = ItemList.Tool_DataStick.get(0);
+ NBTTagCompound dataStickTag = new NBTTagCompound();
+ dataStickTag.setInteger("integer", 123456);
+ dataStick.setTagCompound(dataStickTag);
+ GT_Recipe checkNBTRecipe = recipeMap.findRecipeQuery()
+ .items(dataStick)
+ .find();
+ assertNotNull(checkNBTRecipe);
+ }
+
+ @Test
+ void rejectWithInsufficientAmount() {
+ GT_Recipe recipe = recipeMap.findRecipeQuery()
+ .items(new ItemStack(log, 1, 0), new ItemStack(planks, 1, 0))
+ .find();
+ assertNull(recipe);
+
+ GT_Recipe stoneRecipe = recipeMap.findRecipeQuery()
+ .items(new ItemStack(stone_slab, 127))
+ .find();
+ assertNull(stoneRecipe);
+ }
+
+ @Test
+ void rejectWithoutNonConsumable() {
+ // https://github.com/GTNewHorizons/GT5-Unofficial/pull/2364/commits/bfc93bff7ed34616021e8c5b6dbdc50dd7096af5
+ GT_Recipe recipe = recipeMap.findRecipeQuery()
+ .items(IC2_LapotronCrystal.get(1))
+ .cachedRecipe(lapotronChipRecipe)
+ .find();
+ assertNull(recipe);
+ }
+
+ @Test
+ void rejectWithoutCorrectNBT() {
+ // For NBT sensitive recipes
+ GT_Recipe nbtSensitiveRecipe = recipeMap.findRecipeQuery()
+ .items(new ItemStack(glass_bottle, 2))
+ .find();
+ assertNull(nbtSensitiveRecipe);
+
+ // For items that need to check NBT, e.g. data sticks
+ GT_Recipe checkNBTRecipe = recipeMap.findRecipeQuery()
+ .items(ItemList.Tool_DataStick.get(0))
+ .find();
+ assertNull(checkNBTRecipe);
+ }
+
+ @Test
+ void findOredicted() {
+ // https://github.com/GTNewHorizons/GT5-Unofficial/pull/2373
+ assertTrue(
+ isItemStackInstanceOf(Circuit_Nanoprocessor.get(1), "circuitAdvanced"),
+ "Nanoprocessor is not registered as HV circuit");
+ GT_Recipe recipeByNanoProcessor = recipeMap.findRecipeQuery()
+ .items(new ItemStack(lapis_block, 1), Circuit_Nanoprocessor.get(1))
+ .find();
+ assertNotNull(recipeByNanoProcessor);
+
+ assertTrue(
+ isItemStackInstanceOf(Circuit_Advanced.get(1), "circuitAdvanced"),
+ "Processor Assembly is not registered as HV circuit");
+ GT_Recipe recipeByCircuitAssembly = recipeMap.findRecipeQuery()
+ .items(new ItemStack(lapis_block, 1), Circuit_Advanced.get(1))
+ .find();
+ assertNotNull(recipeByCircuitAssembly);
+ }
+
+ @Test
+ void findWithSpecificOreDictionary() {
+ // https://github.com/GTNewHorizons/GT5-Unofficial/pull/2379
+ // We cannot use circuit assembling recipe like the issue mentioned above,
+ // as mUnificationTarget is not set for circuits in GT5.
+ // But it works in the same way; specific circuit -> GT ore block, unificated circuit -> vanilla ore block
+ GT_Recipe recipeCorrectOre = recipeMap.findRecipeQuery()
+ .items(getModItem(GregTech.ID, "gt.blockores", 1, 32))
+ .find();
+ assertNotNull(recipeCorrectOre);
+
+ GT_Recipe recipeWrongOre = recipeMap.findRecipeQuery()
+ .items(new ItemStack(iron_ore, 1))
+ .find();
+ assertNull(recipeWrongOre);
+ }
+}
diff --git a/src/functionalTest/java/gregtech/test/mock/MockIVoidableMachine.java b/src/functionalTest/java/gregtech/test/mock/MockIVoidableMachine.java
new file mode 100644
index 0000000000..4796d1d3ee
--- /dev/null
+++ b/src/functionalTest/java/gregtech/test/mock/MockIVoidableMachine.java
@@ -0,0 +1,55 @@
+package gregtech.test.mock;
+
+import java.util.List;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+import gregtech.api.enums.VoidingMode;
+import gregtech.api.interfaces.fluid.IFluidStore;
+import gregtech.api.interfaces.tileentity.IVoidable;
+
+public class MockIVoidableMachine implements IVoidable {
+
+ protected VoidingMode voidingMode = getDefaultVoidingMode();
+
+ @Override
+ public boolean supportsVoidProtection() {
+ return true;
+ }
+
+ @Override
+ public VoidingMode getVoidingMode() {
+ return voidingMode;
+ }
+
+ @Override
+ public void setVoidingMode(VoidingMode mode) {
+ voidingMode = mode;
+ }
+
+ @Override
+ public List<ItemStack> getItemOutputSlots(ItemStack[] toOutput) {
+ return null;
+ }
+
+ @Override
+ public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) {
+ return null;
+ }
+
+ @Override
+ public boolean canDumpItemToME() {
+ return false;
+ }
+
+ @Override
+ public boolean canDumpFluidToME() {
+ return false;
+ }
+
+ @Override
+ public VoidingMode getDefaultVoidingMode() {
+ return VoidingMode.VOID_ALL;
+ }
+}
diff --git a/src/functionalTest/java/kubatech/test/EIGTests.java b/src/functionalTest/java/kubatech/test/EIGTests.java
new file mode 100644
index 0000000000..1bb88814a4
--- /dev/null
+++ b/src/functionalTest/java/kubatech/test/EIGTests.java
@@ -0,0 +1,342 @@
+/*
+ * spotless:off
+ * KubaTech - Gregtech Addon
+ * Copyright (C) 2022 - 2024 kuba6000
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <https://www.gnu.org/licenses/>.
+ * spotless:on
+ */
+
+package kubatech.test;
+
+import static gregtech.api.util.GT_RecipeBuilder.MINUTES;
+import static gregtech.api.util.GT_RecipeBuilder.SECONDS;
+import static kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse.EIG_BALANCE_IC2_ACCELERATOR_TIER;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Map;
+
+import net.minecraft.block.Block;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.world.MinecraftException;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldProvider;
+import net.minecraft.world.WorldProviderSurface;
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.WorldSettings;
+import net.minecraft.world.WorldType;
+import net.minecraft.world.chunk.storage.IChunkLoader;
+import net.minecraft.world.storage.IPlayerFileData;
+import net.minecraft.world.storage.ISaveHandler;
+import net.minecraft.world.storage.WorldInfo;
+import net.minecraftforge.common.DimensionManager;
+
+import org.junit.jupiter.api.Test;
+
+import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
+
+import gregtech.api.GregTech_API;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.common.blocks.GT_Item_Machines;
+import ic2.api.crops.CropCard;
+import ic2.api.crops.Crops;
+import ic2.core.Ic2Items;
+import ic2.core.crop.TileEntityCrop;
+import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse;
+
+public class EIGTests {
+
+ private static final int EIG_CONTROLLER_METADATA = 12_792;
+ private static final int NUMBER_OF_CROPS_PER_TEST = 90;
+ private static final int NUMBER_OF_TESTS_TO_DO = 30;
+
+ static World myWorld;
+
+ public EIGTests() {
+ if (!DimensionManager.isDimensionRegistered(256)) {
+ DimensionManager.registerProviderType(256, WorldProviderSurface.class, false);
+ DimensionManager.registerDimension(256, 256);
+ }
+ if (myWorld == null) {
+ myWorld = new WorldServer(MinecraftServer.getServer(), new ISaveHandler() {
+
+ @Override
+ public WorldInfo loadWorldInfo() {
+ return null;
+ }
+
+ @Override
+ public void checkSessionLock() throws MinecraftException {
+
+ }
+
+ @Override
+ public IChunkLoader getChunkLoader(WorldProvider p_75763_1_) {
+ return null;
+ }
+
+ @Override
+ public void saveWorldInfoWithPlayer(WorldInfo p_75755_1_, NBTTagCompound p_75755_2_) {
+
+ }
+
+ @Override
+ public void saveWorldInfo(WorldInfo p_75761_1_) {
+
+ }
+
+ @Override
+ public IPlayerFileData getSaveHandler() {
+ return null;
+ }
+
+ @Override
+ public void flush() {
+
+ }
+
+ @Override
+ public File getWorldDirectory() {
+ return null;
+ }
+
+ @Override
+ public File getMapFileFromName(String p_75758_1_) {
+ return null;
+ }
+
+ @Override
+ public String getWorldDirectoryName() {
+ return "dummy";
+ }
+ },
+ "DummyTestWorld",
+ 256,
+ new WorldSettings(256, WorldSettings.GameType.SURVIVAL, false, false, WorldType.DEFAULT),
+ MinecraftServer.getServer().theProfiler) {
+
+ @Override
+ public File getChunkSaveLocation() {
+ return new File("ignoreme");
+ }
+
+ @Override
+ public int getBlockLightValue(int p_72957_1_, int p_72957_2_, int p_72957_3_) {
+ return 4;
+ }
+ };
+ }
+ }
+
+ private static int leftOverTicksFromRealRun = 0;
+
+ ItemStackMap<Integer> getRealDrops(TileEntityCrop cropTile, CropCard cc, int growth, int gain, int resistance) {
+ cropTile.setCrop(cc);
+ cropTile.setGrowth((byte) growth);
+ cropTile.setGain((byte) gain);
+ cropTile.setResistance((byte) resistance);
+ cropTile.tick();
+
+ ItemStackMap<Integer> expected = new ItemStackMap<>();
+
+ // run for 30 minutes
+ for (int k = 0; k < NUMBER_OF_CROPS_PER_TEST; k++) {
+ cropTile.ticker = 1;
+ cropTile.setSize((byte) cc.maxSize());
+ cropTile.setSize(cc.getSizeAfterHarvest(cropTile));
+ cropTile.growthPoints = 0;
+ int lastHarvestedAt = 0;
+ int i;
+ for (i = 0; i < (30 * MINUTES) * (1 << EIG_BALANCE_IC2_ACCELERATOR_TIER);) {
+ i += TileEntityCrop.tickRate;
+ cropTile.tick();
+ if (!cc.canGrow(cropTile)) {
+ lastHarvestedAt = i;
+ ItemStack[] stacks = cropTile.harvest_automated(false);
+ for (ItemStack stack : stacks) {
+ expected.merge(stack, stack.stackSize, Integer::sum);
+ }
+ }
+ }
+ leftOverTicksFromRealRun += i - lastHarvestedAt;
+ }
+
+ return expected;
+ }
+
+ ItemStackMap<Integer> getEIGDrops(GT_MetaTileEntity_ExtremeIndustrialGreenhouse EIG, ItemStack stack) {
+ ItemStackMap<Integer> generated = new ItemStackMap<>();
+ int imax = (30 * MINUTES) / (5 * SECONDS);
+ double ticks_to_ignore_per_operation = Math
+ .ceil((double) leftOverTicksFromRealRun / (NUMBER_OF_CROPS_PER_TEST * imax));
+ for (int j = 0; j < NUMBER_OF_CROPS_PER_TEST; j++) {
+ GT_MetaTileEntity_ExtremeIndustrialGreenhouse.GreenHouseSlot slot = new GT_MetaTileEntity_ExtremeIndustrialGreenhouse.GreenHouseSlot(
+ EIG,
+ stack.copy(),
+ true,
+ false);
+ if (slot.isValid) {
+ for (int i = 0; i < imax; i++) {
+ int ticks_to_ignore = (int) Math.min(ticks_to_ignore_per_operation, leftOverTicksFromRealRun);
+ leftOverTicksFromRealRun -= ticks_to_ignore;
+ for (ItemStack ic2Drop : slot.getIC2Drops(
+ EIG,
+ (5 * SECONDS * (1 << EIG_BALANCE_IC2_ACCELERATOR_TIER)) - (double) ticks_to_ignore)) {
+ generated.merge(ic2Drop, ic2Drop.stackSize, Integer::sum);
+ }
+ }
+ }
+ }
+
+ return generated;
+ }
+
+ @Test
+ void EIGDrops() {
+
+ myWorld.setBlock(10, 80, 0, Blocks.farmland, 0, 0);
+ myWorld.setBlock(10, 81, 0, Block.getBlockFromItem(Ic2Items.crop.getItem()), 0, 0);
+ CropCard cc = Crops.instance.getCropCard("gregtech", "Indigo");
+ TileEntityCrop cropTile = (TileEntityCrop) myWorld.getTileEntity(10, 81, 0);
+ ItemStack ccStack = cropTile.generateSeeds(cc, (byte) 10, (byte) 10, (byte) 10, (byte) 1);
+ for (int i = 0; i < TileEntityCrop.tickRate; i++) {
+ cropTile.waterStorage = 200;
+ cropTile.updateEntity();
+ }
+
+ GT_Item_Machines itemMachines = (GT_Item_Machines) Item.getItemFromBlock(GregTech_API.sBlockMachines);
+ itemMachines.placeBlockAt(
+ new ItemStack(itemMachines, 1, EIG_CONTROLLER_METADATA),
+ null,
+ myWorld,
+ 0,
+ 81,
+ 0,
+ 2,
+ 0,
+ 0,
+ 0,
+ EIG_CONTROLLER_METADATA);
+ IGregTechTileEntity te = (IGregTechTileEntity) myWorld.getTileEntity(0, 81, 0);
+ GT_MetaTileEntity_ExtremeIndustrialGreenhouse EIG = (GT_MetaTileEntity_ExtremeIndustrialGreenhouse) te
+ .getMetaTileEntity();
+
+ int[] abc = new int[] { 0, -2, 3 };
+ int[] xyz = new int[] { 0, 0, 0 };
+ EIG.getExtendedFacing()
+ .getWorldOffset(abc, xyz);
+ xyz[0] += te.getXCoord();
+ xyz[1] += te.getYCoord();
+ xyz[2] += te.getZCoord();
+
+ myWorld.setBlock(xyz[0], xyz[1] - 2, xyz[2], GregTech_API.sBlockCasings4, 1, 0);
+ myWorld.setBlock(xyz[0], xyz[1] - 1, xyz[2], Blocks.farmland, 0, 0);
+
+ ItemStack stackToTest = null;
+
+ for (int n = 0; n < 5; n++) {
+
+ int[] x = new int[NUMBER_OF_TESTS_TO_DO];
+ int[] y = new int[NUMBER_OF_TESTS_TO_DO];
+
+ // MinecraftServer.getServer()
+ // .addChatMessage(new ChatComponentText("[EIGTest results]"));
+
+ for (int i = 0; i < NUMBER_OF_TESTS_TO_DO; i++) {
+ leftOverTicksFromRealRun = 0;
+ ItemStackMap<Integer> expected = getRealDrops(cropTile, cc, 10, 10, 10);
+ ItemStackMap<Integer> generated = getEIGDrops(EIG, ccStack);
+
+ // MinecraftServer.getServer()
+ // .addChatMessage(new ChatComponentText("[TEST" + i + "]Real crop drops:"));
+ // for (Map.Entry<ItemStack, Integer> entry : expected.entrySet()) {
+ // MinecraftServer.getServer()
+ // .addChatMessage(new ChatComponentText("- " + entry.getKey().getDisplayName() + " x" +
+ // entry.getValue()));
+ // }
+
+ // MinecraftServer.getServer()
+ // .addChatMessage(new ChatComponentText("[TEST" + i + "]EIG crop drops:"));
+ // for (Map.Entry<ItemStack, Integer> entry : generated.entrySet()) {
+ // MinecraftServer.getServer()
+ // .addChatMessage(new ChatComponentText("- " + entry.getKey().getDisplayName() + " x" +
+ // entry.getValue()));
+ // }
+
+ // we are only comparing one item from drops
+ if (stackToTest == null) {
+ stackToTest = expected.entrySet()
+ .stream()
+ .max(Comparator.comparingInt(Map.Entry::getValue))
+ .get()
+ .getKey();
+ }
+
+ int expectedValue = expected.getOrDefault(stackToTest, 0);
+ int generatedValue = generated.getOrDefault(stackToTest, 0);
+
+ x[i] = expectedValue;
+ y[i] = generatedValue;
+ }
+
+ double real_average = Arrays.stream(x)
+ .average()
+ .getAsDouble();
+ double eig_average = Arrays.stream(y)
+ .average()
+ .getAsDouble();
+
+ double real_variance = 0d;
+ double a = 0d;
+ for (int i : x) {
+ a += (i - real_average) * (i - real_average);
+ }
+ a /= NUMBER_OF_TESTS_TO_DO;
+ real_variance = a;
+
+ double eig_variance = 0d;
+ a = 0d;
+ for (int i : y) {
+ a += (i - eig_average) * (i - eig_average);
+ }
+ a /= NUMBER_OF_TESTS_TO_DO;
+ eig_variance = a;
+
+ double u = (real_average - eig_average)
+ / Math.sqrt((real_variance / NUMBER_OF_TESTS_TO_DO) + (eig_variance / NUMBER_OF_TESTS_TO_DO));
+ MinecraftServer.getServer()
+ .addChatMessage(
+ new ChatComponentText(
+ "real average = " + Math
+ .round(real_average) + " eig average = " + Math.round(eig_average) + " u = " + u));
+ double test_critical_value = 1.959964d;
+ boolean passed = Math.abs(u) < test_critical_value;
+ boolean instafail = Math.abs(u) > test_critical_value * 2;
+ if (passed) return;
+ assertFalse(instafail);
+ }
+ fail();
+
+ }
+
+}
diff --git a/src/functionalTest/java/kubatech/test/kubatechTestMod.java b/src/functionalTest/java/kubatech/test/kubatechTestMod.java
new file mode 100644
index 0000000000..bc68d3f203
--- /dev/null
+++ b/src/functionalTest/java/kubatech/test/kubatechTestMod.java
@@ -0,0 +1,101 @@
+package kubatech.test;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.ChatComponentText;
+
+import org.apache.commons.io.output.CloseShieldOutputStream;
+import org.junit.platform.engine.discovery.DiscoverySelectors;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.LauncherSession;
+import org.junit.platform.launcher.TestPlan;
+import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
+import org.junit.platform.launcher.core.LauncherFactory;
+import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
+import org.junit.platform.launcher.listeners.TestExecutionSummary;
+import org.junit.platform.reporting.legacy.xml.LegacyXmlReportGeneratingListener;
+
+import cpw.mods.fml.common.FMLCommonHandler;
+import cpw.mods.fml.common.Mod;
+import cpw.mods.fml.common.Mod.EventHandler;
+import cpw.mods.fml.common.event.FMLPreInitializationEvent;
+import cpw.mods.fml.common.event.FMLServerStartedEvent;
+import gregtech.GT_Mod;
+
+@Mod(
+ modid = "kubatech-tests",
+ name = "KubaTech Dev Tests",
+ version = "1.0",
+ dependencies = "required-after:kubatech;required-after:gregtech;after:berriespp;")
+public class kubatechTestMod {
+
+ @EventHandler
+ public void preInit(FMLPreInitializationEvent ev) {
+ // Disable GT5u messing with vanilla recipes for unit tests
+ GT_Mod.gregtechproxy.mNerfedWoodPlank = false;
+ GT_Mod.gregtechproxy.mNerfedVanillaTools = false;
+ }
+
+ @EventHandler
+ public void onServerStarted(FMLServerStartedEvent startedEv) {
+ MinecraftServer.getServer()
+ .addChatMessage(new ChatComponentText("Running KT unit tests..."));
+ runTests();
+ MinecraftServer.getServer()
+ .addChatMessage(new ChatComponentText("Running KT unit tests finished"));
+ }
+
+ public void runTests() {
+ // https://junit.org/junit5/docs/current/user-guide/#launcher-api
+ System.setProperty("junit.platform.reporting.open.xml.enabled", "false");
+ final Path testsXmlOutDir = FileSystems.getDefault()
+ .getPath("./junit-out/")
+ .toAbsolutePath();
+ final File testsXmlOutDirFile = testsXmlOutDir.toFile();
+ testsXmlOutDirFile.mkdirs();
+ {
+ File[] fileList = testsXmlOutDirFile.listFiles();
+ if (fileList != null) {
+ for (File child : fileList) {
+ if (child.isFile() && child.getName()
+ .endsWith(".xml")) {
+ child.delete();
+ }
+ }
+ }
+ }
+ final LauncherDiscoveryRequest discovery = LauncherDiscoveryRequestBuilder.request()
+ .selectors(DiscoverySelectors.selectPackage("kubatech.test"))
+ .build();
+ final SummaryGeneratingListener summaryGenerator = new SummaryGeneratingListener();
+ final TestExecutionSummary summary;
+ try (PrintWriter stderrWriter = new PrintWriter(new CloseShieldOutputStream(System.err), true)) {
+ final LegacyXmlReportGeneratingListener xmlGenerator = new LegacyXmlReportGeneratingListener(
+ testsXmlOutDir,
+ stderrWriter);
+ try (LauncherSession session = LauncherFactory.openSession()) {
+ final Launcher launcher = session.getLauncher();
+ final TestPlan plan = launcher.discover(discovery);
+ launcher.registerTestExecutionListeners(summaryGenerator, xmlGenerator);
+ launcher.execute(plan);
+ }
+ summary = summaryGenerator.getSummary();
+
+ summary.printFailuresTo(stderrWriter, 32);
+ summary.printTo(stderrWriter);
+ stderrWriter.flush();
+ }
+ // Throw an exception if running via `runServer`
+ if (summary.getTotalFailureCount() > 0 && FMLCommonHandler.instance()
+ .getSide()
+ .isServer()) {
+ throw new RuntimeException("Some of the unit tests failed to execute, check the log for details");
+ }
+ }
+
+}