Add unit tests for part of base library plus fixes to [gs]etfenv, [gs]etmetatable
This commit is contained in:
@@ -47,6 +47,7 @@ public class BaseLib extends LFunction {
|
||||
"tonumber",
|
||||
"rawget",
|
||||
"rawset",
|
||||
"getfenv",
|
||||
"setfenv",
|
||||
"select",
|
||||
"collectgarbage",
|
||||
@@ -72,15 +73,16 @@ public class BaseLib extends LFunction {
|
||||
private static final int TONUMBER = 11;
|
||||
private static final int RAWGET = 12;
|
||||
private static final int RAWSET = 13;
|
||||
private static final int SETFENV = 14;
|
||||
private static final int SELECT = 15;
|
||||
private static final int COLLECTGARBAGE = 16;
|
||||
private static final int DOFILE = 17;
|
||||
private static final int LOADSTRING = 18;
|
||||
private static final int LOAD = 19;
|
||||
private static final int TOSTRING = 20;
|
||||
private static final int UNPACK = 21;
|
||||
private static final int NEXT = 22;
|
||||
private static final int GETFENV = 14;
|
||||
private static final int SETFENV = 15;
|
||||
private static final int SELECT = 16;
|
||||
private static final int COLLECTGARBAGE = 17;
|
||||
private static final int DOFILE = 18;
|
||||
private static final int LOADSTRING = 19;
|
||||
private static final int LOAD = 20;
|
||||
private static final int TOSTRING = 21;
|
||||
private static final int UNPACK = 22;
|
||||
private static final int NEXT = 23;
|
||||
|
||||
public static void install(LTable globals) {
|
||||
for ( int i=1; i<NAMES.length; i++ )
|
||||
@@ -130,20 +132,26 @@ public class BaseLib extends LFunction {
|
||||
break;
|
||||
}
|
||||
case GETMETATABLE: {
|
||||
if ( 0 == vm.getmetatable(2) )
|
||||
if ( 0 == vm.getmetatable(2) ) {
|
||||
vm.settop(0);
|
||||
else {
|
||||
vm.pushnil();
|
||||
} else {
|
||||
vm.insert(1);
|
||||
vm.settop(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SETMETATABLE: {
|
||||
if ( ! vm.istable(2) )
|
||||
vm.error("bad argument #1 to '?' (table expected, got "+vm.typename(2)+")");
|
||||
vm.setmetatable(2);
|
||||
vm.remove(1);
|
||||
break;
|
||||
}
|
||||
case TYPE: {
|
||||
// TODO: generalize, compute location insofar as possible
|
||||
if ( vm.gettop() < 2 )
|
||||
vm.error("bad argument #1 to '?' (value expected)");
|
||||
LValue v = vm.topointer(2);
|
||||
vm.settop(0);
|
||||
vm.pushlstring( v.luaGetTypeName() );
|
||||
@@ -163,7 +171,7 @@ public class BaseLib extends LFunction {
|
||||
break;
|
||||
}
|
||||
case ERROR: {
|
||||
vm.error(vm.tostring(2), vm.gettop()>2? vm.tointeger(3): 1);
|
||||
vm.error(vm.tostring(2), vm.gettop()>=3? vm.tointeger(3): 1);
|
||||
break;
|
||||
}
|
||||
case ASSERT: {
|
||||
@@ -211,9 +219,38 @@ public class BaseLib extends LFunction {
|
||||
vm.error( "expected table" );
|
||||
}
|
||||
} break;
|
||||
case SETFENV:
|
||||
setfenv( (LuaState) vm );
|
||||
case GETFENV: {
|
||||
if ( vm.gettop() <= 1 ) {
|
||||
vm.pushlvalue(vm._G);
|
||||
} else {
|
||||
if ( ! vm.isfunction(2) ) {
|
||||
int i = (vm.isnil(2)? 1: vm.tointeger(2));
|
||||
vm.pushlvalue( vm.getStackFrame(i).closure );
|
||||
}
|
||||
vm.getfenv(-1);
|
||||
}
|
||||
vm.insert(1);
|
||||
vm.settop(1);
|
||||
break;
|
||||
}
|
||||
case SETFENV: {
|
||||
LTable t = vm.totable(-1);
|
||||
if ( vm.setfenv(2) != 0 ) {
|
||||
vm.remove(1);
|
||||
break;
|
||||
}
|
||||
int i = vm.tointeger(2);
|
||||
if ( i == 0 ) {
|
||||
vm._G = t;
|
||||
vm.settop(0);
|
||||
} else {
|
||||
LClosure c = vm.getStackFrame(i-1).closure;
|
||||
c.luaSetEnv(t);
|
||||
vm.settop(0);
|
||||
vm.pushlvalue(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SELECT:
|
||||
select( vm );
|
||||
break;
|
||||
@@ -269,43 +306,6 @@ public class BaseLib extends LFunction {
|
||||
}
|
||||
}
|
||||
|
||||
private void setfenv( LuaState state ) {
|
||||
LValue f = state.topointer(2);
|
||||
LValue newenv = state.topointer(3);
|
||||
|
||||
LClosure c = null;
|
||||
|
||||
// Lua reference manual says that first argument, f, can be a "Lua
|
||||
// function" or an integer. Lots of things extend LFunction, but only
|
||||
// instances of Closure are "Lua functions".
|
||||
if ( f instanceof LClosure ) {
|
||||
c = (LClosure) f;
|
||||
} else {
|
||||
int callStackDepth = f.toJavaInt();
|
||||
if ( callStackDepth > 0 ) {
|
||||
CallInfo frame = state.getStackFrame( callStackDepth );
|
||||
if ( frame != null ) {
|
||||
c = frame.closure;
|
||||
}
|
||||
} else {
|
||||
// This is supposed to set the environment of the current
|
||||
// "thread". But, we have not implemented coroutines yet.
|
||||
throw new LuaErrorException( "not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( c != null ) {
|
||||
if ( newenv instanceof LTable ) {
|
||||
c.env = (LTable) newenv;
|
||||
}
|
||||
state.settop(0);
|
||||
state.pushlvalue( c );
|
||||
return;
|
||||
}
|
||||
|
||||
state.settop(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// closes the input stream, provided its not null or System.in
|
||||
private static void closeSafely(InputStream is) {
|
||||
|
||||
@@ -57,4 +57,11 @@ public class LClosure extends LFunction {
|
||||
vm.prepStackCall();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Set the environment if a thread, or closure, and return 1, otherwise return 0 */
|
||||
public int luaSetEnv(LTable t) {
|
||||
this.env = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,12 @@ public class LThread extends LValue implements Runnable {
|
||||
return "thread: "+hashCode();
|
||||
}
|
||||
|
||||
/** Set the environment if a thread, or closure, and return 1, otherwise return 0 */
|
||||
public int luaSetEnv(LTable t) {
|
||||
threadVm._G = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return NAMES[status];
|
||||
}
|
||||
|
||||
@@ -297,4 +297,9 @@ public class LValue {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Set the environment if a thread, or closure, and return 1, otherwise return 0 */
|
||||
public int luaSetEnv(LTable t) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -958,8 +958,8 @@ public class LuaState extends Lua {
|
||||
* after filling line number information first when level > 0.
|
||||
*/
|
||||
public void error(String message, int level) {
|
||||
if ( level > 0 )
|
||||
message = getFileLine(cc + 1 - level) + ": " + message;
|
||||
if ( level > 1 )
|
||||
message = getFileLine(cc + 2 - level) + ": " + message;
|
||||
throw new LuaErrorException( message );
|
||||
}
|
||||
|
||||
@@ -1117,7 +1117,8 @@ public class LuaState extends Lua {
|
||||
* index.
|
||||
*/
|
||||
public void getfenv(int index) {
|
||||
notImplemented();
|
||||
LValue f = topointer(index);
|
||||
pushlvalue( ((LClosure) f).env );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1130,8 +1131,10 @@ public class LuaState extends Lua {
|
||||
* returns 0. Otherwise it returns 1.
|
||||
*/
|
||||
public int setfenv(int index) {
|
||||
notImplemented();
|
||||
return 0;
|
||||
LTable t = totable(-1);
|
||||
LValue f = topointer(index);
|
||||
pop(1);
|
||||
return f.luaSetEnv(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,15 +24,9 @@ package org.luaj.sample;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.lib.CoroutineLib;
|
||||
import org.luaj.lib.MathLib;
|
||||
import org.luaj.lib.PackageLib;
|
||||
import org.luaj.lib.StringLib;
|
||||
import org.luaj.lib.TableLib;
|
||||
import org.luaj.lib.j2se.LuajavaLib;
|
||||
import org.luaj.compiler.LuaC;
|
||||
import org.luaj.vm.LClosure;
|
||||
import org.luaj.vm.LPrototype;
|
||||
import org.luaj.vm.LTable;
|
||||
import org.luaj.vm.LValue;
|
||||
import org.luaj.vm.LoadState;
|
||||
import org.luaj.vm.LuaState;
|
||||
@@ -56,6 +50,7 @@ public class LuaRunner {
|
||||
|
||||
// add standard bindings
|
||||
state.installStandardLibs();
|
||||
LuaC.install();
|
||||
|
||||
// load the file
|
||||
InputStream is = LuaRunner.class.getResourceAsStream( script );
|
||||
|
||||
@@ -6,13 +6,14 @@ import java.io.OutputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.compiler.LuaC;
|
||||
import org.luaj.debug.DebugLuaState;
|
||||
import org.luaj.lib.BaseLib;
|
||||
import org.luaj.lib.j2se.LuajavaLib;
|
||||
|
||||
|
||||
public class LuaJTest extends TestCase {
|
||||
|
||||
|
||||
public void testTest1() throws IOException, InterruptedException {
|
||||
runTest( "test1" );
|
||||
}
|
||||
@@ -45,6 +46,10 @@ public class LuaJTest extends TestCase {
|
||||
runTest( "autoload" );
|
||||
}
|
||||
|
||||
public void testBaseLib() throws IOException, InterruptedException {
|
||||
runTest( "baselib" );
|
||||
}
|
||||
|
||||
public void testBoolean() throws IOException, InterruptedException {
|
||||
runTest( "boolean" );
|
||||
}
|
||||
@@ -81,6 +86,10 @@ public class LuaJTest extends TestCase {
|
||||
runTest( "select" );
|
||||
}
|
||||
|
||||
public void testSetfenv() throws IOException, InterruptedException {
|
||||
runTest( "setfenv" );
|
||||
}
|
||||
|
||||
public void testSetlist() throws IOException, InterruptedException {
|
||||
runTest( "setlist" );
|
||||
}
|
||||
@@ -108,7 +117,7 @@ public class LuaJTest extends TestCase {
|
||||
public void testUpvalues2() throws IOException, InterruptedException {
|
||||
runTest( "upvalues2" );
|
||||
}
|
||||
|
||||
//*/
|
||||
private void runTest( String testName ) throws IOException, InterruptedException {
|
||||
|
||||
// new lua state
|
||||
@@ -119,6 +128,7 @@ public class LuaJTest extends TestCase {
|
||||
|
||||
// add luajava
|
||||
LuajavaLib.install( state._G );
|
||||
LuaC.install();
|
||||
|
||||
// load the file
|
||||
LPrototype p = loadScriptResource( state, testName );
|
||||
|
||||
92
src/test/res/baselib.lua
Normal file
92
src/test/res/baselib.lua
Normal file
@@ -0,0 +1,92 @@
|
||||
-- unit tests for functions in BaseLib.java
|
||||
|
||||
-- assert
|
||||
print( 'assert(true)', assert(true) )
|
||||
print( 'pcall(assert,true)', pcall(assert,true) )
|
||||
print( 'pcall(assert,false)', pcall(assert,false) )
|
||||
print( 'pcall(assert,nil)', pcall(assert,nil) )
|
||||
print( 'pcall(assert,true,"msg")', pcall(assert,true,"msg") )
|
||||
print( 'pcall(assert,false,"msg")', pcall(assert,false,"msg") )
|
||||
print( 'pcall(assert,nil,"msg")', pcall(assert,nil,"msg") )
|
||||
print( 'pcall(assert,false,"msg","msg2")', pcall(assert,false,"msg","msg2") )
|
||||
|
||||
-- collectgarbage (not supported)
|
||||
-- dofile (not supported)
|
||||
|
||||
-- error
|
||||
print( 'pcall(error)', pcall(error) )
|
||||
print( 'pcall(error,"msg")', pcall(error,"msg") )
|
||||
print( 'pcall(error,"msg",1)', pcall(error,"msg",1) )
|
||||
print( 'pcall(error,"msg",2)', pcall(error,"msg",2) )
|
||||
local function le(level)
|
||||
error("msg",level)
|
||||
end
|
||||
function ge(level)
|
||||
error("msg",level)
|
||||
end
|
||||
for i = 0,4 do
|
||||
print( 'pcall(le,i)', i, pcall(le,i) )
|
||||
print( 'pcall(ge,i)', i, pcall(ge,i) )
|
||||
end
|
||||
|
||||
-- _G
|
||||
print( '_G["abc"] (before)', _G["abc"] )
|
||||
abc='def'
|
||||
print( '_G["abc"] (after)', _G["abc"] )
|
||||
|
||||
-- type
|
||||
print( 'type(nil)', type(nil) )
|
||||
print( 'type("a")', type("a") )
|
||||
print( 'type(1)', type(1) )
|
||||
print( 'type(1.5)', type(1.5) )
|
||||
print( 'type(function() end)', type(function() end) )
|
||||
print( 'type({})', type({}) )
|
||||
print( 'type(true)', type(true) )
|
||||
print( 'type(false)', type(false) )
|
||||
print( 'pcall(type,type)', pcall(type,type) )
|
||||
print( 'pcall(type)', pcall(type) )
|
||||
print( '(function() return pcall(type) end)()', (function() return pcall(type) end)() )
|
||||
local function la() return pcall(type) end
|
||||
print( 'la()', la() )
|
||||
function ga() return pcall(type) end
|
||||
print( 'ga()', ga() )
|
||||
|
||||
-- getfenv, setfenv: tested in setfenv.lua
|
||||
-- getmetatable, setmetatable
|
||||
ta = { aa1="aaa1", aa2="aaa2" }
|
||||
tb = { bb1="bbb1", bb2="bbb2" }
|
||||
print( 'getmetatable(ta)', getmetatable(ta) )
|
||||
print( 'getmetatable(tb)', getmetatable(tb) )
|
||||
print( 'setmetatable(ta),{cc1="ccc1"}', type( setmetatable(ta,{cc1="ccc1"}) ) )
|
||||
print( 'setmetatable(tb),{dd1="ddd1"}', type( setmetatable(tb,{dd1="ddd1"}) ) )
|
||||
print( 'getmetatable(ta)["cc1"]', getmetatable(ta)["cc1"] )
|
||||
print( 'getmetatable(tb)["dd1"]', getmetatable(tb)["dd1"] )
|
||||
print( 'getmetatable(1)', getmetatable(1) )
|
||||
print( 'pcall(setmetatable,1)', pcall(setmetatable,1) )
|
||||
print( 'pcall(setmetatable,nil)', pcall(setmetatable,nil) )
|
||||
print( 'pcall(setmetatable,"ABC")', pcall(setmetatable,"ABC") )
|
||||
print( 'pcall(setmetatable,function() end)', pcall(setmetatable,function() end) )
|
||||
|
||||
-- ipairs
|
||||
-- load
|
||||
-- loadfile
|
||||
-- loadstring
|
||||
-- next
|
||||
-- pairs
|
||||
-- pcall
|
||||
-- print
|
||||
-- rawget
|
||||
-- rawset
|
||||
-- select
|
||||
-- tonumber
|
||||
-- tostring
|
||||
-- unpack
|
||||
--[[
|
||||
print( 'pcall(unpack)', pcall(unpack) );
|
||||
print( 'unpack({"aa"})', unpack({"aa"}) );
|
||||
print( 'unpack({"aa","bb"})', unpack({"aa","bb"}) );
|
||||
print( 'unpack({"aa","bb","cc"})', unpack({"aa","bb","cc"}) );
|
||||
|
||||
-- _VERSION
|
||||
print( '_VERSION', _VERSION )
|
||||
--]]
|
||||
BIN
src/test/res/baselib.luac
Normal file
BIN
src/test/res/baselib.luac
Normal file
Binary file not shown.
40
src/test/res/setfenv.lua
Normal file
40
src/test/res/setfenv.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
-- unit tests for getfenv, setfenv
|
||||
local function f3(level,value)
|
||||
if value then
|
||||
setfenv( level, {setfenv=setfenv, abc=value} )
|
||||
end
|
||||
return abc
|
||||
end
|
||||
local function f2(...)
|
||||
local r = f3(...)
|
||||
return abc,r
|
||||
end
|
||||
local function f1(...)
|
||||
local r,s = f2(...)
|
||||
return abc,r,s
|
||||
end
|
||||
print( 'getfenv,setfenv - before')
|
||||
print( 'getfenv(f1)["abc"]', getfenv(f1)["abc"] )
|
||||
print( 'getfenv(f2)["abc"]', getfenv(f2)["abc"] )
|
||||
print( 'getfenv(f3)["abc"]', getfenv(f3)["abc"] )
|
||||
print( 'getfenv()["abc"]', getfenv()["abc"] )
|
||||
print( 'abc,f1()', abc,f1() )
|
||||
setfenv(f1,{setfenv=setfenv, abc='ghi'})
|
||||
setfenv(f2,{setfenv=setfenv, abc='jkl'})
|
||||
setfenv(f3,{setfenv=setfenv, abc='mno'})
|
||||
print( 'getfenv,setfenv - after')
|
||||
print( 'getfenv(f1)["abc"]', getfenv(f1)["abc"] )
|
||||
print( 'getfenv(f2)["abc"]', getfenv(f2)["abc"] )
|
||||
print( 'getfenv(f3)["abc"]', getfenv(f3)["abc"] )
|
||||
print( 'getfenv()["abc"]', getfenv()["abc"] )
|
||||
print( 'abc,f1()', abc,f1() )
|
||||
print( 'abc,f1(1,"pqr")', abc,f1(1,"pqr") )
|
||||
print( 'abc,f1(2,"stu")', abc,f1(2,"stu") )
|
||||
print( 'abc,f1(3,"vwx")', abc,f1(3,"vwx") )
|
||||
print( 'abc', abc )
|
||||
local c = coroutine.create( function()
|
||||
print( 'pcall(f1,0,"abc")', pcall(f1,0,"234") )
|
||||
end )
|
||||
print( 'resume', coroutine.resume(c) )
|
||||
print( 'abc,pcall(f1)', abc,pcall(f1) )
|
||||
print( 'abc (out)', abc )
|
||||
BIN
src/test/res/setfenv.luac
Normal file
BIN
src/test/res/setfenv.luac
Normal file
Binary file not shown.
Reference in New Issue
Block a user