From 66292a6a85cf22cae31520ea4d08c76f544e338a Mon Sep 17 00:00:00 2001
From: Benoit Giannangeli <benoit.giannangeli@boursorama.fr>
Date: Tue, 21 Mar 2017 08:38:41 +0100
Subject: string.gsub tests

---
 src/lapi.js      |   2 +-
 src/lauxlib.js   |   4 +-
 src/ljstype.js   |  10 +--
 src/lstrlib.js   |   6 +-
 tests/lstrlib.js | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 201 insertions(+), 10 deletions(-)

diff --git a/src/lapi.js b/src/lapi.js
index 6840ef9..5872545 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -542,7 +542,7 @@ const lua_toboolean = function(L, idx) {
 const lua_tolstring = function(L, idx) {
     let o = index2addr(L, idx);
 
-    if (!o.ttisstring() && !o.ttisnumber())
+    if ((!o.ttisstring() && !o.ttisnumber()))
         return null;
 
     return o.ttisstring() ? o.jsstring() : `${o.value}`;
diff --git a/src/lauxlib.js b/src/lauxlib.js
index 879d081..ac7ab00 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -299,10 +299,12 @@ const luaL_tolstring = function(L, idx) {
     } else {
         switch(lapi.lua_type(L, idx)) {
             case CT.LUA_TNUMBER:
-            case CT.LUA_TSTRING:
             case CT.LUA_TBOOLEAN:
                 lapi.lua_pushstring(L, `${lapi.index2addr(L, idx).value}`);
                 break;
+            case CT.LUA_TSTRING:
+                lapi.lua_pushstring(L, lapi.index2addr(L, idx).jsstring());
+                break;
             case CT.LUA_TNIL:
                 lapi.lua_pushstring(L, `nil`);
                 break;
diff --git a/src/ljstype.js b/src/ljstype.js
index ef4be1d..7de9d9a 100644
--- a/src/ljstype.js
+++ b/src/ljstype.js
@@ -3,23 +3,23 @@
 const assert = require('assert');
 
 const lisdigit = function(c) {
-    return /^\d$/.test(c.charAt(0));
+    return typeof c === 'string' && /^\d$/.test(c.charAt(0));
 };
 
 const lisxdigit = function(c) {
-    return /^[0-9a-fA-F]$/.test(c.charAt(0));
+    return typeof c === 'string' && /^[0-9a-fA-F]$/.test(c.charAt(0));
 };
 
 const lisspace = function(c) {
-    return /^\s$/.test(c.charAt(0));
+    return typeof c === 'string' && /^\s$/.test(c.charAt(0));
 };
 
 const lislalpha = function(c) {
-    return /^[_a-zA-Z]$/.test(c.charAt(0));
+    return typeof c === 'string' && /^[_a-zA-Z]$/.test(c.charAt(0));
 };
 
 const lislalnum = function(c) {
-    return /^[_a-zA-Z0-9]$/.test(c.charAt(0));
+    return typeof c === 'string' && /^[_a-zA-Z0-9]$/.test(c.charAt(0));
 };
 
 module.exports.lisdigit   = lisdigit;
diff --git a/src/lstrlib.js b/src/lstrlib.js
index dc3845b..3872cb2 100644
--- a/src/lstrlib.js
+++ b/src/lstrlib.js
@@ -176,7 +176,7 @@ const MAX_FORMAT = 32;
 const isalpha = e => /^[a-zA-Z]$/.test(e.charAt(0));
 const isdigit = e => "0".charCodeAt(0) <= e && e <= "9".charCodeAt(0);
 const iscntrl = e => (0x00 <= e && e <= 0x1f) || e === 0x7f;
-const isgraph = e => e.charCodeAt(0) > 32 && e.charCodeAt < 127; // TODO: Will only work for ASCII
+const isgraph = e => e.charCodeAt(0) > 32 && e.charCodeAt(0) < 127; // TODO: Will only work for ASCII
 const islower = e => /^(?![A-Z]).*$/.test(e.charAt(0));
 const isupper = e => /^(?![a-z]).*$/.test(e.charAt(0));
 const isalnum = e => /^[a-zA-Z0-9]$/.test(e.charAt(0));
@@ -1269,7 +1269,7 @@ const add_s = function(ms, b, s, e) {
             lauxlib.luaL_addchar(b, news.charAt(i));
         else {
             i++;  /* skip ESC */
-            if (!isdigit(news.charAt(i))) {
+            if (!isdigit(news.charCodeAt(i))) {
                 if (news.charAt(i) !== sL_ESC)
                     lauxlib.luaL_error(L, `invalid use of '${sL_ESC}' in replacement string`);
                 lauxlib.luaL_addchar(b, news.charAt(i));
@@ -1277,7 +1277,7 @@ const add_s = function(ms, b, s, e) {
                 lauxlib.luaL_addlstring(b, ms.src.slice(s), e - s);
             else {
                 push_onecapture(ms, news.charCodeAt(i) - '1'.charCodeAt(0), s, e);
-                lauxlib.luaL_tostring(L, -1);
+                lauxlib.luaL_tolstring(L, -1);
                 lapi.lua_remove(L, -2);  /* remove original value */
                 lauxlib.luaL_addvalue(b);  /* add capture to accumulated result */
             }
diff --git a/tests/lstrlib.js b/tests/lstrlib.js
index ce77bdc..12df173 100644
--- a/tests/lstrlib.js
+++ b/tests/lstrlib.js
@@ -677,4 +677,193 @@ test('string.gmatch', function (t) {
         "Lua",
         "Correct element(s) on the stack"
     );
+});
+
+
+test('string.gsub', function (t) {
+    let luaCode = `
+        return string.gsub("hello world", "(%w+)", "%1 %1")
+    `, L;
+    
+    t.plan(4);
+
+    t.doesNotThrow(function () {
+
+        L = lauxlib.luaL_newstate();
+
+        linit.luaL_openlibs(L);
+
+        lauxlib.luaL_loadstring(L, luaCode);
+
+    }, "Lua program loaded without error");
+
+    t.doesNotThrow(function () {
+
+        lapi.lua_call(L, 0, -1);
+
+    }, "Lua program ran without error");
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -2),
+        "hello hello world world",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tointeger(L, -1),
+        2,
+        "Correct element(s) on the stack"
+    );
+});
+
+
+test('string.gsub (number)', function (t) {
+    let luaCode = `
+        return string.gsub("hello world", "%w+", "%0 %0", 1)
+    `, L;
+    
+    t.plan(4);
+
+    t.doesNotThrow(function () {
+
+        L = lauxlib.luaL_newstate();
+
+        linit.luaL_openlibs(L);
+
+        lauxlib.luaL_loadstring(L, luaCode);
+
+    }, "Lua program loaded without error");
+
+    t.doesNotThrow(function () {
+
+        lapi.lua_call(L, 0, -1);
+
+    }, "Lua program ran without error");
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -2),
+        "hello hello world",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tointeger(L, -1),
+        1,
+        "Correct element(s) on the stack"
+    );
+});
+
+
+test('string.gsub (pattern)', function (t) {
+    let luaCode = `
+        return string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
+    `, L;
+    
+    t.plan(4);
+
+    t.doesNotThrow(function () {
+
+        L = lauxlib.luaL_newstate();
+
+        linit.luaL_openlibs(L);
+
+        lauxlib.luaL_loadstring(L, luaCode);
+
+    }, "Lua program loaded without error");
+
+    t.doesNotThrow(function () {
+
+        lapi.lua_call(L, 0, -1);
+
+    }, "Lua program ran without error");
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -2),
+        "world hello Lua from",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tointeger(L, -1),
+        2,
+        "Correct element(s) on the stack"
+    );
+});
+
+
+test('string.gsub (function)', function (t) {
+    let luaCode = `
+        return string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
+            return load(s)()
+        end)
+    `, L;
+    
+    t.plan(4);
+
+    t.doesNotThrow(function () {
+
+        L = lauxlib.luaL_newstate();
+
+        linit.luaL_openlibs(L);
+
+        lauxlib.luaL_loadstring(L, luaCode);
+
+    }, "Lua program loaded without error");
+
+    t.doesNotThrow(function () {
+
+        lapi.lua_call(L, 0, -1);
+
+    }, "Lua program ran without error");
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -2),
+        "4+5 = 9",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tointeger(L, -1),
+        1,
+        "Correct element(s) on the stack"
+    );
+});
+
+
+
+test('string.gsub (table)', function (t) {
+    let luaCode = `
+        local t = {name="lua", version="5.3"}
+        return string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
+    `, L;
+    
+    t.plan(4);
+
+    t.doesNotThrow(function () {
+
+        L = lauxlib.luaL_newstate();
+
+        linit.luaL_openlibs(L);
+
+        lauxlib.luaL_loadstring(L, luaCode);
+
+    }, "Lua program loaded without error");
+
+    t.doesNotThrow(function () {
+
+        lapi.lua_call(L, 0, -1);
+
+    }, "Lua program ran without error");
+
+    t.strictEqual(
+        lapi.lua_tostring(L, -2),
+        "lua-5.3.tar.gz",
+        "Correct element(s) on the stack"
+    );
+
+    t.strictEqual(
+        lapi.lua_tointeger(L, -1),
+        2,
+        "Correct element(s) on the stack"
+    );
 });
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2