diff options
Diffstat (limited to 'src/functionalTest/java')
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"); + } + } + +} |