Some test harness stuffs. Time to get the registry manager properly tested.
This commit is contained in:
parent
5f234fdcf8
commit
22394f87d5
7 changed files with 362 additions and 4 deletions
|
@ -204,7 +204,7 @@ public class Loader
|
|||
}
|
||||
|
||||
modClassLoader = new ModClassLoader(getClass().getClassLoader());
|
||||
if (!mccversion.equals(MC_VERSION))
|
||||
if (mccversion !=null && !mccversion.equals(MC_VERSION))
|
||||
{
|
||||
FMLLog.severe("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, MC_VERSION);
|
||||
throw new LoaderException(String.format("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, MC_VERSION));
|
||||
|
@ -1023,7 +1023,10 @@ public class Loader
|
|||
|
||||
public void fireRemapEvent(Map<ResourceLocation, Integer[]> remapBlocks, Map<ResourceLocation, Integer[]> remapItems, boolean isFreezing)
|
||||
{
|
||||
modController.propogateStateMessage(new FMLModIdMappingEvent(remapBlocks, remapItems, isFreezing));
|
||||
if (modController!=null)
|
||||
{
|
||||
modController.propogateStateMessage(new FMLModIdMappingEvent(remapBlocks, remapItems, isFreezing));
|
||||
}
|
||||
}
|
||||
|
||||
public void runtimeDisableMod(String modId)
|
||||
|
|
|
@ -55,7 +55,10 @@ public class ModClassLoader extends URLClassLoader
|
|||
|
||||
public ModClassLoader(ClassLoader parent) {
|
||||
super(new URL[0], null);
|
||||
this.mainClassLoader = (LaunchClassLoader)parent;
|
||||
if (parent instanceof LaunchClassLoader)
|
||||
{
|
||||
this.mainClassLoader = (LaunchClassLoader)parent;
|
||||
}
|
||||
this.sources = Lists.newArrayList();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ import com.google.common.collect.Sets.SetView;
|
|||
@SuppressWarnings("WeakerAccess")
|
||||
public class PersistentRegistryManager
|
||||
{
|
||||
private enum PersistentRegistry
|
||||
enum PersistentRegistry
|
||||
{
|
||||
ACTIVE, VANILLA, FROZEN, STAGING;
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ public class FMLRelaunchLog {
|
|||
private static void configureLogging()
|
||||
{
|
||||
log.myLog = LogManager.getLogger("FML");
|
||||
// Default side to client for test harness purposes
|
||||
if (side == null) side = Side.CLIENT;
|
||||
ThreadContext.put("side", side.name().toLowerCase(Locale.ENGLISH));
|
||||
configured = true;
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
package net.minecraftforge.fml.common.registry;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runner.Runner;
|
||||
import org.junit.runner.notification.Failure;
|
||||
import org.junit.runner.notification.RunNotifier;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
|
||||
/**
|
||||
* Uses {@code ResettingClassLoader} to load the test class, meaning the
|
||||
* {@code Quarantine} annotation can be used to ensure certain classes are
|
||||
* loaded separately.
|
||||
*
|
||||
* Use of a separate class loader allows classes to be reloaded for each test
|
||||
* class, which is handy when you're testing frameworks that make use of static
|
||||
* members.
|
||||
*
|
||||
* The selective quarantining is required because if the test class and its
|
||||
* 'children' are all loaded by a different class loader, then the {@code Test}
|
||||
* annotations yield different {@code Class} instances. JUnit then thinks there
|
||||
* are no runnable methods, because it looks them up by Class.
|
||||
*
|
||||
* This is a simplified copy of https://github.com/BinaryTweed/quarantining-test-runner
|
||||
* tailored for Minecraft use.
|
||||
*
|
||||
*/
|
||||
public class ForgeTestRunner extends Runner
|
||||
{
|
||||
private final Object innerRunner;
|
||||
private final Class<?> innerRunnerClass;
|
||||
|
||||
public ForgeTestRunner(Class<?> testFileClass) throws InitializationError
|
||||
{
|
||||
Class<? extends Runner> delegateRunningTo = JUnit4.class;
|
||||
|
||||
String testFileClassName = testFileClass.getName();
|
||||
String delegateRunningToClassName = delegateRunningTo.getName();
|
||||
|
||||
String[] allPatterns = new String[] {testFileClassName, delegateRunningToClassName};
|
||||
|
||||
ResettingClassLoader classLoader = new ResettingClassLoader(allPatterns);
|
||||
|
||||
try
|
||||
{
|
||||
innerRunnerClass = classLoader.loadClass(delegateRunningToClassName);
|
||||
Class<?> testClass = classLoader.loadClass(testFileClassName);
|
||||
innerRunner = innerRunnerClass.cast(innerRunnerClass.getConstructor(Class.class).newInstance(testClass));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InitializationError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Description getDescription()
|
||||
{
|
||||
try
|
||||
{
|
||||
return (Description) innerRunnerClass.getMethod("getDescription").invoke(innerRunner);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("Could not get description", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(RunNotifier notifier)
|
||||
{
|
||||
try
|
||||
{
|
||||
innerRunnerClass.getMethod("run", RunNotifier.class).invoke(innerRunner, notifier);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
notifier.fireTestFailure(new Failure(getDescription(), e));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a class name starts with any of the supplied patterns, it is loaded by
|
||||
* <em>this</em> classloader; otherwise it is loaded by the parent classloader.
|
||||
*
|
||||
*/
|
||||
private class ResettingClassLoader extends URLClassLoader
|
||||
{
|
||||
private final Set<String> quarantinedClassNames;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param quarantinedClassNames prefixes to match against when deciding how to load a class
|
||||
*/
|
||||
public ResettingClassLoader(String... quarantinedClassNames)
|
||||
{
|
||||
super(((URLClassLoader) getSystemClassLoader()).getURLs());
|
||||
|
||||
this.quarantinedClassNames = Sets.newHashSet();
|
||||
Collections.addAll(this.quarantinedClassNames, quarantinedClassNames);
|
||||
Collections.addAll(this.quarantinedClassNames, "net.minecraft", "net.minecraftforge");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If a class name starts with any of the supplied patterns, it is loaded by
|
||||
* <em>this</em> classloader; otherwise it is loaded by the parent classloader.
|
||||
*
|
||||
* @param name class to load
|
||||
*/
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
boolean quarantine = false;
|
||||
|
||||
for(String quarantinedPattern : quarantinedClassNames)
|
||||
{
|
||||
if(name.startsWith(quarantinedPattern))
|
||||
{
|
||||
quarantine = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(quarantine)
|
||||
{
|
||||
try
|
||||
{
|
||||
return findClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return super.loadClass(name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package net.minecraftforge.fml.common.registry;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Created by cpw on 04/07/16.
|
||||
*/
|
||||
@RunWith(ForgeTestRunner.class)
|
||||
public class FreezingTests
|
||||
{
|
||||
|
||||
private static RTest r1;
|
||||
private static RTest r2;
|
||||
private static RTest r3;
|
||||
private static RTest r4;
|
||||
private static RTest r5;
|
||||
private static RTest r6;
|
||||
private static PersistentRegistryManager.GameDataSnapshot ss;
|
||||
|
||||
static class RTest extends IForgeRegistryEntry.Impl<RTest> {
|
||||
public RTest(String name) {
|
||||
setRegistryName(name);
|
||||
}
|
||||
}
|
||||
|
||||
public static IForgeRegistry<RTest> registry;
|
||||
public static ResourceLocation resloc = new ResourceLocation("fmltest:test");
|
||||
|
||||
@BeforeClass
|
||||
public static void setup()
|
||||
{
|
||||
Loader.instance();
|
||||
System.setProperty("fml.queryResult", "confirm");
|
||||
registry = PersistentRegistryManager.createRegistry(resloc, RTest.class, null, 0, 255, false, null, null, null);
|
||||
PersistentRegistryManager.createRegistry(PersistentRegistryManager.BLOCKS, Block.class, null, 0, 255, false, null, null, null);
|
||||
PersistentRegistryManager.createRegistry(PersistentRegistryManager.ITEMS, Item.class, null, 0, 255, false, null, null, null);
|
||||
r1 = new RTest("test1");
|
||||
r2 = new RTest("test2");
|
||||
r3 = new RTest("test3");
|
||||
r4 = new RTest("test4");
|
||||
r5 = new RTest("test5");
|
||||
r6 = new RTest("test6");
|
||||
ss = new PersistentRegistryManager.GameDataSnapshot();
|
||||
ss.entries.put(PersistentRegistryManager.BLOCKS, new PersistentRegistryManager.GameDataSnapshot.Entry());
|
||||
ss.entries.put(PersistentRegistryManager.ITEMS, new PersistentRegistryManager.GameDataSnapshot.Entry());
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r1);
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r2);
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r3);
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r4);
|
||||
ss.entries.put(resloc, new PersistentRegistryManager.GameDataSnapshot.Entry(PersistentRegistryManager.PersistentRegistry.ACTIVE.getRegistry(RTest.class)));
|
||||
PersistentRegistryManager.PersistentRegistry.ACTIVE.clean();
|
||||
PersistentRegistryManager.PersistentRegistry.FROZEN.clean();
|
||||
registry = PersistentRegistryManager.createRegistry(resloc, RTest.class, null, 0, 255, false, null, null, null);
|
||||
PersistentRegistryManager.createRegistry(PersistentRegistryManager.BLOCKS, Block.class, null, 0, 255, false, null, null, null);
|
||||
PersistentRegistryManager.createRegistry(PersistentRegistryManager.ITEMS, Item.class, null, 0, 255, false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreezeCycle()
|
||||
{
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r6);
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r5);
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r4);
|
||||
PersistentRegistryManager.findRegistryByType(RTest.class).register(r3);
|
||||
FMLControlledNamespacedRegistry<RTest> r = (FMLControlledNamespacedRegistry)PersistentRegistryManager.findRegistry(r3);
|
||||
int r3id = r.getId(r3);
|
||||
PersistentRegistryManager.freezeData();
|
||||
RTest q1 = PersistentRegistryManager.PersistentRegistry.FROZEN.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Frozen object is the same", r3, q1);
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.ACTIVE.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Active object is the same", r3, q1);
|
||||
PersistentRegistryManager.injectSnapshot(ss, false, false);
|
||||
assertNotEquals("IDs don't match", r3id, r.getId(r3));
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.FROZEN.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Frozen object is the same", r3, q1);
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.ACTIVE.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Active object is the same", r3, q1);
|
||||
PersistentRegistryManager.revertToFrozen();
|
||||
assertEquals("IDs match", r3id, r.getId(r3));
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.FROZEN.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Frozen object is the same", r3, q1);
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.ACTIVE.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Active object is the same", r3, q1);
|
||||
PersistentRegistryManager.injectSnapshot(ss, true, true);
|
||||
assertNotEquals("IDs don't match", r3id, r.getId(r3));
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.FROZEN.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Frozen object is the same", r3, q1);
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.ACTIVE.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Active object is the same", r3, q1);
|
||||
PersistentRegistryManager.revertToFrozen();
|
||||
assertEquals("IDs match", r3id, r.getId(r3));
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.FROZEN.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Frozen object is the same", r3, q1);
|
||||
q1 = PersistentRegistryManager.PersistentRegistry.ACTIVE.getRegistry(RTest.class).getValue(new ResourceLocation("test3"));
|
||||
assertEquals("Active object is the same", r3, q1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package net.minecraftforge.fml.common.registry;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Bootstrap;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Vanilla registry tests
|
||||
*/
|
||||
@RunWith(ForgeTestRunner.class)
|
||||
public class VanillaRegistryTests
|
||||
{
|
||||
@BeforeClass
|
||||
public static void setupHarness()
|
||||
{
|
||||
Loader.instance();
|
||||
Bootstrap.register();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetup()
|
||||
{
|
||||
// All the blocks loaded
|
||||
assertEquals("We have all the blocks via GameData",219,Block.REGISTRY.getKeys().size());
|
||||
|
||||
// All the items loaded
|
||||
assertEquals("We have all the items via GameData",371,Item.REGISTRY.getKeys().size());
|
||||
|
||||
// Our lookups find the same stuff vanilla sees
|
||||
final IForgeRegistry<Block> blocks = PersistentRegistryManager.findRegistry(Blocks.AIR);
|
||||
assertEquals("We have the right blocks for a block", blocks, Block.REGISTRY);
|
||||
|
||||
// We can look up stuff through our APIs
|
||||
Block bl = blocks.getValue(new ResourceLocation("minecraft:air"));
|
||||
assertEquals("We got air when we asked for it", Blocks.AIR, bl);
|
||||
|
||||
// Default values work
|
||||
Block blch = blocks.getValue(new ResourceLocation("minecraft:cheese"));
|
||||
assertEquals("We got air when we asked for cheese", Blocks.AIR, blch);
|
||||
|
||||
// Our lookups find the same stuff vanilla sees
|
||||
final IForgeRegistry<Item> items = PersistentRegistryManager.findRegistry(Items.BED);
|
||||
assertEquals("We have the right items for an item", items, Item.REGISTRY);
|
||||
|
||||
// We can look up stuff through our APIs
|
||||
Item it = items.getValue(new ResourceLocation("minecraft:bed"));
|
||||
assertEquals("We got a bed item when we asked for it", Items.BED, it);
|
||||
|
||||
// We find nothing for a non-defaulted registry
|
||||
Item none = items.getValue(new ResourceLocation("minecraft:cheese"));
|
||||
assertEquals("We got nothing (items) when we asked for cheese", null, none);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistration()
|
||||
{
|
||||
Block myBlock = GameRegistry.register(new Block(Material.CAKE) {}, new ResourceLocation("minecraft:testy"));
|
||||
assertNotNull("Registered my block", myBlock);
|
||||
|
||||
// Our lookups find the same stuff vanilla sees
|
||||
final IForgeRegistry<Block> blocks = PersistentRegistryManager.findRegistry(myBlock);
|
||||
assertEquals("We have the right blocks for a block", blocks, Block.REGISTRY);
|
||||
|
||||
Block found = blocks.getValue(new ResourceLocation("minecraft:testy"));
|
||||
assertEquals("Registry lookup works", myBlock, found);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistryStates()
|
||||
{
|
||||
final FMLControlledNamespacedRegistry<Block> blockVanilla = PersistentRegistryManager.PersistentRegistry.VANILLA.getRegistry(Block.class);
|
||||
final FMLControlledNamespacedRegistry<Block> blockActive = PersistentRegistryManager.PersistentRegistry.ACTIVE.getRegistry(Block.class);
|
||||
|
||||
assertNotEquals("Registry states are distinct", blockActive, blockVanilla);
|
||||
|
||||
final Block stoneActive = blockActive.getValue(new ResourceLocation("minecraft:stone"));
|
||||
final Block stoneVanilla = blockVanilla.getValue(new ResourceLocation("minecraft:stone"));
|
||||
|
||||
assertEquals("Stone from active and vanilla are the same", stoneActive, stoneVanilla);
|
||||
|
||||
int activeId = blockActive.getId(stoneActive);
|
||||
int vanillaId = blockVanilla.getId(stoneVanilla);
|
||||
|
||||
assertEquals("Stone has correct id", 1, activeId);
|
||||
assertEquals("Stone has correct id", 1, vanillaId);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in a new issue