Skip to content

Commit 0f4faa9

Browse files
committed
tests: add remaining tests
There are a few functions I don't think are worth testing at this point, so I will consider this to be full test coverage for my purposes!
1 parent ec9799b commit 0f4faa9

File tree

2 files changed

+214
-40
lines changed

2 files changed

+214
-40
lines changed

src/tests.zig

Lines changed: 186 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ test "type of and getting values" {
299299

300300
try expectEqual(@as(Number, 0.1), try lua.toNumber(6));
301301
try expectEqual(@as(Integer, 1), try lua.toInteger(3));
302+
303+
try expectEqualStrings("number", lua.typeNameIndex(3));
302304
}
303305

304306
test "typenames" {
@@ -1343,25 +1345,194 @@ test "loadBuffer" {
13431345
try expectEqual(@as(Integer, 10), try lua.toInteger(-1));
13441346
}
13451347

1348+
test "where" {
1349+
var lua = try Lua.init(testing.allocator);
1350+
defer lua.deinit();
1351+
1352+
const whereFn = ziglua.wrap(struct {
1353+
fn inner(l: *Lua) i32 {
1354+
l.where(1);
1355+
return 1;
1356+
}
1357+
}.inner);
1358+
1359+
lua.pushFunction(whereFn);
1360+
lua.setGlobal("whereFn");
1361+
1362+
try lua.doString(
1363+
\\
1364+
\\ret = whereFn()
1365+
);
1366+
1367+
try lua.getGlobal("ret");
1368+
try expectEqualStrings("[string \"...\"]:2: ", try lua.toBytes(-1));
1369+
}
1370+
1371+
test "ref" {
1372+
var lua = try Lua.init(testing.allocator);
1373+
defer lua.deinit();
1374+
1375+
lua.pushNil();
1376+
try expectError(error.Fail, lua.ref(ziglua.registry_index));
1377+
try expectEqual(@as(Integer, 0), lua.getTop());
1378+
1379+
lua.pushBytes("Hello there");
1380+
const ref = try lua.ref(ziglua.registry_index);
1381+
1382+
_ = lua.rawGetIndex(ziglua.registry_index, ref);
1383+
try expectEqualStrings("Hello there", try lua.toBytes(-1));
1384+
1385+
lua.unref(ziglua.registry_index, ref);
1386+
}
1387+
1388+
test "args and errors" {
1389+
var lua = try Lua.init(testing.allocator);
1390+
defer lua.deinit();
1391+
1392+
const argCheck = ziglua.wrap(struct {
1393+
fn inner(l: *Lua) i32 {
1394+
l.argCheck(true, 1, "error!");
1395+
return 0;
1396+
}
1397+
}.inner);
1398+
1399+
lua.pushFunction(argCheck);
1400+
try expectError(error.Runtime, lua.protectedCall(0, 0, 0));
1401+
1402+
const argExpected = ziglua.wrap(struct {
1403+
fn inner(l: *Lua) i32 {
1404+
l.argExpected(true, 1, "string");
1405+
return 0;
1406+
}
1407+
}.inner);
1408+
1409+
lua.pushFunction(argExpected);
1410+
try expectError(error.Runtime, lua.protectedCall(0, 0, 0));
1411+
1412+
const raisesError = ziglua.wrap(struct {
1413+
fn inner(l: *Lua) i32 {
1414+
l.raiseErrorAux("some error %s!", .{"zig"});
1415+
unreachable;
1416+
}
1417+
}.inner);
1418+
1419+
lua.pushFunction(raisesError);
1420+
try expectError(error.Runtime, lua.protectedCall(0, 0, 0));
1421+
try expectEqualStrings("some error zig!", try lua.toBytes(-1));
1422+
}
1423+
1424+
test "traceback" {
1425+
var lua = try Lua.init(testing.allocator);
1426+
defer lua.deinit();
1427+
1428+
const tracebackFn = ziglua.wrap(struct {
1429+
fn inner(l: *Lua) i32 {
1430+
l.traceback(l, "", 1);
1431+
return 1;
1432+
}
1433+
}.inner);
1434+
1435+
lua.pushFunction(tracebackFn);
1436+
lua.setGlobal("tracebackFn");
1437+
try lua.doString("res = tracebackFn()");
1438+
1439+
try lua.getGlobal("res");
1440+
try expectEqualStrings("\nstack traceback:\n\t[string \"res = tracebackFn()\"]:1: in main chunk", try lua.toBytes(-1));
1441+
}
1442+
1443+
test "getSubtable" {
1444+
var lua = try Lua.init(testing.allocator);
1445+
defer lua.deinit();
1446+
1447+
try lua.doString(
1448+
\\a = {
1449+
\\ b = {},
1450+
\\}
1451+
);
1452+
try lua.getGlobal("a");
1453+
1454+
// get the subtable a.b
1455+
try lua.getSubtable(-1, "b");
1456+
1457+
// fail to get the subtable a.c (but it is created)
1458+
try expectError(error.Fail, lua.getSubtable(-2, "c"));
1459+
1460+
// now a.c will pass
1461+
try lua.getSubtable(-3, "b");
1462+
}
1463+
1464+
test "userdata" {
1465+
var lua = try Lua.init(testing.allocator);
1466+
defer lua.deinit();
1467+
1468+
const Type = struct { a: i32, b: f32 };
1469+
try lua.newMetatable("Type");
1470+
1471+
var t = lua.newUserdataUV(Type, 0);
1472+
lua.setMetatableAux("Type");
1473+
t.a = 1234;
1474+
t.b = 3.14;
1475+
1476+
const checkUdata = ziglua.wrap(struct {
1477+
fn inner(l: *Lua) i32 {
1478+
const ptr = ziglua.opaqueCast(Type, l.checkUserdata(1, "Type"));
1479+
if (ptr.a != 1234) {
1480+
l.pushBytes("error!");
1481+
l.raiseError();
1482+
}
1483+
if (ptr.b != 3.14) {
1484+
l.pushBytes("error!");
1485+
l.raiseError();
1486+
}
1487+
return 1;
1488+
}
1489+
}.inner);
1490+
1491+
lua.pushFunction(checkUdata);
1492+
lua.rotate(-2, 1);
1493+
1494+
// call checkUdata asserting that the udata passed in with the
1495+
// correct metatable and values
1496+
try lua.protectedCall(1, 1, 0);
1497+
1498+
const testUdata = ziglua.wrap(struct {
1499+
fn inner(l: *Lua) i32 {
1500+
const ptr = ziglua.opaqueCast(Type, l.testUserdata(1, "Type") catch {
1501+
l.pushBytes("error!");
1502+
l.raiseError();
1503+
});
1504+
if (ptr.a != 1234) {
1505+
l.pushBytes("error!");
1506+
l.raiseError();
1507+
}
1508+
if (ptr.b != 3.14) {
1509+
l.pushBytes("error!");
1510+
l.raiseError();
1511+
}
1512+
return 0;
1513+
}
1514+
}.inner);
1515+
1516+
lua.pushFunction(testUdata);
1517+
lua.rotate(-2, 1);
1518+
1519+
// call checkUdata asserting that the udata passed in with the
1520+
// correct metatable and values
1521+
try lua.protectedCall(1, 0, 0);
1522+
}
1523+
13461524
test "refs" {
1347-
// temporary test that includes a reference to all functions so
1348-
// they will be type-checked
1525+
// tests for functions that aren't tested or will not be tested in ziglua
1526+
// but ensures that the signatures are at least type checked
13491527

1350-
// auxlib
1351-
_ = Lua.argCheck;
1352-
_ = Lua.argExpected;
1353-
_ = Lua.checkUserdata;
1528+
// no need to test file loading
13541529
_ = Lua.doFile;
1355-
_ = Lua.raiseErrorAux;
1356-
_ = Lua.exeResult;
1357-
_ = Lua.fileResult;
1358-
_ = Lua.getSubtable;
13591530
_ = Lua.loadFile;
13601531
_ = Lua.loadFileX;
1532+
1533+
// probably not needed in ziglua
1534+
_ = Lua.execResult;
1535+
_ = Lua.fileResult;
1536+
13611537
_ = Lua.testUserdata;
1362-
_ = Lua.traceback;
1363-
_ = Lua.typeError;
1364-
_ = Lua.typeNameAux;
1365-
_ = Lua.unref;
1366-
_ = Lua.where;
13671538
}

src/ziglua.zig

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ pub const Lua = struct {
698698
/// This function creates and pushes a new full userdata onto the stack
699699
/// with `num_uvalue` associated Lua values, plus an associated block of raw memory with `size` bytes
700700
/// Returns the address of the block of memory
701+
/// TODO: rename to newUserdata?
701702
pub fn newUserdataUV(lua: *Lua, comptime T: type, new_uvalue: i32) *T {
702703
// safe to .? because this function throws a Lua error on out of memory
703704
// so the returned pointer should never be null
@@ -721,6 +722,7 @@ pub const Lua = struct {
721722
}
722723

723724
/// Calls a function (or callable object) in protected mode
725+
/// NOTE: it might be good to make the args named struct params?
724726
pub fn protectedCall(lua: *Lua, num_args: i32, num_results: i32, msg_handler: i32) !void {
725727
// The translate-c version of lua_pcall does not type-check so we must rewrite it
726728
// (macros don't always translate well with translate-c)
@@ -1095,6 +1097,7 @@ pub const Lua = struct {
10951097
}
10961098

10971099
/// Returns the name of the given `LuaType` as a null-terminated slice
1100+
/// TODO: return a spanned string
10981101
pub fn typeName(lua: *Lua, t: LuaType) [*:0]const u8 {
10991102
return c.lua_typename(lua.state, @enumToInt(t));
11001103
}
@@ -1297,7 +1300,7 @@ pub const Lua = struct {
12971300
/// Possibly never returns
12981301
pub fn argCheck(lua: *Lua, cond: bool, arg: i32, extra_msg: [:0]const u8) void {
12991302
// translate-c failed
1300-
if (cond) lua.typeError(arg, extra_msg);
1303+
if (cond) lua.argError(arg, extra_msg);
13011304
}
13021305

13031306
/// Raises an error reporting a problem with argument `arg` of the C function that called it
@@ -1383,7 +1386,9 @@ pub const Lua = struct {
13831386

13841387
/// Checks whether the function argument `arg` is a userdata of the type `type_name`
13851388
/// Returns the userdata's memory-block address
1389+
/// TODO: accept type as param?
13861390
pub fn checkUserdata(lua: *Lua, arg: i32, type_name: [:0]const u8) *anyopaque {
1391+
// the returned pointer will not be null
13871392
return c.luaL_checkudata(lua.state, arg, type_name).?;
13881393
}
13891394

@@ -1409,11 +1414,12 @@ pub const Lua = struct {
14091414

14101415
/// Raises an error
14111416
pub fn raiseErrorAux(lua: *Lua, fmt: [:0]const u8, args: anytype) noreturn {
1412-
@call(.{}, c.luaL_error, .{ lua.state, fmt } ++ args);
1417+
_ = @call(.{}, c.luaL_error, .{ lua.state, fmt } ++ args);
1418+
unreachable;
14131419
}
14141420

14151421
/// This function produces the return values for process-related functions in the standard library
1416-
pub fn exeResult(lua: *Lua, stat: i32) i32 {
1422+
pub fn execResult(lua: *Lua, stat: i32) i32 {
14171423
return c.luaL_execresult(lua.state, stat);
14181424
}
14191425

@@ -1439,8 +1445,8 @@ pub const Lua = struct {
14391445
}
14401446

14411447
/// Ensures that the value t[`field`], where t is the value at `index`, is a table, and pushes that table onto the stack.
1442-
pub fn getSubtable(lua: *Lua, index: i32, field: [:0]const u8) bool {
1443-
return c.luaL_getsubtable(lua.state, index, field) != 0;
1448+
pub fn getSubtable(lua: *Lua, index: i32, field: [:0]const u8) !void {
1449+
if (c.luaL_getsubtable(lua.state, index, field) == 0) return error.Fail;
14441450
}
14451451

14461452
/// Creates a copy of string `str`, replacing any occurrence of the string `pat` with the string `rep`
@@ -1455,7 +1461,7 @@ pub const Lua = struct {
14551461
return c.luaL_len(lua.state, index);
14561462
}
14571463

1458-
/// The same as `Lua.loadBufferX` with `mode` set to null
1464+
/// The same as `Lua.loadBufferX` with `mode` set to binary+text
14591465
pub fn loadBuffer(lua: *Lua, buf: []const u8, name: [:0]const u8) !void {
14601466
try lua.loadBufferX(buf, name, .binary_text);
14611467
}
@@ -1476,21 +1482,17 @@ pub const Lua = struct {
14761482
}
14771483
}
14781484

1479-
/// Equivalent to `Lua.loadFileX()` with mode equal to null
1485+
/// Equivalent to `Lua.loadFileX()` with mode equal to binary+text
14801486
pub fn loadFile(lua: *Lua, file_name: [:0]const u8) !void {
1481-
return loadFileX(lua, file_name, null);
1487+
try lua.loadFileX(file_name, .binary_text);
14821488
}
14831489

14841490
/// Loads a file as a Lua chunk
1485-
pub fn loadFileX(lua: *Lua, file_name: [:0]const u8, mode: ?Mode) !void {
1486-
const mode_str = blk: {
1487-
if (mode == null) break :blk "bt";
1488-
1489-
break :blk switch (mode.?) {
1490-
.binary => "b",
1491-
.text => "t",
1492-
.binary_text => "bt",
1493-
};
1491+
pub fn loadFileX(lua: *Lua, file_name: [:0]const u8, mode: Mode) !void {
1492+
const mode_str = switch (mode) {
1493+
.binary => "b",
1494+
.text => "t",
1495+
.binary_text => "bt",
14941496
};
14951497
const ret = c.luaL_loadfilex(lua.state, file_name, mode_str);
14961498
switch (ret) {
@@ -1581,9 +1583,9 @@ pub const Lua = struct {
15811583

15821584
/// Creates and returns a reference in the table at index `index` for the object on the top of the stack
15831585
/// Pops the object
1584-
pub fn ref(lua: *Lua, index: i32) ?i32 {
1586+
pub fn ref(lua: *Lua, index: i32) !i32 {
15851587
const ret = c.luaL_ref(lua.state, index);
1586-
return if (ret == ref_nil) null else ret;
1588+
return if (ret == ref_nil) error.Fail else ret;
15871589
}
15881590

15891591
/// If package.loaded[`mod_name`] is not true, calls the function `open_fn` with `mod_name`
@@ -1614,9 +1616,11 @@ pub const Lua = struct {
16141616
c.luaL_setmetatable(lua.state, table_name);
16151617
}
16161618

1617-
/// This function works like `Lua.checkUserdata()` except it returns null instead of raising an error on fail
1618-
pub fn testUserdata(lua: *Lua, arg: i32, type_name: [:0]const u8) ?*anyopaque {
1619-
return c.luaL_testudata(lua.state, arg, type_name);
1619+
/// This function works like `Lua.checkUserdata()` except it returns a Zig error instead of raising a Lua error on fail
1620+
pub fn testUserdata(lua: *Lua, arg: i32, type_name: [:0]const u8) !*anyopaque {
1621+
if (c.luaL_testudata(lua.state, arg, type_name)) |ptr| {
1622+
return ptr;
1623+
} else return error.Fail;
16201624
}
16211625

16221626
/// Converts any Lua value at the given index into a string in a reasonable format
@@ -1627,7 +1631,7 @@ pub const Lua = struct {
16271631
}
16281632

16291633
/// Creates and pushes a traceback of the stack of `other`
1630-
pub fn traceback(lua: *Lua, other: Lua, msg: [:0]const u8, level: i32) void {
1634+
pub fn traceback(lua: *Lua, other: *Lua, msg: [:0]const u8, level: i32) void {
16311635
c.luaL_traceback(lua.state, other.state, msg, level);
16321636
}
16331637

@@ -1638,8 +1642,7 @@ pub const Lua = struct {
16381642
}
16391643

16401644
/// Returns the name of the type of the value at the given `index`
1641-
/// TODO: maybe typeNameIndex?
1642-
pub fn typeNameAux(lua: *Lua, index: i32) [:0]const u8 {
1645+
pub fn typeNameIndex(lua: *Lua, index: i32) [:0]const u8 {
16431646
return std.mem.span(c.luaL_typename(lua.state, index));
16441647
}
16451648

0 commit comments

Comments
 (0)