Skip to content

Commit fc58e1f

Browse files
committed
tests: add many tests
1 parent 087033a commit fc58e1f

File tree

1 file changed

+142
-24
lines changed

1 file changed

+142
-24
lines changed

src/ziglua.zig

Lines changed: 142 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,11 @@ pub const Lua = struct {
460460

461461
/// Pushes onto the stack the `n`th user value associated with the full userdata at the given `index`
462462
/// Returns the type of the pushed value
463-
pub fn getIUserValue(lua: *Lua, index: i32, n: i32) LuaType {
464-
return @intToEnum(LuaType, c.lua_getiuservalue(lua.state, index, n));
463+
/// Returns an error if the userdata does not have that value
464+
pub fn getIndexUserValue(lua: *Lua, index: i32, n: i32) !LuaType {
465+
const val_type = @intToEnum(LuaType, c.lua_getiuservalue(lua.state, index, n));
466+
if (val_type == .none) return Error.Fail;
467+
return val_type;
465468
}
466469

467470
/// If the value at the given `index` has a metatable, the function pushes that metatable onto the stack
@@ -608,8 +611,11 @@ pub const Lua = struct {
608611
/// Returns the address of the block of memory
609612
/// TODO: use comptime to return the a pointer to a block of type T for safety?
610613
/// See how this is used if that would be useful
611-
pub fn newUserdataUV(lua: *Lua, size: usize, new_uvalue: i32) *anyopaque {
612-
return c.lua_newuserdatauv(lua.state, size, new_uvalue).?;
614+
pub fn newUserdataUV(lua: *Lua, comptime T: type, new_uvalue: i32) *T {
615+
// safe to .? because this function throws a Lua error on out of memory
616+
// so the returned pointer should never be null
617+
const ptr = c.lua_newuserdatauv(lua.state, @sizeOf(T), new_uvalue).?;
618+
return opaqueCast(T, ptr);
613619
}
614620

615621
/// Pops a key from the stack, and pushes a key-value pair from the table at the given `index`
@@ -658,7 +664,6 @@ pub const Lua = struct {
658664

659665
/// Pushes a new C Closure onto the stack
660666
/// `n` tells how many upvalues this function will have
661-
/// TODO: add a Zig interface to pass Zig functions wrapped
662667
pub fn pushCClosure(lua: *Lua, c_fn: CFn, n: i32) void {
663668
c.lua_pushcclosure(lua.state, c_fn, n);
664669
}
@@ -756,7 +761,7 @@ pub const Lua = struct {
756761

757762
/// Pushes onto the stack the value t[k] where t is the table at the given `index` and
758763
/// k is the pointer `p` represented as a light userdata
759-
pub fn rawGetP(lua: *Lua, index: i32, p: *anyopaque) LuaType {
764+
pub fn rawGetPtr(lua: *Lua, index: i32, p: *const anyopaque) LuaType {
760765
return @intToEnum(LuaType, c.lua_rawgetp(lua.state, index, p));
761766
}
762767

@@ -783,7 +788,7 @@ pub const Lua = struct {
783788
/// Does the equivalent of t[p] = v where t is the table at the given `index`
784789
/// `p` is encoded as a light user data, and v is the value at the top of the stack
785790
/// Pops the value from the stack. Does not use __newindex metavalue
786-
pub fn rawSetP(lua: *Lua, index: i32, p: *anyopaque) void {
791+
pub fn rawSetPtr(lua: *Lua, index: i32, p: *const anyopaque) void {
787792
c.lua_rawsetp(lua.state, index, p);
788793
}
789794

@@ -854,7 +859,7 @@ pub const Lua = struct {
854859
/// Pops a value from the stack and sets it as the new `n`th user value associated to
855860
/// the full userdata at the given index
856861
/// Returns an error if the userdata does not have that value
857-
pub fn setIUserValue(lua: *Lua, index: i32, n: i32) !void {
862+
pub fn setIndexUserValue(lua: *Lua, index: i32, n: i32) !void {
858863
if (c.lua_setiuservalue(lua.state, index, n) == 0) return Error.Fail;
859864
}
860865

@@ -960,8 +965,9 @@ pub const Lua = struct {
960965
}
961966

962967
/// Converts the value at the given `index` to an opaque pointer
963-
pub fn toPointer(lua: *Lua, index: i32) ?*const anyopaque {
964-
return c.lua_topointer(lua.state, index);
968+
pub fn toPointer(lua: *Lua, index: i32) !*const anyopaque {
969+
if (c.lua_topointer(lua.state, index)) |ptr| return ptr;
970+
return Error.Fail;
965971
}
966972

967973
/// Converts the Lua value at the given `index` to a zero-terminated slice (string)
@@ -985,9 +991,10 @@ pub const Lua = struct {
985991

986992
/// If the value at the given `index` is a full userdata, returns its memory-block address
987993
/// If the value is a light userdata, returns its value (a pointer)
988-
/// Otherwise returns null
989-
pub fn toUserdata(lua: *Lua, index: i32) ?*anyopaque {
990-
return c.lua_touserdata(lua.state, index);
994+
/// Otherwise returns an error
995+
pub fn toUserdata(lua: *Lua, index: i32) !*anyopaque {
996+
if (c.lua_touserdata(lua.state, index)) |ptr| return ptr;
997+
return Error.Fail;
991998
}
992999

9931000
/// Returns the `LuaType` of the value at the given index
@@ -2508,26 +2515,137 @@ test "dump and load" {
25082515
try expectEqual(@as(Integer, 11), lua.toInteger(-1));
25092516
}
25102517

2518+
test "threads" {
2519+
var lua = try Lua.init(testing.allocator);
2520+
defer lua.deinit();
2521+
2522+
var new_thread = lua.newThread();
2523+
try expectEqual(@as(i32, 1), lua.getTop());
2524+
try expectEqual(@as(i32, 0), new_thread.getTop());
2525+
2526+
lua.pushInteger(10);
2527+
lua.pushNil();
2528+
2529+
lua.xMove(new_thread, 2);
2530+
try expectEqual(@as(i32, 2), new_thread.getTop());
2531+
}
2532+
2533+
test "userdata and uservalues" {
2534+
var lua = try Lua.init(testing.allocator);
2535+
defer lua.deinit();
2536+
2537+
const Data = struct {
2538+
val: i32,
2539+
code: [4]u8,
2540+
};
2541+
2542+
// create a Lua-owned pointer to a Data with 2 associated user values
2543+
var data = lua.newUserdataUV(Data, 2);
2544+
data.val = 1;
2545+
std.mem.copy(u8, &data.code, "abcd");
2546+
2547+
// assign the user values
2548+
lua.pushNumber(1234.56);
2549+
try lua.setIndexUserValue(1, 1);
2550+
2551+
_ = lua.pushString("test string");
2552+
try lua.setIndexUserValue(1, 2);
2553+
2554+
try expectEqual(LuaType.number, try lua.getIndexUserValue(1, 1));
2555+
try expectEqual(@as(Number, 1234.56), lua.toNumber(-1));
2556+
try expectEqual(LuaType.string, try lua.getIndexUserValue(1, 2));
2557+
try expectEqualStrings("test string", lua.toString(-1).?);
2558+
2559+
try expectError(Error.Fail, lua.setIndexUserValue(1, 3));
2560+
try expectError(Error.Fail, lua.getIndexUserValue(1, 3));
2561+
2562+
try expectEqual(data, opaqueCast(Data, try lua.toUserdata(1)));
2563+
try expectEqual(@ptrCast(*const anyopaque, data), @alignCast(@alignOf(Data), try lua.toPointer(1)));
2564+
}
2565+
2566+
test "upvalues" {
2567+
var lua = try Lua.init(testing.allocator);
2568+
defer lua.deinit();
2569+
2570+
// counter from PIL
2571+
const counter = struct {
2572+
fn inner(l: *Lua) i32 {
2573+
var counter = l.toInteger(Lua.upvalueIndex(1));
2574+
counter += 1;
2575+
l.pushInteger(counter);
2576+
l.copy(-1, Lua.upvalueIndex(1));
2577+
return 1;
2578+
}
2579+
}.inner;
2580+
2581+
// Initialize the counter at 0
2582+
lua.pushInteger(0);
2583+
lua.pushCClosure(wrap(counter), 1);
2584+
lua.setGlobal("counter");
2585+
2586+
// call the function repeatedly, each time ensuring the result increases by one
2587+
var expected: Integer = 1;
2588+
while (expected <= 10) : (expected += 1) {
2589+
_ = lua.getGlobal("counter");
2590+
lua.call(0, 1);
2591+
try expectEqual(expected, lua.toInteger(-1));
2592+
lua.pop(1);
2593+
}
2594+
}
2595+
2596+
test "table traversal" {
2597+
var lua = try Lua.init(testing.allocator);
2598+
defer lua.deinit();
2599+
2600+
try lua.doString("t = { key = 'value', second = true, third = 1 }");
2601+
_ = lua.getGlobal("t");
2602+
2603+
lua.pushNil();
2604+
2605+
while (lua.next(1)) {
2606+
switch (lua.typeOf(-1)) {
2607+
.string => {
2608+
try expectEqualStrings("key", lua.toString(-2).?);
2609+
try expectEqualStrings("value", lua.toString(-1).?);
2610+
},
2611+
.boolean => {
2612+
try expectEqualStrings("second", lua.toString(-2).?);
2613+
try expectEqual(true, lua.toBoolean(-1));
2614+
},
2615+
.number => {
2616+
try expectEqualStrings("third", lua.toString(-2).?);
2617+
try expectEqual(@as(Integer, 1), lua.toInteger(-1));
2618+
},
2619+
else => unreachable,
2620+
}
2621+
lua.pop(1);
2622+
}
2623+
}
2624+
2625+
test "registry" {
2626+
var lua = try Lua.init(testing.allocator);
2627+
defer lua.deinit();
2628+
2629+
const key = "mykey";
2630+
2631+
// store a string in the registry
2632+
_ = lua.pushString("hello there");
2633+
lua.rawSetPtr(registry_index, key);
2634+
2635+
// get key from the registry
2636+
_ = lua.rawGetPtr(registry_index, key);
2637+
try expectEqualStrings("hello there", lua.toString(-1).?);
2638+
}
2639+
25112640
test "refs" {
25122641
// temporary test that includes a reference to all functions so
25132642
// they will be type-checked
25142643

25152644
// stdlib
25162645
_ = Lua.closeSlot;
25172646
_ = Lua.raiseError;
2518-
_ = Lua.getIUserValue;
25192647
_ = Lua.isYieldable;
2520-
_ = Lua.newThread;
2521-
_ = Lua.newUserdataUV;
2522-
_ = Lua.next;
2523-
_ = Lua.rawGetP;
2524-
_ = Lua.rawSetP;
2525-
_ = Lua.setIUserValue;
25262648
_ = Lua.toClose;
2527-
_ = Lua.toPointer;
2528-
_ = Lua.toUserdata;
2529-
_ = Lua.upvalueIndex;
2530-
_ = Lua.xMove;
25312649
_ = Lua.yield;
25322650
_ = Lua.yieldCont;
25332651

0 commit comments

Comments
 (0)