diff options
Diffstat (limited to 'src/functionalTest/java/kubatech/test')
-rw-r--r-- | src/functionalTest/java/kubatech/test/EIGTests.java | 277 | ||||
-rw-r--r-- | src/functionalTest/java/kubatech/test/kubatechTestMod.java | 101 |
2 files changed, 378 insertions, 0 deletions
diff --git a/src/functionalTest/java/kubatech/test/EIGTests.java b/src/functionalTest/java/kubatech/test/EIGTests.java new file mode 100644 index 0000000000..7cdfa8dae4 --- /dev/null +++ b/src/functionalTest/java/kubatech/test/EIGTests.java @@ -0,0 +1,277 @@ +/* + * 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.HOURS; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +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.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.biome.BiomeGenBase; +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 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 ic2.core.item.ItemCropSeed; +import kubatech.api.eig.EIGDropTable; +import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse; +import kubatech.tileentity.gregtech.multiblock.eigbuckets.EIGIC2Bucket; + +public class EIGTests { + + private static final int EIG_CONTROLLER_METADATA = 12_792; + private static final int EIG_SIMULATION_TIME = 24 * HOURS; + private static final int NUMBER_OF_TESTS_TO_DO = 1000; + + 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; + } + + @Override + public BiomeGenBase getBiomeGenForCoords(int x, int z) { + // give the environment a fighting chance of being bearable for crops + return BiomeGenBase.jungle; + } + }; + } + } + + EIGDropTable 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); + EIGDropTable expected = new EIGDropTable(); + byte startingHumidity = cropTile.humidity; + byte startingNutrients = cropTile.nutrients; + byte startingAirQuality = cropTile.airQuality; + int startingNutrientStorage = cropTile.nutrientStorage; + int startingWaterStorage = cropTile.waterStorage; + // reset the crop to it's stage after harvest + cropTile.setSize((byte) cc.maxSize()); + cropTile.setSize(cc.getSizeAfterHarvest(cropTile)); + for (int timeElapsed = 0; timeElapsed < EIG_SIMULATION_TIME; timeElapsed += TileEntityCrop.tickRate) { + // force reset the stats to max because the eig shouldn't make them change. + // some crops check water storage in the can grow and we are ticking which consumes water. + cropTile.humidity = startingHumidity; + cropTile.nutrients = startingNutrients; + cropTile.airQuality = startingAirQuality; + cropTile.nutrientStorage = startingNutrientStorage; + cropTile.waterStorage = startingWaterStorage; + // if fully grown harvest the crop + if (cropTile.getSize() >= cc.maxSize()) { + ItemStack[] stacks = cropTile.harvest_automated(false); + for (ItemStack stack : stacks) { + expected.addDrop(stack, stack.stackSize); + } + } + cropTile.tick(); + } + // ensure it leaves the same way it came in + cropTile.humidity = startingHumidity; + cropTile.nutrients = startingNutrients; + cropTile.airQuality = startingAirQuality; + cropTile.nutrientStorage = startingNutrientStorage; + cropTile.waterStorage = startingWaterStorage; + return expected; + } + + EIGDropTable getEIGDrops(GT_MetaTileEntity_ExtremeIndustrialGreenhouse EIG, ItemStack stack) { + EIGDropTable generated = new EIGDropTable(); + EIGIC2Bucket bucket = new EIGIC2Bucket(stack, stack.stackSize, null, false); + bucket.revalidate(EIG); + bucket.addProgress(EIG_SIMULATION_TIME, generated); + 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); + // using stickreed since it has a random stage after harvest. + // it's also more preferable to test using faster growing crops since they can be harvested more often. + CropCard cc = Crops.instance.getCropCard("IC2", "stickreed"); + TileEntityCrop cropTile = (TileEntityCrop) myWorld.getTileEntity(10, 81, 0); + ItemStack ccStack = ItemCropSeed.generateItemStackFromValues(cc, (byte) 10, (byte) 10, (byte) 10, (byte) 1); + + 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(); + + // update stats of crop TE to those provided by the EIG + cropTile.humidity = EIGIC2Bucket.getHumidity(EIG, false); + cropTile.nutrients = EIGIC2Bucket.getNutrients(EIG); + cropTile.airQuality = EIGIC2Bucket.getAirQuality(EIG); + + 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; + + double realAvg = 0, eigAvg = 0; + + for (int i = 0; i < NUMBER_OF_TESTS_TO_DO; i++) { + EIGDropTable expected = getRealDrops(cropTile, cc, 10, 10, 10); + EIGDropTable generated = getEIGDrops(EIG, ccStack); + + // we are only comparing one item from drops + if (stackToTest == null) { + stackToTest = expected.entrySet() + .stream() + .max(Map.Entry.comparingByValue()) + .get() + .getKey(); + } + + realAvg += expected.getItemAmount(stackToTest); + // EIG with ic2 crops doesn't actually have variance, it uses very precise approximations that create + // accurate growth rate and drop quality approximations. + eigAvg += generated.getItemAmount(stackToTest); + } + realAvg /= NUMBER_OF_TESTS_TO_DO; + eigAvg /= NUMBER_OF_TESTS_TO_DO; + double accuracy = Math.min(realAvg / eigAvg, eigAvg / realAvg); + + String debugInfo = String.format("realAvg: %.5f | eigAvg : %.5f | accuracy = %.5f", realAvg, eigAvg, accuracy); + System.out.println(debugInfo); + + // We aim for about 99% accuracy over here. + assertTrue(accuracy >= 0.99d); + } + +} 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"); + } + } + +} |