1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-03-03 18:25:18 +00:00

Add some tests for the new executor system

And fix a couple of bugs picked up by said tests
This commit is contained in:
SquidDev 2018-09-18 18:21:00 +01:00
parent 4b741739e8
commit 8819f2559d
11 changed files with 558 additions and 30 deletions

View File

@ -197,3 +197,9 @@ gradle.projectsEvaluated {
runClient.outputs.upToDateWhen { false } runClient.outputs.upToDateWhen { false }
runServer.outputs.upToDateWhen { false } runServer.outputs.upToDateWhen { false }
test {
testLogging {
events "failed", "standardOut", "standardError"
}
}

View File

@ -44,10 +44,12 @@ public interface ILuaObject
* for the possible values and conversion rules. * for the possible values and conversion rules.
* @return An array of objects, representing the values you wish to return to the Lua program. See * @return An array of objects, representing the values you wish to return to the Lua program. See
* {@link MethodResult#of(Object...)} for the valid values and conversion rules. * {@link MethodResult#of(Object...)} for the valid values and conversion rules.
* @throws LuaException If the task could not be queued, or if the task threw an exception. * @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
* @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended, * @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended,
* InterruptedException will be thrown. This exception must not be caught or * InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.w * intercepted, or the computer will leak memory and end up in a broken state.
* @see IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[]) * @see IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])
* @deprecated Use {@link #callMethod(ICallContext, int, Object[])} instead. * @deprecated Use {@link #callMethod(ICallContext, int, Object[])} instead.
*/ */
@ -68,12 +70,14 @@ public interface ILuaObject
* for the possible values and conversion rules. * for the possible values and conversion rules.
* @return The result of calling this method. Use {@link MethodResult#empty()} to return nothing or * @return The result of calling this method. Use {@link MethodResult#empty()} to return nothing or
* {@link MethodResult#of(Object...)} to return several values. * {@link MethodResult#of(Object...)} to return several values.
* @throws LuaException If the task could not be queued, or if the task threw an exception. * @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
* @see IPeripheral#callMethod(IComputerAccess, ICallContext, int, Object[]) * @see IPeripheral#callMethod(IComputerAccess, ICallContext, int, Object[])
* @see MethodResult * @see MethodResult
*/ */
@Nonnull @Nonnull
@SuppressWarnings({ "deprecation" }) @SuppressWarnings( { "deprecation" } )
default MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException default MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{ {
return MethodResult.withLuaContext( lua -> callMethod( lua, method, arguments ) ); return MethodResult.withLuaContext( lua -> callMethod( lua, method, arguments ) );

View File

@ -89,16 +89,17 @@ public abstract class MethodResult
* Normally you'll wish to consume the event using {@link #then(ILuaFunction)}. This can be done slightly more * Normally you'll wish to consume the event using {@link #then(ILuaFunction)}. This can be done slightly more
* easily with {@link #pullEvent(String, ILuaFunction)}. * easily with {@link #pullEvent(String, ILuaFunction)}.
* *
* @param filter The event name to filter on.
* @return The constructed method result. This evaluates to the name of the event that occurred, and any event * @return The constructed method result. This evaluates to the name of the event that occurred, and any event
* parameters. * parameters.
* @see #pullEvent(String, ILuaFunction) * @see #pullEvent(String, ILuaFunction)
* @see #pullEvent() * @see #pullEvent()
*/ */
@Nonnull @Nonnull
public static MethodResult pullEvent( @Nonnull String event ) public static MethodResult pullEvent( @Nonnull String filter )
{ {
Preconditions.checkNotNull( event, "event cannot be null" ); Preconditions.checkNotNull( filter, "event cannot be null" );
return new OnEvent( false, event ); return new OnEvent( false, filter );
} }
/** /**
@ -108,6 +109,7 @@ public abstract class MethodResult
* If you want to listen to a specific event, it's easier to use {@link #pullEvent(String, ILuaFunction)} rather * If you want to listen to a specific event, it's easier to use {@link #pullEvent(String, ILuaFunction)} rather
* than running until the desired event is found. * than running until the desired event is found.
* *
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}. * @return The constructed method result. This evaluates to the result of the {@code callback}.
* @see #pullEvent() * @see #pullEvent()
* @see #pullEvent(String, ILuaFunction) * @see #pullEvent(String, ILuaFunction)
@ -123,6 +125,8 @@ public abstract class MethodResult
* Wait for the specified event to occur on the computer, suspending the coroutine until it arises. This method to * Wait for the specified event to occur on the computer, suspending the coroutine until it arises. This method to
* {@link #pullEvent(String)} and {@link #then(ILuaFunction)}. * {@link #pullEvent(String)} and {@link #then(ILuaFunction)}.
* *
* @param filter The event name to filter on.
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}. * @return The constructed method result. This evaluates to the result of the {@code callback}.
* @see #pullEvent(String) * @see #pullEvent(String)
* @see #pullEvent(ILuaFunction) * @see #pullEvent(ILuaFunction)
@ -151,19 +155,21 @@ public abstract class MethodResult
* The same as {@link #pullEvent(String)}, except {@code terminated} events are also passed to the callback, instead * The same as {@link #pullEvent(String)}, except {@code terminated} events are also passed to the callback, instead
* of throwing an error. Only use this if you want to prevent program termination, which is not recommended. * of throwing an error. Only use this if you want to prevent program termination, which is not recommended.
* *
* @param filter The event name to filter on.
* @return The constructed method result. This evaluates to the name of the event that occurred, and any event * @return The constructed method result. This evaluates to the name of the event that occurred, and any event
* parameters. * parameters.
*/ */
@Nonnull @Nonnull
public static MethodResult pullEventRaw( @Nonnull String event ) public static MethodResult pullEventRaw( @Nonnull String filter )
{ {
return new OnEvent( true, event ); return new OnEvent( true, filter );
} }
/** /**
* The same as {@link #pullEvent(ILuaFunction)}, except {@code terminated} events are also passed to the callback, * The same as {@link #pullEvent(ILuaFunction)}, except {@code terminated} events are also passed to the callback,
* instead of throwing an error. Only use this if you want to prevent program termination, which is not recommended. * instead of throwing an error. Only use this if you want to prevent program termination, which is not recommended.
* *
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}. * @return The constructed method result. This evaluates to the result of the {@code callback}.
*/ */
@Nonnull @Nonnull
@ -178,6 +184,8 @@ public abstract class MethodResult
* callback, instead of throwing an error. Only use this if you want to prevent program termination, which is not * callback, instead of throwing an error. Only use this if you want to prevent program termination, which is not
* recommended. * recommended.
* *
* @param filter The event name to filter on.
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}. * @return The constructed method result. This evaluates to the result of the {@code callback}.
*/ */
@Nonnull @Nonnull
@ -237,6 +245,8 @@ public abstract class MethodResult
* *
* @param context The context to execute with. * @param context The context to execute with.
* @return The resulting values. * @return The resulting values.
* @throws LuaException If an error was thrown while executing one of the methods within this future.
* @throws InterruptedException If the user shuts down or reboots the computer while the coroutine is suspended.
* @see #withLuaContext(ILuaContextTask) * @see #withLuaContext(ILuaContextTask)
* @deprecated This should not be used except to interface between the two call systems. * @deprecated This should not be used except to interface between the two call systems.
*/ */

View File

@ -968,7 +968,7 @@ public class Computer
return; return;
} }
} }
final Computer computer = this; final Computer computer = this;
ITask task = new ITask() { ITask task = new ITask() {
@Override @Override

View File

@ -157,11 +157,14 @@ class CobaltLuaContext extends CobaltCallContext implements ILuaContext
} ); } );
} }
Object[] resume( LuaState state, CobaltLuaMachine machine, Object[] args ) throws LuaError, UnwindThrowable void resume( Object[] args )
{ {
values = args; values = args;
resume.signal(); resume.signal();
}
Object[] await( LuaState state, CobaltLuaMachine machine ) throws LuaError, UnwindThrowable
{
if( !done ) if( !done )
{ {
try try
@ -170,14 +173,12 @@ class CobaltLuaContext extends CobaltCallContext implements ILuaContext
} }
catch( InterruptedException e ) catch( InterruptedException e )
{ {
state.debug.onReturn();
throw new LuaError( "Java Exception Thrown: " + e.toString(), 0 ); throw new LuaError( "Java Exception Thrown: " + e.toString(), 0 );
} }
} }
if( done ) if( done )
{ {
state.debug.onReturn();
if( exception != null ) throw exception; if( exception != null ) throw exception;
return values; return values;
} }

View File

@ -235,6 +235,7 @@ public class CobaltLuaMachine implements ILuaMachine
} }
catch( LuaError e ) catch( LuaError e )
{ {
if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Main thread crashed", e );
m_mainRoutine.abandon(); m_mainRoutine.abandon();
m_mainRoutine = null; m_mainRoutine = null;
} }

View File

@ -13,8 +13,6 @@ import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.Computer;
import org.squiddev.cobalt.*; import org.squiddev.cobalt.*;
import org.squiddev.cobalt.debug.DebugFrame;
import org.squiddev.cobalt.debug.DebugHandler;
import org.squiddev.cobalt.debug.DebugState; import org.squiddev.cobalt.debug.DebugState;
import org.squiddev.cobalt.function.VarArgFunction; import org.squiddev.cobalt.function.VarArgFunction;
@ -62,12 +60,19 @@ class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWr
throw new LuaError( "Java Exception Thrown: " + e.toString(), 0 ); throw new LuaError( "Java Exception Thrown: " + e.toString(), 0 );
} }
// Verify we've a "well formed" future
if( future == null ) if( future == null )
{ {
ComputerCraft.log.error( "Null result from " + delegate ); ComputerCraft.log.error( "Null result from " + delegate );
throw new LuaError( "Java Exception Thrown: Null result" ); throw new LuaError( "Java Exception Thrown: Null result" );
} }
// Fast path for immediate results
if( future instanceof MethodResult.Immediate )
{
return machine.toValues( ((MethodResult.Immediate) future).getResult() );
}
State context = new State(); State context = new State();
try try
{ {
@ -75,12 +80,11 @@ class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWr
} }
catch( UnwindThrowable e ) catch( UnwindThrowable e )
{ {
// Push our state onto the stack if need-be. // Push our state onto the stack if need-be. Normally this wouldn't be safe and we
DebugHandler handler = state.debug; // should do this at the very beginning, but we know that we won't be calling anything
DebugState ds = handler.getDebugState(); // else which will push to the resume stack.
DebugFrame di = handler.onCall( ds, this ); DebugState ds = state.debug.getDebugState();
di.state = context; state.debug.onCall( ds, this, context );
throw e; throw e;
} }
} }
@ -88,11 +92,10 @@ class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWr
@Override @Override
public Varargs resume( LuaState state, State context, Varargs args ) throws LuaError, UnwindThrowable public Varargs resume( LuaState state, State context, Varargs args ) throws LuaError, UnwindThrowable
{ {
Varargs result;
try try
{ {
Varargs result = doResume( state, context, args ); result = doResume( state, context, args );
state.debug.onReturn();
return result;
} }
catch( LuaError e ) catch( LuaError e )
{ {
@ -104,6 +107,9 @@ class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWr
state.debug.onReturn(); state.debug.onReturn();
throw new LuaError( e ); throw new LuaError( e );
} }
state.debug.onReturn();
return result;
} }
private Varargs doResume( LuaState state, State context, Varargs args ) throws LuaError, UnwindThrowable private Varargs doResume( LuaState state, State context, Varargs args ) throws LuaError, UnwindThrowable
@ -126,7 +132,7 @@ class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWr
if( args.arg( 3 ).toBoolean() ) if( args.arg( 3 ).toBoolean() )
{ {
// Extract the return values from the event and return them // Extract the return values from the event and return them
return runCallback( state, context, CobaltLuaMachine.toObjects( args, 4 ) ); return runFuture( state, context, context.taskResult );
} }
else else
{ {
@ -142,7 +148,8 @@ class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWr
} }
else if( future instanceof MethodResult.WithLuaContext ) else if( future instanceof MethodResult.WithLuaContext )
{ {
return runCallback( state, context, context.luaContext.resume( state, machine, CobaltLuaMachine.toObjects( args, 1 ) ) ); context.luaContext.resume( CobaltLuaMachine.toObjects( args, 1 ) );
return runCallback( state, context, context.luaContext.await( state, machine ) );
} }
else else
{ {
@ -223,6 +230,7 @@ class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWr
context.pending = future; context.pending = future;
CobaltLuaContext luaContext = context.luaContext = new CobaltLuaContext( computer, state ); CobaltLuaContext luaContext = context.luaContext = new CobaltLuaContext( computer, state );
luaContext.execute( withContext.getConsumer() ); luaContext.execute( withContext.getConsumer() );
return runCallback( state, context, luaContext.await( state, machine ) );
} }
else else
{ {

View File

@ -0,0 +1,91 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.core.filesystem.FileMount;
import net.minecraftforge.fml.common.Loader;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
public class FakeComputerEnvironment implements IComputerEnvironment
{
private final boolean colour;
private final int id;
public FakeComputerEnvironment( int id, boolean colour )
{
this.colour = colour;
this.id = id;
}
@Override
public int getDay()
{
return 0;
}
@Override
public double getTimeOfDay()
{
return 0;
}
@Override
public boolean isColour()
{
return colour;
}
@Override
public int assignNewID()
{
return id;
}
@Override
public IWritableMount createSaveDirMount( String subPath, long capacity )
{
return new FileMount( new File( "computer/" + subPath ), capacity );
}
@Override
public IMount createResourceMount( String domain, String subPath )
{
String fullPath = "assets/" + domain + "/" + subPath;
URL url = ComputerCraft.class.getProtectionDomain().getCodeSource().getLocation();
File file = new File( url.getPath(), fullPath );
if( !file.exists() ) file = new File( "src/main/resources", fullPath );
if( !file.exists() ) throw new RuntimeException( "Cannot find ROM in " + file );
return new FileMount( file, 0 );
}
@Override
public InputStream createResourceFile( String domain, String subPath )
{
String fullPath = "assets/" + domain + "/" + subPath;
return ComputerCraft.class.getClassLoader().getResourceAsStream( fullPath );
}
@Override
public long getComputerSpaceLimit()
{
return ComputerCraft.computerSpaceLimit;
}
@Override
public String getHostString()
{
return "ComputerCraft ${version} (Minecraft " + Loader.MC_VERSION + ")";
}
}

View File

@ -0,0 +1,155 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.core.terminal.Terminal;
import org.apache.logging.log4j.LogManager;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.function.Consumer;
import static org.junit.Assert.fail;
public final class RunOnComputer
{
public static final int STARTUP_TIMEOUT = 10;
public static final int RUN_TIMEOUT = 100;
public static void run( String task ) throws Exception
{
run( task, x -> {
} );
}
public static void run( String task, Consumer<Computer> setup ) throws Exception
{
if( ComputerCraft.log == null ) ComputerCraft.log = LogManager.getLogger( "computercraft" );
ComputerCraft.logPeripheralErrors = true;
// Setup computer
Terminal terminal = new Terminal( ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer );
Computer computer = new Computer( new FakeComputerEnvironment( 0, true ), terminal, 0 );
// Register APIS
TestAPI api = new TestAPI( computer );
computer.addAPI( api );
setup.accept( computer );
// Setup the startup file
try( OutputStream stream = computer.getRootMount().openForWrite( "startup.lua" ) )
{
String program = "" +
"local function exec()\n" +
" " + task + "\n" +
"end\n" +
"test.finish(pcall(exec))\n";
stream.write( program.getBytes( StandardCharsets.UTF_8 ) );
}
// Turn on
ComputerThread.start();
computer.turnOn();
// Run until shutdown or we timeout
boolean everOn = false;
int ticks = 0;
do
{
computer.advance( 0.05 );
MainThread.executePendingTasks();
Thread.sleep( 50 );
ticks++;
everOn |= computer.isOn();
}
while( (computer.isOn() || (!everOn && ticks < STARTUP_TIMEOUT)) && ticks <= RUN_TIMEOUT );
// If we never finished (say, startup errored) then print the terminal. Otherwise throw the error
// where needed.
if( !api.finished )
{
int height = terminal.getHeight() - 1;
while( height >= 0 && terminal.getLine( height ).toString().trim().isEmpty() ) height--;
for( int y = 0; y <= height; y++ )
{
System.out.printf( "%2d | %s\n", y + 1, terminal.getLine( y ) );
}
fail( "Computer never finished" );
}
else if( api.error != null )
{
fail( api.error );
}
ComputerThread.stop();
}
private static class TestAPI implements ILuaAPI
{
private final Computer computer;
private boolean finished = false;
private String error;
private TestAPI( Computer computer )
{
this.computer = computer;
}
@Override
public String[] getNames()
{
return new String[]{ "test" };
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[]{ "log", "finish" };
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
@Nonnull
@Override
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments )
{
switch( method )
{
case 0:
ComputerCraft.log.info( Objects.toString( arguments.length <= 0 ? null : arguments[0] ) );
return MethodResult.empty();
case 1:
{
if( arguments.length <= 0 || arguments[0] == null || arguments[0] == Boolean.FALSE )
{
error = Objects.toString( arguments.length <= 1 ? null : arguments[1] );
}
finished = true;
computer.shutdown();
return MethodResult.empty();
}
default:
return MethodResult.empty();
}
}
}
}

View File

@ -0,0 +1,243 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.lua;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.core.computer.RunOnComputer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
@RunWith( Parameterized.class )
public class CobaltWrapperFunctionTest
{
@Parameterized.Parameter( 0 )
public String name;
@Parameterized.Parameter( 1 )
public String code;
@Parameterized.Parameters( name = "{0}" )
public static Collection<Object[]> parameters()
{
return Arrays.stream( new Object[][]{
new Object[]{ "empty", "assert(select('#', funcs.empty()) == 0)" },
new Object[]{ "identity", "assert(select('#', funcs.identity(1, 2, 3)) == 3)" },
new Object[]{ "pullEvent", "os.queueEvent('test') assert(funcs.pullEvent() == 'test')" },
new Object[]{ "pullEventTerminate", "os.queueEvent('terminate') assert(not pcall(funcs.pullEvent))" },
new Object[]{ "pullEventRaw", "os.queueEvent('test') assert(funcs.pullEventRaw() == 'test')" },
new Object[]{ "pullEventRawTerminate", "os.queueEvent('terminate') assert(funcs.pullEventRaw() == 'terminate')" },
new Object[]{ "mainThread", "assert(funcs.mainThread() == 1)" },
new Object[]{ "mainThreadMany", "for i = 1, 4 do assert(funcs.mainThread() == 1) end" }
} ).collect( Collectors.toList() );
}
/**
* Tests executing functions defined through the {@link MethodResult} API.
*/
@Test
public void testMethodResult() throws Exception
{
RunOnComputer.run( code, c -> c.addAPI( new MethodResultAPI() ) );
}
/**
* Tests executing functions defined through the {@link MethodResult} API called with the
* {@link ILuaContext} evaluator.
*/
@Test
public void testMethodResultEvaluate() throws Exception
{
RunOnComputer.run( code, c -> c.addAPI( new WrapperAPI( new MethodResultAPI() )
{
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
} ) );
}
/**
* Tests using {@link MethodResult#then(ILuaFunction)} afterwards
*/
@Test
public void testMethodResultThen() throws Exception
{
RunOnComputer.run( code, c -> c.addAPI( new WrapperAPI( new MethodResultAPI() ) {
@Nonnull
@Override
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
return super.callMethod( context, method, arguments )
.then( x -> MethodResult.onMainThread( () -> MethodResult.of( x ).then( MethodResult::of ) ) )
.then( MethodResult::of );
}
} ) );
}
/**
* Tests executing functions defined through the {@link ILuaContext} API.
*/
@Test
public void testLuaContext() throws Exception
{
RunOnComputer.run( code, c -> c.addAPI( new LuaContextAPI() ) );
}
/**
* Tests executing functions defined through the {@link ILuaContext} API called with the
* {@link MethodResult} evaluator.
*/
@Test
public void testWithLuaContext() throws Exception
{
RunOnComputer.run( code, c -> c.addAPI( new WrapperAPI( new LuaContextAPI() )
{
@Nonnull
@Override
@SuppressWarnings( "deprecation" )
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
return MethodResult.withLuaContext( c -> callMethod( c, method, arguments ) );
}
} ) );
}
private static class MethodResultAPI implements ILuaAPI
{
@Override
public String[] getNames()
{
return new String[]{ "funcs" };
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[]{ "empty", "identity", "pullEvent", "pullEventRaw", "mainThread" };
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
@Nonnull
@Override
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments )
{
switch( method )
{
case 0:
return MethodResult.empty();
case 1:
return MethodResult.of( arguments );
case 2:
return MethodResult.pullEvent( "test" );
case 3:
return MethodResult.pullEventRaw( "test" );
case 4:
return MethodResult.onMainThread( () -> MethodResult.of( 1 ) );
default:
return MethodResult.empty();
}
}
}
private static class LuaContextAPI implements ILuaAPI
{
@Override
public String[] getNames()
{
return new String[]{ "funcs" };
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[]{ "empty", "identity", "pullEvent", "pullEventRaw", "mainThread" };
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
switch( method )
{
case 0:
return null;
case 1:
return arguments;
case 2:
return context.pullEvent( "test" );
case 3:
return context.pullEventRaw( "test" );
case 4:
return context.executeMainThreadTask( () -> new Object[]{ 1 } );
default:
return null;
}
}
}
public static class WrapperAPI implements ILuaAPI
{
private final ILuaAPI api;
public WrapperAPI( ILuaAPI api )
{
this.api = api;
}
@Override
public String[] getNames()
{
return api.getNames();
}
@Nonnull
@Override
public String[] getMethodNames()
{
return api.getMethodNames();
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return api.callMethod( context, method, arguments );
}
@Nonnull
@Override
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
return api.callMethod( context, method, arguments );
}
}
}

View File

@ -4,8 +4,9 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNetwork; import dan200.computercraft.api.network.wired.IWiredNetwork;
import dan200.computercraft.api.network.wired.IWiredNetworkChange; import dan200.computercraft.api.network.wired.IWiredNetworkChange;
@ -249,7 +250,7 @@ public class NetworkTest
} }
@Test @Test
@Ignore("Takes a long time to run, mostly for stress testing") @Ignore( "Takes a long time to run, mostly for stress testing" )
public void testLarge() public void testLarge()
{ {
final int BRUTE_SIZE = 16; final int BRUTE_SIZE = 16;
@ -410,11 +411,19 @@ public class NetworkTest
@Nullable @Nullable
@Override @Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException @Deprecated
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments )
{ {
return new Object[0]; return new Object[0];
} }
@Nonnull
@Override
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object[] arguments )
{
return MethodResult.empty();
}
@Override @Override
public boolean equals( @Nullable IPeripheral other ) public boolean equals( @Nullable IPeripheral other )
{ {
@ -427,7 +436,7 @@ public class NetworkTest
private final int size; private final int size;
private final T[] box; private final T[] box;
@SuppressWarnings("unchecked") @SuppressWarnings( "unchecked" )
public Grid( int size ) public Grid( int size )
{ {
this.size = size; this.size = size;