From 09b201c87c904066e1de5d44cf1e02538970c168 Mon Sep 17 00:00:00 2001
From: Philipp Janda <siffiejoe@gmx.net>
Date: Sat, 16 Sep 2017 17:19:35 +0200
Subject: Add tests for `luaL_load{buffer,file}x`.

Fix bug regarding empty input in `lua_load`.
Adapt error message and error code.
---
 c-api/compat-5.3.c |  19 +++----
 tests/test.lua     | 157 +++++++++++++++++++++++++++++++----------------------
 tests/testmod.c    |  29 ++++++++++
 3 files changed, 129 insertions(+), 76 deletions(-)

diff --git a/c-api/compat-5.3.c b/c-api/compat-5.3.c
index 4bd984a..e87808c 100644
--- a/c-api/compat-5.3.c
+++ b/c-api/compat-5.3.c
@@ -447,7 +447,7 @@ COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
 
 static int compat53_checkmode (lua_State *L, const char *mode, const char *modename, int err) {
   if (mode && strchr(mode, modename[0]) == NULL) {
-    lua_pushfstring(L, "attempt to load a %s chunk when 'mode' is '%s'", modename, mode);
+    lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode);
     return err;
   }
   return LUA_OK;
@@ -475,17 +475,16 @@ static const char *compat53_reader (lua_State *L, void *ud, size_t *size) {
 
 
 COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *source, const char *mode) {
+  int status = LUA_OK;
   compat53_reader_data compat53_data = { reader, data, 1, 0, 0 };
   compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size));
-  if (compat53_data.peeked_data && compat53_data.peeked_data_size) {
-    int status = LUA_OK;
-    if (compat53_data.peeked_data[0] == LUA_SIGNATURE[0])  /* binary file? */
-      status = compat53_checkmode(L, mode, "binary", LUA_ERRFILE);
-    else
-      status = compat53_checkmode(L, mode, "text", LUA_ERRFILE);
-    if (status != LUA_OK)
-      return status;
-  }
+  if (compat53_data.peeked_data && compat53_data.peeked_data_size &&
+      compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */
+      status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX);
+  else
+      status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX);
+  if (status != LUA_OK)
+    return status;
   /* we need to call the original 5.1 version of lua_load! */
 #undef lua_load
   return lua_load(L, compat53_reader, &compat53_data, source);
diff --git a/tests/test.lua b/tests/test.lua
index 582f55e..8fafdf3 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -657,133 +657,158 @@ ___''
 print("testing C API ...")
 local mod = require("testmod")
 ___''
-print(mod.isinteger(1))
-print(mod.isinteger(0))
-print(mod.isinteger(1234567))
-print(mod.isinteger(12.3))
-print(mod.isinteger(math.huge))
-print(mod.isinteger(math.sqrt(-1)))
+print("isinteger", mod.isinteger(1))
+print("isinteger", mod.isinteger(0))
+print("isinteger", mod.isinteger(1234567))
+print("isinteger", mod.isinteger(12.3))
+print("isinteger", mod.isinteger(math.huge))
+print("isinteger", mod.isinteger(math.sqrt(-1)))
 
 
 ___''
-print(mod.rotate(1, 1, 2, 3, 4, 5, 6))
-print(mod.rotate(-1, 1, 2, 3, 4, 5, 6))
-print(mod.rotate(4, 1, 2, 3, 4, 5, 6))
-print(mod.rotate(-4, 1, 2, 3, 4, 5, 6))
+print("rotate", mod.rotate(1, 1, 2, 3, 4, 5, 6))
+print("rotate", mod.rotate(-1, 1, 2, 3, 4, 5, 6))
+print("rotate", mod.rotate(4, 1, 2, 3, 4, 5, 6))
+print("rotate", mod.rotate(-4, 1, 2, 3, 4, 5, 6))
 
 
 ___''
-print(mod.strtonum("+123"))
-print(mod.strtonum(" 123 "))
-print(mod.strtonum("-1.23"))
-print(mod.strtonum(" 123 abc"))
-print(mod.strtonum("jkl"))
+print("strtonum", mod.strtonum("+123"))
+print("strtonum", mod.strtonum(" 123 "))
+print("strtonum", mod.strtonum("-1.23"))
+print("strtonum", mod.strtonum(" 123 abc"))
+print("strtonum", mod.strtonum("jkl"))
 
 
 ___''
 local a, b, c = mod.requiref()
-print( type(a), type(b), type(c),
-       a.boolean, b.boolean, c.boolean,
-       type(requiref1), type(requiref2), type(requiref3))
+print("requiref", type(a), type(b), type(c),
+      a.boolean, b.boolean, c.boolean,
+      type(requiref1), type(requiref2), type(requiref3))
 
 ___''
 local proxy, backend = {}, {}
 setmetatable(proxy, { __index = backend, __newindex = backend })
-print(rawget(proxy, 1), rawget(backend, 1))
-print(mod.getseti(proxy, 1))
-print(rawget(proxy, 1), rawget(backend, 1))
-print(mod.getseti(proxy, 1))
-print(rawget(proxy, 1), rawget(backend, 1))
+print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
+print("geti/seti", mod.getseti(proxy, 1))
+print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
+print("geti/seti", mod.getseti(proxy, 1))
+print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
 
 -- tests for Lua 5.1
 ___''
-print(mod.tonumber(12))
-print(mod.tonumber("12"))
-print(mod.tonumber("0"))
-print(mod.tonumber(false))
-print(mod.tonumber("error"))
+print("tonumber", mod.tonumber(12))
+print("tonumber", mod.tonumber("12"))
+print("tonumber", mod.tonumber("0"))
+print("tonumber", mod.tonumber(false))
+print("tonumber", mod.tonumber("error"))
 
 ___''
-print(mod.tointeger(12))
-print(mod.tointeger("12"))
-print(mod.tointeger("0"))
-print( "aaa" )
-print(mod.tointeger(math.pi))
-print( "bbb" )
-print(mod.tointeger(false))
-print(mod.tointeger("error"))
+print("tointeger", mod.tointeger(12))
+print("tointeger", mod.tointeger("12"))
+print("tointeger", mod.tointeger("0"))
+print("tointeger", mod.tointeger(math.pi))
+print("tointeger", mod.tointeger(false))
+print("tointeger", mod.tointeger("error"))
 
 ___''
-print(mod.len("123"))
-print(mod.len({ 1, 2, 3}))
-print(pcall(mod.len, true))
+print("len", mod.len("123"))
+print("len", mod.len({ 1, 2, 3}))
+print("len", pcall(mod.len, true))
 local ud, meta = mod.newproxy()
 meta.__len = function() return 5 end
-print(mod.len(ud))
+print("len", mod.len(ud))
 meta.__len = function() return true end
-print(pcall(mod.len, ud))
+print("len", pcall(mod.len, ud))
 
 ___''
-print(mod.copy(true, "string", {}, 1))
+print("copy", mod.copy(true, "string", {}, 1))
 
 ___''
-print(mod.rawxetp())
-print(mod.rawxetp("I'm back"))
+print("rawgetp/rawsetp", mod.rawxetp())
+print("rawgetp/rawsetp", mod.rawxetp("I'm back"))
 
 ___''
-print(F(mod.globals()), mod.globals() == _G)
+print("globals", F(mod.globals()), mod.globals() == _G)
 
 ___''
 local t = {}
-print(F(mod.subtable(t)))
+print("getsubtable", F(mod.subtable(t)))
 local x, msg = mod.subtable(t)
-print(F(x, msg, x == t.xxx))
+print("getsubtable", F(x, msg, x == t.xxx))
 
 ___''
-print(F(mod.udata()))
-print(mod.udata("nosuchtype"))
+print("udata", F(mod.udata()))
+print("udata", mod.udata("nosuchtype"))
 
 ___''
-print(F(mod.uservalue()))
+print("uservalue", F(mod.uservalue()))
 
 ___''
-print(mod.getupvalues())
+print("upvalues", mod.getupvalues())
 
 ___''
-print(mod.absindex("hi", true))
+print("absindex", mod.absindex("hi", true))
 
 ___''
-print(mod.arith(2, 1))
-print(mod.arith(3, 5))
+print("arith", mod.arith(2, 1))
+print("arith", mod.arith(3, 5))
 
 ___''
-print(mod.compare(1, 1))
-print(mod.compare(2, 1))
-print(mod.compare(1, 2))
+print("compare", mod.compare(1, 1))
+print("compare", mod.compare(2, 1))
+print("compare", mod.compare(1, 2))
 
 ___''
-print(mod.tolstring("string"))
+print("tolstring", mod.tolstring("string"))
 local t = setmetatable({}, {
   __tostring = function(v) return "mytable" end
 })
-print(mod.tolstring(t))
+print("tolstring", mod.tolstring(t))
 local t = setmetatable({}, {
   __tostring = function(v) return nil end
 })
-print(pcall(mod.tolstring, t))
+print("tolstring", pcall(mod.tolstring, t))
 local ud, meta = mod.newproxy()
 meta.__name = "XXX"
-print(mod.tolstring(ud):gsub(":.*$", ": yyy"))
+print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy"))
 
 ___''
-print(mod.pushstring())
+print("pushstring", mod.pushstring())
 
 ___''
-print(mod.buffer())
+print("Buffer", mod.buffer())
 
 ___''
-print(mod.exec("exit 0"))
-print(mod.exec("exit 1"))
-print(mod.exec("exit 25"))
+print("execresult", mod.exec("exit 0"))
+print("execresult", mod.exec("exit 1"))
+print("execresult", mod.exec("exit 25"))
+
+___''
+do
+  local bin = string.dump(function() end)
+  local modes = { "t", "b", "bt" }
+  local codes = {
+    "", "return true", bin, "invalidsource", "\27invalidbinary"
+  }
+  for _,m in ipairs(modes) do
+    for i,c in ipairs(codes) do
+      print("loadbufferx", m, i, F(mod.loadstring(c, m)))
+    end
+  end
+
+  ___''
+  local bom = "\239\187\191"
+  local shebang = "#!/usr/bin/env lua\n"
+  codes[#codes+1] = bom .. shebang .. "return true"
+  codes[#codes+1] = bom .. shebang .. bin
+  codes[#codes+1] = bom .. shebang .. "invalidsource"
+  codes[#codes+1] = bom .. shebang .. "\027invalidbinary"
+  for _,m in ipairs(modes) do
+    for i,c in ipairs(codes) do
+      print("loadfilex", m, i, F(mod.loadfile(c, m)))
+    end
+  end
+end
 ___''
 
diff --git a/tests/testmod.c b/tests/testmod.c
index 868136b..1034d20 100644
--- a/tests/testmod.c
+++ b/tests/testmod.c
@@ -274,6 +274,33 @@ static int test_exec (lua_State *L) {
   return luaL_execresult(L, system(cmd));
 }
 
+static int test_loadstring (lua_State *L) {
+  size_t len = 0;
+  char const* s = luaL_checklstring(L, 1, &len);
+  char const* mode = luaL_optstring(L, 2, "bt");
+  lua_pushinteger(L, luaL_loadbufferx(L, s, len, s, mode));
+  return 2;
+}
+
+static int test_loadfile (lua_State *L) {
+  char filename[L_tmpnam+1] = { 0 };
+  size_t len = 0;
+  char const* s = luaL_checklstring(L, 1, &len);
+  char const* mode = luaL_optstring(L, 2, "bt");
+  if (tmpnam(filename)) {
+    FILE* f = fopen(filename, "wb");
+    if (f) {
+      fwrite(s, 1, len, f);
+      fclose(f);
+      lua_pushinteger(L, luaL_loadfilex(L, filename, mode));
+      remove(filename);
+      return 2;
+    } else
+      remove(filename);
+  }
+  return 0;
+}
+
 
 static const luaL_Reg funcs[] = {
   { "isinteger", test_isinteger },
@@ -297,6 +324,8 @@ static const luaL_Reg funcs[] = {
   { "pushstring", test_pushstring },
   { "buffer", test_buffer },
   { "exec", test_exec },
+  { "loadstring", test_loadstring },
+  { "loadfile", test_loadfile },
   { NULL, NULL }
 };
 
-- 
cgit v1.2.3-55-g6feb