package com.laytonsmith.testing;
import com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery;
import com.laytonsmith.PureUtilities.Common.StackTraceUtils;
import com.laytonsmith.PureUtilities.DaemonManager;
import com.laytonsmith.PureUtilities.RunnableQueue;
import com.laytonsmith.abstraction.AbstractConvertor;
import com.laytonsmith.abstraction.Convertor;
import com.laytonsmith.abstraction.ConvertorHelper;
import com.laytonsmith.abstraction.Implementation;
import com.laytonsmith.abstraction.MCColor;
import com.laytonsmith.abstraction.MCCommandSender;
import com.laytonsmith.abstraction.MCConsoleCommandSender;
import com.laytonsmith.abstraction.MCEnchantment;
import com.laytonsmith.abstraction.MCEntity;
import com.laytonsmith.abstraction.MCFireworkBuilder;
import com.laytonsmith.abstraction.MCInventory;
import com.laytonsmith.abstraction.MCItemMeta;
import com.laytonsmith.abstraction.MCItemStack;
import com.laytonsmith.abstraction.MCLocation;
import com.laytonsmith.abstraction.MCMetadataValue;
import com.laytonsmith.abstraction.MCNote;
import com.laytonsmith.abstraction.MCPattern;
import com.laytonsmith.abstraction.MCPlayer;
import com.laytonsmith.abstraction.MCPlugin;
import com.laytonsmith.abstraction.MCPluginMeta;
import com.laytonsmith.abstraction.MCPotionData;
import com.laytonsmith.abstraction.MCRecipe;
import com.laytonsmith.abstraction.MCServer;
import com.laytonsmith.abstraction.MCWorld;
import com.laytonsmith.abstraction.blocks.MCMaterial;
import com.laytonsmith.abstraction.bukkit.BukkitConvertor;
import com.laytonsmith.abstraction.bukkit.BukkitMCLocation;
import com.laytonsmith.abstraction.bukkit.BukkitMCWorld;
import com.laytonsmith.abstraction.enums.MCDyeColor;
import com.laytonsmith.abstraction.enums.MCPatternShape;
import com.laytonsmith.abstraction.enums.MCPotionType;
import com.laytonsmith.abstraction.enums.MCRecipeType;
import com.laytonsmith.abstraction.enums.MCTone;
import com.laytonsmith.annotations.convert;
import com.laytonsmith.annotations.noboilerplate;
import com.laytonsmith.annotations.typeof;
import com.laytonsmith.commandhelper.CommandHelperPlugin;
import com.laytonsmith.core.AliasCore;
import com.laytonsmith.core.CHLog;
import com.laytonsmith.core.MethodScriptCompiler;
import com.laytonsmith.core.MethodScriptComplete;
import com.laytonsmith.core.Optimizable;
import com.laytonsmith.core.Prefs;
import com.laytonsmith.core.Script;
import com.laytonsmith.core.Static;
import com.laytonsmith.core.constructs.CBoolean;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.Construct;
import com.laytonsmith.core.constructs.Target;
import com.laytonsmith.core.constructs.Token;
import com.laytonsmith.core.environments.CommandHelperEnvironment;
import com.laytonsmith.core.environments.Environment;
import com.laytonsmith.core.events.AbstractEvent;
import com.laytonsmith.core.events.BindableEvent;
import com.laytonsmith.core.events.EventMixinInterface;
import com.laytonsmith.core.exceptions.CRE.AbstractCREException;
import com.laytonsmith.core.exceptions.CRE.CREFormatException;
import com.laytonsmith.core.exceptions.CRE.CREThrowable;
import com.laytonsmith.core.exceptions.CancelCommandException;
import com.laytonsmith.core.exceptions.ConfigRuntimeException;
import com.laytonsmith.core.exceptions.EventException;
import com.laytonsmith.core.exceptions.FunctionReturnException;
import com.laytonsmith.core.exceptions.LoopBreakException;
import com.laytonsmith.core.exceptions.LoopContinueException;
import com.laytonsmith.core.extensions.ExtensionManager;
import com.laytonsmith.core.functions.BasicLogic.equals;
import com.laytonsmith.core.functions.Function;
import com.laytonsmith.core.functions.FunctionBase;
import org.mockito.Mockito;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
//import static org.powermock.api.mockito.PowerMockito.mock;
//import org.powermock.modules.junit4.PowerMockRunner;
/**
*
*
*/
//@RunWith(PowerMockRunner.class)
public class StaticTest {
static com.laytonsmith.core.environments.Environment env;
static {
try {
Implementation.setServerType(Implementation.Type.TEST);
env = Static.GenerateStandaloneEnvironment();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* Tests the boilerplate functions in a Function. While all functions should
* conform to at least this, it is useful to also use the more strict
* TestBoilerplate function.
*
* @param ff
* @param name
* @throws java.lang.Exception
*/
public static void TestBoilerplate(FunctionBase ff, String name) throws Exception {
if (!(ff instanceof Function)) {
return;
}
Function f = (Function) ff;
//For the "quality test code coverage" number, set this to true
boolean runQualityTestsOnly = false;
MCServer fakeServer = StaticTest.GetFakeServer();
MCPlayer fakePlayer = StaticTest.GetOnlinePlayer("Player01", fakeServer);
//make sure that these functions don't throw an exception. Any other results
//are fine
f.isRestricted();
f.runAsync();
f.preResolveVariables();
f.thrown();
//name should match the given value
if (!f.getName().equals(name)) {
fail("Expected name of function to be " + name + ", but was given " + f.getName());
}
//docs needs to at least be more than a non-empty string, though in the future this should follow a more strict
//requirement set.
if (f.docs().length() <= 0) {
fail("docs must return a non-empty string");
}
TestDocs(f);
if (f.numArgs().length == 0) {
fail("numArgs must return an Integer array with more than zero values");
}
//If we want a "quality test coverage" number, we can't run this section, because it bombards the code
//with random data to see if it fails in expected ways (to simulate how a user could run the scripts)
//If we are interested in tests that are specific to the functions however, we shouldn't run this.
if (!runQualityTestsOnly && f.getClass().getAnnotation(noboilerplate.class) == null) {
TestExec(f, fakePlayer, "fake player");
TestExec(f, null, "null command sender");
TestExec(f, StaticTest.GetFakeConsoleCommandSender(), "fake console command sender");
}
//Let's make sure that if execs is defined in the class, useSpecialExec returns true.
//Same thing for optimize/canOptimize and optimizeDynamic/canOptimizeDynamic
if (f instanceof Optimizable) {
Set<Optimizable.OptimizationOption> options = ((Optimizable) f).optimizationOptions();
if (options.contains(Optimizable.OptimizationOption.CONSTANT_OFFLINE) && options.contains(Optimizable.OptimizationOption.OPTIMIZE_CONSTANT)) {
fail(f.getName() + " declares both CONSTANT_OFFLINE and OPTIMIZE_CONSTANT, which are mutually exclusive.");
}
}
for (Method method : f.getClass().getDeclaredMethods()) {
if (method.getName().equals("execs")) {
if (!f.useSpecialExec()) {
fail(f.getName() + " declares execs, but returns false for useSpecialExec.");
}
}
if (f instanceof Optimizable) {
Set<Optimizable.OptimizationOption> options = ((Optimizable) f).optimizationOptions();
if (method.getName().equals("optimize")) {
if (!options.contains(Optimizable.OptimizationOption.OPTIMIZE_CONSTANT)) {
fail(f.getName() + " declares optimize, but does not declare that it can OPTIMIZE_CONSTANT");
}
}
if (method.getName().equals("optimizeDynamic")) {
if (!options.contains(Optimizable.OptimizationOption.OPTIMIZE_DYNAMIC)) {
fail(f.getName() + " declares optimizeDynamic, but does not declare that it can OPTIMIZE_DYNAMIC");
}
}
}
}
//now the only function left to test is exec. This cannot be abstracted, unfortunately.
}
/**
* Checks to see if the documentation follows the specified format
*
* @param f
*/
public static void TestDocs(Function f) {
//TODO
}
private static ArrayList<String> tested = new ArrayList<String>();
public static void TestExec(Function f, MCCommandSender p, String commandType) throws Exception {
if (tested.contains(f.getName() + String.valueOf(p))) {
return;
}
tested.add(f.getName() + String.valueOf(p));
env.getEnv(CommandHelperEnvironment.class).SetCommandSender(p);
//See if the function throws something other than a ConfigRuntimeException or CancelCommandException if we send it bad arguments,
//keeping in mind of course, that it isn't supposed to be able to accept the wrong number of arguments. Specifically, we want to try
//strings, numbers, arrays, and nulls
for (Integer i : f.numArgs()) {
if (i == Integer.MAX_VALUE) {
//er.. let's just try with 10...
i = 10;
}
Construct[] con = new Construct[i];
//Throw the book at it. Most functions will fail, and that is ok, what isn't
//ok is if it throws an unexpected type of exception. It should only ever
//throw a ConfigRuntimeException, or a CancelCommandException. Further,
//if it throws a ConfigRuntimeException, the documentation should state so.
for (int z = 0; z < 10; z++) {
for (int a = 0; a < i; a++) {
switch (z) {
case 0:
con[a] = C.onstruct("hi");
break;
case 1:
con[a] = C.onstruct(1);
break;
case 2:
con[a] = C.Array(C.onstruct("hi"), C.onstruct(1));
break;
case 3:
con[a] = C.Null();
break;
case 4:
con[a] = C.onstruct(-1);
break;
case 5:
con[a] = C.onstruct(0);
break;
case 6:
con[a] = C.onstruct(100);
break;
case 7:
con[a] = C.onstruct(a);
break;
case 8:
con[a] = C.onstruct(true);
break;
case 9:
con[a] = C.onstruct(false);
break;
}
}
try {
f.exec(Target.UNKNOWN, env, con);
} catch (CancelCommandException e) {
} catch (ConfigRuntimeException e) {
if (f.getName().equals("throw")) {
// throw() can throw anything.
return;
}
String name = AbstractCREException.getExceptionName(e);
// This eventually needs to be changed. It should return class
// objects instead, but for now, it returns an enum. This will
// be a large change.
List<String> expectedNames = new ArrayList<>();
for (Class<? extends CREThrowable> tt : f.thrown()) {
expectedNames.add(tt.getAnnotation(typeof.class).value());
}
if (f.thrown() == null || !expectedNames.contains(name)) {
fail("The documentation for " + f.getName() + " doesn't state that it can throw a "
+ name + ", but it did.");
}
} catch (Throwable e) {
if (e instanceof LoopBreakException && !f.getName().equals("break")) {
fail("Only break() can throw LoopBreakExceptions");
}
if (e instanceof LoopContinueException && !f.getName().equals("continue")) {
fail("Only continue() can throw LoopContinueExceptions");
}
if (e instanceof FunctionReturnException && !f.getName().equals("return")) {
fail("Only return() can throw FunctionReturnExceptions");
}
if (e instanceof NullPointerException) {
String error = (f.getName() + " breaks if you send it the following while using a " + commandType + ": " + Arrays.deepToString(con) + "\n");
error += ("Here is the first few stack trace lines:\n");
error += ("\t" + e.getStackTrace()[0].toString() + "\n");
error += ("\t" + e.getStackTrace()[1].toString() + "\n");
error += ("\t" + e.getStackTrace()[2].toString() + "\n");
System.err.println(StackTraceUtils.GetStacktrace(e));
if (!brokenJunk.contains(error)) {
brokenJunk.add(error);
}
}
}
}
}
}
static Set<String> brokenJunk = new TreeSet<String>();
public static void TestClassDocs(String docs, Class container) {
if (docs.length() <= 0) {
fail("The docs for the " + container.getSimpleName() + " class are missing");
}
}
/**
* Gets the value out of s construct, ignoring information like line
* numbers.
*
* @param c
* @return
*/
public static Object Val(Construct c) {
return c.val();
}
/**
* Checks to see if two constructs are equal, using the same method that
* MethodScript equals() uses. In fact, this method depends on equals()
* working, as it actually uses the function.
*
* @param expected
* @param actual
*/
public static void assertCEquals(Construct expected, Construct actual) throws CancelCommandException {
equals e = new equals();
CBoolean ret = (CBoolean) e.exec(Target.UNKNOWN, null, expected, actual);
if (ret.getBoolean() == false) {
throw new AssertionError("Expected " + expected + " and " + actual + " to be equal to each other");
}
}
/**
* Does the opposite of assertCEquals
*
* @param expected
* @param actual
* @throws CancelCommandException
*/
public static void assertCNotEquals(Construct expected, Construct actual) throws CancelCommandException {
equals e = new equals();
CBoolean ret = (CBoolean) e.exec(Target.UNKNOWN, null, expected, actual);
if (ret.getBoolean() == true) {
throw new AssertionError("Did not expect " + expected + " and " + actual + " to be equal to each other");
}
}
/**
* Verifies that the given construct <em>resolves</em> to true. The
* resolution uses Static.getBoolean to do the resolution.
*
* @param actual
*/
public static void assertCTrue(Construct actual) {
if (!Static.getBoolean(actual)) {
fail("Expected '" + actual.val() + "' to resolve to true, but it did not");
}
}
/**
* Verifies that the given construct <em>resolves</em> to false. The
* resolution uses Static.getBoolean to do the resolution.
*
* @param actual
*/
public static void assertCFalse(Construct actual) {
if (Static.getBoolean(actual)) {
fail("Expected '" + actual.val() + "' to resolve to false, but it did not");
}
}
/**
* This function is used to assert that the type of a construct is one of
* the specified types.
*
* @param test
* @param retTypes
*/
public static void assertReturn(Construct test, Class... retTypes) {
if (!Arrays.asList(retTypes).contains(test.getClass())) {
StringBuilder b = new StringBuilder();
if (retTypes.length == 1) {
b.append("Expected return type to be ").append(retTypes[0].getSimpleName()).append(", but found ").append(test.getClass().getSimpleName());
} else if (retTypes.length == 2) {
b.append("Expected return type to be either ").append(retTypes[0].getSimpleName()).append(" or ").append(retTypes[1].getSimpleName()).append(", but found ").append(test.getClass().getSimpleName());
} else {
b.append("Expected return type to be one of: ");
for (int i = 0; i < retTypes.length; i++) {
if (i < retTypes.length - 1) {
b.append(retTypes[i].getSimpleName()).append(", ");
} else {
b.append("or ").append(retTypes[i].getSimpleName());
}
}
b.append(", but found ").append(test.getClass().getSimpleName());
}
throw new AssertionError(b);
}
}
public static List<Token> tokens(Token... array) {
List<Token> tokens = new ArrayList<Token>();
tokens.addAll(Arrays.asList(array));
return tokens;
}
public static MCPlayer GetOnlinePlayer() {
MCServer s = GetFakeServer();
return GetOnlinePlayer("Player01", s);
}
public static MCPlayer GetOnlinePlayer(MCServer s) {
return GetOnlinePlayer("Player01", s);
}
public static MCPlayer GetOnlinePlayer(String name, MCServer s) {
return GetOnlinePlayer(name, "world", s);
}
public static MCPlayer GetOnlinePlayer(String name, String worldName, MCServer s) {
MCPlayer p = mock(MCPlayer.class);
MCWorld w = mock(MCWorld.class);
MCLocation fakeLocation = StaticTest.GetFakeLocation(w, 0, 0, 0);
MCItemStack fakeItemStack = mock(MCItemStack.class);
when(w.getName()).thenReturn(worldName);
when(p.getWorld()).thenReturn(w);
when(p.isOnline()).thenReturn(true);
when(p.getName()).thenReturn(name);
when(p.getServer()).thenReturn(s);
when(p.isOp()).thenReturn(true);
if (s != null && s.getOnlinePlayers() != null) {
Collection<MCPlayer> online = s.getOnlinePlayers();
boolean alreadyOnline = false;
for (MCPlayer o : online) {
if (o.getName().equals(name)) {
alreadyOnline = true;
break;
}
}
if (!alreadyOnline) {
online.add(p);
when(s.getOnlinePlayers()).thenReturn(new HashSet<MCPlayer>());
}
}
//Plethora of fake data
when(p.getCompassTarget()).thenReturn(fakeLocation);
when(p.getItemAt((Integer) Mockito.any())).thenReturn(fakeItemStack);
return p;
}
public static MCPlayer GetOp(String name, MCServer s) {
MCPlayer p = GetOnlinePlayer(name, s);
when(p.isOp()).thenReturn(true);
return p;
}
public static BukkitMCWorld GetWorld(String name) {
BukkitMCWorld w = mock(BukkitMCWorld.class);
when(w.getName()).thenReturn(name);
return w;
}
public static MCConsoleCommandSender GetFakeConsoleCommandSender() {
MCConsoleCommandSender c = mock(MCConsoleCommandSender.class);
when(c.getName()).thenReturn("CONSOLE");
MCServer s = GetFakeServer();
when(c.getServer()).thenReturn(s);
return c;
}
public static MCLocation GetFakeLocation(MCWorld w, double x, double y, double z) {
MCLocation loc = mock(BukkitMCLocation.class);
when(loc.getWorld()).thenReturn(w);
when(loc.getX()).thenReturn(x);
when(loc.getY()).thenReturn(y - 1);
when(loc.getZ()).thenReturn(z);
return loc;
}
public static Object GetVariable(Object instance, String var) throws Exception {
return GetVariable(instance.getClass(), var, instance);
}
public static Object GetVariable(Class c, String var, Object instance) throws Exception {
Field f = c.getField(var);
f.setAccessible(true);
return f.get(instance);
}
/**
* Lexes, compiles, and runs a given MethodScript, using the given player.
*
* @param script
* @param player
* @throws Exception
*/
public static void Run(String script, MCCommandSender player) throws Exception {
Run(script, player, null, null);
}
public static void Run(String script, MCCommandSender player, MethodScriptComplete done, Environment env) throws Exception {
InstallFakeServerFrontend();
if (env == null) {
env = StaticTest.env;
}
env.getEnv(CommandHelperEnvironment.class).SetCommandSender(player);
MethodScriptCompiler.execute(MethodScriptCompiler.compile(MethodScriptCompiler.lex(script, null, true)), env, done, null);
}
public static void RunCommand(String combinedScript, MCCommandSender player, String command) throws Exception {
RunCommand(combinedScript, player, command, env);
}
public static void RunCommand(String combinedScript, MCCommandSender player, String command, Environment env) throws Exception {
InstallFakeServerFrontend();
if (env == null) {
env = StaticTest.env;
}
env.getEnv(CommandHelperEnvironment.class).SetCommandSender(player);
List<Script> scripts = MethodScriptCompiler.preprocess(MethodScriptCompiler.lex(combinedScript, null, false));
for (Script s : scripts) {
s.compile();
if (s.match(command)) {
s.run(s.getVariables(command), env, null);
}
}
}
public static String SRun(String script, MCCommandSender player, Environment env) throws Exception {
InstallFakeServerFrontend();
final StringBuffer b = new StringBuffer();
Run(script, player, new MethodScriptComplete() {
@Override
public void done(String output) {
b.append(output);
}
}, env);
return b.toString();
}
public static String SRun(String script, MCCommandSender player) throws Exception {
return SRun(script, player, env);
}
//TODO: Fix this
// public static void RunVars(List<Variable> vars, String script, MCCommandSender player) throws Exception{
// Env env = new Env();
// env.SetCommandSender(player);
// MethodScriptCompiler.compile(MethodScriptCompiler.lex(script, null));
// injectAliasCore();
// Script s = MethodScriptCompiler.preprocess(MethodScriptCompiler.lex(script, null), env).get(0);
// s.compile();
// s.run(vars, env, null);
//
// }
//Blarg. Dumb thing.
// private static void injectAliasCore() throws Exception{
// PermissionsResolverManager prm = mock(PermissionsResolverManager.class);
// CommandHelperPlugin chp = mock(CommandHelperPlugin.class);
// AliasCore ac = new AliasCore(new File("plugins/CommandHelper/config.txt"),
// new File("plugins/CommandHelper/LocalPackages"),
// new File("plugins/CommandHelper/preferences.ini"),
// new File("plugins/CommandHelper/main.ms"), prm, chp);
// try{
// Field aliasCore = CommandHelperPlugin.class.getDeclaredField("ac");
// aliasCore.setAccessible(true);
// aliasCore.set(null, ac);
// } catch(Exception e){
// throw new RuntimeException("Core could not be injected", e);
// }
// }
/**
* Creates an entire fake server environment, adding players and everything.
*
* @return The fake MCServer
*/
public static MCServer GetFakeServer() {
MCServer fakeServer = mock(MCServer.class);
String[] pnames = new String[]{"player1", "player2", "player3"};
ArrayList<MCPlayer> pps = new ArrayList<MCPlayer>();
for (String p : pnames) {
MCPlayer pp = GetOnlinePlayer(p, fakeServer);
pps.add(pp);
}
when(fakeServer.getOnlinePlayers()).thenReturn(new HashSet<MCPlayer>());
CommandHelperPlugin.myServer = fakeServer;
return fakeServer;
}
private static boolean frontendInstalled = false;
/**
* This installs a fake server frontend. You must have already included
*
* @PrepareForTest(Static.class) in the calling test code, which will allow
* the proper static methods to be mocked.
*/
public static void InstallFakeServerFrontend() {
if (frontendInstalled) {
return;
}
ClassDiscovery.getDefaultInstance().addDiscoveryLocation(ClassDiscovery.GetClassContainer(Static.class));
ClassDiscovery.getDefaultInstance().addDiscoveryLocation(ClassDiscovery.GetClassContainer(StaticTest.class));
ExtensionManager.Initialize(ClassDiscovery.getDefaultInstance());
Implementation.setServerType(Implementation.Type.TEST);
AliasCore fakeCore = mock(AliasCore.class);
fakeCore.autoIncludes = new ArrayList<File>();
SetPrivate(CommandHelperPlugin.class, "ac", fakeCore, AliasCore.class);
frontendInstalled = true;
try {
Prefs.init(new File("preferences.ini"));
} catch (IOException ex) {
Logger.getLogger(StaticTest.class.getName()).log(Level.SEVERE, null, ex);
}
CHLog.initialize(new File("."));
}
/**
* Installs the fake convertor into the server, so event based calls will
* work. Additionally, adds the fakePlayer to the server, if player based
* events are to be called, this is the player returned.
*
* @param fakePlayer
* @throws java.lang.Exception
*/
public static void InstallFakeConvertor(MCPlayer fakePlayer) throws Exception {
InstallFakeServerFrontend();
try {
//We need to add the test directory to the ClassDiscovery path
//This should probably not be hard coded at some point.
ClassDiscovery.getDefaultInstance().addDiscoveryLocation(new File("./target/test-classes").toURI().toURL());
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
Implementation.setServerType(Implementation.Type.TEST);
MCServer fakeServer = GetFakeServer();
TestConvertor.fakeServer = fakeServer;
FakeServerMixin.fakePlayer = fakePlayer;
}
@convert(type = Implementation.Type.TEST)
public static class TestConvertor extends AbstractConvertor {
private static MCServer fakeServer;
private RunnableQueue queue = new RunnableQueue("TestConvertorRunnableQueue");
@Override
public MCLocation GetLocation(MCWorld w, double x, double y, double z, float yaw, float pitch) {
return StaticTest.GetFakeLocation(w, x, y + 1, z);
}
@Override
public Class GetServerEventMixin() {
return FakeServerMixin.class;
}
@Override
public MCEnchantment[] GetEnchantmentValues() {
Convertor c = new BukkitConvertor();
return c.GetEnchantmentValues();
}
@Override
public MCEnchantment GetEnchantmentByName(String name) {
Convertor c = new BukkitConvertor();
return c.GetEnchantmentByName(name);
}
@Override
public MCServer GetServer() {
return fakeServer;
}
@Override
public void Startup(CommandHelperPlugin chp) {
//Nothing.
}
@Override
public int LookupItemId(String materialName) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String LookupMaterialName(int id) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCItemStack GetItemStack(int type, int qty) {
Convertor c = new BukkitConvertor();
return c.GetItemStack(type, qty);
}
@Override
public MCItemStack GetItemStack(int type, int data, int qty) {
Convertor c = new BukkitConvertor();
return c.GetItemStack(type, data, qty);
}
@Override
public MCItemStack GetItemStack(MCMaterial type, int qty) {
Convertor c = new BukkitConvertor();
return c.GetItemStack(type, qty);
}
@Override
public MCItemStack GetItemStack(MCMaterial type, int data, int qty) {
Convertor c = new BukkitConvertor();
return c.GetItemStack(type, data, qty);
}
@Override
public MCItemStack GetItemStack(String type, int qty) {
Convertor c = new BukkitConvertor();
return c.GetItemStack(type, qty);
}
@Override
public MCItemStack GetItemStack(String type, int data, int qty) {
Convertor c = new BukkitConvertor();
return c.GetItemStack(type, data, qty);
}
@Override
public MCPotionData GetPotionData(MCPotionType type, boolean extended, boolean upgraded) {
Convertor c = new BukkitConvertor();
return c.GetPotionData(type, extended, upgraded);
}
@Override
public int SetFutureRunnable(DaemonManager dm, long ms, Runnable r) {
//This needs fixing later
queue.invokeLater(dm, r);
return 0;
}
@Override
public void ClearAllRunnables() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void ClearFutureRunnable(int id) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int SetFutureRepeater(DaemonManager dm, long ms, long initialDelay, Runnable r) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCEntity GetCorrectEntity(MCEntity e) {
return e;
}
@Override
public MCInventory GetEntityInventory(MCEntity entity) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCInventory GetLocationInventory(MCLocation location) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCNote GetNote(int octave, MCTone tone, boolean sharp) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCColor GetColor(final int red, final int green, final int blue) {
return new MCColor() {
@Override
public int getRed() {
return red;
}
@Override
public int getGreen() {
return green;
}
@Override
public int getBlue() {
return blue;
}
@Override
public MCColor build(int red, int green, int blue) {
return GetColor(red, green, blue);
}
};
}
@Override
public MCPattern GetPattern(MCDyeColor color, MCPatternShape shape) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCFireworkBuilder GetFireworkBuilder() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCPluginMeta GetPluginMeta() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCMaterial getMaterial(int id) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCItemMeta GetCorrectMeta(MCItemMeta im) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public List<MCEntity> GetEntitiesAt(MCLocation loc, double radius) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCRecipe GetNewRecipe(MCRecipeType type, MCItemStack result) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCRecipe GetRecipe(MCRecipe unspecific) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCMaterial GetMaterial(String name) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCMetadataValue GetMetadataValue(Object value, MCPlugin plugin) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String GetPluginName() {
return new BukkitConvertor().GetPluginName();
}
@Override
public MCPlugin GetPlugin() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public MCColor GetColor(String colorName, Target t) throws CREFormatException {
return ConvertorHelper.GetColor(colorName, t);
}
@Override
public String GetUser(Environment env) {
return "testUser";
}
}
public static class FakeServerMixin implements EventMixinInterface {
public static MCPlayer fakePlayer;
public boolean cancelled = false;
public FakeServerMixin(AbstractEvent e) {
}
@Override
public void cancel(BindableEvent e, boolean state) {
cancelled = state;
}
@Override
public boolean isCancellable(BindableEvent o) {
return true;
}
@Override
public Map<String, Construct> evaluate_helper(BindableEvent e) throws EventException {
Map<String, Construct> map = new HashMap<String, Construct>();
if (fakePlayer != null) {
map.put("player", new CString(fakePlayer.getName(), Target.UNKNOWN));
}
return map;
}
@Override
public void manualTrigger(BindableEvent e) {
throw new RuntimeException("Manual triggering is not supported in tests yet");
}
@Override
public boolean isCancelled(BindableEvent o) {
return cancelled;
}
}
/**
* Returns the value of a private (or any other variable for that matter)
* data member contained in the object provided. If the value isn't there,
* the test fails automatically.
*
* @param in The object to look in, or the Class object for static varibles.
* @param name The name of the variable to get.
* @param expected The type of the value that you expect to be. This is the
* type that will be returned.
* @return
*/
public static <T> T GetPrivate(Object in, String name, Class<T> expected) {
return GetSetPrivate(in, name, null, false, expected);
}
/**
* Sets the value of a private (or any other variable for that matter) data
* member contained in the object provided.
*
* @param in Either the class of the object (for static variables) or an
* instance of the object.
* @param name The name of the field
* @param value The actual value to set
* @param expected The type of the value that you expect to be in the code.
*/
public static void SetPrivate(Object in, String name, Object value, Class expected) {
GetSetPrivate(in, name, value, true, expected);
}
private static <T> T GetSetPrivate(Object in, String name, Object value, boolean isSet, Class<T> expected) {
Object ret = null;
try {
Field f = null;
Class search = in.getClass();
if (in instanceof Class) {
search = (Class) in;
}
while (search != null) {
try {
f = search.getDeclaredField(name);
break;
} catch (NoSuchFieldException e) {
search = search.getSuperclass();
}
}
if (f == null) {
throw new NoSuchFieldException();
}
f.setAccessible(true);
if (expected != null && !expected.isAssignableFrom(f.getType())) {
fail("Expected the value to be a " + expected.getName() + ", but it was actually a " + f.getType().getName());
}
if (isSet) {
f.set(in, value);
} else {
ret = f.get(in);
}
} catch (IllegalArgumentException ex) {
//This shouldn't happen ever, since we are using the class provided by in, and sending
//get/set in as well.
fail(ex.getMessage());
} catch (IllegalAccessException ex) {
//This shouldn't happen ever, since we set it to accessible
fail(ex.getMessage());
} catch (NoSuchFieldException ex) {
fail("No such field \"" + name + "\" exists in the class " + in.getClass().getName());
} catch (SecurityException ex) {
fail("A security policy is preventing the test from getting \"" + name + "\" in the object provided.");
}
return (T) ret;
}
/**
* Installs a fake logger. Returns the proxied object.
*
* @return
*/
public static CHLog InstallFakeLogger() {
CHLog l = mock(CHLog.class);
SetPrivate(CHLog.class, "instance", l, CHLog.class);
return l;
}
}