From 106a349f6a33c1ccbe2e0aa5dcf9b7a1b3771eac Mon Sep 17 00:00:00 2001
From: Benoit Giannangeli <giann008@gmail.com>
Date: Thu, 25 May 2017 15:36:09 +0200
Subject: ltests.js: newstate, loadlib, doremote, closestate

---
 tests/test-suite/inprogress/coroutine.js | 56 +++++++++++++++++++++
 tests/test-suite/ltests.js               | 86 +++++++++++++++++++++++++++++++-
 2 files changed, 140 insertions(+), 2 deletions(-)

diff --git a/tests/test-suite/inprogress/coroutine.js b/tests/test-suite/inprogress/coroutine.js
index 29461d3..2aece7d 100644
--- a/tests/test-suite/inprogress/coroutine.js
+++ b/tests/test-suite/inprogress/coroutine.js
@@ -1291,6 +1291,62 @@ test("[test-suite] coroutine: resuming running coroutine", function (t) {
     }, "Lua program ran without error");
 });
 
+test("[test-suite] coroutine: using a main thread as a coroutine", function (t) {
+    let luaCode = `
+        local state = T.newstate()
+        T.loadlib(state)
+
+        assert(T.doremote(state, [[
+          coroutine = require'coroutine';
+          X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
+          return 'ok']]))
+
+        t = table.pack(T.testC(state, [[
+          rawgeti R 1     # get main thread
+          pushstring 'XX'
+          getglobal X    # get function for body
+          pushstring AA      # arg
+          resume 1 1      # 'resume' shadows previous stack!
+          gettop
+          setglobal T    # top
+          setglobal B    # second yielded value
+          setglobal A    # fist yielded value
+          rawgeti R 1     # get main thread
+          pushnum 5       # arg (noise)
+          resume 1 1      # after coroutine ends, previous stack is back
+          pushstatus
+          return *
+        ]]))
+        assert(t.n == 4 and t[2] == 'XX' and t[3] == 'CC' and t[4] == 'OK')
+        assert(T.doremote(state, "return T") == '2')
+        assert(T.doremote(state, "return A") == 'AA')
+        assert(T.doremote(state, "return B") == 'BB')
+
+        T.closestate(state)
+    `, L;
+    
+    t.plan(2);
+
+    t.doesNotThrow(function () {
+
+        L = lauxlib.luaL_newstate();
+
+        lualib.luaL_openlibs(L);
+
+        ltests.luaopen_tests(L);
+
+        lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode));
+
+    }, "Lua program loaded without error");
+
+    t.doesNotThrow(function () {
+
+        lua.lua_call(L, 0, -1);
+
+    }, "Lua program ran without error");
+});
+
+
 test("[test-suite] coroutine: tests for coroutine API", { skip: true }, function (t) {
     t.comment("TODO");
 });
diff --git a/tests/test-suite/ltests.js b/tests/test-suite/ltests.js
index 1f26d45..225e8f7 100644
--- a/tests/test-suite/ltests.js
+++ b/tests/test-suite/ltests.js
@@ -2,6 +2,8 @@
 
 global.WEB = false;
 
+const assert  = require("assert");
+
 const lua     = require('../../src/lua.js');
 const lauxlib = require('../../src/lauxlib.js');
 const ljstype = require('../../src/ljstype.js');
@@ -342,12 +344,88 @@ const testJS = function(L) {
     return runJS(L, L1, { script: pc, offset: 0 });
 };
 
+const newstate = function(L) {
+    let L1 = lua.lua_newstate();
+    if (L1) {
+        lua.lua_atpanic(L1, tpanic);
+        lua.lua_pushlightuserdata(L, L1);
+    }
+    else
+        lua.lua_pushnil(L);
+    return 1;
+};
+
 const getstate = function(L) {
     let L1 = lua.lua_touserdata(L, 1);
     lauxlib.luaL_argcheck(L, L1 !== null, 1, lua.to_luastring("state expected", true));
     return L1;
 };
 
+const luaopen_base      = require("../../src/lbaselib.js").luaopen_base;
+const luaopen_coroutine = require("../../src/lcorolib.js").luaopen_coroutine;
+const luaopen_debug     = require("../../src/ldblib.js").luaopen_debug;
+const luaopen_io        = require("../../src/liolib.js").luaopen_io;
+const luaopen_os        = require("../../src/loslib.js").luaopen_os;
+const luaopen_math      = require("../../src/lmathlib.js").luaopen_math;
+const luaopen_string    = require("../../src/lstrlib.js").luaopen_string;
+const luaopen_table     = require("../../src/ltablib.js").luaopen_table;
+const luaopen_package   = require("../../src/loadlib.js").luaopen_package;
+
+const loadlib = function(L) {
+    let libs = {
+        "_G": luaopen_base,
+        "coroutine": luaopen_coroutine,
+        "debug": luaopen_debug,
+        "io": luaopen_io,
+        "os": luaopen_os,
+        "math": luaopen_math,
+        "string": luaopen_string,
+        "table": luaopen_table
+    };
+    let L1 = getstate(L);
+    lauxlib.luaL_requiref(L1, lua.to_luastring("package", true), luaopen_package, 0);
+    assert(lua.lua_type(L1, -1) == lua.LUA_TTABLE);
+    /* 'requiref' should not reload module already loaded... */
+    lauxlib.luaL_requiref(L1, lua.to_luastring("package", true), null, 1);    /* seg. fault if it reloads */
+    /* ...but should return the same module */
+    assert(lua.lua_compare(L1, -1, -2, lua.LUA_OPEQ));
+    lauxlib.luaL_getsubtable(L1, lua.LUA_REGISTRYINDEX, lua.to_luastring(lauxlib.LUA_PRELOAD_TABLE, true));
+    for (let name in libs) {
+        lua.lua_pushcfunction(L1, libs[name]);
+        lua.lua_setfield(L1, -2, lua.to_luastring(name, true));
+    }
+    return 0;
+};
+
+const closestate = function(L) {
+    let L1 = getstate(L);
+    lua.lua_close(L1);
+    return 0;
+};
+
+const doremote = function(L) {
+    let L1 = getstate(L);
+    let lcode;
+    let code = lauxlib.luaL_checklstring(L, 2, lcode);
+    let status;
+    lua.lua_settop(L1, 0);
+    status = lauxlib.luaL_loadbuffer(L1, code, lcode, code);
+    if (status === lua.LUA_OK)
+        status = lua.lua_pcall(L1, 0, lua.LUA_MULTRET, 0);
+    if (status !== lua.LUA_OK) {
+        lua.lua_pushnil(L);
+        lua.lua_pushstring(L, lua.lua_tostring(L1, -1));
+        lua.lua_pushinteger(L, status);
+        return 3;
+    }
+    else {
+        let i = 0;
+        while (!lua.lua_isnone(L1, ++i))
+            lua.lua_pushstring(L, lua.lua_tostring(L1, i));
+        lua.lua_pop(L1, i-1);
+        return i-1;
+    }
+};
 
 const tpanic = function(L) {
     console.error(`PANIC: unprotected error in call to Lua API (${lua.lua_tojsstring(L, -1)})\n`);
@@ -439,11 +517,15 @@ const coresume = function(L) {
 };
 
 const tests_funcs = {
+    "closestate": closestate,
+    "doremote": doremote,
+    "loadlib": loadlib,
+    "newstate": newstate,
     "newuserdata": newuserdata,
     "resume": coresume,
     "sethook": sethook,
-    "testJS": testJS,
-    "testC": testJS
+    "testC": testJS,
+    "testJS": testJS
 };
 
 const luaB_opentests = function(L) {
-- 
cgit v1.2.3-70-g09d2