[Tarantool-patches] [PATCH luajit 1/6] test: add lua-Harness test suite

Sergey Kaplun skaplun at tarantool.org
Fri Mar 12 08:27:29 MSK 2021


This patch adds lua-Harness test suite:
https://fperrad.frama.io/lua-Harness/

For lua binary name detection the new function `get_lua_binary_name()`
is introduced. It is necessary because LUAJIT_TEST_COMMAND
always extends an amount of line argument by two and a new universal
way to detect program name is required.

Some tests may fail after this commit. They will be disabled
or adapted in the next patches.

Part of tarantool/tarantool#5844
Part of tarantool/tarantool#4473
---
Author: Mergen Imeev <imeevma at gmail.com>

 .luacheckrc                                   |   1 +
 test/CMakeLists.txt                           |   4 +-
 test/lua-Harness-tests/000-sanity.t           |  54 ++
 test/lua-Harness-tests/001-if.t               |  88 ++
 test/lua-Harness-tests/002-table.t            |  67 ++
 test/lua-Harness-tests/011-while.t            |  89 ++
 test/lua-Harness-tests/012-repeat.t           |  85 ++
 test/lua-Harness-tests/014-fornum.t           | 151 +++
 test/lua-Harness-tests/015-forlist.t          | 111 +++
 test/lua-Harness-tests/090-tap.t              |  37 +
 test/lua-Harness-tests/091-profile.t          |  45 +
 test/lua-Harness-tests/101-boolean.t          | 127 +++
 test/lua-Harness-tests/102-function.t         | 206 +++++
 test/lua-Harness-tests/103-nil.t              | 127 +++
 test/lua-Harness-tests/104-number.t           | 246 +++++
 test/lua-Harness-tests/105-string.t           | 277 ++++++
 test/lua-Harness-tests/106-table.t            | 135 +++
 test/lua-Harness-tests/107-thread.t           | 135 +++
 test/lua-Harness-tests/108-userdata.t         | 132 +++
 test/lua-Harness-tests/200-examples.t         | 104 +++
 test/lua-Harness-tests/201-assign.t           | 150 +++
 test/lua-Harness-tests/202-expr.t             | 157 ++++
 test/lua-Harness-tests/203-lexico.t           | 143 +++
 test/lua-Harness-tests/204-grammar.t          | 233 +++++
 test/lua-Harness-tests/211-scope.t            |  86 ++
 test/lua-Harness-tests/212-function.t         | 288 ++++++
 test/lua-Harness-tests/213-closure.t          |  98 ++
 test/lua-Harness-tests/214-coroutine.t        | 244 +++++
 test/lua-Harness-tests/221-table.t            | 120 +++
 test/lua-Harness-tests/222-constructor.t      | 119 +++
 test/lua-Harness-tests/223-iterator.t         | 203 +++++
 test/lua-Harness-tests/231-metatable.t        | 602 ++++++++++++
 test/lua-Harness-tests/232-object.t           | 314 +++++++
 test/lua-Harness-tests/241-standalone.t       | 269 ++++++
 test/lua-Harness-tests/242-luac.t             | 341 +++++++
 test/lua-Harness-tests/301-basic.t            | 856 ++++++++++++++++++
 test/lua-Harness-tests/303-package.t          | 290 ++++++
 test/lua-Harness-tests/304-string.t           | 633 +++++++++++++
 test/lua-Harness-tests/305-utf8.t             |  55 ++
 test/lua-Harness-tests/306-table.t            | 372 ++++++++
 test/lua-Harness-tests/307-math.t             | 375 ++++++++
 test/lua-Harness-tests/308-io.t               | 397 ++++++++
 test/lua-Harness-tests/309-os.t               | 271 ++++++
 test/lua-Harness-tests/310-debug.t            | 322 +++++++
 test/lua-Harness-tests/311-bit32.t            | 127 +++
 test/lua-Harness-tests/314-regex.t            | 222 +++++
 test/lua-Harness-tests/320-stdin.t            | 133 +++
 test/lua-Harness-tests/401-bitop.t            | 106 +++
 test/lua-Harness-tests/402-ffi.t              | 142 +++
 test/lua-Harness-tests/403-jit.t              | 163 ++++
 test/lua-Harness-tests/404-ext.t              | 171 ++++
 test/lua-Harness-tests/411-luajit.t           | 211 +++++
 test/lua-Harness-tests/CMakeLists.txt         |  49 +
 test/lua-Harness-tests/lexico52/lexico.t      |  45 +
 test/lua-Harness-tests/lexico53/boolean.t     |  43 +
 test/lua-Harness-tests/lexico53/function.t    |  66 ++
 test/lua-Harness-tests/lexico53/lexico.t      |  30 +
 test/lua-Harness-tests/lexico53/nil.t         |  43 +
 test/lua-Harness-tests/lexico53/number.t      | 181 ++++
 test/lua-Harness-tests/lexico53/string.t      | 169 ++++
 test/lua-Harness-tests/lexico53/table.t       |  43 +
 test/lua-Harness-tests/lexico53/thread.t      |  45 +
 test/lua-Harness-tests/lexico53/userdata.t    |  45 +
 test/lua-Harness-tests/lexico53/utf8.t        | 179 ++++
 test/lua-Harness-tests/lexico54/lexico.t      |  19 +
 test/lua-Harness-tests/lexico54/metatable.t   |  38 +
 test/lua-Harness-tests/lexico54/utf8.t        |  54 ++
 test/lua-Harness-tests/lexicojit/basic.t      |  27 +
 test/lua-Harness-tests/lexicojit/ext.t        |  52 ++
 test/lua-Harness-tests/lexicojit/lexico.t     |  32 +
 test/lua-Harness-tests/profile.lua            |  53 ++
 test/lua-Harness-tests/profile_lua51.lua      |  46 +
 .../profile_lua51_strict.lua                  |  46 +
 test/lua-Harness-tests/profile_lua52.lua      |  46 +
 .../profile_lua52_strict.lua                  |  46 +
 test/lua-Harness-tests/profile_lua53.lua      |  52 ++
 .../profile_lua53_noconv.lua                  |  55 ++
 .../profile_lua53_strict.lua                  |  52 ++
 test/lua-Harness-tests/profile_lua54.lua      |  52 ++
 .../profile_lua54_noconv.lua                  |  55 ++
 .../profile_lua54_strict.lua                  |  53 ++
 test/lua-Harness-tests/profile_luajit20.lua   |  53 ++
 .../profile_luajit20_compat52.lua             |  53 ++
 test/lua-Harness-tests/profile_luajit21.lua   |  53 ++
 .../profile_luajit21_compat52.lua             |  53 ++
 test/lua-Harness-tests/profile_openresty.lua  |  53 ++
 test/lua-Harness-tests/profile_ravi.lua       |  58 ++
 test/lua-Harness-tests/profile_tiny_fork.lua  |  60 ++
 test/lua-Harness-tests/rx_captures            |  13 +
 test/lua-Harness-tests/rx_charclass           |  38 +
 test/lua-Harness-tests/rx_metachars           | 117 +++
 test/lua-Harness-tests/tap.lua                | 212 +++++
 92 files changed, 12912 insertions(+), 1 deletion(-)
 create mode 100755 test/lua-Harness-tests/000-sanity.t
 create mode 100755 test/lua-Harness-tests/001-if.t
 create mode 100755 test/lua-Harness-tests/002-table.t
 create mode 100755 test/lua-Harness-tests/011-while.t
 create mode 100755 test/lua-Harness-tests/012-repeat.t
 create mode 100755 test/lua-Harness-tests/014-fornum.t
 create mode 100755 test/lua-Harness-tests/015-forlist.t
 create mode 100755 test/lua-Harness-tests/090-tap.t
 create mode 100755 test/lua-Harness-tests/091-profile.t
 create mode 100755 test/lua-Harness-tests/101-boolean.t
 create mode 100755 test/lua-Harness-tests/102-function.t
 create mode 100755 test/lua-Harness-tests/103-nil.t
 create mode 100755 test/lua-Harness-tests/104-number.t
 create mode 100755 test/lua-Harness-tests/105-string.t
 create mode 100755 test/lua-Harness-tests/106-table.t
 create mode 100755 test/lua-Harness-tests/107-thread.t
 create mode 100755 test/lua-Harness-tests/108-userdata.t
 create mode 100755 test/lua-Harness-tests/200-examples.t
 create mode 100755 test/lua-Harness-tests/201-assign.t
 create mode 100755 test/lua-Harness-tests/202-expr.t
 create mode 100755 test/lua-Harness-tests/203-lexico.t
 create mode 100755 test/lua-Harness-tests/204-grammar.t
 create mode 100755 test/lua-Harness-tests/211-scope.t
 create mode 100755 test/lua-Harness-tests/212-function.t
 create mode 100755 test/lua-Harness-tests/213-closure.t
 create mode 100755 test/lua-Harness-tests/214-coroutine.t
 create mode 100755 test/lua-Harness-tests/221-table.t
 create mode 100755 test/lua-Harness-tests/222-constructor.t
 create mode 100755 test/lua-Harness-tests/223-iterator.t
 create mode 100755 test/lua-Harness-tests/231-metatable.t
 create mode 100755 test/lua-Harness-tests/232-object.t
 create mode 100755 test/lua-Harness-tests/241-standalone.t
 create mode 100755 test/lua-Harness-tests/242-luac.t
 create mode 100755 test/lua-Harness-tests/301-basic.t
 create mode 100755 test/lua-Harness-tests/303-package.t
 create mode 100755 test/lua-Harness-tests/304-string.t
 create mode 100755 test/lua-Harness-tests/305-utf8.t
 create mode 100755 test/lua-Harness-tests/306-table.t
 create mode 100755 test/lua-Harness-tests/307-math.t
 create mode 100755 test/lua-Harness-tests/308-io.t
 create mode 100755 test/lua-Harness-tests/309-os.t
 create mode 100755 test/lua-Harness-tests/310-debug.t
 create mode 100755 test/lua-Harness-tests/311-bit32.t
 create mode 100755 test/lua-Harness-tests/314-regex.t
 create mode 100755 test/lua-Harness-tests/320-stdin.t
 create mode 100755 test/lua-Harness-tests/401-bitop.t
 create mode 100755 test/lua-Harness-tests/402-ffi.t
 create mode 100755 test/lua-Harness-tests/403-jit.t
 create mode 100755 test/lua-Harness-tests/404-ext.t
 create mode 100755 test/lua-Harness-tests/411-luajit.t
 create mode 100644 test/lua-Harness-tests/CMakeLists.txt
 create mode 100644 test/lua-Harness-tests/lexico52/lexico.t
 create mode 100644 test/lua-Harness-tests/lexico53/boolean.t
 create mode 100644 test/lua-Harness-tests/lexico53/function.t
 create mode 100644 test/lua-Harness-tests/lexico53/lexico.t
 create mode 100644 test/lua-Harness-tests/lexico53/nil.t
 create mode 100644 test/lua-Harness-tests/lexico53/number.t
 create mode 100644 test/lua-Harness-tests/lexico53/string.t
 create mode 100644 test/lua-Harness-tests/lexico53/table.t
 create mode 100644 test/lua-Harness-tests/lexico53/thread.t
 create mode 100644 test/lua-Harness-tests/lexico53/userdata.t
 create mode 100644 test/lua-Harness-tests/lexico53/utf8.t
 create mode 100644 test/lua-Harness-tests/lexico54/lexico.t
 create mode 100644 test/lua-Harness-tests/lexico54/metatable.t
 create mode 100644 test/lua-Harness-tests/lexico54/utf8.t
 create mode 100644 test/lua-Harness-tests/lexicojit/basic.t
 create mode 100644 test/lua-Harness-tests/lexicojit/ext.t
 create mode 100644 test/lua-Harness-tests/lexicojit/lexico.t
 create mode 100644 test/lua-Harness-tests/profile.lua
 create mode 100644 test/lua-Harness-tests/profile_lua51.lua
 create mode 100644 test/lua-Harness-tests/profile_lua51_strict.lua
 create mode 100644 test/lua-Harness-tests/profile_lua52.lua
 create mode 100644 test/lua-Harness-tests/profile_lua52_strict.lua
 create mode 100644 test/lua-Harness-tests/profile_lua53.lua
 create mode 100644 test/lua-Harness-tests/profile_lua53_noconv.lua
 create mode 100644 test/lua-Harness-tests/profile_lua53_strict.lua
 create mode 100644 test/lua-Harness-tests/profile_lua54.lua
 create mode 100644 test/lua-Harness-tests/profile_lua54_noconv.lua
 create mode 100644 test/lua-Harness-tests/profile_lua54_strict.lua
 create mode 100644 test/lua-Harness-tests/profile_luajit20.lua
 create mode 100644 test/lua-Harness-tests/profile_luajit20_compat52.lua
 create mode 100644 test/lua-Harness-tests/profile_luajit21.lua
 create mode 100644 test/lua-Harness-tests/profile_luajit21_compat52.lua
 create mode 100644 test/lua-Harness-tests/profile_openresty.lua
 create mode 100644 test/lua-Harness-tests/profile_ravi.lua
 create mode 100644 test/lua-Harness-tests/profile_tiny_fork.lua
 create mode 100644 test/lua-Harness-tests/rx_captures
 create mode 100644 test/lua-Harness-tests/rx_charclass
 create mode 100644 test/lua-Harness-tests/rx_metachars
 create mode 100644 test/lua-Harness-tests/tap.lua

diff --git a/.luacheckrc b/.luacheckrc
index 1a76108..a5f90b9 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -8,5 +8,6 @@ read_globals = { 'misc' }
 exclude_files = {
   'dynasm/',
   'src/',
+  'test/lua-Harness-tests/',
   'test/LuaJIT-tests/',
 }
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 99471db..3a42f41 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -43,10 +43,12 @@ endif()
 set(LUAJIT_TEST_COMMAND "${LUAJIT_TEST_BINARY} -e dofile[[${LUAJIT_TEST_INIT}]]")
 separate_arguments(LUAJIT_TEST_COMMAND)
 
-add_subdirectory(tarantool-tests)
+add_subdirectory(lua-Harness-tests)
 add_subdirectory(LuaJIT-tests)
+add_subdirectory(tarantool-tests)
 
 add_custom_target(${PROJECT_NAME}-test DEPENDS
+  lua-Harness-tests
   LuaJIT-tests
   tarantool-tests
 )
diff --git a/test/lua-Harness-tests/000-sanity.t b/test/lua-Harness-tests/000-sanity.t
new file mode 100755
index 0000000..e039153
--- /dev/null
+++ b/test/lua-Harness-tests/000-sanity.t
@@ -0,0 +1,54 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua test suite
+
+=head2 Synopsis
+
+    % prove 000-sanity.t
+
+=head2 Description
+
+=cut
+
+]]
+
+function f (n)
+    return n + 1
+end
+
+function g (m, p)
+    return m + p
+end
+
+print('1..9')
+print("ok 1 -")
+print('ok', 2, "- list")
+print("ok " .. tostring(3) .. " - concatenation")
+i = 4
+print("ok " .. tostring(i) .. " - var")
+i = i + 1
+print("ok " .. tostring(i) .. " - var incr")
+print("ok " .. tostring(i+1) .. " - expr")
+j = f(i + 1)
+print("ok " .. tostring(j) .. " - call f")
+k = g(i, 3)
+print("ok " .. tostring(k) .. " - call g")
+local print = print
+print("ok 9 - local")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/001-if.t b/test/lua-Harness-tests/001-if.t
new file mode 100755
index 0000000..b84e331
--- /dev/null
+++ b/test/lua-Harness-tests/001-if.t
@@ -0,0 +1,88 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua if statement
+
+=head2 Synopsis
+
+    % prove 001-if.t
+
+=head2 Description
+
+See section "Control Structures" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.4.4>,
+L<https://www.lua.org/manual/5.2/manual.html#3.3.4>,
+L<https://www.lua.org/manual/5.3/manual.html#3.3.4>,
+L<https://www.lua.org/manual/5.4/manual.html#3.3.4>
+
+=cut
+
+]]
+
+print("1..6")
+
+if true then
+    print("ok 1")
+else
+    print("not ok 1")
+end
+
+if not true then
+    print("not ok 2")
+else
+    print("ok 2")
+end
+
+a = 12
+b = 34
+if a < b then
+    print("ok 3")
+else
+    print("not ok 3")
+end
+
+a = 0
+b = 4
+if a < b then
+    print("ok 4")
+elseif a == b then
+    print("not ok 4")
+else
+    print("not ok 4")
+end
+
+a = 5
+b = 5
+if a < b then
+    print("not ok 5")
+elseif a == b then
+    print("ok 5")
+else
+    print("not ok 5")
+end
+
+a = 10
+b = 6
+if a < b then
+    print("not ok 6")
+elseif a == b then
+    print("not ok 6")
+else
+    print("ok 6")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/002-table.t b/test/lua-Harness-tests/002-table.t
new file mode 100755
index 0000000..b84afd6
--- /dev/null
+++ b/test/lua-Harness-tests/002-table.t
@@ -0,0 +1,67 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua table
+
+=head2 Synopsis
+
+    % prove 002-table.t
+
+=head2 Description
+
+See section "Tables" in "Programming in Lua".
+
+=cut
+
+]]
+
+print("1..8")
+
+a = {"ok 1", "ok 2", "ok 3"}
+print(a[1])
+i = 2
+print(a[i])
+print(a[i+1])
+if #a == 3 then
+    print("ok 4 - len")
+else
+    print("not ok 4")
+end
+if a[7] == nil then
+    print("ok 5")
+else
+    print("not ok 5")
+end
+
+t = {a=10, b=100}
+if t['a'] == 10 then
+    print("ok 6")
+else
+    print("not ok 6")
+end
+if t.b == 100 then
+    print("ok 7")
+else
+    print("not ok 7")
+end
+if t.z == nil then
+    print("ok 8")
+else
+    print("not ok 8")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/011-while.t b/test/lua-Harness-tests/011-while.t
new file mode 100755
index 0000000..8ba4c6b
--- /dev/null
+++ b/test/lua-Harness-tests/011-while.t
@@ -0,0 +1,89 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua while statement
+
+=head2 Synopsis
+
+    % prove 011-while.t
+
+=head2 Description
+
+See section "Control Structures" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.4.4>,
+L<https://www.lua.org/manual/5.2/manual.html#3.3.4>,
+L<https://www.lua.org/manual/5.3/manual.html#3.3.4>,
+L<https://www.lua.org/manual/5.4/manual.html#3.3.4>
+
+=cut
+
+]]
+
+print("1..11")
+
+do
+    local a = {}
+    local i = 1
+    while a[i] do
+        i = i + 1
+    end
+    if i == 1 then
+        print("ok 1 - while empty")
+    else
+        print("not ok 1 - " .. i)
+    end
+end
+
+do
+    local a = {"ok 2 - while ", "ok 3", "ok 4"}
+    local i = 1
+    while a[i] do
+        print(a[i])
+        i = i + 1
+    end
+end
+
+do
+    local a = {"ok 5 - with break", "ok 6", "stop", "more"}
+    local i = 1
+    while a[i] do
+        if a[i] == 'stop' then break end
+        print(a[i])
+        i = i + 1
+    end
+    if i == 3 then
+        print("ok 7 - break")
+    else
+        print("not ok 7 - " .. i)
+    end
+end
+
+do
+    local x = 3
+    local i = 1
+    while i<=x do
+        print("ok " .. tostring(7+i))
+        i = i + 1
+    end
+    if i == 4 then
+        print("ok 11")
+    else
+        print("not ok 11 - " .. tostring(i))
+    end
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/012-repeat.t b/test/lua-Harness-tests/012-repeat.t
new file mode 100755
index 0000000..527db63
--- /dev/null
+++ b/test/lua-Harness-tests/012-repeat.t
@@ -0,0 +1,85 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua repeat statement
+
+=head2 Synopsis
+
+    % prove 012-repeat.t
+
+=head2 Description
+
+See section "Control Structures" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.4.4>,
+L<https://www.lua.org/manual/5.2/manual.html#3.3.4>,
+L<https://www.lua.org/manual/5.3/manual.html#3.3.4>,
+L<https://www.lua.org/manual/5.4/manual.html#3.3.4>
+
+=cut
+
+]]
+
+print("1..8")
+
+do
+    local a = {"ok 1 - repeat", "ok 2", "ok 3"}
+    local i = 0
+    repeat
+        i = i + 1
+        if a[i] then
+            print(a[i])
+        end
+    until not a[i]
+    if i == 4 then
+        print("ok 4")
+    else
+        print("not ok 4 - " .. i)
+    end
+end
+
+do
+    local a = {"ok 5 - with break", "ok 6", 'stop', 'more'}
+    local i = 0
+    repeat
+        i = i + 1
+        if a[i] == 'stop' then break end
+        print(a[i])
+    until not a[i]
+    if a[i] == 'stop' then
+        print("ok 7 - break")
+    else
+        print("not ok 7 - " .. a[i])
+    end
+end
+
+do
+    local function f () return true end
+
+    local i = 1
+    repeat
+        local v = f()
+        if i == 1 then
+            print("ok 8 - scope")
+        else
+            print("not ok")
+            break
+        end
+        i = i + 1
+    until v
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/014-fornum.t b/test/lua-Harness-tests/014-fornum.t
new file mode 100755
index 0000000..3f6d1b1
--- /dev/null
+++ b/test/lua-Harness-tests/014-fornum.t
@@ -0,0 +1,151 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua for statement
+
+=head2 Synopsis
+
+    % prove 014-fornum.t
+
+=head2 Description
+
+See section "For Statement" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.4.5>,
+L<https://www.lua.org/manual/5.2/manual.html#3.3.5>,
+L<https://www.lua.org/manual/5.3/manual.html#3.3.5>,
+L<https://www.lua.org/manual/5.4/manual.html#3.3.5>
+
+=cut
+
+--]]
+
+print("1..36")
+
+for i = 1.0, 3.0, 0.5 do
+    print("ok " .. tostring(2*i-1) .. " - for 1.0, 3.0, 0.5")
+end
+
+for i = 1.0, 3.0, 0.5 do
+    local function f ()
+        print("ok " .. tostring(2*i+4) .. " - for 1.0, 3.0, 0.5 lex")
+    end
+    f()
+end
+
+local function f (i)
+    print("ok " .. tostring(2*i+9) .. " - for 1.0, 3.0, 0.5 !lex")
+end
+for i = 1.0, 3.0, 0.5 do
+    f(i)
+end
+
+for i = 3, 5 do
+    print("ok " .. tostring(13+i) .. " - for 3, 5")
+    i = i + 1
+end
+
+for i = 5, 1, -1 do
+    print("ok " .. tostring(24-i) .. " - for 5, 1, -1")
+end
+
+for i = 5, 5 do
+    print("ok " .. tostring(19+i) .. " - for 5, 5")
+end
+
+for i = 5, 5, -1 do
+    print("ok " .. tostring(20+i) .. " - for 5, 5, -1")
+end
+
+do
+    local v = false
+    for i = 5, 3 do
+        v = true
+    end
+    if v then
+        print("not ok 26 - for 5, 3")
+    else
+        print("ok 26 - for 5, 3")
+    end
+end
+
+do
+    local v = false
+    for i = 5, 7, -1 do
+        v = true
+    end
+    if v then
+        print("not ok 27 - for 5, 7, -1")
+    else
+        print("ok 27 - for 5, 7, -1")
+    end
+end
+
+do
+    local v = false
+    if _VERSION <= 'Lua 5.3' then
+        for i = 5, 7, 0 do
+            v = true
+            break -- avoid infinite loop with LuaJIT
+        end
+    end
+    if jit then
+        print("not ok 28 - for 5, 7, 0 # TODO # LuaJIT intentional.")
+    elseif v then
+        print("not ok 28 - for 5, 7, 0")
+    else
+        print("ok 28 - for 5, 7, 0")
+    end
+end
+
+do
+    local v = nil
+    for i = 1, 10, 2 do
+        if i > 4 then break end
+        print("ok " .. tostring((i+57)/2) .. " - for break")
+        v = i
+    end
+    if v == 3 then
+        print("ok 31 - break")
+    else
+        print("not ok 31 - " .. v)
+    end
+end
+
+do
+    local function first() return 1 end
+    local function limit() return 8 end
+    local function step()  return 2 end
+    for i = first(), limit(), step() do
+        print("ok " .. tostring((i+63)/2) .. " - with functions")
+    end
+end
+
+do
+    local a = {}
+    for i = 1, 10 do
+        a[i] = function () return i end
+    end
+    local v = a[5]()
+    if v == 5 then
+        print("ok 36 - for & upval")
+    else
+        print("not ok 36 - for & upval")
+        print("#", v)
+    end
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/015-forlist.t b/test/lua-Harness-tests/015-forlist.t
new file mode 100755
index 0000000..cd9db61
--- /dev/null
+++ b/test/lua-Harness-tests/015-forlist.t
@@ -0,0 +1,111 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua for statement
+
+=head2 Synopsis
+
+    % prove 015-forlist.t
+
+=head2 Description
+
+See section "For Statement" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.4.5>,
+L<https://www.lua.org/manual/5.2/manual.html#3.3.5>,
+L<https://www.lua.org/manual/5.3/manual.html#3.3.5>,
+L<https://www.lua.org/manual/5.4/manual.html#3.3.5>
+
+=cut
+
+--]]
+
+print("1..18")
+
+do
+    local a = {"ok 1 - for ipairs", "ok 2 - for ipairs", "ok 3 - for ipairs"}
+
+    for _, v in ipairs(a) do
+        print(v)
+    end
+
+    for i, v in ipairs(a) do
+        print("ok " .. tostring(3+i) .. " - for ipairs")
+    end
+
+    for k in pairs(a) do
+        print("ok " .. tostring(6+k) .. " - for pairs")
+    end
+end
+
+do
+    local r = false
+    local t = {a=10, b=100}
+
+    for i, v in ipairs(t) do
+        print(i, v)
+        r = true
+    end
+    if r then
+        print("not ok 10 - for ipairs (hash)")
+    else
+        print("ok 10 - for ipairs (hash)")
+    end
+
+    local i = 1
+    for k in pairs(t) do
+        if k == 'a' or k == 'b' then
+            print("ok " .. tostring(10+i) .. " - for pairs (hash)")
+        else
+            print("not ok " .. tostring(10+i) .. " - " .. k)
+        end
+        i = i + 1
+    end
+end
+
+do
+    local a = {"ok 13 - for break", "ok 14 - for break", "stop", "more"}
+    local i
+    for _, v in ipairs(a) do
+        if v == "stop" then break end
+        print(v)
+        i = _
+    end
+    if i == 2 then
+        print("ok 15 - break")
+    else
+        print("not ok 15 - " .. i)
+    end
+end
+
+do
+    local a = {"ok 16 - for & upval", "ok 17 - for & upval", "ok 18 - for & upval"}
+    local b = {}
+    for i, v in ipairs(a) do
+        b[i] = function () return v end
+    end
+    for i, v in ipairs(a) do
+        local r = b[i]()
+        if r == a[i] then
+            print(r)
+        else
+            print("not " .. a[i])
+            print("#", r)
+        end
+    end
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/090-tap.t b/test/lua-Harness-tests/090-tap.t
new file mode 100755
index 0000000..92f04d8
--- /dev/null
+++ b/test/lua-Harness-tests/090-tap.t
@@ -0,0 +1,37 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua test suite
+
+=head2 Synopsis
+
+    % prove 090-tap.t
+
+=head2 Description
+
+=cut
+
+]]
+
+require'tap'
+
+plan(3)
+ok( true, 'ok' )
+is( 42, 42, '42 == 42' )
+pass( 'pass' )
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/091-profile.t b/test/lua-Harness-tests/091-profile.t
new file mode 100755
index 0000000..db47438
--- /dev/null
+++ b/test/lua-Harness-tests/091-profile.t
@@ -0,0 +1,45 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua test suite
+
+=head2 Synopsis
+
+    % prove 091-profile.t
+
+=head2 Description
+
+=cut
+
+]]
+
+require'tap'
+
+plan'no_plan'
+
+type_ok(_VERSION, 'string', "variable _VERSION")
+like(_VERSION, '^Lua 5%.%d$')
+
+if jit then
+    type_ok(jit.version_num, 'number', "variable jit.version_num")
+end
+
+local profile = require_ok'profile'
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/101-boolean.t b/test/lua-Harness-tests/101-boolean.t
new file mode 100755
index 0000000..0033eff
--- /dev/null
+++ b/test/lua-Harness-tests/101-boolean.t
@@ -0,0 +1,127 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1  Lua boolean & coercion
+
+=head2 Synopsis
+
+    % prove 101-boolean.t
+
+=head2 Description
+
+=cut
+
+]]
+
+require'tap'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+error_like(function () return -true end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a %w+ value",
+           "-true")
+
+error_like(function () return #true end,
+           "^[^:]+:%d+: attempt to get length of a boolean value",
+           "#true")
+
+is(not false, true, "not false")
+
+error_like(function () return true + 10 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "true + 10")
+
+error_like(function () return true - 2 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "true - 2")
+
+error_like(function () return true * 3.14 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "true * 3.14")
+
+error_like(function () return true / -7 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "true / -7")
+
+error_like(function () return true % 4 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "true % 4")
+
+error_like(function () return true ^ 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "true ^ 3")
+
+error_like(function () return true .. 'end' end,
+           "^[^:]+:%d+: attempt to concatenate a boolean value",
+           "true .. 'end'")
+
+is(true == true, true, "true == true")
+
+is(true ~= false, true, "true ~= false")
+
+is(true == 1, false, "true == 1")
+
+is(true ~= 1, true, "true ~= 1")
+
+error_like(function () return true < false end,
+           "^[^:]+:%d+: attempt to compare two boolean values",
+           "true < false")
+
+error_like(function () return true <= false end,
+           "^[^:]+:%d+: attempt to compare two boolean values",
+           "true <= false")
+
+error_like(function () return true > false end,
+           "^[^:]+:%d+: attempt to compare two boolean values",
+           "true > false")
+
+error_like(function () return true >= false end,
+           "^[^:]+:%d+: attempt to compare two boolean values",
+           "true >= false")
+
+error_like(function () return true < 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "true < 0")
+
+error_like(function () return true <= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "true <= 0")
+
+error_like(function () return true > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "true > 0")
+
+error_like(function () return true >= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "true >= 0")
+
+error_like(function () local a = true; local b = a[1]; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+error_like(function () local a = true; a[1] = 1; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+if has_op53 then
+    dofile'lexico53/boolean.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/102-function.t b/test/lua-Harness-tests/102-function.t
new file mode 100755
index 0000000..48ed814
--- /dev/null
+++ b/test/lua-Harness-tests/102-function.t
@@ -0,0 +1,206 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua function & coercion
+
+=head2 Synopsis
+
+    % prove 102-function.t
+
+=head2 Description
+
+=cut
+
+--]]
+
+require'tap'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+local f = function () return 1 end
+
+error_like(function () return -f end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "-f")
+
+error_like(function () f = print; return -f end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return #f end,
+           "^[^:]+:%d+: attempt to get length of",
+           "#f")
+
+error_like(function () f = print; return #f end,
+           "^[^:]+:%d+: attempt to get length of")
+
+is(not f, false, "not f")
+
+is(not print, false)
+
+error_like(function () return f + 10 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "f + 10")
+
+error_like(function () f = print; return f + 10 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return f - 2 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "f - 2")
+
+error_like(function () f = print; return f - 2 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return f * 3.14 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "f * 3.14")
+
+error_like(function () f = print; return f * 3.14 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return f / -7 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "f / -7")
+
+error_like(function () f = print; return f / -7 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return f % 4 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "f % 4")
+
+error_like(function () f = print; return f % 4 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return f ^ 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "f ^ 3")
+
+error_like(function () f = print; return f ^ 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return f .. 'end' end,
+           "^[^:]+:%d+: attempt to concatenate",
+           "f .. 'end'")
+
+error_like(function () f = print; return f .. 'end' end,
+           "^[^:]+:%d+: attempt to concatenate")
+
+local g = f
+is(f == g, true, "f == f")
+
+g = print
+is(g == print, true)
+
+g = function () return 2 end
+is(f ~= g, true, "f ~= g")
+local h = type
+is(f ~= h, true)
+
+is(print ~= g, true)
+is(print ~= h, true)
+
+is(f == 1, false, "f == 1")
+
+is(print == 1, false)
+
+is(f ~= 1, true, "f ~= 1")
+
+is(print ~= 1, true)
+
+error_like(function () return f < g end,
+           "^[^:]+:%d+: attempt to compare two function values",
+           "f < g")
+
+error_like(function () f = print; g = type; return f < g end,
+           "^[^:]+:%d+: attempt to compare two function values")
+
+error_like(function () return f <= g end,
+           "^[^:]+:%d+: attempt to compare two function values",
+           "f <= g")
+
+error_like(function () f = print; g = type; return f <= g end,
+           "^[^:]+:%d+: attempt to compare two function values")
+
+error_like(function () return f > g end,
+           "^[^:]+:%d+: attempt to compare two function values",
+           "f > g")
+
+error_like(function () f = print; g = type; return f > g end,
+           "^[^:]+:%d+: attempt to compare two function values")
+
+error_like(function () return f >= g end,
+           "^[^:]+:%d+: attempt to compare two function values",
+           "f >= g")
+
+error_like(function () f = print; g = type; return f >= g end,
+           "^[^:]+:%d+: attempt to compare two function values")
+
+error_like(function () return f < 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "f < 0")
+
+error_like(function () f = print; return f < 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+")
+
+error_like(function () return f <= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "f <= 0")
+
+error_like(function () f = print; return f <= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+")
+
+error_like(function () return f > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "f > 0")
+
+error_like(function () f = print; return f > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+")
+
+error_like(function () return f > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "f >= 0")
+
+error_like(function () f = print; return f >= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+")
+
+error_like(function () local a = f; local b = a[1]; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+error_like(function () local a = print; local b = a[1]; end,
+           "^[^:]+:%d+: attempt to index")
+
+error_like(function () local a = f; a[1] = 1; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+error_like(function () local a = print; a[1] = 1; end,
+           "^[^:]+:%d+: attempt to index")
+
+local t = {}
+t[print] = true
+ok(t[print])
+
+if has_op53 then
+    dofile'lexico53/function.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/103-nil.t b/test/lua-Harness-tests/103-nil.t
new file mode 100755
index 0000000..561b101
--- /dev/null
+++ b/test/lua-Harness-tests/103-nil.t
@@ -0,0 +1,127 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua nil & coercion
+
+=head2 Synopsis
+
+    % prove 103-nil.t
+
+=head2 Description
+
+=cut
+
+--]]
+
+require'tap'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+error_like(function () return -nil end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "-nil")
+
+error_like(function () return #nil end,
+           "^[^:]+:%d+: attempt to get length of a nil value",
+           "#nil")
+
+is(not nil, true, "not nil")
+
+error_like(function () return nil + 10 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "nil + 10")
+
+error_like(function () return nil - 2 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "nil - 2")
+
+error_like(function () return nil * 3.14 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "nil * 3.14")
+
+error_like(function () return nil / -7 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "nil / -7")
+
+error_like(function () return nil % 4 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "nil % 4")
+
+error_like(function () return nil ^ 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "nil ^ 3")
+
+error_like(function () return nil .. 'end' end,
+           "^[^:]+:%d+: attempt to concatenate a nil value",
+           "nil .. 'end'")
+
+is(nil == nil, true, "nil == nil")
+
+is(nil ~= nil, false, "nil ~= nil")
+
+is(nil == 1, false, "nil == 1")
+
+is(nil ~= 1, true, "nil ~= 1")
+
+error_like(function () return nil < nil end,
+           "^[^:]+:%d+: attempt to compare two nil values",
+           "nil < nil")
+
+error_like(function () return nil <= nil end,
+           "^[^:]+:%d+: attempt to compare two nil values",
+           "nil <= nil")
+
+error_like(function () return nil > nil end,
+           "^[^:]+:%d+: attempt to compare two nil values",
+           "nil > nil")
+
+error_like(function () return nil > nil end,
+           "^[^:]+:%d+: attempt to compare two nil values",
+           "nil >= nil")
+
+error_like(function () return nil < 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "nil < 0")
+
+error_like(function () return nil <= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "nil <= 0")
+
+error_like(function () return nil > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "nil > 0")
+
+error_like(function () return nil >= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "nil >= 0")
+
+error_like(function () local a = nil; local b = a[1]; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+error_like(function () local a = nil; a[1] = 1; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+if has_op53 then
+    dofile'lexico53/nil.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/104-number.t b/test/lua-Harness-tests/104-number.t
new file mode 100755
index 0000000..0d4d3fd
--- /dev/null
+++ b/test/lua-Harness-tests/104-number.t
@@ -0,0 +1,246 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua number & coercion
+
+=head2 Synopsis
+
+    % prove 104-number.t
+
+=head2 Description
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+is(-1, -(1), "-1")
+
+is(not 1, false, "not 1")
+
+is(10 + 2, 12, "10 + 2")
+
+is(2 - 10.5, -8.5, "2 - 10.5")
+
+is(2 * 3, 6, "2 * 3")
+
+is(3.14 * 1, 3.14, "3.14 * 1")
+
+is(-7 / 0.5, -14, "-7 / 0.5")
+
+type_ok(1.0 / 0.0, 'number', "1.0 / 0.0")
+
+is(-25 % 3, 2, "-25 % 3")
+
+if _VERSION >= 'Lua 5.3' then
+    error_like(function () return 1 % 0 end,
+               "^[^:]+:%d+: attempt to perform 'n%%0'",
+               "1 % 0")
+else
+    type_ok(1 % 0, 'number', "1 % 0")
+end
+
+error_like(function () return 10 + true end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "10 + true")
+
+error_like(function () return 2 - nil end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "2 - nil")
+
+error_like(function () return 2 * {} end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a table value",
+           "2 * {}")
+
+error_like(function () return 3.14 * false end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "3.14 * false")
+
+error_like(function () return -7 / {} end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a table value",
+           "-7 / {}")
+
+error_like(function () return 3 ^ true end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "3 ^ true")
+
+error_like(function () return -25 % false end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "-25 % false")
+
+error_like(function () return 10 + 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "10 + 'text'")
+
+error_like(function () return 2 - 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "2 - 'text'")
+
+error_like(function () return 2 * 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "2 * 'text'")
+
+error_like(function () return 3.14 * 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "3.14 * 'text'")
+
+error_like(function () return -7 / 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "-7 / 'text'")
+
+error_like(function () return 25 % 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "25 % 'text'")
+
+error_like(function () return 3 ^ 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "3 ^ 'text'")
+
+if profile.nocvts2n then
+    error_like(function () return 10 + '2' end,
+               "^[^:]+:%d+: attempt to",
+               "10 + '2'")
+
+    error_like(function () return 2 - '10.5' end,
+               "^[^:]+:%d+: attempt to",
+               "2 - '10.5'")
+
+    error_like(function () return 2 * '3' end,
+               "^[^:]+:%d+: attempt to",
+               "2 * '3'")
+
+    error_like(function () return 3.14 * '1' end,
+               "^[^:]+:%d+: attempt to",
+               "3.14 * '1'")
+
+    error_like(function () return -7 / '0.5' end,
+               "^[^:]+:%d+: attempt to",
+               "-7 / '0.5'")
+
+    error_like(function () return -25 % '3' end,
+               "^[^:]+:%d+: attempt to",
+               "-25 % '3'")
+
+    error_like(function () return 3 ^ '3' end,
+               "^[^:]+:%d+: attempt to",
+               "3 ^ '3'")
+else
+    is(10 + '2', 12, "10 + '2'")
+
+    is(2 - '10.5', -8.5, "2 - '10.5'")
+
+    is(2 * '3', 6, "2 * '3'")
+
+    is(3.14 * '1', 3.14, "3.14 * '1'")
+
+    is(-7 / '0.5', -14, "-7 / '0.5'")
+
+    is(-25 % '3', 2, "-25 % '3'")
+
+    is(3 ^ '3', 27, "3 ^ '3'")
+end
+
+if profile.nocvtn2s then
+    error_like(function () return 1 .. 'end' end,
+               "^[^:]+:%d+: attempt to concatenate a number value",
+               "1 .. 'end'")
+
+    error_like(function () return 1 .. 2 end,
+               "^[^:]+:%d+: attempt to concatenate a number value",
+               "1 .. 2")
+else
+    is(1 .. 'end', '1end', "1 .. 'end'")
+
+    is(1 .. 2, '12', "1 .. 2")
+end
+
+error_like(function () return 1 .. true end,
+           "^[^:]+:%d+: attempt to concatenate a %w+ value",
+           "1 .. true")
+
+is(1.0 == 1, true, "1.0 == 1")
+
+is(1 ~= 2, true, "1 ~= 2")
+
+is(1 == true, false, "1 == true")
+
+is(1 ~= nil, true, "1 ~= nil")
+
+is(1 == '1', false, "1 == '1'")
+
+is(1 ~= '1', true, "1 ~= '1'")
+
+is(1 < 0, false, "1 < 0")
+
+is(1 <= 0, false, "1 <= 0")
+
+is(1 > 0, true, "1 > 0")
+
+is(1 >= 0, true, "1 >= 0")
+
+error_like(function () return 1 < false end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 < false")
+
+error_like(function () return 1 <= nil end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 <= nil")
+
+error_like(function () return 1 > true end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 > true")
+
+error_like(function () return 1 >= {} end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 >= {}")
+
+error_like(function () return 1 < '0' end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 < '0'")
+
+error_like(function () return 1 <= '0' end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 <= '0'")
+
+error_like(function () return 1 > '0' end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 > '0'")
+
+error_like(function () return 1 >= '0' end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "1 >= '0'")
+
+error_like(function () local a= 3.14; local b = a[1]; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+error_like(function () local a = 3.14; a[1] = 1; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+if has_op53 then
+    dofile'lexico53/number.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/105-string.t b/test/lua-Harness-tests/105-string.t
new file mode 100755
index 0000000..cd8c88b
--- /dev/null
+++ b/test/lua-Harness-tests/105-string.t
@@ -0,0 +1,277 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua string & coercion
+
+=head2 Synopsis
+
+    % prove 105-string.t
+
+=head2 Description
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+if profile.nocvts2n then
+    error_like(function () return - '1' end,
+               "^[^:]+:%d+: attempt to",
+               "-'1'")
+else
+    is(- '1', -1, "-'1'")
+end
+
+error_like(function () return - 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "-'text'")
+
+is(# 'text', 4, "#'text'")
+
+is(not 'text', false, "not 'text'")
+
+if profile.nocvts2n then
+    error_like(function () return '10' + 2 end,
+               "^[^:]+:%d+: attempt to",
+               "'10' + 2")
+
+    error_like(function () return '2' - 10.5 end,
+               "^[^:]+:%d+: attempt to",
+               "'2' - 10.5")
+
+    error_like(function () return '2' * 3 end,
+               "^[^:]+:%d+: attempt to",
+               "'2' * 3")
+
+    error_like(function () return '3.14' * 1 end,
+               "^[^:]+:%d+: attempt to",
+               "'3.14' * 1")
+
+    error_like(function () return '-7' / 0.5 end,
+               "^[^:]+:%d+: attempt to",
+               "'-7' / 0.5")
+
+    error_like(function () return '-25' % 3 end,
+               "^[^:]+:%d+: attempt to",
+               "'-25' % 3")
+
+    error_like(function () return '3' ^ 3 end,
+               "^[^:]+:%d+: attempt to",
+               "'3' ^ 3")
+else
+    is('10' + 2, 12, "'10' + 2")
+
+    is('2' - 10.5, -8.5, "'2' - 10.5")
+
+    is('2' * 3, 6, "'2' * 3")
+
+    is('3.14' * 1, 3.14, "'3.14' * 1")
+
+    is('-7' / 0.5, -14, "'-7' / 0.5")
+
+    is('-25' % 3, 2, "'-25' % 3")
+
+    is('3' ^ 3, 27, "'3' ^ 3")
+end
+
+error_like(function () return '10' + true end,
+           "^[^:]+:%d+: attempt to",
+           "'10' + true")
+
+error_like(function () return '2' - nil end,
+           "^[^:]+:%d+: attempt to",
+           "'2' - nil")
+
+error_like(function () return '2' * {} end,
+           "^[^:]+:%d+: attempt to",
+           "'2' * {}")
+
+error_like(function () return '3.14' * false end,
+           "^[^:]+:%d+: attempt to",
+           "'3.14' * false")
+
+error_like(function () return '-7' / {} end,
+           "^[^:]+:%d+: attempt to",
+           "'-7' / {}")
+
+error_like(function () return '-25' % false end,
+           "^[^:]+:%d+: attempt to",
+           "'-25' % false")
+
+error_like(function () return '3' ^ true end,
+           "^[^:]+:%d+: attempt to",
+           "'3' ^ true")
+
+error_like(function () return '10' + 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'10' + 'text'")
+
+error_like(function () return '2' - 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'2' - 'text'")
+
+error_like(function () return '3.14' * 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'3.14' * 'text'")
+
+error_like(function () return '-7' / 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'-7' / 'text'")
+
+error_like(function () return '-25' % 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'-25' % 'text'")
+
+error_like(function () return '3' ^ 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'3' ^ 'text'")
+
+if profile.nocvts2n then
+    error_like(function () return '10' + '2' end,
+               "^[^:]+:%d+: attempt to",
+               "'10' + '2'")
+
+    error_like(function () return '2' - '10.5' end,
+               "^[^:]+:%d+: attempt to",
+               "'2' - '10.5'")
+
+    error_like(function () return '2' * '3' end,
+               "^[^:]+:%d+: attempt to",
+               "'2' * '3'")
+
+    error_like(function () return '3.14' * '1' end,
+               "^[^:]+:%d+: attempt to",
+               "'3.14' * '1'")
+
+    error_like(function () return '-7' / '0.5' end,
+               "^[^:]+:%d+: attempt to",
+               "'-7' / '0.5'")
+
+    error_like(function () return '-25' % '3' end,
+               "^[^:]+:%d+: attempt to",
+               "'-25' % '3'")
+
+    error_like(function () return '3' ^ '3' end,
+               "^[^:]+:%d+: attempt to",
+               "'3' ^ '3'")
+else
+    is('10' + '2', 12, "'10' + '2'")
+
+    is('2' - '10.5', -8.5, "'2' - '10.5'")
+
+    is('2' * '3', 6, "'2' * '3'")
+
+    is('3.14' * '1', 3.14, "'3.14' * '1'")
+
+    is('-7' / '0.5', -14, "'-7' / '0.5'")
+
+    is('-25' % '3', 2, "'-25' % '3'")
+
+    is('3' ^ '3', 27, "'3' ^ '3'")
+end
+
+is('1' .. 'end', '1end', "'1' .. 'end'")
+
+if profile.nocvtn2s then
+    error_like(function () return '1' .. 2 end,
+               "^[^:]+:%d+: attempt to concatenate a number value",
+               "'1' .. 2")
+else
+    is('1' .. 2, '12', "'1' .. 2")
+end
+
+error_like(function () return '1' .. true end,
+           "^[^:]+:%d+: attempt to concatenate a boolean value",
+           "'1' .. true")
+
+is('foo\0bar' <= 'foo\0baz', true, "'foo\\0bar' <= 'foo\\0baz'")
+
+is('foo\0bar' ~= 'foo', true, "'foo\\0bar' ~= 'foo'")
+
+is('foo\0bar' >= 'foo', true, "'foo\\0bar' >= 'foo'")
+
+is('1.0' == '1', false, "'1.0' == '1'")
+
+is('1' ~= '2', true, "'1' ~= '2'")
+
+is('1' == true, false, "'1' == true")
+
+is('1' ~= nil, true, "'1' ~= nil")
+
+is('1' == 1, false, "'1' == 1")
+
+is('1' ~= 1, true, "'1' ~= 1")
+
+is('1' < '0', false, "'1' < '0'")
+
+is('1' <= '0', false, "'1' <= '0'")
+
+is('1' > '0', true, "'1' > '0'")
+
+is('1' >= '0', true, "'1' >= '0'")
+
+error_like(function () return '1' < false end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' < false")
+
+error_like(function () return '1' <= nil end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' <= nil")
+
+error_like(function () return '1' > true end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' > true")
+
+error_like(function () return '1' >= {} end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' >= {}")
+
+error_like(function () return '1' < 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' < 0")
+
+error_like(function () return '1' <= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' <= 0")
+
+error_like(function () return '1' > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' > 0")
+
+error_like(function () return '1' > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "'1' >== 0")
+
+local a = 'text'
+is(a[1], nil, "index")
+
+error_like(function () a = 'text'; a[1] = 1; end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+if has_op53 then
+    dofile'lexico53/string.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/106-table.t b/test/lua-Harness-tests/106-table.t
new file mode 100755
index 0000000..0c0ba49
--- /dev/null
+++ b/test/lua-Harness-tests/106-table.t
@@ -0,0 +1,135 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua table & coercion
+
+=head2 Synopsis
+
+    % prove 106-table.t
+
+=head2 Description
+
+=cut
+
+--]]
+
+require'tap'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+error_like(function () return -{} end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "-{}")
+
+is(# {}, 0, "#{}")
+is(# {4,5,6}, 3)
+
+is(not {}, false, "not {}")
+
+error_like(function () return {} + 10 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "{} + 10")
+
+error_like(function () return {} - 2 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "{} - 2")
+
+error_like(function () return {} * 3.14 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "{} * 3.14")
+
+error_like(function () return {} / 7 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "{} / 7")
+
+error_like(function () return {} % 4 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "{} % 4")
+
+error_like(function () return {} ^ 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "{} ^ 3")
+
+error_like(function () return {} .. 'end' end,
+           "^[^:]+:%d+: attempt to concatenate",
+           "{} .. 'end'")
+
+is({} == {}, false, "{} == {}")
+
+local t1 = {}
+local t2 = {}
+is(t1 == t1, true, "t1 == t1")
+is(t1 == t2, false, "t1 == t2")
+is(t1 ~= t2, true, "t1 ~= t2")
+
+is({} == 1, false, "{} == 1")
+
+is({} ~= 1, true, "{} ~= 1")
+
+error_like(function () return t1 < t2 end,
+           "^[^:]+:%d+: attempt to compare two table values",
+           "t1 < t2")
+
+error_like(function () return t1 <= t2 end,
+           "^[^:]+:%d+: attempt to compare two table values",
+           "t1 <= t2")
+
+error_like(function () return t1 > t2 end,
+           "^[^:]+:%d+: attempt to compare two table values",
+           "t1 > t2")
+
+error_like(function () return t1 >= t2 end,
+           "^[^:]+:%d+: attempt to compare two table values",
+           "t1 >= t2")
+
+error_like(function () return {} < 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "{} < 0")
+
+error_like(function () return {} <= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "{} <= 0")
+
+error_like(function () return {} > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "{} > 0")
+
+error_like(function () return {} >= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "{} >= 0")
+
+local t = {}
+is( t[1], nil, "index" )
+t[1] = 42
+is( t[1], 42, "index" )
+
+error_like(function () t = {}; t[nil] = 42 end,
+           "^[^:]+:%d+: table index is nil",
+           "table index is nil")
+
+error_like(function () t = {}; t[0/0] = 42 end,
+           "^[^:]+:%d+: table index is NaN",
+           "table index is NaN")
+
+if has_op53 then
+    dofile'lexico53/table.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/107-thread.t b/test/lua-Harness-tests/107-thread.t
new file mode 100755
index 0000000..3d4af18
--- /dev/null
+++ b/test/lua-Harness-tests/107-thread.t
@@ -0,0 +1,135 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua thread & coercion
+
+=head2 Synopsis
+
+    % prove 107-thread.t
+
+=head2 Description
+
+=cut
+
+--]]
+
+require'tap'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+local co = coroutine.create(function () return 1 end)
+
+error_like(function () return -co end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "-co")
+
+error_like(function () return #co end,
+           "^[^:]+:%d+: attempt to get length of",
+           "#co")
+
+is(not co, false, "not co")
+
+error_like(function () return co + 10 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "co + 10")
+
+error_like(function () return co - 2 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "co - 2")
+
+error_like(function () return co * 3.14 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "co * 3.14")
+
+error_like(function () return co / 7 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "co / 7")
+
+error_like(function () return co % 4 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "co % 4")
+
+error_like(function () return co ^ 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "co ^ 3")
+
+error_like(function () return co .. 'end' end,
+           "^[^:]+:%d+: attempt to concatenate",
+           "co .. 'end'")
+
+is(co == co, true, "co == co")
+
+local co1 = coroutine.create(function () return 1 end)
+local co2 = coroutine.create(function () return 2 end)
+is(co1 ~= co2, true, "co1 ~= co2")
+
+is(co == 1, false, "co == 1")
+
+is(co ~= 1, true, "co ~= 1")
+
+error_like(function () return co1 < co2 end,
+           "^[^:]+:%d+: attempt to compare two thread values",
+           "co1 < co2")
+
+error_like(function () return co1 <= co2 end,
+           "^[^:]+:%d+: attempt to compare two thread values",
+           "co1 <= co2")
+
+error_like(function () return co1 > co2 end,
+           "^[^:]+:%d+: attempt to compare two thread values",
+           "co1 > co2")
+
+error_like(function () return co1 >= co2 end,
+           "^[^:]+:%d+: attempt to compare two thread values",
+           "co1 >= co2")
+
+error_like(function () return co < 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "co < 0")
+
+error_like(function () return co <= 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "co <= 0")
+
+error_like(function () return co > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "co > 0")
+
+error_like(function () return co > 0 end,
+           "^[^:]+:%d+: attempt to compare %w+ with %w+",
+           "co >= 0")
+
+error_like(function () local a = co[1] end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+error_like(function () co[1] = 1 end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+local t = {}
+t[co] = true
+ok(t[co])
+
+if has_op53 then
+    dofile'lexico53/thread.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/108-userdata.t b/test/lua-Harness-tests/108-userdata.t
new file mode 100755
index 0000000..b1e3641
--- /dev/null
+++ b/test/lua-Harness-tests/108-userdata.t
@@ -0,0 +1,132 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua userdata & coercion
+
+=head2 Synopsis
+
+    % prove 108-userdata.t
+
+=head2 Description
+
+=cut
+
+--]]
+
+require'tap'
+local has_op53 = _VERSION >= 'Lua 5.3'
+
+plan'no_plan'
+
+local u = io.stdin
+
+error_like(function () return -u end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "-u")
+
+error_like(function () return #u end,
+           "^[^:]+:%d+: attempt to get length of",
+           "#u")
+
+is(not u, false, "not u")
+
+error_like(function () return u + 10 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "u + 10")
+
+error_like(function () return u - 2 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "u - 2")
+
+error_like(function () return u * 3.14 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "u * 3.14")
+
+error_like(function () return u / 7 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "u / 7")
+
+error_like(function () return u % 4 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "u % 4")
+
+error_like(function () return u ^ 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "u ^ 3")
+
+error_like(function () return u .. 'end' end,
+           "^[^:]+:%d+: attempt to concatenate",
+           "u .. 'end'")
+
+is(u == u, true, "u == u")
+
+local v = io.stdout
+is(u ~= v, true, "u ~= v")
+
+is(u == 1, false, "u == 1")
+
+is(u ~= 1, true, "u ~= 1")
+
+error_like(function () return u < v end,
+           "^[^:]+:%d+: attempt to compare two",
+           "u < v")
+
+error_like(function () return u <= v end,
+           "^[^:]+:%d+: attempt to compare two",
+           "u <= v")
+
+error_like(function () return u > v end,
+           "^[^:]+:%d+: attempt to compare two",
+           "u > v")
+
+error_like(function () return u >= v end,
+           "^[^:]+:%d+: attempt to compare two",
+           "u >= v")
+
+error_like(function () return u < 0 end,
+           "^[^:]+:%d+: attempt to compare",
+           "u < 0")
+
+error_like(function () return u <= 0 end,
+           "^[^:]+:%d+: attempt to compare",
+           "u <= 0")
+
+error_like(function () return u > 0 end,
+           "^[^:]+:%d+: attempt to compare",
+           "u > 0")
+
+error_like(function () return u > 0 end,
+           "^[^:]+:%d+: attempt to compare",
+           "u >= 0")
+
+is(u[1], nil, "index")
+
+error_like(function () u[1] = 1 end,
+           "^[^:]+:%d+: attempt to index",
+           "index")
+
+local t = {}
+t[u] = true
+ok(t[u])
+
+if has_op53 then
+    dofile'lexico53/userdata.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/200-examples.t b/test/lua-Harness-tests/200-examples.t
new file mode 100755
index 0000000..362aae3
--- /dev/null
+++ b/test/lua-Harness-tests/200-examples.t
@@ -0,0 +1,104 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 some Lua code examples
+
+=head2 Synopsis
+
+    % prove 200-examples.t
+
+=head2 Description
+
+First tests in order to check infrastructure.
+
+=cut
+
+--]]
+
+require'tap'
+
+plan(5)
+
+function factorial (n)
+    if n == 0 then
+        return 1
+    else
+        return n * factorial(n-1)
+    end
+end
+is(factorial(7), 5040, "factorial (recursive)")
+
+local function local_factorial (n)
+    if n == 0 then
+        return 1
+    else
+        return n * local_factorial(n-1)
+    end
+end
+is(local_factorial(7), 5040, "factorial (recursive)")
+
+local function loop_factorial (n)
+    local a = 1
+    for i = 1, n, 1 do
+        a = a*i
+    end
+    return a
+end
+is(loop_factorial(7), 5040, "factorial (loop)")
+
+local function iter_factorial (n)
+    local function iter (product, counter)
+        if counter > n then
+            return product
+        else
+            return iter(counter*product, counter+1)
+        end
+    end
+    return iter(1, 1)
+end
+is(iter_factorial(7), 5040, "factorial (iter)")
+
+--[[
+
+  Knuth's "man or boy" test.
+  See http://en.wikipedia.org/wiki/Man_or_boy_test
+
+]]
+
+local function A (k, x1, x2, x3, x4, x5)
+    local function B ()
+        k = k - 1
+        return A(k, B, x1, x2, x3, x4)
+    end
+    if k <= 0 then
+        return x4() + x5()
+    else
+        return B()
+    end
+end
+
+is(A(10,
+        function () return 1 end,
+        function () return -1 end,
+        function () return -1 end,
+        function () return 1 end,
+        function () return 0 end),
+   -67,
+   "man or boy"
+)
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/201-assign.t b/test/lua-Harness-tests/201-assign.t
new file mode 100755
index 0000000..7d023d8
--- /dev/null
+++ b/test/lua-Harness-tests/201-assign.t
@@ -0,0 +1,150 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua assignment
+
+=head2 Synopsis
+
+    % prove 201-assign.t
+
+=head2 Description
+
+See section "Assignment" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.4.3>,
+L<https://www.lua.org/manual/5.2/manual.html#3.3.3>,
+L<https://www.lua.org/manual/5.3/manual.html#3.3.3>,
+L<https://www.lua.org/manual/5.4/manual.html#3.3.3>
+
+=cut
+
+--]]
+
+require'tap'
+local has_env = _VERSION >= 'Lua 5.2'
+
+plan'no_plan'
+
+do
+    is(b, nil, "global variable")
+    b = 10
+    is(b, 10)
+    if has_env then
+        is(_ENV.b, 10, "_ENV")
+        is(_G, _ENV, "_G")
+        error_like([[ _ENV = nil; b = 20 ]],
+                   "attempt to ")
+    else
+        is(_ENV, nil, "no _ENV");
+    end
+    b = nil
+    is(b, nil)
+end
+
+do
+    local a = {}
+    local i = 3
+    i, a[i] = i+1, 20
+    -- this behavior is undefined
+    -- see http://lua-users.org/lists/lua-l/2006-06/msg00378.html
+    is(i, 4, "check eval")
+    is(a[3], 20)
+end
+
+do
+    local x = 1.
+    local y = 2.
+    x, y = y, x -- swap
+    is(x, 2, "check swap")
+    is(y, 1)
+end
+
+do
+    local a, b, c = 0, 1
+    is(a, 0, "check padding")
+    is(b, 1)
+    is(c, nil)
+    a, b = a+1, b+1, a+b
+    is(a, 1)
+    is(b, 2)
+    a, b, c = 0
+    is(a, 0)
+    is(b, nil)
+    is(c, nil)
+end
+
+do
+    local function f() return 1, 2 end
+    local a, b, c, d = f()
+    is(a, 1, "adjust with function")
+    is(b, 2)
+    is(c, nil)
+    is(d, nil)
+end
+
+do
+    local function f() print('# f') end
+    local a = 2
+    local b, c
+    a, b, c = f(), 3
+    is(a, nil, "padding with function")
+    is(b, 3)
+    is(c, nil)
+end
+
+do
+    local my_i = 1
+    is(my_i, 1, "local variable")
+    local my_i = 2
+    is(my_i, 2)
+end
+
+do
+    local i = 1
+    local j = i
+    is(i, 1, "local variable")
+    is(j, 1)
+    j = 2
+    is(i, 1)
+    is(j, 2)
+end
+
+do
+    local function f(x) return 2*x end
+    is(f(2), 4, "param & result of function")
+    local a = 2
+    a = f(a)
+    is(a, 4)
+    local b = 2
+    b = f(b)
+    is(b, 4)
+end
+
+do
+    local n1 = 1
+    local n2 = 2
+    local n3 = 3
+    local n4 = 4
+    n1,n2,n3,n4 = n4,n3,n2,n1
+    is(n1, 4, "assignment list swap values")
+    is(n2, 3)
+    is(n3, 2)
+    is(n4, 1)
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/202-expr.t b/test/lua-Harness-tests/202-expr.t
new file mode 100755
index 0000000..2576750
--- /dev/null
+++ b/test/lua-Harness-tests/202-expr.t
@@ -0,0 +1,157 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua expression
+
+=head2 Synopsis
+
+    % prove 202-expr.t
+
+=head2 Description
+
+See section "Expressions" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.5>,
+L<https://www.lua.org/manual/5.2/manual.html#3.4>,
+L<https://www.lua.org/manual/5.3/manual.html#3.4>,
+L<https://www.lua.org/manual/5.4/manual.html#3.4>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local nocvtn2s = profile.nocvtn2s
+local nocvts2n = profile.nocvts2n
+
+plan'no_plan'
+
+local x = math.pi
+is(tostring(x - x%0.0001), tostring(3.1415), "modulo")
+
+local a = {}; a.x = 1; a.y = 0;
+local b = {}; b.x = 1; b.y = 0;
+local c = a
+is(a == c, true, "relational op (by reference)")
+is(a ~= b, true)
+
+is('0' == 0, false, "relational op")
+is(2 < 15, true)
+is('2' < '15', false)
+
+error_like(function () return 2 < '15' end,
+           "compare",
+           "relational op")
+
+error_like(function () return '2' < 15 end,
+           "compare",
+           "relational op")
+
+is(4 and 5, 5, "logical op")
+is(nil and 13, nil)
+is(false and 13, false)
+is(4 or 5, 4)
+is(false or 5, 5)
+is(false or 'text', 'text')
+
+is(10 or 20, 10, "logical op")
+is(10 or error(), 10)
+is(nil or 'a', 'a')
+is(nil and 10, nil)
+is(false and error(), false)
+is(false and nil, false)
+is(false or nil, nil)
+is(10 and 20, 20)
+
+is(not nil, true, "logical not")
+is(not false, true)
+is(not 0, false)
+is(not not nil, false)
+is(not 'text', false)
+a = {}
+is(not a, false)
+is(not (a == a), false)
+is(not (a ~= a), true)
+
+is("Hello " .. "World", "Hello World", "concatenation")
+if not nocvtn2s then
+    is(0 .. 1, '01')
+end
+a = "Hello"
+is(a .. " World", "Hello World")
+is(a, "Hello")
+
+if not nocvts2n then
+    is('10' + 1, 11, "coercion")
+    is('-5.3' * '2', -10.6)
+end
+is(tostring(10), '10')
+if not nocvtn2s then
+    is(10 .. 20, '1020')
+    is(10 .. '', '10')
+end
+
+error_like(function () return 'hello' + 1 end,
+           ((not nocvts2n and _VERSION >= 'Lua 5.4') or ravi) and "attempt to add" or "perform arithmetic",
+           "no coercion")
+
+error_like(function ()
+                local function first() return end
+                local function limit() return 2 end
+                local function step()  return 1 end
+                for i = first(), limit(), step() do
+                    print(i)
+                end
+           end,
+           "^[^:]+:%d+:.- 'for' initial value",
+           "for tonumber")
+
+error_like(function ()
+                local function first() return 1 end
+                local function limit() return end
+                local function step()  return 2 end
+                for i = first(), limit(), step() do
+                    print(i)
+                end
+           end,
+           "^[^:]+:%d+:.- 'for' limit",
+           "for tonumber")
+
+error_like(function ()
+                local function first() return 1 end
+                local function limit() return 2 end
+                local function step()  return end
+                for i = first(), limit(), step() do
+                    print(i)
+                end
+           end,
+           "^[^:]+:%d+:.- 'for' step",
+           "for tonumber")
+
+if _VERSION >= 'Lua 5.4' then
+    error_like(function ()
+                    for i = 1, 10, 0 do
+                        print(i)
+                    end
+               end,
+               "^[^:]+:%d+: 'for' step is zero",
+               "for step zero")
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/203-lexico.t b/test/lua-Harness-tests/203-lexico.t
new file mode 100755
index 0000000..c1abebf
--- /dev/null
+++ b/test/lua-Harness-tests/203-lexico.t
@@ -0,0 +1,143 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2010-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Lexicography
+
+=head2 Synopsis
+
+    % prove 203-lexico.t
+
+=head2 Description
+
+See "Lua 5.3 Reference Manual", section 3.1 "Lexical Conventions",
+L<http://www.lua.org/manual/5.3/manual.html#3.1>.
+
+See section "Lexical Conventions"
+L<https://www.lua.org/manual/5.1/manual.html#2.1>,
+L<https://www.lua.org/manual/5.2/manual.html#3.1>,
+L<https://www.lua.org/manual/5.3/manual.html#3.1>,
+L<https://www.lua.org/manual/5.4/manual.html#3.1>
+
+=cut
+
+--]]
+
+require'tap'
+local loadstring = loadstring or load
+local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT')
+
+plan'no_plan'
+
+is("\65", "A")
+is("\065", "A")
+
+is(string.byte("\a"), 7)
+is(string.byte("\b"), 8)
+is(string.byte("\f"), 12)
+is(string.byte("\n"), 10)
+is(string.byte("\r"), 13)
+is(string.byte("\t"), 9)
+is(string.byte("\v"), 11)
+is(string.byte("\\"), 92)
+
+is(string.len("A\0B"), 3)
+
+do
+    local f, msg = loadstring [[a = "A\300"]]
+    if _VERSION == 'Lua 5.1' then
+        like(msg, "^[^:]+:%d+: .- near")
+    else
+        like(msg, "^[^:]+:%d+: .- escape .- near")
+    end
+
+    f, msg = loadstring [[a = " unfinished string ]]
+    like(msg, "^[^:]+:%d+: unfinished string near")
+
+    f, msg = loadstring [[a = " unfinished string
+]]
+    like(msg, "^[^:]+:%d+: unfinished string near")
+
+    f, msg = loadstring [[a = " unfinished string \
+]]
+    like(msg, "^[^:]+:%d+: unfinished string near")
+
+    f, msg = loadstring [[a = " unfinished string \]]
+    like(msg, "^[^:]+:%d+: unfinished string near")
+
+    f, msg = loadstring "a = [[ unfinished long string "
+    like(msg, "^[^:]+:%d+: unfinished long string .-near")
+
+    f, msg = loadstring "a = [== invalid long string delimiter "
+    like(msg, "^[^:]+:%d+: invalid long string delimiter near")
+end
+
+do
+    local a = 'alo\n123"'
+    is('alo\n123"', a)
+    is("alo\n123\"", a)
+    is('\97lo\10\04923"', a)
+    is([[alo
+123"]], a)
+    is([==[
+alo
+123"]==], a)
+end
+
+is(3.0, 3)
+is(314.16e-2, 3.1416)
+is(0.31416E1, 3.1416)
+is(.3, 0.3)
+is(0xff, 255)
+is(0x56, 86)
+
+do
+    local f, msg = loadstring [[a = 12e34e56]]
+    like(msg, "^[^:]+:%d+: malformed number near")
+end
+
+--[===[
+--[[
+--[=[
+    nested long comments
+--]=]
+--]]
+--]===]
+
+do
+    local f, msg = loadstring "  --[[ unfinished long comment "
+    like(msg, "^[^:]+:%d+: unfinished long comment .-near")
+end
+
+if _VERSION >= 'Lua 5.2' or jit then
+    dofile'lexico52/lexico.t'
+end
+
+if _VERSION >= 'Lua 5.3' or luajit21 then
+    dofile'lexico53/lexico.t'
+end
+
+if _VERSION >= 'Lua 5.4' then
+    dofile'lexico54/lexico.t'
+end
+
+if jit and pcall(require, 'ffi') then
+    dofile'lexicojit/lexico.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/204-grammar.t b/test/lua-Harness-tests/204-grammar.t
new file mode 100755
index 0000000..d9ae3a6
--- /dev/null
+++ b/test/lua-Harness-tests/204-grammar.t
@@ -0,0 +1,233 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2010-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Grammar
+
+=head2 Synopsis
+
+    % prove 204-grammar.t
+
+=head2 Description
+
+See section "The Complete Syntax of Lua" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#8>,
+L<https://www.lua.org/manual/5.2/manual.html#9>,
+L<https://www.lua.org/manual/5.3/manual.html#9>,
+L<https://www.lua.org/manual/5.4/manual.html#9>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local has_goto = _VERSION >= 'Lua 5.2' or jit
+local has_attr = _VERSION >= 'Lua 5.4'
+local loadstring = loadstring or load
+
+plan'no_plan'
+
+do --[[ empty statement ]]
+    local f, msg = loadstring [[; a = 1]]
+    if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then
+        like(msg, "^[^:]+:%d+: unexpected symbol near ';'", "empty statement")
+    else
+        type_ok(f, 'function', "empty statement")
+    end
+
+    f = loadstring [[a = 1; a = 2]]
+    type_ok(f, 'function')
+
+    f, msg = loadstring [[a = 1;;; a = 2]]
+    if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then
+        like(msg, "^[^:]+:%d+: unexpected symbol near ';'")
+    else
+        type_ok(f, 'function')
+    end
+end
+
+do --[[ orphan break ]]
+    local f, msg = loadstring [[
+function f()
+    print "before"
+    do
+        print "inner"
+        break
+    end
+    print "after"
+end
+]]
+    if _VERSION == 'Lua 5.1' then
+        like(msg, "^[^:]+:%d+: no loop to break", "orphan break")
+    elseif _VERSION <= 'Lua 5.3' then
+        like(msg, "^[^:]+:%d+: <break> at line 5 not inside a loop", "orphan break")
+    else
+        like(msg, "^[^:]+:%d+: break outside loop at line 5", "orphan break")
+    end
+end
+
+do --[[ break anywhere ]]
+    local f, msg = loadstring [[
+function f()
+    print "before"
+    while true do
+        print "inner"
+        break
+        print "break"
+    end
+    print "after"
+end
+]]
+    if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then
+        like(msg, "^[^:]+:%d+: 'end' expected %(to close 'while' at line 3%) near 'print'", "break anywhere")
+    else
+        type_ok(f, 'function', "break anywhere")
+    end
+
+    f, msg = loadstring [[
+function f()
+    print "before"
+    while true do
+        print "inner"
+        if cond then
+            break
+            print "break"
+        end
+    end
+    print "after"
+end
+]]
+    if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then
+        like(msg, "^[^:]+:%d+: 'end' expected %(to close 'if' at line 5%) near 'print'", "break anywhere")
+    else
+        type_ok(f, 'function', "break anywhere")
+    end
+end
+
+--[[ goto ]]
+if has_goto then
+    local f, msg = loadstring [[
+::label::
+    goto unknown
+]]
+    if jit then
+        like(msg, ":%d+: undefined label 'unknown'", "unknown goto")
+    else
+        like(msg, ":%d+: no visible label 'unknown' for <goto> at line %d+", "unknown goto")
+    end
+
+    f, msg = loadstring [[
+::label::
+    goto label
+::label::
+]]
+    if jit then
+        like(msg, ":%d+: duplicate label 'label'", "duplicate label")
+    else
+        like(msg, ":%d+: label 'label' already defined on line %d+", "duplicate label")
+    end
+
+    f, msg = loadstring [[
+::e::
+    goto f
+    local x
+::f::
+    goto e
+]]
+    if jit then
+        like(msg, ":%d+: <goto f> jumps into the scope of local 'x'", "bad goto")
+    else
+        like(msg, ":%d+: <goto f> at line %d+ jumps into the scope of local 'x'", "bad goto")
+    end
+
+    f= loadstring [[
+do
+::s1:: ;
+    goto s2
+
+::s2::
+    goto s3
+
+::s3::
+end
+]]
+    type_ok(f, 'function', "goto")
+else
+    diag("no goto")
+end
+
+do --[[ syntax error ]]
+    local f, msg = loadstring [[a = { 1, 2, 3)]]
+    like(msg, ":%d+: '}' expected near '%)'", "constructor { }")
+
+    f, msg = loadstring [[a = (1 + 2}]]
+    like(msg, ":%d+: '%)' expected near '}'", "expr ( )")
+
+    f, msg = loadstring [[a = f(1, 2}]]
+    like(msg, ":%d+: '%)' expected near '}'", "expr ( )")
+
+    f, msg = loadstring [[function f () return 1]]
+    like(msg, ":%d+: 'end' expected near '?<eof>'?", "function end")
+
+    f, msg = loadstring [[do local a = f()]]
+    like(msg, ":%d+: 'end' expected near '?<eof>'?", "do end")
+
+    f, msg = loadstring [[for i = 1, 2 do print(i)]]
+    like(msg, ":%d+: 'end' expected near '?<eof>'?", "for end")
+
+    f, msg = loadstring [[if true then f()]]
+    like(msg, ":%d+: 'end' expected near '?<eof>'?", "if end")
+
+    f, msg = loadstring [[while true do f()]]
+    like(msg, ":%d+: 'end' expected near '?<eof>'?", "while end")
+
+    f, msg = loadstring [[repeat f()]]
+    like(msg, ":%d+: 'until' expected near '?<eof>'?", "repeat until")
+
+    f, msg = loadstring [[function f (a, 2) return a * 2 end]]
+    like(msg, ":%d+: <name> or '...' expected near '2'", "function parameter list")
+
+    f, msg = loadstring [[a = o:m[1, 2)]]
+    like(msg, ":%d+: function arguments expected near '%['", "function argument list")
+
+    f, msg = loadstring [[for i do print(i) end]]
+    like(msg, ":%d+: '=' or 'in' expected near 'do'", "for init")
+
+    f, msg = loadstring [[for i = 1, 2 print(i) end]]
+    like(msg, ":%d+: 'do' expected near 'print'", "for do")
+
+    f, msg = loadstring [[if true f() end]]
+    like(msg, ":%d+: 'then' expected near 'f'", "if then")
+
+    f, msg = loadstring [[while true f() end]]
+    like(msg, ":%d+: 'do' expected near 'f", "while do")
+end
+
+if has_attr then
+    local f, msg = load [[local foo < bar > = 'bar']]
+    like(msg, "^[^:]+:%d+: unknown attribute 'bar'")
+
+    f, msg = load [[local foo <const> = 'bar'; foo = 'baz']]
+    like(msg, "^[^:]+:%d+: attempt to assign to const variable 'foo'")
+
+    f, msg = load [[local foo <close> = 'bar'; foo = 'baz']]
+    like(msg, "^[^:]+:%d+: attempt to assign to const variable 'foo'")
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/211-scope.t b/test/lua-Harness-tests/211-scope.t
new file mode 100755
index 0000000..64eed52
--- /dev/null
+++ b/test/lua-Harness-tests/211-scope.t
@@ -0,0 +1,86 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua scope
+
+=head2 Synopsis
+
+    % prove 211-scope.t
+
+=head2 Description
+
+See section "Visibility Rules" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.6>,
+L<https://www.lua.org/manual/5.2/manual.html#3.5>,
+L<https://www.lua.org/manual/5.3/manual.html#3.5>,
+L<https://www.lua.org/manual/5.4/manual.html#3.5>
+
+See section "Local Variables and Blocks" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+
+plan(10)
+
+--[[ scope ]]
+x = 10
+do
+    local x = x
+    is(x, 10, "scope")
+    x = x + 1
+    do
+        local x = x + 1
+        is(x, 12)
+    end
+    is(x, 11)
+end
+is(x, 10)
+
+--[[ scope ]]
+x = 10
+local i = 1
+
+while i<=x do
+    local x = i*2
+--    print(x)
+    i = i + 1
+end
+
+if i > 20 then
+    local x
+    x = 20
+    nok("scope")
+else
+    is(x, 10, "scope")
+end
+
+is(x, 10)
+
+--[[ scope ]]
+local a, b = 1, 10
+if a < b then
+    is(a, 1, "scope")
+    local a
+    is(a, nil)
+end
+is(a, 1)
+is(b, 10)
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/212-function.t b/test/lua-Harness-tests/212-function.t
new file mode 100755
index 0000000..2851053
--- /dev/null
+++ b/test/lua-Harness-tests/212-function.t
@@ -0,0 +1,288 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua functions
+
+=head2 Synopsis
+
+    % prove 212-function.t
+
+=head2 Description
+
+See section "Function Definitions" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.5.9>,
+L<https://www.lua.org/manual/5.2/manual.html#3.4.10>,
+L<https://www.lua.org/manual/5.3/manual.html#3.4.11>,
+L<https://www.lua.org/manual/5.4/manual.html#3.4.11>
+
+See section "Functions" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+local loadstring = loadstring or load
+
+plan(68)
+
+do --[[ add ]]
+    local function add (a)
+        local sum = 0
+        for i,v in ipairs(a) do
+            sum = sum + v
+        end
+        return sum
+    end
+
+    local t = { 10, 20, 30, 40 }
+    is(add(t), 100, "add")
+end
+
+do --[[ f ]]
+    local function f(a, b) return a or b end
+
+    is(f(3), 3, "f")
+    is(f(3, 4), 3)
+    is(f(3, 4, 5), 3)
+end
+
+do --[[ incCount ]]
+    local count = 0
+
+    local function incCount (n)
+        n = n or 1
+        count = count + n
+    end
+
+    is(count, 0, "inCount")
+    incCount()
+    is(count, 1)
+    incCount(2)
+    is(count, 3)
+    incCount(1)
+    is(count, 4)
+end
+
+do --[[ maximum ]]
+    local function maximum (a)
+        local mi = 1                -- maximum index
+        local m = a[mi]             -- maximum value
+        for i,val in ipairs(a) do
+            if val > m then
+                mi = i
+                m = val
+            end
+        end
+        return m, mi
+    end
+
+    local m, mi = maximum({8,10,23,12,5})
+    is(m, 23, "maximum")
+    is(mi, 3)
+end
+
+do --[[ call by value ]]
+    local function f (n)
+        n = n - 1
+        return n
+    end
+
+    local a = 12
+    is(a, 12, "call by value")
+    local b = f(a)
+    is(b, 11)
+    is(a, 12)
+    local c = f(12)
+    is(c, 11)
+    is(a, 12)
+end
+
+do --[[ call by ref ]]
+    local function f (t)
+        t[#t+1] = 'end'
+        return t
+    end
+
+    local a = { 'a', 'b', 'c' }
+    is(table.concat(a, ','), 'a,b,c', "call by ref")
+    local b = f(a)
+    is(table.concat(b, ','), 'a,b,c,end')
+    is(table.concat(a, ','), 'a,b,c,end')
+end
+
+do --[[ var args ]]
+    local function g1(a, b, ...)
+        local arg = {...}
+        is(a, 3, "vararg")
+        is(b, nil)
+        is(#arg, 0)
+        is(arg[1], nil)
+    end
+    g1(3)
+
+    local function g2(a, b, ...)
+        local arg = {...}
+        is(a, 3)
+        is(b, 4)
+        is(#arg, 0)
+        is(arg[1], nil)
+    end
+    g2(3, 4)
+
+    local function g3(a, b, ...)
+        local arg = {...}
+        is(a, 3)
+        is(b, 4)
+        is(#arg, 2)
+        is(arg[1], 5)
+        is(arg[2], 8)
+    end
+    g3(3, 4, 5, 8)
+end
+
+do --[[ var args ]]
+    local function g1(a, b, ...)
+        local c, d, e = ...
+        is(a, 3, "var args")
+        is(b, nil)
+        is(c, nil)
+        is(d, nil)
+        is(e, nil)
+    end
+    g1(3)
+
+    local function g2(a, b, ...)
+        local c, d, e = ...
+        is(a, 3)
+        is(b, 4)
+        is(c, nil)
+        is(d, nil)
+        is(e, nil)
+    end
+    g2(3, 4)
+
+    local function g3(a, b, ...)
+        local c, d, e = ...
+        is(a, 3)
+        is(b, 4)
+        is(c, 5)
+        is(d, 8)
+        is(e, nil)
+    end
+    g3(3, 4, 5, 8)
+end
+
+do --[[ var args ]]
+    local function g1(a, b, ...)
+        is(#{a, b, ...}, 1, "varargs")
+    end
+    g1(3)
+
+    local function g2(a, b, ...)
+        is(#{a, b, ...}, 2)
+    end
+    g2(3, 4)
+
+    local function g3(a, b, ...)
+        is(#{a, b, ...}, 4)
+    end
+    g3(3, 4, 5, 8)
+end
+
+do --[[ var args ]]
+    local function f() return 1, 2 end
+    local function g() return 'a', f() end
+    local function h() return f(), 'b' end
+    local function k() return 'c', (f()) end
+
+    local x, y = f()
+    is(x, 1, "var args")
+    is(y, 2)
+    local z
+    x, y, z = g()
+    is(x, 'a')
+    is(y, 1)
+    is(z, 2)
+    x, y = h()
+    is(x, 1)
+    is(y, 'b')
+    x, y, z = k()
+    is(x, 'c')
+    is(y, 1)
+    is(z, nil)
+end
+
+do --[[ invalid var args ]]
+    local f, msg = loadstring [[
+function f ()
+    print(...)
+end
+]]
+    like(msg, "^[^:]+:%d+: cannot use '...' outside a vararg function", "invalid var args")
+end
+
+do --[[ tail call ]]
+    local output = {}
+    local function foo (n)
+        output[#output+1] = n
+        if n > 0 then
+            return foo(n -1)
+        end
+        return 'end', 0
+    end
+
+    eq_array({foo(3)}, {'end', 0}, "tail call")
+    eq_array(output, {3, 2, 1, 0})
+end
+
+do --[[ no tail call ]]
+    local output = {}
+    local function foo (n)
+        output[#output+1] = n
+        if n > 0 then
+            return (foo(n -1))
+        end
+        return 'end', 0
+    end
+
+    is(foo(3), 'end', "no tail call")
+    eq_array(output, {3, 2, 1, 0})
+end
+
+do --[[ no tail call ]]
+    local output = {}
+    local function foo (n)
+        output[#output+1] = n
+        if n > 0 then
+            foo(n -1)
+        end
+    end
+
+    is(foo(3), nil, "no tail call")
+    eq_array(output, {3, 2, 1, 0})
+end
+
+do --[[ sub name ]]
+    local function f () return 1 end
+    is(f(), 1, "sub name")
+
+    function f () return 2 end
+    is(f(), 2)
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/213-closure.t b/test/lua-Harness-tests/213-closure.t
new file mode 100755
index 0000000..fc3bd29
--- /dev/null
+++ b/test/lua-Harness-tests/213-closure.t
@@ -0,0 +1,98 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua closures
+
+=head2 Synopsis
+
+    % prove 213-closure.t
+
+=head2 Description
+
+See section "Closures" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+
+plan(15)
+
+do --[[ inc ]]
+    local counter = 0
+
+    local function inc (x)
+        counter = counter + x
+        return counter
+    end
+
+    is(inc(1), 1, "inc")
+    is(inc(2), 3)
+end
+
+do --[[ newCounter ]]
+    local function newCounter ()
+        local i = 0
+        return function ()  -- anonymous function
+                   i = i + 1
+                   return i
+               end
+    end
+
+    local c1 = newCounter()
+    is(c1(), 1, "newCounter")
+    is(c1(), 2)
+
+    local c2 = newCounter()
+    is(c2(), 1)
+    is(c1(), 3)
+    is(c2(), 2)
+end
+
+do --[[
+The loop creates ten closures (that is, ten instances of the anonymous
+function). Each of these closures uses a different y variable, while all
+of them share the same x.
+]]
+    local a = {}
+    local x = 20
+    for i=1,10 do
+        local y = 0
+        a[i] = function () y=y+1; return x+y end
+    end
+
+    is(a[1](), 21, "ten closures")
+    is(a[1](), 22)
+    is(a[2](), 21)
+end
+
+do --[[ add ]]
+    local function add(x)
+        return function (y) return (x + y) end
+    end
+
+    local f = add(2)
+    type_ok(f, 'function', "add")
+    is(f(10), 12)
+    local g = add(5)
+    is(g(1), 6)
+    is(g(10), 15)
+    is(f(1), 3)
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/214-coroutine.t b/test/lua-Harness-tests/214-coroutine.t
new file mode 100755
index 0000000..92929e1
--- /dev/null
+++ b/test/lua-Harness-tests/214-coroutine.t
@@ -0,0 +1,244 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua coroutines
+
+=head2 Synopsis
+
+    % prove 214-coroutine.t
+
+=head2 Description
+
+See section "Coroutines" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.11>,
+L<https://www.lua.org/manual/5.2/manual.html#2.6>,
+L<https://www.lua.org/manual/5.3/manual.html#2.6>,
+L<https://www.lua.org/manual/5.4/manual.html#2.6>
+
+See section "Coroutines" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT')
+local has_coroutine52 = _VERSION >= 'Lua 5.2' or jit
+local has_running52 = _VERSION >= 'Lua 5.2' or (profile.luajit_compat52 and not ujit)
+local has_isyieldable = _VERSION >= 'Lua 5.3' or luajit21
+local has_close = _VERSION >= 'Lua 5.4'
+
+plan'no_plan'
+
+do
+    local output = {}
+
+    local function foo1 (a)
+        output[#output+1] = "foo " .. tostring(a)
+        return coroutine.yield(2*a)
+    end
+
+    local co = coroutine.create(function (a,b)
+        local r, s
+        output[#output+1] = "co-body " .. tostring(a) .." " .. tostring(b)
+        r = foo1(a+1)
+        output[#output+1] = "co-body " .. r
+        r, s = coroutine.yield(a+b, a-b)
+        output[#output+1] = "co-body " .. r .. " " .. s
+        return b, 'end'
+    end)
+
+    eq_array({coroutine.resume(co, 1, 10)}, {true, 4}, "foo1")
+    eq_array({coroutine.resume(co, 'r')}, {true, 11, -9})
+    eq_array({coroutine.resume(co, "x", "y")}, {true, 10, 'end'})
+    eq_array({coroutine.resume(co, "x", "y")}, {false, "cannot resume dead coroutine"})
+    eq_array(output, {
+        'co-body 1 10',
+        'foo 2',
+        'co-body r',
+        'co-body x y',
+    })
+end
+
+do
+    local output = ''
+    local co = coroutine.create(function ()
+        output = 'hi'
+    end)
+    like(co, '^thread: 0?[Xx]?%x+$', "basics")
+
+    is(coroutine.status(co), 'suspended')
+    coroutine.resume(co)
+    is(output, 'hi')
+    is(coroutine.status(co), 'dead')
+
+    error_like(function () coroutine.create(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'create' %(.- expected")
+
+    error_like(function () coroutine.resume(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'resume' %(.- expected")
+
+    error_like(function () coroutine.status(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'status' %(.- expected")
+end
+
+do
+    local output = {}
+    local co = coroutine.create(function ()
+        for i=1,10 do
+            output[#output+1] = i
+            coroutine.yield()
+        end
+    end)
+
+    coroutine.resume(co)
+    if has_running52 then
+        local thr, ismain = coroutine.running()
+        type_ok(thr, 'thread', "running")
+        is(ismain, true, "running")
+    else
+        local thr = coroutine.running()
+        is(thr, nil, "main thread")
+    end
+    is(coroutine.status(co), 'suspended', "basics")
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    coroutine.resume(co)
+    eq_array({coroutine.resume(co)}, {false, 'cannot resume dead coroutine'})
+    eq_array(output, {1,2,3,4,5,6,7,8,9,10})
+end
+
+do
+    local co = coroutine.create(function (a,b)
+        coroutine.yield(a + b, a - b)
+    end)
+
+    eq_array({coroutine.resume(co, 20, 10)}, {true, 30, 10}, "basics")
+end
+
+do
+    local co = coroutine.create(function ()
+        return 6, 7
+    end)
+
+    eq_array({coroutine.resume(co)}, {true, 6, 7}, "basics")
+end
+
+if has_coroutine52 then
+    local co = coroutine.wrap(function(...)
+        return pcall(function(...)
+            return coroutine.yield(...)
+        end, ...)
+    end)
+    eq_array({co("Hello")}, {"Hello"})
+    eq_array({co("World")}, {true, "World"})
+end
+
+if has_coroutine52 then
+    local co = coroutine.wrap(function(...)
+        local function backtrace ()
+            return 'not a back trace'
+        end
+        return xpcall(function(...)
+            return coroutine.yield(...)
+        end, backtrace, ...)
+    end)
+    eq_array({co("Hello")}, {"Hello"})
+    eq_array({co("World")}, {true, "World"})
+end
+
+if has_coroutine52 then
+    local output = {}
+    local co = coroutine.wrap(function()
+        while true do
+            local t = setmetatable({}, {
+                __eq = function(...)
+                    return coroutine.yield(...)
+                end}
+            )
+            local t2 = setmetatable({}, getmetatable(t))
+            output[#output+1] = t == t2
+        end
+    end)
+    co()
+    co(true)
+    co(false)
+    eq_array(output, {true, false})
+end
+
+if has_coroutine52 then
+    local co = coroutine.wrap(print)
+    type_ok(co, 'function')
+
+    error_like(function () coroutine.wrap(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'wrap' %(function expected, got boolean%)")
+
+    co = coroutine.wrap(function () error"in coro" end)
+    error_like(function () co() end,
+               "^[^:]+:%d+: [^:]+:%d+: in coro$")
+end
+
+do
+    local co = coroutine.create(function ()
+        error "in coro"
+    end)
+    local r, msg = coroutine.resume(co)
+    is(r, false)
+    like(msg, "^[^:]+:%d+: in coro$")
+end
+
+do
+    error_like(function () coroutine.yield() end,
+               "attempt to yield")
+
+    if has_isyieldable then
+        is(coroutine.isyieldable(), false, "isyieldable")
+    else
+        is(coroutine.isyieldable, nil, "no coroutine.isyieldable")
+    end
+end
+
+-- close
+if has_close then
+    local output = ''
+    local co = coroutine.create(function ()
+        output = 'hi'
+    end)
+    is(coroutine.close(co), true, "close")
+    is(coroutine.status(co), 'dead')
+    is(coroutine.close(co), true, "close again")
+
+    error_like(function () coroutine.close(coroutine.running()) end,
+               "^[^:]+:%d+: cannot close a running coroutine")
+
+    error_like(function () coroutine.close(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'close' %(thread expected, got number%)")
+else
+    is(coroutine.close, nil, "no coroutine.close")
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/221-table.t b/test/lua-Harness-tests/221-table.t
new file mode 100755
index 0000000..c064a33
--- /dev/null
+++ b/test/lua-Harness-tests/221-table.t
@@ -0,0 +1,120 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua tables
+
+=head2 Synopsis
+
+    % prove 221-table.t
+
+=head2 Description
+
+See section "Tables" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+
+plan(25)
+
+do
+    local a = {}
+    local k = 'x'
+    a[k] = 10
+    a[20] = 'great'
+    is(a['x'], 10)
+    k = 20
+    is(a[k], 'great')
+    a['x'] = a ['x'] + 1
+    is(a['x'], 11)
+end
+
+do
+    local a = {}
+    a['x'] = 10
+    local b = a
+    is(b['x'], 10)
+    b['x'] = 20
+    is(a['x'], 20)
+    a = nil
+    b = nil
+end
+
+do
+    local a = {}
+    for i=1,1000 do a[i] = i*2 end
+    is(a[9], 18)
+    a['x'] = 10
+    is(a['x'], 10)
+    is(a['y'], nil)
+end
+
+do
+    local a = {}
+    local x = 'y'
+    a[x] = 10
+    is(a[x], 10)
+    is(a.x, nil)
+    is(a.y, 10)
+end
+
+do
+    local i = 10; local j = '10'; local k = '+10'
+    local a = {}
+    a[i] = "one value"
+    a[j] = "another value"
+    a[k] = "yet another value"
+    is(a[j], "another value")
+    is(a[k], "yet another value")
+    is(a[tonumber(j)], "one value")
+    is(a[tonumber(k)], "one value")
+end
+
+do
+    local t = { {'a','b','c'}, 10 }
+    is(t[2], 10)
+    is(t[1][3], 'c')
+    t[1][1] = 'A'
+    is(table.concat(t[1],','), 'A,b,c')
+end
+
+do
+    local tt = { {'a','b','c'}, 10 }
+    is(tt[2], 10)
+    is(tt[1][3], 'c')
+    tt[1][1] = 'A'
+    is(table.concat(tt[1],','), 'A,b,c')
+end
+
+do
+    local a = {}
+    error_like(function () a() end,
+               "^[^:]+:%d+: .- call")
+end
+
+do
+    local tt = { {'a','b','c'}, 10 }
+    is((tt)[2], 10)
+    is((tt[1])[3], 'c');
+    (tt)[1][2] = 'B'
+    (tt[1])[3] = 'C'
+    is(table.concat(tt[1],','), 'a,B,C')
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/222-constructor.t b/test/lua-Harness-tests/222-constructor.t
new file mode 100755
index 0000000..a01be2e
--- /dev/null
+++ b/test/lua-Harness-tests/222-constructor.t
@@ -0,0 +1,119 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Table Constructors
+
+=head2 Synopsis
+
+    % prove 222-constructor.t
+
+=head2 Description
+
+See section "Table Constructors" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.5.7>,
+L<https://www.lua.org/manual/5.2/manual.html#3.4.8>,
+L<https://www.lua.org/manual/5.3/manual.html#3.4.9>,
+L<https://www.lua.org/manual/5.4/manual.html#3.4.9>
+
+See section "Table Constructors" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+
+plan(16)
+
+do --[[ list-style init ]]
+    local days = {'Sunday', 'Monday', 'Tuesday', 'Wednesday',
+                  'Thursday', 'Friday', 'Saturday'}
+    is(days[4], 'Wednesday', "list-style init")
+    is(#days, 7)
+end
+
+do
+    local large = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }
+    is(#large, 100)
+    large = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }
+    is(#large, 200)
+end
+
+do --[[ record-style init ]]
+    local a = {x=0, y=0}
+    is(a.x, 0, "record-style init")
+    is(a.y, 0)
+end
+
+do
+    local w = {x=0, y=0, label='console'}
+    local x = {0, 1, 2}
+    w[1] = "another field"
+    x.f = w
+    is(w['x'], 0, "ctor")
+    is(w[1], "another field")
+    is(x.f[1], "another field")
+    w.x = nil
+end
+
+do --[[ mix record-style and list-style init ]]
+    local polyline = {color='blue', thickness=2, npoints=4,
+                       {x=0,   y=0},
+                       {x=-10, y=0},
+                       {x=-10, y=1},
+                       {x=0,   y=1}
+                     }
+    is(polyline[2].x, -10, "mix record-style and list-style init")
+end
+
+do
+    local opnames = {['+'] = 'add', ['-'] = 'sub',
+                     ['*'] = 'mul', ['/'] = 'div'}
+    local i = 20; local s = '-'
+    local a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s}
+    is(opnames[s], 'sub', "ctor")
+    is(a[22], '---')
+end
+
+do
+    local function f() return 10, 20 end
+
+    eq_array({f()}, {10, 20}, "ctor")
+    eq_array({'a', f()}, {'a', 10, 20})
+    eq_array({f(), 'b'}, {10, 'b'})
+    eq_array({'c', (f())}, {'c', 10})
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/223-iterator.t b/test/lua-Harness-tests/223-iterator.t
new file mode 100755
index 0000000..777ad73
--- /dev/null
+++ b/test/lua-Harness-tests/223-iterator.t
@@ -0,0 +1,203 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua iterators
+
+=head2 Synopsis
+
+    % prove 223-iterator.t
+
+=head2 Description
+
+See section "Iterators and the Generic for" and
+section "Coroutines as Iterators" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+
+plan(8)
+
+do --[[ list_iter ]]
+    local function list_iter (t)
+        local i = 0
+        local n = #t
+        return function ()
+                   i = i + 1
+                   if i <= n then
+                       return t[i]
+                   else
+                       return nil
+                   end
+               end
+    end
+
+    local t = {10, 20, 30}
+    local output = {}
+    for element in list_iter(t) do
+        output[#output+1] = element
+    end
+    eq_array(output, t, "list_iter")
+end
+
+do --[[ values ]]
+    local function values (t)
+        local i = 0
+        return function ()
+                   i = i + 1
+                   return t[i]
+               end
+    end
+
+    local t = {10, 20, 30}
+    local output = {}
+    for element in values(t) do
+        output[#output+1] = element
+    end
+    eq_array(output, t, "values")
+end
+
+do --[[ emul ipairs ]]
+    local function iter (a, i)
+        i = i + 1
+        local v = a[i]
+        if v then
+            return i, v
+        end
+    end
+
+    local function my_ipairs (a)
+        return iter, a, 0
+    end
+
+    local a = {'one', 'two', 'three'}
+    local output = {}
+    for i, v in my_ipairs(a) do
+        output[#output+1] = i
+        output[#output+1] = v
+    end
+    eq_array(output, {1, 'one', 2, 'two', 3, 'three'}, "emul ipairs")
+end
+
+do --[[ emul pairs ]]
+    local function my_pairs (t)
+        return next, t, nil
+    end
+
+    local a = {'one', 'two', 'three'}
+    local output = {}
+    for k, v in my_pairs(a) do
+        output[#output+1] = k
+        output[#output+1] = v
+    end
+    eq_array(output, {1, 'one', 2, 'two', 3, 'three'}, "emul ipairs")
+end
+
+do --[[ with next ]]
+    local t = {'one', 'two', 'three'}
+    local output = {}
+    for k, v in next, t do
+        output[#output+1] = k
+        output[#output+1] = v
+    end
+    eq_array(output, {1, 'one', 2, 'two', 3, 'three'}, "with next")
+end
+
+do --[[ permutations ]]
+    local function permgen (a, n)
+        n = n or #a         -- default for 'n' is size of 'a'
+        if n <= 1 then      -- nothing to change?
+            coroutine.yield(a)
+        else
+            for i=1,n do
+                -- put i-th element as the last one
+                a[n], a[i] = a[i], a[n]
+                -- generate all permutations of the other elements
+                permgen(a, n - 1)
+                -- restore i-th element
+                a[n], a[i] = a[i], a[n]
+            end
+        end
+    end
+
+    local function permutations (a)
+        local co = coroutine.create(function () permgen(a) end)
+        return function ()  -- iterator
+                   local code, res = coroutine.resume(co)
+                   return res
+               end
+    end
+
+    local output = {}
+    for p in permutations{'a', 'b', 'c'} do
+        output[#output+1] = table.concat(p, ' ')
+    end
+    eq_array(output, {'b c a','c b a','c a b','a c b','b a c','a b c'}, "permutations")
+end
+
+do --[[ permutations with wrap ]]
+    local function permgen (a, n)
+        n = n or #a         -- default for 'n' is size of 'a'
+        if n <= 1 then      -- nothing to change?
+            coroutine.yield(a)
+        else
+            for i=1,n do
+                -- put i-th element as the last one
+                a[n], a[i] = a[i], a[n]
+                -- generate all permutations of the other elements
+                permgen(a, n - 1)
+                -- restore i-th element
+                a[n], a[i] = a[i], a[n]
+            end
+        end
+    end
+
+    local function permutations (a)
+        return coroutine.wrap(function () permgen(a) end)
+    end
+
+    local output = {}
+    for p in permutations{'a', 'b', 'c'} do
+        output[#output+1] = table.concat(p, ' ')
+    end
+    eq_array(output, {'b c a','c b a','c a b','a c b','b a c','a b c'}, "permutations with wrap")
+end
+
+do --[[ fibo ]]
+    local function fibogen ()
+        local x, y = 0, 1
+        while true do
+            coroutine.yield(x)
+            x, y = y, x + y
+        end
+    end
+
+    local function fibo ()
+        return coroutine.wrap(function () fibogen() end)
+    end
+
+    local output = {}
+    for n in fibo() do
+        output[#output+1] = n
+        if n > 30 then break end
+    end
+    eq_array(output, {0, 1, 1, 2, 3, 5, 8, 13, 21, 34}, "fibo")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/231-metatable.t b/test/lua-Harness-tests/231-metatable.t
new file mode 100755
index 0000000..a2c6499
--- /dev/null
+++ b/test/lua-Harness-tests/231-metatable.t
@@ -0,0 +1,602 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua metatables
+
+=head2 Synopsis
+
+    % prove 231-metatable.t
+
+=head2 Description
+
+See section "Metatables and Metamethods" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#2.8>,
+L<https://www.lua.org/manual/5.2/manual.html#2.4>,
+L<https://www.lua.org/manual/5.3/manual.html#2.4>,
+L<https://www.lua.org/manual/5.4/manual.html#2.4>
+
+See section "Metatables and Metamethods" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local has_metamethod52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_metamethod_ipairs = _VERSION == 'Lua 5.2' or profile.compat52 or profile.luajit_compat52
+local has_metamethod_le_emulated = _VERSION <= 'Lua 5.3' or profile.compat53
+local has_metamethod_pairs = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_metamethod_tostring53 = _VERSION >= 'Lua 5.3'
+local has_metamethod_tostring54 = _VERSION >= 'Lua 5.4'
+local has_anno_toclose = _VERSION >= 'Lua 5.4'
+
+plan'no_plan'
+
+do
+    local t = {}
+    is(getmetatable(t), nil, "metatable")
+    local t1 = {}
+    is(setmetatable(t, t1), t)
+    is(getmetatable(t), t1)
+    is(setmetatable(t, nil), t)
+    error_like(function () setmetatable(t, true) end,
+               "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected")
+
+    local mt = {}
+    mt.__metatable = "not your business"
+    setmetatable(t, mt)
+    is(getmetatable(t), "not your business", "protected metatable")
+    error_like(function () setmetatable(t, {}) end,
+               "^[^:]+:%d+: cannot change a protected metatable")
+
+    is(getmetatable('').__index, string, "metatable for string")
+
+    is(getmetatable(nil), nil, "metatable for nil")
+    is(getmetatable(false), nil, "metatable for boolean")
+    is(getmetatable(2), nil, "metatable for number")
+    is(getmetatable(print), nil, "metatable for function")
+end
+
+do
+    local t = {}
+    local mt = { __tostring=function () return '__TABLE__' end }
+    setmetatable(t, mt)
+    is(tostring(t), '__TABLE__', "__tostring")
+end
+
+do
+    local t = {}
+    local mt = {}
+    local a = nil
+    function mt.__tostring () a = "return nothing" end
+    setmetatable(t, mt)
+    if has_metamethod_tostring53 then
+        error_like(function () tostring(t) end,
+                   "^[^:]+:%d+: '__tostring' must return a string")
+        is(a, "return nothing")
+        if has_metamethod_tostring54 then
+            error_like(function () print(t) end,
+                       "^[^:]+:%d+: '__tostring' must return a string")
+        else
+            error_is(function () print(t) end,
+                     "'__tostring' must return a string")
+        end
+    else
+        is(tostring(t), nil, "__tostring no-output")
+        is(a, "return nothing")
+        error_like(function () print(t) end,
+                   "^[^:]+:%d+: 'tostring' must return a string to 'print'")
+    end
+
+    mt.__tostring = function () return '__FIRST__', 2 end
+    setmetatable(t, mt)
+    is(tostring(t), '__FIRST__', "__tostring too-many-output")
+end
+
+do
+    local t = {}
+    t.mt = {}
+    setmetatable(t, t.mt)
+    t.mt.__tostring = "not a function"
+    error_like(function () tostring(t) end,
+               "attempt to call",
+               "__tostring invalid")
+end
+
+do
+    local t = {}
+    local mt = { __len=function () return 42 end }
+    setmetatable(t, mt)
+    if has_metamethod52 then
+        is(#t, 42, "__len")
+    else
+        is(#t, 0, "__len 5.1")
+    end
+end
+
+if has_metamethod52 then
+    local t = {}
+    local mt = { __len=function () return nil end }
+    setmetatable(t, mt)
+    if jit then
+        todo("not with LuaJIT")
+    end
+    error_like(function () print(table.concat(t)) end,
+               "object length is not a.-er",
+               "__len invalid")
+end
+
+do
+    local t = {}
+    local mt = {
+        __tostring=function () return 't' end,
+        __concat=function (op1, op2)
+            return tostring(op1) .. '|' .. tostring(op2)
+        end,
+    }
+    setmetatable(t, mt)
+    is(t .. t .. t ..'end' .. '.', "t|t|t|end.", "__concat")
+end
+
+do --[[ Cplx ]]
+    local Cplx = {}
+    Cplx.mt = {}
+    local tointeger = math.tointeger or math.floor
+
+    function Cplx.new (re, im)
+        local c = {}
+        setmetatable(c, Cplx.mt)
+        c.re = tonumber(re)
+        if im == nil then
+            c.im = 0.0
+        else
+            c.im = tonumber(im)
+        end
+        return c
+    end
+
+    function Cplx.mt.__tostring (c)
+        return '(' .. tostring(tointeger(c.re)) .. ',' .. tostring(tointeger(c.im)) .. ')'
+    end
+
+    function Cplx.mt.__add (a, b)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        if type(b) ~= 'table' then
+            b = Cplx.new(b, 0)
+        end
+        local r = Cplx.new(a.re + b.re, a.im + b.im)
+        return r
+    end
+
+    local c1 = Cplx.new(1, 3)
+    local c2 = Cplx.new(2, -1)
+
+    is(tostring(c1 + c2), '(3,2)', "cplx __add")
+    is(tostring(c1 + 3), '(4,3)')
+    is(tostring(-2 + c1), '(-1,3)')
+    is(tostring(c1 + '3'), '(4,3)')
+    is(tostring('-2' + c1), '(-1,3)')
+
+    function Cplx.mt.__sub (a, b)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        if type(b) ~= 'table' then
+            b = Cplx.new(b, 0)
+        end
+        local r = Cplx.new(a.re - b.re, a.im - b.im)
+        return r
+    end
+
+    is(tostring(c1 - c2), '(-1,4)', "cplx __sub")
+    is(tostring(c1 - 3), '(-2,3)')
+    is(tostring(-2 - c1), '(-3,-3)')
+    is(tostring(c1 - '3'), '(-2,3)')
+    is(tostring('-2' - c1), '(-3,-3)')
+
+    function Cplx.mt.__mul (a, b)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        if type(b) ~= 'table' then
+            b = Cplx.new(b, 0)
+        end
+        local r = Cplx.new(a.re*b.re - a.im*b.im,
+            a.re*b.im + a.im*b.re)
+        return r
+    end
+
+    is(tostring(c1 * c2), '(5,5)', "cplx __mul")
+    is(tostring(c1 * 3), '(3,9)')
+    is(tostring(-2 * c1), '(-2,-6)')
+    is(tostring(c1 * '3'), '(3,9)')
+    is(tostring('-2' * c1), '(-2,-6)')
+
+    function Cplx.mt.__div (a, b)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        if type(b) ~= 'table' then
+            b = Cplx.new(b, 0)
+        end
+        local n = b.re*b.re + b.im*b.im
+        local inv = Cplx.new(b.re/n, b.im/n)
+        local r = Cplx.new(a.re*inv.re - a.im*inv.im,
+                           a.re*inv.im + a.im*inv.re)
+        return r
+    end
+
+    c1 = Cplx.new(2, 6)
+    c2 = Cplx.new(2, 0)
+
+    is(tostring(c1 / c2), '(1,3)', "cplx __div")
+    is(tostring(c1 / 2), '(1,3)')
+    is(tostring(-4 / c2), '(-2,0)')
+    is(tostring(c1 / '2'), '(1,3)')
+    is(tostring('-4' / c2), '(-2,0)')
+
+    function Cplx.mt.__unm (a)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        local r = Cplx.new(-a.re, -a.im)
+        return r
+    end
+
+    c1 = Cplx.new(1, 3)
+    is(tostring(- c1), '(-1,-3)', "cplx __unm")
+
+    function Cplx.mt.__len (a)
+        return math.sqrt(a.re*a.re + a.im*a.im)
+    end
+
+    c1 = Cplx.new(3, 4)
+    if has_metamethod52 then
+        is( #c1, 5, "cplx __len")
+    else
+        is( #c1, 0, "__len 5.1")
+    end
+
+    function Cplx.mt.__eq (a, b)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        if type(b) ~= 'table' then
+            b = Cplx.new(b, 0)
+        end
+        return (a.re == b.re) and (b.im == b.im)
+    end
+
+    c1 = Cplx.new(2, 0)
+    c2 = Cplx.new(1, 3)
+    local c3 = Cplx.new(2, 0)
+
+    is(c1 ~= c2, true, "cplx __eq")
+    is(c1 == c3, true)
+    is(c1 == 2, false)
+    is(Cplx.mt.__eq(c1, 2), true)
+
+    function Cplx.mt.__lt (a, b)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        if type(b) ~= 'table' then
+            b = Cplx.new(b, 0)
+        end
+        local ra = a.re*a.re + a.im*a.im
+        local rb = b.re*b.re + b.im*b.im
+        return ra < rb
+    end
+
+    is(c1 < c2, true, "cplx __lt")
+    is(c1 < c3, false)
+    if has_metamethod_le_emulated then
+        is(c1 <= c3, true)
+    end
+    if has_metamethod52 then
+        is(c1 < 1, false)
+        is(c1 < 4, true)
+    end
+
+    function Cplx.mt.__le (a, b)
+        if type(a) ~= 'table' then
+            a = Cplx.new(a, 0)
+        end
+        if type(b) ~= 'table' then
+            b = Cplx.new(b, 0)
+        end
+        local ra = a.re*a.re + a.im*a.im
+        local rb = b.re*b.re + b.im*b.im
+        return ra <= rb
+    end
+
+    is(c1 < c2, true, "cplx __lt __le")
+    is(c1 < c3, false)
+    is(c1 <= c3, true)
+
+    local a = nil
+    function Cplx.mt.__call (obj)
+        a = "Cplx.__call " .. tostring(obj)
+        return true
+    end
+
+    c1 = Cplx.new(2, 0)
+    local r = c1()
+    is(r, true, "cplx __call (without args)")
+    is(a, "Cplx.__call (2,0)")
+
+    function Cplx.mt.__call (obj, ...)
+        a = "Cplx.__call " .. tostring(obj) .. ", " .. table.concat({...}, ", ")
+        return true
+    end
+
+    is(c1(), true, "cplx __call (with args)")
+    is(a, "Cplx.__call (2,0), ")
+    is(c1('a'), true)
+    is(a, "Cplx.__call (2,0), a")
+    is(c1('a', 'b', 'c'), true)
+    is(a, "Cplx.__call (2,0), a, b, c")
+end
+
+--[[ delegate ]]
+if has_metamethod_pairs then
+    local t = {
+        _VALUES = {
+            a = 1,
+            b = 'text',
+            c = true,
+        }
+    }
+    local mt = {
+        __pairs = function (op)
+            return next, op._VALUES
+        end
+    }
+    setmetatable(t, mt)
+
+    local r = {}
+    for k in pairs(t) do
+        r[#r+1] = k
+    end
+    table.sort(r)
+    is( table.concat(r, ','), 'a,b,c', "__pairs" )
+end
+if has_metamethod_ipairs then
+    local t = {
+        _VALUES = { 'a', 'b', 'c' }
+    }
+    local mt = {
+        __ipairs = function (op)
+            return ipairs(op._VALUES)
+        end
+    }
+    setmetatable(t, mt)
+
+    local r = ''
+    for i, v in ipairs(t) do
+        r = r .. v
+    end
+    is( r, 'abc', "__ipairs" )
+end
+
+do --[[ Window ]]
+    -- create a namespace
+    local Window = {}
+    -- create a prototype with default values
+    Window.prototype = {x=0, y=0, width=100, heigth=100, }
+    -- create a metatable
+    Window.mt = {}
+    -- declare the constructor function
+    function Window.new (o)
+        setmetatable(o, Window.mt)
+        return o
+    end
+
+    Window.mt.__index = function (table, key)
+        return Window.prototype[key]
+    end
+
+    local w = Window.new{x=10, y=20}
+    is(w.x, 10, "table-access")
+    is(w.width, 100)
+    is(rawget(w, 'x'), 10)
+    is(rawget(w, 'width'), nil)
+
+    Window.mt.__index = Window.prototype  -- just a table
+    w = Window.new{x=10, y=20}
+    is(w.x, 10, "table-access")
+    is(w.width, 100)
+    is(rawget(w, 'x'), 10)
+    is(rawget(w, 'width'), nil)
+end
+
+do --[[ tables with default values ]]
+    local function setDefault_1 (t, d)
+        local mt = {__index = function () return d end}
+        setmetatable (t, mt)
+    end
+
+    local tab = {x=10, y=20}
+    is(tab.x, 10, "tables with default values")
+    is(tab.z, nil)
+    setDefault_1(tab, 0)
+    is(tab.x, 10)
+    is(tab.z, 0)
+end
+
+do --[[ tables with default values ]]
+    local mt = {__index = function (t) return t.___ end}
+    local function setDefault_2 (t, d)
+        t.___ = d
+        setmetatable (t, mt)
+    end
+
+    local tab = {x=10, y=20}
+    is(tab.x, 10, "tables with default values")
+    is(tab.z, nil)
+    setDefault_2(tab, 0)
+    is(tab.x, 10)
+    is(tab.z, 0)
+end
+
+do --[[ tables with default values ]]
+    local key = {}
+    local mt = {__index = function (t) return t[key] end}
+    local function setDefault_3 (t, d)
+        t[key] = d
+        setmetatable (t, mt)
+    end
+
+    local tab = {x=10, y=20}
+    is(tab.x, 10, "tables with default values")
+    is(tab.z, nil)
+    setDefault_3(tab, 0)
+    is(tab.x, 10)
+    is(tab.z, 0)
+end
+
+do --[[ private access ]]
+    local t = {}  -- original table
+    -- keep a private access to original table
+    local _t = t
+    -- create proxy
+    t = {}
+
+    local w = nil
+    local r = nil
+    -- create metatable
+    local mt = {
+        __index = function (t,k)
+            r = "*access to element " .. tostring(k)
+            return _t[k]  -- access the original table
+        end,
+
+        __newindex = function (t,k,v)
+             w = "*update of element " .. tostring(k) ..
+                                " to " .. tostring(v)
+            _t[k] = v  -- update original table
+        end
+    }
+    setmetatable(t, mt)
+
+    t[2] = 'hello'
+    is(t[2], 'hello', "tracking table accesses")
+    is(w, "*update of element 2 to hello")
+    is(r, "*access to element 2")
+end
+
+do --[[ private access ]]
+    -- create private index
+    local index = {}
+
+    local w = nil
+    local r = nil
+    -- create metatable
+    local mt = {
+        __index = function (t,k)
+            r = "*access to element " .. tostring(k)
+            return t[index][k]  -- access the original table
+        end,
+
+        __newindex = function (t,k,v)
+            w = "*update of element " .. tostring(k) ..
+                               " to " .. tostring(v)
+            t[index][k] = v  -- update original table
+        end
+    }
+    local function track (t)
+        local proxy = {}
+        proxy[index] = t
+        setmetatable(proxy, mt)
+        return proxy
+    end
+
+    local t = {}
+    t = track(t)
+
+    t[2] = 'hello'
+    is(t[2], 'hello', "tracking table accesses")
+    is(w, "*update of element 2 to hello")
+    is(r, "*access to element 2")
+end
+
+do --[[ read-only table ]]
+    local function readOnly (t)
+        local proxy = {}
+        local mt = {
+            __index = t,
+            __newindex = function (_t,k,v)
+                error("attempt to update a read-only table", 2)
+            end
+        }
+        setmetatable(proxy, mt)
+        return proxy
+    end
+
+    local days = readOnly{'Sunday', 'Monday', 'Tuesday', 'Wednesday',
+                         'Thurday', 'Friday', 'Saturday'}
+
+    is(days[1], 'Sunday', "read-only tables")
+
+    error_like(function () days[2] = 'Noday' end,
+               "^[^:]+:%d+: attempt to update a read%-only table")
+end
+
+do --[[ declare global ]]
+    local function declare (name, initval)
+        rawset(_G, name, initval or false)
+    end
+
+    setmetatable(_G, {
+        __newindex = function (_, n)
+            error("attempt to write to undeclared variable " .. n, 2)
+        end,
+        __index = function (_, n)
+            error("attempt to read undeclared variable" .. n, 2)
+        end,
+    })
+
+    error_like(function () new_a = 1 end,
+               "^[^:]+:%d+: attempt to write to undeclared variable new_a",
+               "declaring global variables")
+
+    declare 'new_a'
+    new_a = 1
+    is(new_a, 1)
+end
+
+do
+    local newindex = {}
+    -- create metatable
+    local mt = {
+        __newindex = newindex
+    }
+    local t = setmetatable({}, mt)
+    t[1] = 42
+    is(newindex[1], 42, "__newindex")
+end
+
+if has_anno_toclose then
+    dofile'lexico54/metatable.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/232-object.t b/test/lua-Harness-tests/232-object.t
new file mode 100755
index 0000000..0d87572
--- /dev/null
+++ b/test/lua-Harness-tests/232-object.t
@@ -0,0 +1,314 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua object
+
+=head2 Synopsis
+
+    % prove 232-object.t
+
+=head2 Description
+
+See section "Object-Oriented Programming" in "Programming in Lua".
+
+=cut
+
+--]]
+
+require'tap'
+
+plan(18)
+
+do --[[ object ]]
+    local Account = {balance = 0}
+
+    function Account.withdraw (self, v)
+        self.balance = self.balance - v
+    end
+
+    local a1 = Account; Account = nil
+    a1.withdraw(a1, 100.00)
+    is(a1.balance, -100, "object")
+
+    local a2 = {balance = 0, withdraw = a1.withdraw}
+    a2.withdraw(a2, 260.00)
+    is(a2.balance, -260)
+end
+
+do --[[ object ]]
+    local Account = {balance = 0}
+
+    function Account:withdraw (v)
+        self.balance = self.balance - v
+    end
+
+    local a = Account
+    a:withdraw(100.00)
+    is(a.balance, -100, "object")
+
+    Account = { balance = 0,
+                withdraw = function (self, v)
+                               self.balance = self.balance -v
+                           end
+              }
+    function Account:deposit (v)
+        self.balance = self.balance + v
+    end
+
+    Account.deposit(Account, 200.00)
+    is(Account.balance, 200, "object")
+    Account:withdraw(100.00)
+    is(Account.balance, 100)
+end
+
+do --[[ class ]]
+    local Account = {balance = 0}
+
+    function Account:new (o)
+        o = o or {}
+        setmetatable(o, self)
+        self.__index = self
+        return o
+    end
+
+    function Account:deposit (v)
+        self.balance = self.balance + v
+    end
+
+    function Account:withdraw (v)
+        self.balance = self.balance - v
+    end
+
+    local a = Account:new{balance = 0}
+    a:deposit(100.00)
+    is(a.balance, 100, "classe")
+
+    local b = Account:new()
+    is(b.balance, 0)
+    b:deposit(200.00)
+    is(b.balance, 200)
+end
+
+do --[[ inheritance ]]
+    local Account = {balance = 0}
+
+    function Account:new (o)
+    --    print "Account:new"
+        o = o or {}
+        setmetatable(o, self)
+        self.__index = self
+        return o
+    end
+
+    function Account:deposit (v)
+    --    print "Account:deposit"
+        self.balance = self.balance + v
+    end
+
+    function Account:withdraw (v)
+    --    print "Account:withdraw"
+        if v > self.balance then error"insuficient funds" end
+        self.balance = self.balance - v
+    end
+
+    local a = Account:new()
+    is(a.balance, 0, "inheritance")
+    -- r, msg = pcall(Account.withdraw, a, 100)
+    -- print(msg)
+
+    local SpecialAccount = Account:new()
+
+    function SpecialAccount:withdraw (v)
+    --    print "SpecialAccount:withdraw"
+        if self.balance - v <= -self:getLimit() then
+            error"insuficient funds"
+        end
+        self.balance = self.balance - v
+    end
+
+    function SpecialAccount:getLimit ()
+    --    print "SpecialAccount:getLimit"
+        return self.limit or 0
+    end
+
+    local s = SpecialAccount:new{limit=1000.00}
+
+    s:deposit(100.00)
+    is(s.balance, 100)
+
+    s:withdraw(200.00)
+    is(s.balance, -100)
+end
+
+do --[[ multiple inheritance ]]
+    -- look up for 'k' in list of tables 'plist'
+    local function search (k, plist)
+        for i=1, #plist do
+            local v = plist[i][k]  -- try 'i'-th superclass
+            if v then return v end
+        end
+    end
+
+    local function createClass (...)
+        local c = {}  -- new class
+        local arg = {...}
+
+        -- class will search for each method in the list of its
+        -- parents ('arg' is the list of parents)
+        setmetatable(c, {__index = function (t, k)
+            return search(k, arg)
+        end})
+
+        -- prepare 'c' to be the metatable of its instance
+        c.__index = c
+
+        -- define a new constructor for this new class
+        function c:new (o)
+            o = o or {}
+            setmetatable(o, c)
+            return o
+        end
+
+        -- return new class
+        return c
+    end
+
+    local Account = {balance = 0}
+    function Account:deposit (v)
+        self.balance = self.balance + v
+    end
+    function Account:withdraw (v)
+        self.balance = self.balance - v
+    end
+
+    local Named = {}
+    function Named:getname ()
+        return self.name
+    end
+    function Named:setname (n)
+        self.name = n
+    end
+
+    local NamedAccount = createClass(Account, Named)
+
+    local account = NamedAccount:new{name = "Paul"}
+    is(account:getname(), 'Paul', "multiple inheritance")
+    account:deposit(100.00)
+    is(account.balance, 100)
+end
+
+do --[[ multiple inheritance (patched) ]]
+    -- look up for 'k' in list of tables 'plist'
+    local function search (k, plist)
+        for i=1, #plist do
+            local v = plist[i][k]  -- try 'i'-th superclass
+            if v then return v end
+        end
+    end
+
+    local function createClass (...)
+        local c = {}  -- new class
+        local arg = {...}
+
+        -- class will search for each method in the list of its
+        -- parents ('arg' is the list of parents)
+        setmetatable(c, {__index = function (t, k)
+            -- return search(k, arg)
+            return (search(k, arg))
+        end})
+
+        -- prepare 'c' to be the metatable of its instance
+        c.__index = c
+
+        -- define a new constructor for this new class
+        function c:new (o)
+            o = o or {}
+            setmetatable(o, c)
+            return o
+        end
+
+        -- return new class
+        return c
+    end
+
+    local Account = {balance = 0}
+    function Account:deposit (v)
+        self.balance = self.balance + v
+    end
+    function Account:withdraw (v)
+        self.balance = self.balance - v
+    end
+
+    local Named = {}
+    function Named:getname ()
+        return self.name
+    end
+    function Named:setname (n)
+        self.name = n
+    end
+
+    local NamedAccount = createClass(Account, Named)
+
+    local account = NamedAccount:new{name = "Paul"}
+    is(account:getname(), 'Paul', "multiple inheritance (patched)")
+    account:deposit(100.00)
+    is(account.balance, 100)
+end
+
+do --[[ privacy ]]
+    local function newAccount (initialBalance)
+        local self = {balance = initialBalance}
+
+        local withdraw = function (v)
+                             self.balance = self.balance - v
+                         end
+
+        local deposit = function (v)
+                            self.balance = self.balance + v
+                        end
+
+        local getBalance = function () return self.balance end
+
+        return {
+            withdraw = withdraw,
+            deposit = deposit,
+            getBalance = getBalance
+        }
+    end
+
+    local acc1 = newAccount(100.00)
+    acc1.withdraw(40.00)
+    is(acc1.getBalance(), 60, "privacy")
+end
+
+do --[[ single-method approach ]]
+    local function newObject (value)
+        return function (action, v)
+            if action == 'get' then return value
+            elseif action == 'set' then value = v
+            else error("invalid action")
+            end
+        end
+    end
+
+    local d = newObject(0)
+    is(d('get'), 0, "single-method approach")
+    d('set', 10)
+    is(d('get'), 10)
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/241-standalone.t b/test/lua-Harness-tests/241-standalone.t
new file mode 100755
index 0000000..c5237ee
--- /dev/null
+++ b/test/lua-Harness-tests/241-standalone.t
@@ -0,0 +1,269 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Stand-alone
+
+=head2 Synopsis
+
+    % prove 241-standalone.t
+
+=head2 Description
+
+See section "Lua Stand-alone" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#6>,
+L<https://www.lua.org/manual/5.2/manual.html#7>,
+L<https://www.lua.org/manual/5.3/manual.html#7>,
+L<https://www.lua.org/manual/5.4/manual.html#7>
+
+=cut
+
+--]]
+
+require'tap'
+local has_bytecode = not ujit and not ravi
+local has_error52 = _VERSION >= 'Lua 5.2'
+local has_error53 = _VERSION >= 'Lua 5.3'
+local has_opt_E = _VERSION >= 'Lua 5.2' or jit
+local has_opt_W = _VERSION >= 'Lua 5.4'
+local banner = '^[%w%s%-%.]-Copyright %(C%) %d%d%d%d'
+if jit and jit.version:match'^RaptorJIT' then
+    banner = '^[%w%s%.]- %-%- '
+elseif ravi then
+    banner = '^Ravi %d%.%d%.%d'
+end
+
+local lua = get_lua_binary_name()
+local luac = jit and lua or (lua .. 'c')
+
+if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
+    skip_all "io.popen not supported"
+end
+
+plan'no_plan'
+diag(lua)
+
+local f = io.open('hello-241.lua', 'w')
+f:write([[
+print 'Hello World'
+]])
+f:close()
+
+local cmd = lua .. " hello-241.lua"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "file")
+f:close()
+
+cmd = lua .. " -- hello-241.lua"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "-- file")
+f:close()
+
+cmd = lua .. " no_file-241.lua 2>&1"
+f = io.popen(cmd)
+like(f:read'*l', "^[^:]+: cannot open no_file%-241%.lua", "no file")
+f:close()
+
+if has_bytecode then
+    if jit then
+        os.execute(lua .. " -b hello-241.lua hello-241.luac")
+    else
+        os.execute(luac .. " -s -o hello-241.luac hello-241.lua")
+    end
+    cmd = lua .. " hello-241.luac"
+    f = io.popen(cmd)
+    is(f:read'*l', 'Hello World', "bytecode")
+    f:close()
+    os.remove('hello-241.luac') -- clean up
+
+    if not jit then
+        os.execute(luac .. " -s -o hello-hello-241.luac hello-241.lua hello-241.lua")
+        cmd = lua .. " hello-hello-241.luac"
+        f = io.popen(cmd)
+        is(f:read'*l', 'Hello World', "combine 1")
+        is(f:read'*l', 'Hello World', "combine 2")
+        f:close()
+        os.remove('hello-hello-241.luac') -- clean up
+    end
+end
+
+cmd = lua .. " < hello-241.lua"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "redirect")
+f:close()
+
+cmd = lua .. " - < hello-241.lua"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "redirect")
+f:close()
+
+cmd = lua .. " -i hello-241.lua < hello-241.lua 2>&1"
+f = io.popen(cmd)
+like(f:read'*l', banner, "-i")
+if ujit then
+    like(f:read'*l', '^JIT:')
+end
+if ravi then
+    like(f:read'*l', '^Copyright %(C%)')
+    like(f:read'*l', '^Portions Copyright %(C%)')
+    like(f:read'*l', '^Options')
+end
+is(f:read'*l', 'Hello World')
+f:close()
+
+cmd = lua .. [[ -e"a=1" -e "print(a)"]]
+f = io.popen(cmd)
+is(f:read'*l', '1', "-e")
+f:close()
+
+cmd = lua .. [[ -e "error('msg')"  2>&1]]
+f = io.popen(cmd)
+is(f:read'*l', lua .. [[: (command line):1: msg]], "error")
+is(f:read'*l', "stack traceback:", "backtrace")
+f:close()
+
+cmd = lua .. [[ -e "error(setmetatable({}, {__tostring=function() return 'MSG' end}))"  2>&1]]
+f = io.popen(cmd)
+if has_error52 or jit then
+    is(f:read'*l', lua .. [[: MSG]], "error with object")
+else
+    is(f:read'*l', lua .. [[: (error object is not a string)]], "error with object")
+end
+if jit then
+    is(f:read'*l', "stack traceback:", "backtrace")
+else
+    is(f:read'*l', nil, "not backtrace")
+end
+f:close()
+
+cmd = lua .. [[ -e "error{}"  2>&1]]
+f = io.popen(cmd)
+if has_error53 then
+    is(f:read'l', lua .. [[: (error object is a table value)]], "error")
+    is(f:read'l', "stack traceback:", "backtrace")
+elseif has_error52 then
+    is(f:read'*l', lua .. [[: (no error message)]], "error")
+    is(f:read'*l', nil, "not backtrace")
+else
+    is(f:read'*l', lua .. [[: (error object is not a string)]], "error")
+    is(f:read'*l', nil, "not backtrace")
+end
+f:close()
+
+cmd = lua .. [[ -e"a=1" -e "print(a)" hello-241.lua]]
+f = io.popen(cmd)
+is(f:read'*l', '1', "-e & script")
+is(f:read'*l', 'Hello World')
+f:close()
+
+cmd = lua .. [[ -e"a=1" -i < hello-241.lua 2>&1]]
+f = io.popen(cmd)
+like(f:read'*l', banner, "-e & -i")
+f:close()
+
+cmd = lua .. [[ -e "?syntax error?" 2>&1]]
+f = io.popen(cmd)
+like(f:read'*l', "^.-%d: unexpected symbol near '%?'", "-e bad")
+f:close()
+
+cmd = lua .. [[ -e 2>&1]]
+f = io.popen(cmd)
+if _VERSION ~= 'Lua 5.1' then
+    like(f:read'*l', "^[^:]+: '%-e' needs argument", "no file")
+end
+like(f:read'*l', "^usage: ", "no file")
+f:close()
+
+cmd = lua .. [[ -v 2>&1]]
+f = io.popen(cmd)
+like(f:read'*l', banner, "-v")
+f:close()
+
+cmd = lua .. [[ -v hello-241.lua 2>&1]]
+f = io.popen(cmd)
+like(f:read'*l', banner, "-v & script")
+if ravi then
+    like(f:read'*l', '^Copyright %(C%)')
+    like(f:read'*l', '^Portions Copyright %(C%)')
+    like(f:read'*l', '^Options')
+end
+is(f:read'*l', 'Hello World')
+f:close()
+
+cmd = lua .. [[ -v -- 2>&1]]
+f = io.popen(cmd)
+like(f:read'*l', banner, "-v --")
+f:close()
+
+if has_opt_E then
+    cmd = lua .. [[ -E hello-241.lua 2>&1]]
+    f = io.popen(cmd)
+    is(f:read'*l', 'Hello World', "-E")
+    f:close()
+else
+    diag("no -E")
+end
+
+cmd = lua .. [[ -u 2>&1]]
+f = io.popen(cmd)
+if _VERSION ~= 'Lua 5.1' then
+    like(f:read'*l', "^[^:]+: unrecognized option '%-u'", "unknown option")
+end
+like(f:read'*l', "^usage: ", "no file")
+f:close()
+
+cmd = lua .. [[ --u 2>&1]]
+f = io.popen(cmd)
+if _VERSION ~= 'Lua 5.1' then
+    like(f:read'*l', "^[^:]+: unrecognized option '%-%-u'", "unknown option")
+end
+like(f:read'*l', "^usage: ", "no file")
+f:close()
+
+cmd = lua .. [[ -ltap -e "print(type(ok))"]]
+f = io.popen(cmd)
+is(f:read'*l', 'function', "-ltap")
+f:close()
+
+cmd = lua .. [[ -l tap -e "print(type(ok))"]]
+f = io.popen(cmd)
+is(f:read'*l', 'function', "-l tap")
+f:close()
+
+cmd = lua .. [[ -l lpeg -e "print(1)" 2>&1]]
+f = io.popen(cmd)
+isnt(f:read'*l', nil, "-l lpeg")
+f:close()
+
+cmd = lua .. [[ -l no_lib hello-241.lua 2>&1]]
+f = io.popen(cmd)
+like(f:read'*l', "^[^:]+: module 'no_lib' not found:", "-l no lib")
+f:close()
+
+if has_opt_W then
+    cmd = lua .. [[ -W -e "warn'foo'" 2>&1]]
+    f = io.popen(cmd)
+    is(f:read'*l', 'Lua warning: foo', "-W")
+    is(f:read'*l', nil)
+    f:close()
+else
+    diag("no -W")
+end
+
+os.remove('hello-241.lua') -- clean up
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/242-luac.t b/test/lua-Harness-tests/242-luac.t
new file mode 100755
index 0000000..a95a334
--- /dev/null
+++ b/test/lua-Harness-tests/242-luac.t
@@ -0,0 +1,341 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2010-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Stand-alone
+
+=head2 Synopsis
+
+    % prove t/242-luac.t
+
+=head2 Description
+
+See section "Lua Stand-alone" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#6>,
+L<https://www.lua.org/manual/5.2/manual.html#7>,
+L<https://www.lua.org/manual/5.3/manual.html#7>,
+L<https://www.lua.org/manual/5.4/manual.html#7>
+
+=cut
+
+--]]
+
+require'tap'
+
+if jit then
+    skip_all("LuaJIT")
+end
+
+if ravi then
+    skip_all("ravi")
+end
+
+local lua = get_lua_binary_name()
+local luac = lua .. 'c'
+
+if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
+    skip_all "io.popen not supported"
+end
+
+plan'no_plan'
+diag(luac)
+
+local signature = "\x1bLua"
+local bin_version
+if     _VERSION == 'Lua 5.1' then
+    bin_version = "\x51"
+elseif _VERSION == 'Lua 5.2' then
+    bin_version = "\x52"
+elseif _VERSION == 'Lua 5.3' then
+    bin_version = "\x53"
+elseif _VERSION == 'Lua 5.4' then
+    bin_version = "\x54"
+end
+local format = "\x00"
+local data = "\x19\x93\r\n\x1a\n"
+local size_i = string.char(string.packsize and string.packsize'i' or 0) -- int
+local size_T = string.char(string.packsize and string.packsize'T' or 0) -- size_t
+local size_I = string.char(string.packsize and string.packsize'I' or 0) -- Instruction
+local size_j = string.char(string.packsize and string.packsize'j' or 0) -- lua_Integer
+local size_n = string.char(string.packsize and string.packsize'n' or 0) -- lua_Number
+local sizes = size_i .. size_T .. size_I .. size_j .. size_n
+
+do -- hello.lua
+    local f = io.open('hello-242.lua', 'w')
+    f:write([[
+print 'Hello World'
+]])
+    f:close()
+end
+
+do -- luac -v
+    local cmd = luac .. [[ -v 2>&1]]
+    local f = io.popen(cmd)
+    like(f:read'*l', '^Lua', "-v")
+    f:close()
+end
+
+do -- luac -v --
+    local cmd = luac .. [[ -v -- 2>&1]]
+    local f = io.popen(cmd)
+    like(f:read'*l', '^Lua', "-v --")
+    f:close()
+end
+
+do -- luac -u
+    local cmd = luac .. [[ -u 2>&1]]
+    local f = io.popen(cmd)
+    like(f:read'*l', "^[^:]+: unrecognized option '%-u'", "unknown option")
+    like(f:read'*l', "^usage:")
+    f:close()
+end
+
+do -- luac --u
+    local cmd = luac .. [[ --u 2>&1]]
+    local f = io.popen(cmd)
+    like(f:read'*l', "^[^:]+: unrecognized option '%-%-u'", "unknown option")
+    like(f:read'*l', "^usage:")
+    f:close()
+end
+
+do -- luac -p hello-242.lua
+    local cmd = luac .. [[ -p hello-242.lua 2>&1]]
+    local f = io.popen(cmd)
+    is(f:read'*l', nil)
+    f:close()
+end
+
+do -- luac -p - < hello-242.lua
+    local cmd = luac .. [[ -p - < hello-242.lua 2>&1]]
+    local f = io.popen(cmd)
+    is(f:read'*l', nil)
+    f:close()
+end
+
+do -- luac -p no_file-242.lua
+    local cmd = luac .. [[ -p no_file-242.lua 2>&1]]
+    local f = io.popen(cmd)
+    like(f:read'*l', "^[^:]+: cannot open no_file%-242%.lua", "no file")
+    f:close()
+end
+
+do -- luac -o
+    local cmd = luac .. [[ -o 2>&1]]
+    local f = io.popen(cmd)
+    like(f:read'*l', "^[^:]+: '%-o' needs argument", "-o needs argument")
+    f:close()
+end
+
+do -- luac -v -l -l hello-242.lua
+    local cmd = luac .. [[ -v -l -l hello-242.lua]]
+    local f = io.popen(cmd)
+    like(f:read'*l', '^Lua', "-v -l -l")
+    is(f:read'*l', '')
+    like(f:read'*l', "^main")
+    f:close()
+end
+
+os.remove('hello-242.lua') -- clean up
+
+do -- luac -l luac.out
+    local cmd = luac .. [[ -l luac.out]]
+    local f = io.popen(cmd)
+    is(f:read'*l', '', "-l luac.out")
+    like(f:read'*l', "^main")
+    f:close()
+end
+
+do -- luac -l
+    local cmd = luac .. [[ -l]]
+    local f = io.popen(cmd)
+    is(f:read'*l', '', "-l")
+    like(f:read'*l', "^main")
+    f:close()
+end
+
+do -- luac -l - < luac.out
+    local cmd = luac .. [[ -l - < luac.out]]
+    local f = io.popen(cmd)
+    is(f:read'*l', '', "-l -")
+    like(f:read'*l', "^main")
+    f:close()
+end
+
+if _VERSION ~= 'Lua 5.1' then
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. format)
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    if _VERSION <= 'Lua 5.3' then
+        like(f:read'*l', "truncated precompiled chunk")
+    else
+        like(f:read'*l', "bad binary format %(truncated chunk%)")
+    end
+    f:close()
+end
+
+if _VERSION ~= 'Lua 5.1' then -- bad signature
+    local f = io.open('luac.out', 'w')
+    f:write("\x1bFoo" .. bin_version .. format .. data .. sizes .. "Foo")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    if _VERSION <= 'Lua 5.3' then
+        like(f:read'*l', "not a precompiled chunk", "bad signature")
+    else
+        like(f:read'*l', "bad binary format %(not a binary chunk%)", "bad signature")
+    end
+    f:close()
+end
+
+if _VERSION ~= 'Lua 5.1' then -- bad version
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. "\x51" .. format .. data .. sizes .. "Foo")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    if _VERSION <= 'Lua 5.3' then
+        like(f:read'*l', "version mismatch in precompiled chunk", "bad version")
+    else
+        like(f:read'*l', "bad binary format %(version mismatch%)", "bad version")
+    end
+    f:close()
+end
+
+if _VERSION ~= 'Lua 5.1' then -- bad format
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. "\x42" .. data .. sizes .. "Foo")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    if _VERSION == 'Lua 5.2' then
+        like(f:read'*l', "version mismatch in precompiled chunk", "bad format")
+    elseif _VERSION == 'Lua 5.3' then
+        like(f:read'*l', "format mismatch in precompiled chunk", "bad format")
+    else
+        like(f:read'*l', "bad binary format %(format mismatch%)", "bad format")
+    end
+    f:close()
+end
+
+if _VERSION == 'Lua 5.2' then -- bad sizes
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. format .. "\xde\xad\xbe\xef\x00" .. data .. "Foo")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    like(f:read'*l', "incompatible precompiled chunk", "incompatible 5.2")
+    f:close()
+end
+
+if _VERSION == 'Lua 5.2' then -- bad data / tail
+    sizes = string.dump(load "a = 1"):sub(7, 12)
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. format .. sizes .. "\x19\x99\r\n\x1a\n")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    like(f:read'*l', "corrupted precompiled chunk", "corrupted 5.2")
+    f:close()
+end
+
+if _VERSION == 'Lua 5.3' then -- bad data
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. format .. "\x19\x99\r\n\x1a\n" .. sizes)
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    like(f:read'*l', "corrupted precompiled chunk", "corrupted")
+    f:close()
+end
+
+if _VERSION == 'Lua 5.3' then -- bad sizes
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. format .. data .. "\xde\xad\xbe\xef\x00")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    like(f:read'*l', "int size mismatch in precompiled chunk", "bad sizes")
+    f:close()
+end
+
+if _VERSION == 'Lua 5.3' then -- bad endianess
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. format .. data .. sizes .. "\0\0\0\0\0\0\0\0")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    like(f:read'*l', "endianness mismatch in precompiled chunk", "bad endian")
+    f:close()
+end
+
+if _VERSION == 'Lua 5.3' then -- bad float format
+    local endian = string.dump(load "a = 1"):sub(18, 18 + string.packsize'n')
+    local f = io.open('luac.out', 'w')
+    f:write(signature .. bin_version .. format .. data .. sizes .. endian .. "\0\0\0\0\0\0\0\0")
+    f:close()
+    local cmd = luac .. [[ luac.out 2>&1]]
+    f = io.popen(cmd)
+    like(f:read'*l', "float format mismatch in precompiled chunk")
+    f:close()
+end
+
+do -- cover.lua
+    local f = io.open('cover-242.lua', 'w')
+    f:write([[
+local a = false
+b = a + 1
+pi = 3.14
+s = "all escaped \1\a\b\f\n\r\t\v\\\""
+local t = { "a", "b", "c", "d", [true] = 1 }
+local f = table.concat
+local function f ()
+    while true do
+        print(a)
+    end
+end
+local function g (...) -- segfault with Lua 5.4.0-beta
+    return {...}
+end
+s = nil
+]])
+    f:close()
+
+    local cmd = luac .. [[ -o cover-242.out cover-242.lua 2>&1]]
+    f = io.popen(cmd)
+    is(f:read'*l', nil, "-o cover-242.out cover-242.lua")
+    f:close()
+
+    cmd = luac .. [[ -l cover-242.out]]
+    f = io.popen(cmd)
+    is(f:read'*l', '', "-l cover-242.out")
+    like(f:read'*l', "^main")
+    f:close()
+
+    cmd = luac .. [[ -l -l cover-242.out]]
+    f = io.popen(cmd)
+    is(f:read'*l', '', "-l -l cover-242.out")
+    like(f:read'*l', "^main")
+    f:close()
+end
+
+os.remove('luac.out') -- clean up
+os.remove('cover-242.lua') -- clean up
+os.remove('cover-242.out') -- clean up
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/301-basic.t b/test/lua-Harness-tests/301-basic.t
new file mode 100755
index 0000000..f4f9235
--- /dev/null
+++ b/test/lua-Harness-tests/301-basic.t
@@ -0,0 +1,856 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Basic Library
+
+=head2 Synopsis
+
+    % prove 301-basic.t
+
+=head2 Description
+
+Tests Lua Basic Library
+
+See section "Basic Functions" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.1>,
+L<https://www.lua.org/manual/5.2/manual.html#6.1>,
+L<https://www.lua.org/manual/5.3/manual.html#6.1>,
+L<https://www.lua.org/manual/5.4/manual.html#6.1>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local has_error53 = _VERSION >= 'Lua 5.3'
+local has_gcinfo = _VERSION == 'Lua 5.1'
+local has_getfenv = _VERSION == 'Lua 5.1'
+local has_ipairs53 = _VERSION >= 'Lua 5.3'
+local has_load52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_loadfile52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_loadstring = _VERSION == 'Lua 5.1'
+local has_alias_loadstring = profile.compat51
+local has_newproxy = _VERSION == 'Lua 5.1'
+local has_rawlen = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_unpack = _VERSION == 'Lua 5.1'
+local has_alias_unpack = profile.compat51
+local has_warn = _VERSION >= 'Lua 5.4'
+local has_xpcall52 = _VERSION >= 'Lua 5.2' or jit
+local has_xpcall53 = _VERSION >= 'Lua 5.3' or jit
+
+local lua = get_lua_binary_name()
+
+plan'no_plan'
+
+do -- assert
+    local v, msg = assert('text', "assert string")
+    is(v, 'text', "function assert")
+    is(msg, "assert string")
+    v, msg = assert({}, "assert table")
+    is(msg, "assert table")
+
+    error_like(function () assert(false, "ASSERTION TEST") end,
+               "^[^:]+:%d+: ASSERTION TEST",
+               "function assert(false, msg)")
+
+    error_like(function () assert(false) end,
+               "^[^:]+:%d+: assertion failed!",
+               "function assert(false)")
+
+    if has_error53 then
+        v, msg = pcall(function() assert(false, 42) end)
+        is(msg, 42, "function assert(false, 42)")
+    else
+        error_like(function () assert(false, 42) end,
+                   "^[^:]+:%d+: 42",
+                   "function assert(false, 42)")
+    end
+
+    if has_error53 then
+        local obj = {}
+        v, msg = pcall(function() assert(false, obj) end)
+        is(msg, obj, "function assert(false, {})")
+    else
+        diag("no assert with table")
+    end
+end
+
+-- collectgarbage
+if jit then
+    is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'")
+    is(collectgarbage('step'), false)
+    is(collectgarbage('restart'), 0)
+    is(collectgarbage('step'), false)
+    is(collectgarbage('collect'), 0)
+    is(collectgarbage('setpause', 10), 200)
+    is(collectgarbage('setstepmul', 200), 200)
+    is(collectgarbage(), 0)
+elseif _VERSION == 'Lua 5.1' then
+    is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'")
+    is(collectgarbage('restart'), 0)
+    is(collectgarbage('step'), false)
+    is(collectgarbage('collect'), 0)
+    is(collectgarbage(), 0)
+elseif _VERSION == 'Lua 5.2' then
+    is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'")
+    is(collectgarbage('isrunning'), false)
+    is(collectgarbage('step'), false)
+    is(collectgarbage('restart'), 0)
+    is(collectgarbage('isrunning'), true)
+    is(collectgarbage('step'), false)
+    is(collectgarbage('collect'), 0)
+    is(collectgarbage('setpause', 10), 200)
+    is(collectgarbage('setstepmul', 200), 200)
+    is(collectgarbage(), 0)
+    is(collectgarbage('generational'), 0)
+    is(collectgarbage('step'), false)
+    is(collectgarbage('incremental'), 0)
+    is(collectgarbage('setmajorinc'), 200)
+elseif _VERSION == 'Lua 5.3' then
+    is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'")
+    is(collectgarbage('isrunning'), false)
+    --is(collectgarbage('step'), false)
+    type_ok(collectgarbage('step'), 'boolean')
+    is(collectgarbage('restart'), 0)
+    is(collectgarbage('isrunning'), true)
+    is(collectgarbage('step'), false)
+    is(collectgarbage('collect'), 0)
+    is(collectgarbage('setpause', 10), 200)
+    is(collectgarbage('setstepmul', 200), 200)
+    is(collectgarbage(), 0)
+    is(collectgarbage('step'), false)
+elseif _VERSION == 'Lua 5.4' then
+    is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'")
+    is(collectgarbage('isrunning'), false)
+    is(collectgarbage('generational'), 'generational')
+    is(collectgarbage('incremental'), 'generational')
+    is(collectgarbage('incremental'), 'incremental')
+    is(collectgarbage('generational'), 'incremental')
+    is(collectgarbage('step'), false)
+    is(collectgarbage('restart'), 0)
+    is(collectgarbage('isrunning'), true)
+    is(collectgarbage('step'), false)
+    is(collectgarbage('collect'), 0)
+    is(collectgarbage('setpause', 10), 200)
+    is(collectgarbage('setstepmul', 200), 100)
+    is(collectgarbage(), 0)
+    is(collectgarbage('step'), false)
+end
+
+type_ok(collectgarbage('count'), 'number', "function collectgarbage 'count'")
+
+error_like(function () collectgarbage('unknown') end,
+           "^[^:]+:%d+: bad argument #1 to 'collectgarbage' %(invalid option 'unknown'%)",
+           "function collectgarbage (invalid)")
+
+do -- dofile
+    local f = io.open('lib-301.lua', 'w')
+    f:write[[
+function norm (x, y)
+    return (x^2 + y^2)^0.5
+end
+
+function twice (x)
+    return 2*x
+end
+]]
+    f:close()
+    dofile('lib-301.lua')
+    local n = norm(3.4, 1.0)
+    like(twice(n), '^7%.088', "function dofile")
+
+    os.remove('lib-301.lua') -- clean up
+
+    error_like(function () dofile('no_file-301.lua') end,
+               "cannot open no_file%-301%.lua: No such file or directory",
+               "function dofile (no file)")
+
+    f = io.open('foo-301.lua', 'w')
+    f:write[[?syntax error?]]
+    f:close()
+    error_like(function () dofile('foo-301.lua') end,
+               "^foo%-301%.lua:%d+:",
+               "function dofile (syntax error)")
+
+    os.remove('foo-301.lua') -- clean up
+end
+
+do -- error
+    error_like(function () error("ERROR TEST") end,
+               "^[^:]+:%d+: ERROR TEST",
+               "function error(msg)")
+
+    error_is(function () error("ERROR TEST", 0) end,
+             "ERROR TEST",
+             "function error(msg, 0)")
+
+    if has_error53 then
+        local v, msg = pcall(function() error(42) end)
+        is(msg, 42, "function error(42)")
+    else
+        error_like(function () error(42) end,
+                   "^[^:]+:%d+: 42",
+                   "function error(42)")
+    end
+
+    local obj = {}
+    local v, msg = pcall(function() error(obj) end)
+    is(msg, obj, "function error({})")
+
+    v, msg = pcall(function() error() end)
+    is(msg, nil, "function error()")
+end
+
+-- gcinfo
+if has_gcinfo then
+    type_ok(gcinfo(), 'number', "function gcinfo")
+else
+    is(gcinfo, nil, "no gcinfo (removed)")
+end
+
+-- getfenv
+if has_getfenv then
+    type_ok(getfenv(0), 'table', "function getfenv")
+    is(getfenv(0), _G)
+    is(getfenv(1), _G)
+    is(getfenv(), _G)
+    local function f () end
+    type_ok(getfenv(f), 'table')
+    is(getfenv(f), _G)
+    type_ok(getfenv(print), 'table')
+    is(getfenv(print), _G)
+
+    error_like(function () getfenv(-3) end,
+               "^[^:]+:%d+: bad argument #1 to 'getfenv' %(.-level.-%)",
+              "function getfenv (negative)")
+
+    error_like(function () getfenv(12) end,
+               "^[^:]+:%d+: bad argument #1 to 'getfenv' %(invalid level%)",
+               "function getfenv (too depth)")
+else
+    is(getfenv, nil, "no getfenv")
+end
+
+do -- getmetatable
+    is(getmetatable(true), nil, "boolean has no metatable by default")
+    is(getmetatable(getmetatable), nil, "function has no metatable by default")
+    is(getmetatable(nil), nil, "nil has no metatable by default")
+    is(getmetatable(3.14), nil, "number has no metatable by default")
+    is(getmetatable({}), nil, "table has no metatable by default")
+    local co = coroutine.create(function () return 1 end)
+    is(getmetatable(co), nil, "thread has no metatable by default")
+
+    type_ok(getmetatable('ABC'), 'table', "string has a metatable")
+    is(getmetatable('ABC'), getmetatable('abc'), "string has a shared metatable")
+end
+
+do -- ipairs
+    local a = {'a','b','c'}
+    if has_ipairs53 then
+        a = setmetatable({
+            [1] = 'a',
+            [3] = 'c',
+        }, {
+            __index = {
+               [2] = 'b',
+            }
+        })
+    end
+    local f, v, s = ipairs(a)
+    type_ok(f, 'function', "function ipairs")
+    type_ok(v, 'table')
+    is(s, 0)
+    s, v = f(a, s)
+    is(s, 1)
+    is(v, 'a')
+    s, v = f(a, s)
+    is(s, 2)
+    is(v, 'b')
+    s, v = f(a, s)
+    is(s, 3)
+    is(v, 'c')
+    s, v = f(a, s)
+    is(s, nil)
+    is(v, nil)
+end
+
+do -- load
+    local t = { [[
+function bar (x)
+    return x
+end
+]] }
+    local i = 0
+    local function reader ()
+        i = i + 1
+        return t[i]
+    end
+    local f, msg = load(reader)
+    if msg then
+        diag(msg)
+    end
+    type_ok(f, 'function', "function load(reader)")
+    is(bar, nil)
+    f()
+    is(bar('ok'), 'ok')
+    bar = nil
+
+    t = { [[
+function baz (x)
+    return x
+end
+]] }
+    i = -1
+    function reader ()
+        i = i + 1
+        return t[i]
+    end
+    f, msg = load(reader)
+    if msg then
+        diag(msg)
+    end
+    type_ok(f, 'function', "function load(pathological reader)")
+    f()
+    if _VERSION == 'Lua 5.1' and not jit then
+        todo("not with 5.1")
+    end
+    is(baz, nil)
+
+    t = { [[?syntax error?]] }
+    i = 0
+    f, msg = load(reader, "errorchunk")
+    is(f, nil, "function load(syntax error)")
+    like(msg, "^%[string \"errorchunk\"%]:%d+:")
+
+    f = load(function () return nil end)
+    type_ok(f, 'function', "when reader returns nothing")
+
+    f, msg = load(function () return {} end)
+    is(f, nil, "reader function must return a string")
+    like(msg, "reader function must return a string")
+
+    if has_load52 then
+        f = load([[
+function bar (x)
+    return x
+end
+]])
+        is(bar, nil, "function load(str)")
+        f()
+        is(bar('ok'), 'ok')
+        bar = nil
+
+        local env = {}
+        f = load([[
+function bar (x)
+    return x
+end
+]], "from string", 't', env)
+        is(env.bar, nil, "function load(str)")
+        f()
+        is(env.bar('ok'), 'ok')
+
+        f, msg = load([[?syntax error?]], "errorchunk")
+        is(f, nil, "function load(syntax error)")
+        like(msg, "^%[string \"errorchunk\"%]:%d+:")
+
+        f, msg = load([[print 'ok']], "chunk txt", 'b')
+        like(msg, "attempt to load")
+        is(f, nil, "mode")
+
+        f, msg = load("\x1bLua", "chunk bin", 't')
+        like(msg, "attempt to load")
+        is(f, nil, "mode")
+    else
+       diag("no load with string")
+    end
+end
+
+do -- loadfile
+    local f = io.open('foo-301.lua', 'w')
+    if _VERSION ~= 'Lua 5.1' or jit then
+        f:write'\xEF\xBB\xBF' -- BOM
+    end
+    f:write[[
+function foo (x)
+    return x
+end
+]]
+    f:close()
+    f = loadfile('foo-301.lua')
+    is(foo, nil, "function loadfile")
+    f()
+    is(foo('ok'), 'ok')
+
+    if has_loadfile52 then
+        local msg
+        f, msg = loadfile('foo-301.lua', 'b')
+        like(msg, "attempt to load")
+        is(f, nil, "mode")
+
+        local env = {}
+        f = loadfile('foo-301.lua', 't', env)
+        is(env.foo, nil, "function loadfile")
+        f()
+        is(env.foo('ok'), 'ok')
+    else
+        diag("no loadfile with mode & env")
+    end
+
+    os.remove('foo-301.lua') -- clean up
+
+    local msg
+    f, msg = loadfile('no_file-301.lua')
+    is(f, nil, "function loadfile (no file)")
+    is(msg, "cannot open no_file-301.lua: No such file or directory")
+
+    f = io.open('foo-301.lua', 'w')
+    f:write[[?syntax error?]]
+    f:close()
+    f, msg = loadfile('foo-301.lua')
+    is(f, nil, "function loadfile (syntax error)")
+    like(msg, '^foo%-301%.lua:%d+:')
+    os.remove('foo-301.lua') -- clean up
+end
+
+-- loadstring
+if has_loadstring then
+    local f = loadstring([[i = i + 1]])
+    i = 0
+    f()
+    is(i, 1, "function loadstring")
+    f()
+    is(i, 2)
+
+    i = 32
+    local i = 0
+    f = loadstring([[i = i + 1; return i]])
+    local g = function () i = i + 1; return i end
+    is(f(), 33, "function loadstring")
+    is(g(), 1)
+
+    local msg
+    f, msg = loadstring([[?syntax error?]])
+    is(f, nil, "function loadstring (syntax error)")
+    like(msg, '^%[string "%?syntax error%?"%]:%d+:')
+elseif has_alias_loadstring then
+    is(loadstring, load, "alias loadstring")
+else
+    is(loadstring, nil, "no loadstring")
+end
+
+-- newproxy
+if has_newproxy then
+    local proxy = newproxy(false)
+    type_ok(proxy, 'userdata', "function newproxy(false)")
+    is(getmetatable(proxy), nil, "without metatable")
+    proxy = newproxy(true)
+    type_ok(proxy, 'userdata', "function newproxy(true)")
+    type_ok(getmetatable(proxy), 'table', "with metatable")
+
+    local proxy2 = newproxy(proxy)
+    type_ok(proxy, 'userdata', "function newproxy(proxy)")
+    is(getmetatable(proxy2), getmetatable(proxy))
+
+    error_like(function () newproxy({}) end,
+               "^[^:]+:%d+: bad argument #1 to 'newproxy' %(boolean or proxy expected%)",
+               "function newproxy({})")
+else
+    is(newproxy, nil, "no newproxy")
+end
+
+do -- next
+    local t = {'a','b','c'}
+    local a = next(t, nil)
+    is(a, 1, "function next (array)")
+    a = next(t, 1)
+    is(a, 2)
+    a = next(t, 2)
+    is(a, 3)
+    a = next(t, 3)
+    is(a, nil)
+
+    error_like(function () a = next() end,
+               "^[^:]+:%d+: bad argument #1 to 'next' %(table expected, got no value%)",
+               "function next (no arg)")
+
+    error_like(function () a = next(t, 6) end,
+               "invalid key to 'next'",
+               "function next (invalid key)")
+
+    t = {'a','b','c'}
+    a = next(t, 2)
+    is(a, 3, "function next (unorderer)")
+    a = next(t, 1)
+    is(a, 2)
+    a = next(t, 3)
+    is(a, nil)
+
+    t = {}
+    a = next(t, nil)
+    is(a, nil, "function next (empty table)")
+end
+
+do -- pairs
+    local a = {'a','b','c'}
+    local f, v, s = pairs(a)
+    type_ok(f, 'function', "function pairs")
+    type_ok(v, 'table')
+    is(s, nil)
+    s = f(v, s)
+    is(s, 1)
+    s = f(v, s)
+    is(s, 2)
+    s = f(v, s)
+    is(s, 3)
+    s = f(v, s)
+    is(s, nil)
+end
+
+do -- pcall
+    local status, result = pcall(assert, 1)
+    is(status, true, "function pcall")
+    is(result, 1)
+    status, result = pcall(assert, false, 'catched')
+    is(status, false)
+    is(result, 'catched')
+    status = pcall(assert)
+    is(status, false)
+end
+
+do -- rawequal
+    local t = {}
+    local a = t
+    is(rawequal(nil, nil), true, "function rawequal -> true")
+    is(rawequal(false, false), true)
+    is(rawequal(3, 3), true)
+    is(rawequal('text', 'text'), true)
+    is(rawequal(t, a), true)
+    is(rawequal(print, print), true)
+
+    is(rawequal(nil, 2), false, "function rawequal -> false")
+    is(rawequal(false, true), false)
+    is(rawequal(false, 2), false)
+    is(rawequal(3, 2), false)
+    is(rawequal(3, '2'), false)
+    is(rawequal('text', '2'), false)
+    is(rawequal('text', 2), false)
+    is(rawequal(t, {}), false)
+    is(rawequal(t, 2), false)
+    is(rawequal(print, type), false)
+    is(rawequal(print, 2), false)
+end
+
+-- rawlen
+if has_rawlen then
+    is(rawlen("text"), 4, "function rawlen (string)")
+    is(rawlen({ 'a', 'b', 'c'}), 3, "function rawlen (table)")
+    error_like(function () local a = rawlen(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'rawlen' %(table ",
+               "function rawlen (bad arg)")
+else
+    is(rawlen, nil, "no rawlen")
+end
+
+do -- rawget
+    local t = {a = 'letter a', b = 'letter b'}
+    is(rawget(t, 'a'), 'letter a', "function rawget")
+end
+
+do -- rawset
+    local t = {}
+    is(rawset(t, 'a', 'letter a'), t, "function rawset")
+    is(t.a, 'letter a')
+
+    error_like(function () t = {}; rawset(t, nil, 42) end,
+               "^table index is nil",
+               "function rawset (table index is nil)")
+end
+
+do -- select
+    is(select('#'), 0, "function select")
+    is(select('#','a','b','c'), 3)
+    eq_array({select(1,'a','b','c')}, {'a','b','c'})
+    eq_array({select(3,'a','b','c')}, {'c'})
+    eq_array({select(5,'a','b','c')}, {})
+    eq_array({select(-1,'a','b','c')}, {'c'})
+    eq_array({select(-2,'a','b','c')}, {'b', 'c'})
+    eq_array({select(-3,'a','b','c')}, {'a', 'b', 'c'})
+
+    error_like(function () select(0,'a','b','c') end,
+               "^[^:]+:%d+: bad argument #1 to 'select' %(index out of range%)",
+               "function select (out of range)")
+
+    error_like(function () select(-4,'a','b','c') end,
+               "^[^:]+:%d+: bad argument #1 to 'select' %(index out of range%)",
+               "function select (out of range)")
+end
+
+-- setfenv
+if has_getfenv then
+    local t = {}
+    local function f () end
+    is(setfenv(f, t), f, "function setfenv")
+    type_ok(getfenv(f), 'table')
+    is(getfenv(f), t)
+
+    save = getfenv(1)
+    a = 1
+    setfenv(1, {g = _G})
+    g.is(a, nil, "function setfenv")
+    g.is(g.a, 1)
+    g.setfenv(1, g.save) -- restore
+
+    save = getfenv(1)
+    a = 1
+    local newgt = {}        -- create new environment
+    setmetatable(newgt, {__index = _G})
+    setfenv(1, newgt)       -- set it
+    is(a, 1, "function setfenv")
+    a = 10
+    is(a, 10)
+    is(_G.a, 1)
+    _G.a = 20
+    is(_G.a, 20)
+    setfenv(1, save) -- restore
+
+    save = getfenv(1)
+    local function factory ()
+        return function ()
+                   return a    -- "global" a
+               end
+    end
+    a = 3
+    local f1 = factory()
+    local f2 = factory()
+    is(f1(), 3, "function setfenv")
+    is(f2(), 3)
+    setfenv(f1, {a = 10})
+    is(f1(), 10)
+    is(f2(), 3)
+    setfenv(1, save) -- restore
+
+    is(setfenv(0, _G), nil, "function setfenv(0)")
+
+    error_like(function () setfenv(-3, {}) end,
+               "^[^:]+:%d+: bad argument #1 to 'setfenv' %(.-level.-%)",
+               "function setfenv (negative)")
+
+    error_like(function () setfenv(12, {}) end,
+               "^[^:]+:%d+: bad argument #1 to 'setfenv' %(invalid level%)",
+               "function setfenv (too depth)")
+
+    t = {}
+    error_like(function () setfenv(t, {}) end,
+               "^[^:]+:%d+: bad argument #1 to 'setfenv' %(number expected, got table%)",
+               "function setfenv (bad arg)")
+
+    error_like(function () setfenv(print, {}) end,
+               "^[^:]+:%d+: 'setfenv' cannot change environment of given object",
+               "function setfenv (forbidden)")
+else
+    is(setfenv, nil, "no setfenv")
+end
+
+do -- setmetatable
+    local mt = {}
+    local t = {}
+    is(t, setmetatable(t, mt), "setmetatable")
+    is(getmetatable(t), mt)
+    is(t, setmetatable(t, nil))
+    is(getmetatable(t), nil)
+
+    error_like(function () setmetatable(t, true) end,
+               "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected",
+               "function setmetatable (bad arg)")
+    error_like(function () setmetatable(true, mt) end,
+               "^[^:]+:%d+: bad argument #1 to 'setmetatable' %(table expected, got boolean%)",
+               "function setmetatable (bad arg)")
+end
+
+do -- type
+    is(type("Hello world"), 'string', "function type")
+    is(type(10.4*3), 'number')
+    is(type(print), 'function')
+    is(type(type), 'function')
+    is(type(true), 'boolean')
+    is(type(nil), 'nil')
+    is(type(io.stdin), 'userdata')
+    is(type(type(X)), 'string')
+
+    local a = nil
+    is(type(a), 'nil', "function type")
+    a = 10
+    is(type(a), 'number')
+    a = "a string!!"
+    is(type(a), 'string')
+    a = print
+    is(type(a), 'function')
+    is(type(function () end), 'function')
+
+    error_like(function () type() end,
+               "^[^:]+:%d+: bad argument #1 to 'type' %(value expected%)",
+               "function type (no arg)")
+end
+
+do -- tonumber
+    is(tonumber('text12'), nil, "function tonumber")
+    is(tonumber('12text'), nil)
+    is(tonumber(3.14), 3.14)
+    is(tonumber('3.14'), 3.14)
+    is(tonumber('  3.14  '), 3.14)
+    is(tonumber(tostring(111), 2), 7)
+    is(tonumber('111', 2), 7)
+    is(tonumber('  111  ', 2), 7)
+    local a = {}
+    is(tonumber(a), nil)
+
+    error_like(function () tonumber() end,
+               "^[^:]+:%d+: bad argument #1 to 'tonumber' %(value expected%)",
+               "function tonumber (no arg)")
+
+    error_like(function () tonumber('111', 200) end,
+               "^[^:]+:%d+: bad argument #2 to 'tonumber' %(base out of range%)",
+               "function tonumber (bad base)")
+end
+
+do -- tostring
+    is(tostring('text'), 'text', "function tostring")
+    is(tostring(3.14), '3.14')
+    is(tostring(nil), 'nil')
+    is(tostring(true), 'true')
+    is(tostring(false), 'false')
+    like(tostring({}), '^table: 0?[Xx]?%x+$')
+    like(tostring(print), '^function: 0?[Xx]?[builtin]*#?%x+$')
+
+    error_like(function () tostring() end,
+               "^[^:]+:%d+: bad argument #1 to 'tostring' %(value expected%)",
+               "function tostring (no arg)")
+end
+
+-- unpack
+if has_unpack then
+    eq_array({unpack({})}, {}, "function unpack")
+    eq_array({unpack({'a'})}, {'a'})
+    eq_array({unpack({'a','b','c'})}, {'a','b','c'})
+    eq_array({(unpack({'a','b','c'}))}, {'a'})
+    eq_array({unpack({'a','b','c','d','e'},2,4)}, {'b','c','d'})
+    eq_array({unpack({'a','b','c'},2,4)}, {'b','c'})
+elseif has_alias_unpack then
+    is(unpack, table.unpack, "alias unpack")
+else
+    is(unpack, nil, "no unpack")
+end
+
+-- warn
+if has_warn then
+    is(warn('foo'), nil, "function warn")
+
+    local r, f = pcall(io.popen, lua .. [[ -W -e "warn'foo'" 2>&1]])
+    if r then
+        is(f:read'*l', 'Lua warning: foo', "warn called with popen")
+        is(f:read'*l', nil)
+        is(f:close(), true)
+    else
+        diag("io.popen not supported")
+    end
+
+    r, f = pcall(io.popen, lua .. [[ -e "warn'@on'; warn'foo'" 2>&1]])
+    if r then
+        is(f:read'*l', 'Lua warning: foo', "warn called with popen")
+        is(f:read'*l', nil)
+        is(f:close(), true)
+    else
+        diag("io.popen not supported")
+    end
+
+    r, f = pcall(io.popen, lua .. [[ -e "warn'@on'; warn('foo', 'bar')" 2>&1]])
+    if r then
+        is(f:read'*l', 'Lua warning: foobar', "warn called with popen")
+        is(f:read'*l', nil)
+        is(f:close(), true)
+    else
+        diag("io.popen not supported")
+    end
+
+    error_like(function () warn('foo', warn) end,
+               "^[^:]+:%d+: bad argument #2 to 'warn' %(string expected, got function%)",
+               "function warn (no arg)")
+
+    error_like(function () warn() end,
+               "^[^:]+:%d+: bad argument #1 to 'warn' %(string expected, got no value%)",
+               "function warn (no arg)")
+else
+    is(warn, nil, "no warn")
+end
+
+do -- xpcall
+    local function err (obj)
+        return obj
+    end
+
+    local function backtrace ()
+        return 'not a back trace'
+    end
+
+    local status, result = xpcall(function () return assert(1) end, err)
+    is(status, true, "function xpcall")
+    is(result, 1)
+    status, result = xpcall(function () return assert(false, 'catched') end, err)
+    is(status, false)
+    if jit then
+        is(result, 'catched')
+    else
+        like(result, ':%d+: catched')
+    end
+    status, result = xpcall(function () return assert(false, 'catched') end, backtrace)
+    is(status, false)
+    is(result, 'not a back trace')
+
+    if has_xpcall52 then
+        status, result = xpcall(assert, err, 1)
+        is(status, true, "function xpcall with args")
+        is(result, 1)
+        status, result = xpcall(assert, err, false, 'catched')
+        is(status, false)
+        is(result, 'catched')
+        status, result = xpcall(assert, backtrace, false, 'catched')
+        is(status, false)
+        is(result, 'not a back trace')
+    end
+
+    error_like(function () xpcall(assert) end,
+               "bad argument #2 to 'xpcall' %(.-",
+               "function xpcall")
+
+    if has_xpcall53 then
+        error_like(function () xpcall(assert, 1) end,
+                   "bad argument #2 to 'xpcall' %(function expected, got number%)",
+                  "function xpcall")
+    else
+        is(xpcall(assert, nil), false, "function xpcall")
+    end
+end
+
+if jit and pcall(require, 'ffi') then
+    dofile'lexicojit/basic.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/303-package.t b/test/lua-Harness-tests/303-package.t
new file mode 100755
index 0000000..7e5216d
--- /dev/null
+++ b/test/lua-Harness-tests/303-package.t
@@ -0,0 +1,290 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Package Library
+
+=head2 Synopsis
+
+    % prove 303-package.t
+
+=head2 Description
+
+Tests Lua Package Library
+
+See section "Modules" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.3>,
+L<https://www.lua.org/manual/5.2/manual.html#6.3>,
+L<https://www.lua.org/manual/5.3/manual.html#6.3>,
+L<https://www.lua.org/manual/5.4/manual.html#6.3>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT')
+local has_loaders = _VERSION == 'Lua 5.1'
+local has_alias_loaders = profile.compat51
+local has_loadlib52 = _VERSION >= 'Lua 5.2' or jit
+local has_module = _VERSION == 'Lua 5.1' or profile.compat51
+local has_searchers = _VERSION >= 'Lua 5.2'
+local has_alias_searchers = luajit21 and profile.luajit_compat52
+local has_searcherpath = _VERSION >= 'Lua 5.2' or jit
+local has_require54 = _VERSION >= 'Lua 5.4'
+
+plan'no_plan'
+
+
+type_ok(package.config, 'string')
+
+type_ok(package.cpath, 'string')
+
+type_ok(package.path, 'string')
+
+if has_loaders then
+    type_ok(package.loaders, 'table', "table package.loaders")
+elseif has_alias_loaders then
+    is(package.loaders, package.searchers, "alias package.loaders")
+else
+    is(package.loaders, nil, "no package.loaders")
+end
+
+if has_searchers then
+    type_ok(package.searchers, 'table', "table package.searchers")
+elseif has_alias_searchers then
+    is(package.searchers, package.loaders, "alias package.searchers")
+else
+    is(package.searchers, nil, "no package.searchers")
+end
+
+do -- loaded
+    ok(package.loaded._G, "table package.loaded")
+    ok(package.loaded.coroutine)
+    ok(package.loaded.io)
+    ok(package.loaded.math)
+    ok(package.loaded.os)
+    ok(package.loaded.package)
+    ok(package.loaded.string)
+    ok(package.loaded.table)
+
+    local m = require'os'
+    is(m, package.loaded['os'])
+end
+
+do -- preload
+    type_ok(package.preload, 'table', "table package.preload")
+    is(# package.preload, 0)
+
+    local foo = {}
+    foo.bar = 1234
+    local function foo_loader ()
+       return foo
+    end
+    package.preload.foo = foo_loader
+    local m = require 'foo'
+    assert(m == foo)
+    is(m.bar, 1234, "function require & package.preload")
+end
+
+do -- loadlib
+    local path_lpeg = package.searchpath and package.searchpath('lpeg', package.cpath)
+
+    local f, msg = package.loadlib('libbar', 'baz')
+    is(f, nil, "loadlib")
+    type_ok(msg, 'string')
+
+    if path_lpeg then
+        f, msg = package.loadlib(path_lpeg, 'baz')
+        is(f, nil, "loadlib")
+        like(msg, 'undefined symbol')
+
+        f = package.loadlib(path_lpeg, 'luaopen_lpeg')
+        type_ok(f, 'function', "loadlib ok")
+    else
+        skip("no lpeg path")
+    end
+
+    if has_loadlib52 then
+        f, msg = package.loadlib('libbar', '*')
+        is(f, nil, "loadlib '*'")
+        type_ok(msg, 'string')
+
+        if path_lpeg then
+            f = package.loadlib(path_lpeg, '*')
+            is(f, true, "loadlib '*'")
+        else
+            skip("no lpeg path")
+        end
+    end
+end
+
+-- searchpath
+if has_searcherpath then
+    local p = package.searchpath('tap', package.path)
+    type_ok(p, 'string', "searchpath")
+    p = package.searchpath('tap', 'bad path')
+    is(p, nil)
+else
+    is(package.searchpath, nil, "no package.searchpath")
+end
+
+do -- require
+    local f = io.open('complex.lua', 'w')
+    f:write [[
+complex = {}
+
+function complex.new (r, i) return {r=r, i=i} end
+
+--defines a constant 'i'
+complex.i = complex.new(0, 1)
+
+function complex.add (c1, c2)
+    return complex.new(c1.r + c2.r, c1.i + c2.i)
+end
+
+function complex.sub (c1, c2)
+    return complex.new(c1.r - c2.r, c1.i - c2.i)
+end
+
+function complex.mul (c1, c2)
+    return complex.new(c1.r*c2.r - c1.i*c2.i,
+                       c1.r*c2.i + c1.i*c2.r)
+end
+
+local function inv (c)
+    local n = c.r^2 + c.i^2
+    return complex.new(c.r/n, -c.i/n)
+end
+
+function complex.div (c1, c2)
+    return complex.mul(c1, inv(c2))
+end
+
+return complex
+]]
+    f:close()
+    if has_require54 then
+        local m1, path1 = require 'complex'
+        is(m1, complex, "function require")
+        is(path1, './complex.lua')
+        local m2, path2 = require 'complex'
+        is(m1, m2)
+        is(path2, nil)
+    else
+        local m1 = require 'complex'
+        is(m1, complex, "function require")
+        local m2 = require 'complex'
+        is(m1, m2)
+    end
+    is(complex.i.r, 0)
+    is(complex.i.i, 1)
+    os.remove('complex.lua') -- clean up
+
+    error_like(function () require('no_module') end,
+               "^[^:]+:%d+: module 'no_module' not found:",
+               "function require (no module)")
+
+    f = io.open('syntax.lua', 'w')
+    f:write [[?syntax error?]]
+    f:close()
+    error_like(function () require('syntax') end,
+               "^error loading module 'syntax' from file '%.[/\\]syntax%.lua':",
+               "function require (syntax error)")
+    os.remove('syntax.lua') -- clean up
+
+    f = io.open('bar.lua', 'w')
+    f:write [[
+    print("    in bar.lua", ...)
+    a = ...
+]]
+    f:close()
+    a = nil
+    require 'bar'
+    is(a, 'bar', "function require (arg)")
+    os.remove('bar.lua') -- clean up
+
+    f = io.open('cplx.lua', 'w')
+    f:write [[
+-- print('cplx.lua', ...)
+local _G = _G
+_ENV = nil
+local cplx = {}
+
+local function new (r, i) return {r=r, i=i} end
+cplx.new = new
+
+--defines a constant 'i'
+cplx.i = new(0, 1)
+
+function cplx.add (c1, c2)
+    return new(c1.r + c2.r, c1.i + c2.i)
+end
+
+function cplx.sub (c1, c2)
+    return new(c1.r - c2.r, c1.i - c2.i)
+end
+
+function cplx.mul (c1, c2)
+    return new(c1.r*c2.r - c1.i*c2.i,
+               c1.r*c2.i + c1.i*c2.r)
+end
+
+local function inv (c)
+    local n = c.r^2 + c.i^2
+    return new(c.r/n, -c.i/n)
+end
+
+function cplx.div (c1, c2)
+    return mul(c1, inv(c2))
+end
+
+_G.cplx = cplx
+return cplx
+]]
+    f:close()
+    require 'cplx'
+    is(cplx.i.r, 0, "function require & module")
+    is(cplx.i.i, 1)
+    os.remove('cplx.lua') -- clean up
+end
+
+-- module & seeall
+local done_testing = done_testing
+if has_module then
+    m = {}
+    package.seeall(m)
+    m.pass("function package.seeall")
+
+    is(mod, nil, "function module & seeall")
+    module('mod', package.seeall)
+    type_ok(mod, 'table')
+    is(mod, package.loaded.mod)
+
+    is(modz, nil, "function module")
+    local _G = _G
+    module('modz')
+    _G.type_ok(_G.modz, 'table')
+    _G.is(_G.modz, _G.package.loaded.modz)
+else
+    is(package.seeall, nil, "package.seeall (removed)")
+    is(module, nil, "module (removed)")
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/304-string.t b/test/lua-Harness-tests/304-string.t
new file mode 100755
index 0000000..991600a
--- /dev/null
+++ b/test/lua-Harness-tests/304-string.t
@@ -0,0 +1,633 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua String Library
+
+=head2 Synopsis
+
+    % prove 304-string.t
+
+=head2 Description
+
+Tests Lua String Library
+
+See section "String Manipulation" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.4>,
+L<https://www.lua.org/manual/5.2/manual.html#6.4>,
+L<https://www.lua.org/manual/5.3/manual.html#6.4>,
+L<https://www.lua.org/manual/5.4/manual.html#6.4>
+
+=cut
+
+]]
+
+require'tap'
+local profile = require'profile'
+local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT')
+local has_dump53 = _VERSION >= 'Lua 5.3' or jit
+local has_format_a = _VERSION >= 'Lua 5.3' or profile.has_string_format_a or jit
+local has_format_p = _VERSION >= 'Lua 5.4'
+local has_format_q52 = _VERSION >= 'Lua 5.2' or jit
+local has_format_q53 = _VERSION >= 'Lua 5.3'
+local has_format_q54 = _VERSION >= 'Lua 5.4'
+local has_gmatch54 = _VERSION >= 'Lua 5.4'
+local has_pack = _VERSION >= 'Lua 5.3' or (jit and jit.version:match'moonjit') or profile.pack
+local has_rep52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_class_g = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local loadstring = loadstring or load
+
+plan'no_plan'
+
+do -- metatable
+    local mt = getmetatable('ABC')
+    type_ok(mt, 'table', "metatable")
+    type_ok(mt.__index, 'table')
+
+    if not profile.nocvts2n and _VERSION >= 'Lua 5.4' then
+        type_ok(mt.__add, 'function')
+        type_ok(mt.__div, 'function')
+        type_ok(mt.__idiv, 'function')
+        type_ok(mt.__mul, 'function')
+        type_ok(mt.__mod, 'function')
+        type_ok(mt.__pow, 'function')
+        type_ok(mt.__sub, 'function')
+        type_ok(mt.__unm, 'function')
+    else
+        is(mt.__add, nil)
+        is(mt.__div, nil)
+        is(mt.__idiv, nil)
+        is(mt.__mul, nil)
+        is(mt.__mod, nil)
+        is(mt.__pow, nil)
+        is(mt.__sub, nil)
+        is(mt.__unm, nil)
+    end
+
+    is(mt.__index.byte, string.byte)
+    is(mt.__index.char, string.char)
+    is(mt.__index.dump, string.dump)
+    is(mt.__index.find, string.find)
+    is(mt.__index.format, string.format)
+    is(mt.__index.gmatch, string.gmatch)
+    is(mt.__index.gsub, string.gsub)
+    is(mt.__index.len, string.len)
+    is(mt.__index.lower, string.lower)
+    is(mt.__index.match, string.match)
+    is(mt.__index.rep, string.rep)
+    is(mt.__index.reverse, string.reverse)
+    is(mt.__index.sub, string.sub)
+    is(mt.__index.upper, string.upper)
+
+    if has_pack then
+        is(mt.__index.pack, string.pack)
+        is(mt.__index.packsize, string.packsize)
+        is(mt.__index.unpack, string.unpack)
+    else
+        is(mt.__index.pack, nil)
+        is(mt.__index.packsize, nil)
+        is(mt.__index.unpack, nil)
+    end
+end
+
+do -- byte
+    is(string.byte('ABC'), 65, "function byte")
+    is(string.byte('ABC', 2), 66)
+    is(string.byte('ABC', -1), 67)
+    is(string.byte('ABC', 4), nil)
+    is(string.byte('ABC', 0), nil)
+    eq_array({string.byte('ABC', 1, 3)}, {65, 66, 67})
+    eq_array({string.byte('ABC', 1, 4)}, {65, 66, 67})
+
+    local s = "ABC"
+    is(s:byte(2), 66, "method s:byte")
+end
+
+do -- char
+    is(string.char(65, 66, 67), 'ABC', "function char")
+    is(string.char(), '')
+
+    error_like(function () string.char(0, 'bad') end,
+               "^[^:]+:%d+: bad argument #2 to 'char' %(number expected, got string%)",
+               "function char (bad arg)")
+
+    error_like(function () string.char(0, 9999) end,
+               "^[^:]+:%d+: bad argument #2 to 'char' %(.-value.-%)",
+               "function char (invalid)")
+end
+
+do -- dump
+    local signature
+    if jit then
+        signature = "\x1bLJ"
+    elseif ravi then
+        signature = "\x1bRavi"
+    elseif _VERSION >= 'Lua 5.2' then
+        signature = "\x1bLua"
+    end
+
+    local function add (a, b)
+        return a + b
+    end
+
+    local d = string.dump(add)
+    type_ok(d, 'string', "function dump")
+    local f = loadstring(d)
+    type_ok(f, 'function')
+    is(f(1, 2), 3)
+
+    if signature then
+        local sig = d:sub(1, #signature)
+        is(sig, signature)
+    end
+
+    if has_dump53 then
+        local d2 = string.dump(add, true)
+        type_ok(d2, 'string', "function dump with strip")
+        f = loadstring(d2)
+        type_ok(f, 'function')
+        is(f(1, 2), 3)
+        isnt(d2:len(), d:len())
+
+        if signature then
+            local sig = d2:sub(1, #signature)
+            is(sig, signature)
+        end
+    end
+
+    error_like(function () string.dump(print) end,
+               "^[^:]+:%d+: unable to dump given function",
+               "function dump (C function)")
+end
+
+do -- find
+    local s = "hello world"
+    eq_array({string.find(s, "hello")}, {1, 5}, "function find (mode plain)")
+    eq_array({string.find(s, "hello", 1, true)}, {1, 5})
+    eq_array({string.find(s, "hello", 1)}, {1, 5})
+    is(string.sub(s, 1, 5), "hello")
+    eq_array({string.find(s, "world")}, {7, 11})
+    eq_array({string.find(s, "l")}, {3, 3})
+    is(string.find(s, "lll"), nil)
+    is(string.find(s, "hello", 2, true), nil)
+    eq_array({string.find(s, "world", 2, true)}, {7, 11})
+    is(string.find(s, "hello", 20), nil)
+
+    s = "hello world"
+    eq_array({string.find(s, "^h.ll.")}, {1, 5}, "function find (with regex & captures)")
+    eq_array({string.find(s, "w.rld", 2)}, {7, 11})
+    is(string.find(s, "W.rld"), nil)
+    eq_array({string.find(s, "^(h.ll.)")}, {1, 5, 'hello'})
+    eq_array({string.find(s, "^(h.)l(l.)")}, {1, 5, 'he', 'lo'})
+    s = "Deadline is 30/05/1999, firm"
+    local date = "%d%d/%d%d/%d%d%d%d"
+    is(string.sub(s, string.find(s, date)), "30/05/1999")
+    date = "%f[%S]%d%d/%d%d/%d%d%d%d"
+    is(string.sub(s, string.find(s, date)), "30/05/1999")
+
+    error_like(function () string.find(s, '%f') end,
+               "^[^:]+:%d+: missing '%[' after '%%f' in pattern",
+               "function find (invalid frontier)")
+end
+
+do -- format
+    is(string.format("pi = %.4f", math.pi), 'pi = 3.1416', "function format")
+    local d = 5; local m = 11; local y = 1990
+    is(string.format("%02d/%02d/%04d", d, m, y), "05/11/1990")
+    is(string.format("%X %x", 126, 126), "7E 7e")
+    local tag, title = "h1", "a title"
+    is(string.format("<%s>%s</%s>", tag, title, tag), "<h1>a title</h1>")
+
+    is(string.format('%q', 'a string with "quotes" and \n new line'), [["a string with \"quotes\" and \
+ new line"]], "function format %q")
+
+    if has_format_q52 then
+        is(string.format('%q', 'a string with \0 and \r.'), [["a string with \0 and \13."]], "function format %q")
+        is(string.format('%q', 'a string with \b and \b2'), [["a string with \8 and \0082"]], "function format %q")
+    else
+        is(string.format('%q', 'a string with \0 and \r.'), [["a string with \000 and \r."]], "function format %q")
+        is(string.format('%q', 'a string with \b and \b2'), '"a string with \b and \b2"', "function format %q")
+    end
+
+    if has_format_q53 then
+        is(string.format('%q', 1.5), '0x1.8p+0', "function format %q")
+        is(string.format('%q', 7), '7', "function format %q")
+    else
+        is(string.format('%q', 1.5), [["1.5"]], "function format %q")
+        is(string.format('%q', 7), [["7"]], "function format %q")
+    end
+
+    if has_format_q53 then
+        is(string.format('%q', nil), 'nil', "function format ('%q', nil)")
+    elseif luajit21 then
+        is(string.format('%q', nil), [["nil"]], "function format ('%q', nil)")
+    else
+        error_like(function () string.format("%q", nil) end,
+                   "^[^:]+:%d+: bad argument #2 to 'format' %(",
+                   "function format ('%q', nil)")
+    end
+
+    if has_format_q54 then
+        is(string.format('%q', 0/0), '(0/0)', "function format ('%q', NaN)")
+        is(string.format('%q', 1/0), '1e9999', "function format ('%q', +Inf)")
+        is(string.format('%q', -1/0), '-1e9999', "function format ('%q', -Inf)")
+
+        error_like(function () string.format("%-q", 0) end,
+                   "^[^:]+:%d+: specifier '%%q' cannot have modifiers",
+                   "function format '%-q'")
+    end
+
+    if luajit21 then
+        like(string.format('%q', {}), [[^"table: ]], "function format ('%q', {})")
+    else
+        error_like(function () string.format("%q", {}) end,
+                   "^[^:]+:%d+: bad argument #2 to 'format' %(",
+                   "function format ('%q', {})")
+    end
+
+    if has_format_a then
+        is(string.format('%a', 1.5), '0x1.8p+0', "function format %a")
+    end
+
+    if has_format_p then
+        is(string.format('table: %p', string), tostring(string), "function format %p")
+    end
+
+    is(string.format("%5s", 'foo'), '  foo', "function format (%5s)")
+
+    if _VERSION >= 'Lua 5.3' then
+        error_like(function () string.format("%5s", "foo\0bar") end,
+                   "^[^:]+:%d+: bad argument #2 to 'format' %(string contains zeros%)",
+                   "function format format (%5s with \\0)")
+    end
+
+    is(string.format("%s %s", 1, 2, 3), '1 2', "function format (too many arg)")
+
+    is(string.format("%% %c %%", 65), '% A %', "function format (%%)")
+
+    local r = string.rep("ab", 100)
+    is(string.format("%s %d", r, r:len()), r .. " 200")
+
+    error_like(function () string.format("%s %s", 1) end,
+               "^[^:]+:%d+: bad argument #3 to 'format' %(.-no value%)",
+               "function format (too few arg)")
+
+    error_like(function () string.format('%d', 'toto') end,
+               "^[^:]+:%d+: bad argument #2 to 'format' %(number expected, got string%)",
+               "function format (bad arg)")
+
+    error_like(function () string.format('%k', 'toto') end,
+               "^[^:]+:%d+: invalid .- '%%k' to 'format'",
+               "function format (invalid conversion)")
+
+    if luajit21 then
+        error_like(function () string.format('%111s', 'toto') end,
+                   "^[^:]+:%d+: invalid option '%%111' to 'format'",
+                   "function format (invalid format)")
+    else
+        error_like(function () string.format('%111s', 'toto') end,
+                   "^[^:]+:%d+: invalid format %(width or precision too long%)",
+                   "function format (invalid format)")
+
+        error_like(function () string.format('%------s', 'toto') end,
+                   "^[^:]+:%d+: invalid format %(repeated flags%)",
+                   "function format (invalid format)")
+    end
+
+    error_like(function () string.format('pi = %.123f', math.pi) end,
+               "^[^:]+:%d+: invalid ",
+               "function format (invalid format)")
+
+    error_like(function () string.format('% 123s', 'toto') end,
+               "^[^:]+:%d+: invalid ",
+               "function format (invalid format)")
+end
+
+do -- gmatch
+    local s = "hello"
+    local output = {}
+    for c in string.gmatch(s, '..') do
+        table.insert(output, c)
+    end
+    eq_array(output, {'he', 'll'}, "function gmatch")
+    if has_gmatch54 then
+        output = {}
+        for c in string.gmatch(s, '..', 2) do
+            table.insert(output, c)
+        end
+        eq_array(output, {'el', 'lo'})
+    end
+    output = {}
+    for c1, c2 in string.gmatch(s, '(.)(.)') do
+        table.insert(output, c1)
+        table.insert(output, c2)
+    end
+    eq_array(output, {'h', 'e', 'l', 'l'})
+    s = "hello world from Lua"
+    output = {}
+    for w in string.gmatch(s, '%a+') do
+        table.insert(output, w)
+    end
+    eq_array(output, {'hello', 'world', 'from', 'Lua'})
+    s = "from=world, to=Lua"
+    output = {}
+    for k, v in string.gmatch(s, '(%w+)=(%w+)') do
+        table.insert(output, k)
+        table.insert(output, v)
+    end
+    eq_array(output, {'from', 'world', 'to', 'Lua'})
+end
+
+do -- gsub
+    is(string.gsub("hello world", "(%w+)", "%1 %1"), "hello hello world world", "function gsub")
+    is(string.gsub("hello world", "%w+", "%0 %0", 1), "hello hello world")
+    is(string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1"), "world hello Lua from")
+    if _VERSION == 'Lua 5.1' then
+        todo("not with 5.1")
+    end
+    error_like(function () string.gsub("hello world", "%w+", "%e") end,
+               "^[^:]+:%d+: invalid use of '%%' in replacement string",
+               "function gsub (invalid replacement string)")
+    is(string.gsub("home = $HOME, user = $USER", "%$(%w+)", string.reverse), "home = EMOH, user = RESU")
+    is(string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return tostring(loadstring(s)()) end), "4+5 = 9")
+    local t = {name='lua', version='5.1'}
+    is(string.gsub("$name-$version.tar.gz", "%$(%w+)", t), "lua-5.1.tar.gz")
+
+    is(string.gsub("Lua is cute", 'cute', 'great'), "Lua is great")
+    is(string.gsub("all lii", 'l', 'x'), "axx xii")
+    is(string.gsub("Lua is great", '^Sol', 'Sun'), "Lua is great")
+    is(string.gsub("all lii", 'l', 'x', 1), "axl lii")
+    is(string.gsub("all lii", 'l', 'x', 2), "axx lii")
+    is(select(2, string.gsub("string with 3 spaces", ' ', ' ')), 3)
+
+    eq_array({string.gsub("hello, up-down!", '%A', '.')}, {"hello..up.down.", 4})
+    eq_array({string.gsub("hello, up-down!", '%A', '%%')}, {"hello%%up%down%", 4})
+    local text = "hello world"
+    local nvow = select(2, string.gsub(text, '[AEIOUaeiou]', ''))
+    is(nvow, 3)
+    eq_array({string.gsub("one, and two; and three", '%a+', 'word')}, {"word, word word; word word", 5})
+    local test = "int x; /* x */  int y; /* y */"
+    eq_array({string.gsub(test, "/%*.*%*/", '<COMMENT>')}, {"int x; <COMMENT>", 1})
+    eq_array({string.gsub(test, "/%*.-%*/", '<COMMENT>')}, {"int x; <COMMENT>  int y; <COMMENT>", 2})
+    local s = "a (enclosed (in) parentheses) line"
+    eq_array({string.gsub(s, '%b()', '')}, {"a  line", 1})
+
+    error_like(function () string.gsub(s, '%b(', '') end,
+               "^[^:]+:%d+: .- pattern",
+               "function gsub (malformed pattern)")
+
+    eq_array({string.gsub("hello Lua!", "%a", "%0-%0")}, {"h-he-el-ll-lo-o L-Lu-ua-a!", 8})
+    eq_array({string.gsub("hello Lua", "(.)(.)", "%2%1")}, {"ehll ouLa", 4})
+
+    local function expand (str)
+        return (string.gsub(str, '$(%w+)', _G))
+    end
+    name = 'Lua'; status= 'great'
+    is(expand("$name is $status, isn't it?"), "Lua is great, isn't it?")
+    is(expand("$othername is $status, isn't it?"), "$othername is great, isn't it?")
+
+    function expand (str)
+        return (string.gsub(str, '$(%w+)', function (n)
+                                            return tostring(_G[n]), 1
+                                       end))
+    end
+    like(expand("print = $print; a = $a"), "^print = function: [0]?[Xx]?[builtin]*#?%x+; a = nil")
+
+    error_like(function () string.gsub("hello world", '(%w+)', '%2 %2') end,
+               "^[^:]+:%d+: invalid capture index",
+               "function gsub (invalid index)")
+
+    error_like(function () string.gsub("hello world", '(%w+)', true) end,
+               "^[^:]+:%d+: bad argument #3 to 'gsub' %(string/function/table expected",
+               "function gsub (bad type)")
+
+    error_like(function ()
+        function expand (str)
+           return (string.gsub(str, '$(%w+)', _G))
+        end
+
+        name = 'Lua'; status= true
+        expand("$name is $status, isn't it?")
+               end,
+               "^[^:]+:%d+: invalid replacement value %(a boolean%)",
+               "function gsub (invalid value)")
+
+    local function trim (str)
+        return (str:gsub('^%s*(.-)%s*$', '%1'))
+    end
+    is(trim('foo'), 'foo', "gsub trim")
+    is(trim('   foo  bar  '), 'foo  bar')
+end
+
+do -- len
+    is(string.len(''), 0, "function len")
+    is(string.len('test'), 4)
+    is(string.len("a\000b\000c"), 5)
+    is(string.len('"'), 1)
+end
+
+do -- lower
+    is(string.lower('Test'), 'test', "function lower")
+    is(string.lower('TeSt'), 'test')
+end
+
+do -- match
+    local s = "hello world"
+    is(string.match(s, '^hello'), 'hello', "function match")
+    is(string.match(s, 'world', 2), 'world')
+    is(string.match(s, 'World'), nil)
+    eq_array({string.match(s, '^(h.ll.)')}, {'hello'})
+    eq_array({string.match(s, '^(h.)l(l.)')}, {'he', 'lo'})
+    local date = "Today is 17/7/1990"
+    is(string.match(date, '%d+/%d+/%d+'), '17/7/1990')
+    eq_array({string.match(date, '(%d+)/(%d+)/(%d+)')}, {'17', '7', '1990'})
+    is(string.match("The number 1298 is even", '%d+'), '1298')
+    local pair = "name = Anna"
+    eq_array({string.match(pair, '(%a+)%s*=%s*(%a+)')}, {'name', 'Anna'})
+
+    s = [[then he said: "it's all right"!]]
+    eq_array({string.match(s, "([\"'])(.-)%1")}, {'"', "it's all right"}, "function match (back ref)")
+    local p = "%[(=*)%[(.-)%]%1%]"
+    s = "a = [=[[[ something ]] ]==]x]=]; print(a)"
+    eq_array({string.match(s, p)}, {'=', '[[ something ]] ]==]x'})
+
+    if has_class_g then
+        is(string.match(s, "%g"), "a", "match graphic char")
+    end
+
+    error_like(function () string.match("hello world", "%1") end,
+               "^[^:]+:%d+: invalid capture index",
+               "function match invalid capture")
+
+    error_like(function () string.match("hello world", "%w)") end,
+               "^[^:]+:%d+: invalid pattern capture",
+               "function match invalid capture")
+end
+
+-- pack
+if has_pack then
+    is(string.pack('b', 0x31), '\x31', "function pack")
+    is(string.pack('>b', 0x31), '\x31')
+    is(string.pack('=b', 0x31), '\x31')
+    is(string.pack('<b', 0x31), '\x31')
+    is(string.pack('>B', 0x91), '\x91')
+    is(string.pack('=B', 0x91), '\x91')
+    is(string.pack('<B', 0x91), '\x91')
+    is(string.byte(string.pack('<h', 1)), 1)
+    is(string.byte(string.pack('>h', 1):reverse()), 1)
+    is(string.byte(string.pack('<H', 1)), 1)
+    is(string.byte(string.pack('>H', 1):reverse()), 1)
+    is(string.byte(string.pack('<l', 1)), 1)
+    is(string.byte(string.pack('>l', 1):reverse()), 1)
+    is(string.byte(string.pack('<L', 1)), 1)
+    is(string.byte(string.pack('>L', 1):reverse()), 1)
+    is(string.byte(string.pack('<j', 1)), 1)
+    is(string.byte(string.pack('>j', 1):reverse()), 1)
+    is(string.byte(string.pack('<J', 1)), 1)
+    is(string.byte(string.pack('>J', 1):reverse()), 1)
+    is(string.byte(string.pack('<T', 1)), 1)
+    is(string.byte(string.pack('>T', 1):reverse()), 1)
+    is(string.byte(string.pack('<i', 1)), 1)
+    is(string.byte(string.pack('>i', 1):reverse()), 1)
+    is(string.byte(string.pack('<I', 1)), 1)
+    is(string.byte(string.pack('>I', 1):reverse()), 1)
+    is(string.pack('i1', 0):len(), 1)
+    is(string.pack('i2', 0):len(), 2)
+    is(string.pack('i4', 0):len(), 4)
+    is(string.pack('i8', 0):len(), 8)
+    is(string.pack('i16', 0):len(), 16)
+    error_like(function () string.pack('i20', 0) end,
+               "^[^:]+:%d+: integral size %(20%) out of limits %[1,16%]",
+               "function pack out limit")
+
+    is(string.pack('!2 i1 i4', 0, 0):len(), 6)
+    is(string.pack('i1 Xb i1', 0, 0):len(), 2)
+    is(string.pack('i1 x x i1', 0, 0):len(), 4)
+
+    is(string.pack('c3', 'foo'), 'foo')
+    is(string.pack('z', 'foo'), 'foo\0')
+    is(string.pack('c4', 'foo'), 'foo\0')   -- padding
+
+    error_like(function () string.pack('w', 0) end,
+               "^[^:]+:%d+: invalid format option 'w'",
+               "function pack invalid format")
+
+    error_like(function () string.pack('i1 Xz i1', 0, 0) end,
+               "^[^:]+:%d+: bad argument #1 to 'pack' %(invalid next option for option 'X'%)",
+               "function pack invalid next")
+
+    error_like(function () string.pack('i', 'foo') end,
+               "^[^:]+:%d+: bad argument #2 to 'pack' %(number expected, got string%)",
+              "function pack bad arg")
+else
+    is(string.pack, nil, "no string.pack");
+end
+
+-- packsize
+if has_pack then
+    is(string.packsize('b'), 1, "function packsize")
+
+    is(string.packsize(''), 0, "function packsize empty")
+
+    error_like(function () string.packsize('z') end,
+               "^[^:]+:%d+: bad argument #1 to 'packsize' %(variable%-length format%)",
+               "function packsize bad arg")
+else
+    is(string.packsize, nil, "no string.packsize");
+end
+
+do -- rep
+    is(string.rep('ab', 3), 'ababab', "function rep")
+    is(string.rep('ab', 0), '')
+    is(string.rep('ab', -1), '')
+    is(string.rep('', 5), '')
+    if has_rep52 then
+        is(string.rep('ab', 3, ','), 'ab,ab,ab', "with sep")
+        local n = 1e6
+        is(string.rep('a', n), string.rep('', n + 1, 'a'))
+    else
+        diag("no rep with separator")
+    end
+
+    if _VERSION >= 'Lua 5.3' then
+        error_like(function () string.rep('foo', 1e9) end,
+                   "^[^:]+:%d+: resulting string too large",
+                   "too large")
+    elseif luajit21 then
+        error_is(function () string.rep('foo', 1e9) end,
+                 "not enough memory",
+                 "too large")
+    end
+
+    if _VERSION >= 'Lua 5.4' or jit then
+        is(string.rep('', 1e8), '', "rep ''")
+    else
+        diag('too slow')
+    end
+end
+
+do -- reverse
+    is(string.reverse('abcde'), 'edcba', "function reverse")
+    is(string.reverse('abcd'), 'dcba')
+    is(string.reverse(''), '')
+end
+
+do -- sub
+    is(string.sub('abcde', 1, 2), 'ab', "function sub")
+    is(string.sub('abcde', 3, 4), 'cd')
+    is(string.sub('abcde', -2), 'de')
+    is(string.sub('abcde', 3, 2), '')
+end
+
+do -- upper
+    is(string.upper('Test'), 'TEST', "function upper")
+    is(string.upper('TeSt'), 'TEST')
+    is(string.upper(string.rep('Test', 10000)), string.rep('TEST', 10000))
+end
+
+-- unpack
+if has_pack then
+    is(string.unpack('<h', string.pack('>h', 1):reverse()), 1, "function unpack")
+    is(string.unpack('<H', string.pack('>H', 1):reverse()), 1)
+    is(string.unpack('<l', string.pack('>l', 1):reverse()), 1)
+    is(string.unpack('<L', string.pack('>L', 1):reverse()), 1)
+    is(string.unpack('<j', string.pack('>j', 1):reverse()), 1)
+    is(string.unpack('<J', string.pack('>J', 1):reverse()), 1)
+    is(string.unpack('<T', string.pack('>T', 1):reverse()), 1)
+    is(string.unpack('<i', string.pack('>i', 1):reverse()), 1)
+    is(string.unpack('<I', string.pack('>I', 1):reverse()), 1)
+    is(string.unpack('<f', string.pack('>f', 1.0):reverse()), 1.0)
+    is(string.unpack('<d', string.pack('>d', 1.0):reverse()), 1.0)
+    is(string.unpack('<n', string.pack('>n', 1.0):reverse()), 1.0)
+
+    is(string.unpack('c3', string.pack('c3', 'foo')), 'foo')
+    is(string.unpack('z', string.pack('z', 'foo')), 'foo')
+    is(string.unpack('s', string.pack('s', 'foo')), 'foo')
+
+    error_like(function () string.unpack('c4', 'foo') end,
+               "^[^:]+:%d+: bad argument #2 to 'unpack' %(data string too short%)",
+               "function unpack data too short")
+
+    error_like(function () string.unpack('c', 'foo') end,
+               "^[^:]+:%d+: missing size for format option 'c'",
+               "function unpack missing size")
+else
+    is(string.unpack, nil, "no string.unpack");
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/305-utf8.t b/test/lua-Harness-tests/305-utf8.t
new file mode 100755
index 0000000..4304b6c
--- /dev/null
+++ b/test/lua-Harness-tests/305-utf8.t
@@ -0,0 +1,55 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2014-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua UTF-8 support Library
+
+=head2 Synopsis
+
+    % prove 305-utf8.t
+
+=head2 Description
+
+Tests Lua UTF-8 Library
+
+This library was introduced in Lua 5.3.
+
+See section "UTF-8 support" in "Reference Manual"
+L<https://www.lua.org/manual/5.3/manual.html#6.5>,
+L<https://www.lua.org/manual/5.4/manual.html#6.5>
+
+=cut
+
+--]]
+
+require 'tap'
+
+local profile = require'profile'
+local has_utf8 = _VERSION >= 'Lua 5.3' or (jit and jit.version:match'moonjit') or profile.utf8
+
+if not utf8 then
+    plan(1)
+    nok(has_utf8, "no has_utf8")
+else
+    plan'no_plan'
+    dofile'lexico53/utf8.t'
+    if _VERSION >= 'Lua 5.4' then
+        dofile'lexico54/utf8.t'
+    end
+    done_testing()
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/306-table.t b/test/lua-Harness-tests/306-table.t
new file mode 100755
index 0000000..9836655
--- /dev/null
+++ b/test/lua-Harness-tests/306-table.t
@@ -0,0 +1,372 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Table Library
+
+=head2 Synopsis
+
+    % prove 305-table.t
+
+=head2 Description
+
+Tests Lua Table Library
+
+See section "Table Manipulation" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.5>,
+L<https://www.lua.org/manual/5.2/manual.html#6.5>,
+L<https://www.lua.org/manual/5.3/manual.html#6.6>,
+L<https://www.lua.org/manual/5.4/manual.html#6.6>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT')
+local has_foreach = _VERSION == 'Lua 5.1'
+local has_foreachi = _VERSION == 'Lua 5.1'
+local has_getn = _VERSION == 'Lua 5.1'
+local has_setn_obsolete = _VERSION == 'Lua 5.1' and not jit
+local has_maxn = _VERSION == 'Lua 5.1' or profile.compat51 or profile.has_table_maxn
+local has_pack = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_move = _VERSION >= 'Lua 5.3' or  luajit21
+local has_unpack = _VERSION >= 'Lua 5.2'
+local has_alias_unpack = profile.luajit_compat52
+local nocvtn2s = profile.nocvtn2s
+
+plan'no_plan'
+
+do -- concat
+    local t = {'a','b','c','d','e'}
+    is(table.concat(t), 'abcde', "function concat")
+    is(table.concat(t, ','), 'a,b,c,d,e')
+    is(table.concat(t, ',',2), 'b,c,d,e')
+    is(table.concat(t, ',', 2, 4), 'b,c,d')
+    is(table.concat(t, ',', 4, 2), '')
+
+    t = {'a','b',3,'d','e'}
+    if nocvtn2s then
+        error_like(function () table.concat(t,',') end,
+               "^[^:]+:%d+: invalid value %(number%) at index 3 in table for 'concat'",
+               "function concat (number no conv)")
+    else
+        is(table.concat(t,','), 'a,b,3,d,e', "function concat (number)")
+    end
+
+    t = {'a','b','c','d','e'}
+    error_like(function () table.concat(t, ',', 2, 7) end,
+               "^[^:]+:%d+: invalid value %(nil%) at index 6 in table for 'concat'",
+               "function concat (out of range)")
+
+    t = {'a','b',true,'d','e'}
+    error_like(function () table.concat(t, ',') end,
+               "^[^:]+:%d+: invalid value %(boolean%) at index 3 in table for 'concat'",
+               "function concat (non-string)")
+end
+
+do -- insert
+    local a = {'10', '20', '30'}
+    table.insert(a, 1, '15')
+    is(table.concat(a,','), '15,10,20,30', "function insert")
+    local t = {}
+    table.insert(t, 'a')
+    is(table.concat(t, ','), 'a')
+    table.insert(t, 'b')
+    is(table.concat(t, ','), 'a,b')
+    table.insert(t, 1, 'c')
+    is(table.concat(t, ','), 'c,a,b')
+    table.insert(t, 2, 'd')
+    is(table.concat(t, ','), 'c,d,a,b')
+    table.insert(t, 5, 'e')
+    is(table.concat(t, ','), 'c,d,a,b,e')
+
+    if _VERSION == 'Lua 5.1' then
+        todo("not with 5.1", 2)
+    end
+    error_like(function () table.insert(t, 7, 'f') end,
+               "^[^:]+:%d+: bad argument #2 to 'insert' %(position out of bounds%)",
+               "function insert (out of bounds)")
+
+    error_like(function () table.insert(t, -9, 'f') end,
+               "^[^:]+:%d+: bad argument #2 to 'insert' %(position out of bounds%)",
+               "function insert (out of bounds)")
+
+    error_like(function () table.insert(t, 2, 'g', 'h')  end,
+               "^[^:]+:%d+: wrong number of arguments to 'insert'",
+               "function insert (too many arg)")
+end
+
+-- foreach 5.0
+if has_foreach then
+    local t = {a=10, b=100}
+    local output = {}
+    table.foreach(t, function (k, v) output[k] = v end)
+    eq_array(output, t, "function foreach (hash)")
+
+    t = {'a','b','c'}
+    output = {}
+    table.foreach(t, function (k, v)
+        table.insert(output, k)
+        table.insert(output, v)
+    end)
+    eq_array(output, {1, 'a', 2, 'b', 3, 'c'}, "function foreach (array)")
+else
+    is(table.foreach, nil, "no table.foreach");
+end
+
+-- foreachi 5.0
+if has_foreachi then
+    local t = {'a','b','c'}
+    local output = {}
+    table.foreachi(t, function (i, v)
+        table.insert(output, i)
+        table.insert(output, v)
+    end)
+    eq_array(output, {1, 'a', 2, 'b', 3, 'c'}, "function foreachi")
+else
+    is(table.foreachi, nil, "no table.foreachi");
+end
+
+if has_getn then
+    is(table.getn{10,2,4}, 3, "function getn")
+    is(table.getn{10,2,nil}, 2)
+else
+    is(table.getn, nil, "no table.getn");
+end
+
+-- maxn
+if has_maxn then
+    local t = {}
+    is(table.maxn(t), 0, "function maxn")
+    t[1] = 'a'
+    t[2] = 'b'
+    is(table.maxn(t), 2)
+    t[6] = 'g'
+    is(table.maxn(t), 6)
+
+    local a = {}
+    a[10000] = 1
+    is(table.maxn(a), 10000)
+else
+    is(table.maxn, nil, "no table.maxn");
+end
+
+-- move
+if has_move then
+    local a = {'a', 'b', 'c'}
+    local t = { 1, 2, 3, 4}
+    table.move(a, 1, 3, 1, t)
+    eq_array(t, {'a', 'b', 'c', 4}, "function move")
+    table.move(a, 1, 3, 3, t)
+    eq_array(t, {'a', 'b', 'a', 'b', 'c'})
+
+    table.move(a, 1, 3, 1)
+    eq_array(a, {'a', 'b', 'c'})
+    table.move(a, 1, 3, 3)
+    eq_array(a, {'a', 'b', 'a', 'b', 'c'})
+
+    error_like(function () table.move(a, 1, 2, 1, 2) end,
+               "^[^:]+:%d+: bad argument #5 to 'move' %(table expected",
+               "function move (bad arg)")
+
+    error_like(function () table.move(a, 1, 2) end,
+               "^[^:]+:%d+: bad argument #4 to 'move' %(number expected, got .-%)",
+               "function move (bad arg)")
+
+    error_like(function () table.move(a, 1) end,
+               "^[^:]+:%d+: bad argument #3 to 'move' %(number expected, got .-%)",
+               "function move (bad arg)")
+else
+    is(table.move, nil, "no table.move");
+end
+
+-- pack
+if has_pack then
+    local t = table.pack("abc", "def", "ghi")
+    eq_array(t, {
+        "abc",
+        "def",
+        "ghi"
+    }, "function pack")
+    is(t.n, 3)
+
+    t = table.pack()
+    eq_array(t, {}, "function pack (no element)")
+    is(t.n, 0)
+else
+    is(table.pack, nil, "no table.pack");
+end
+
+do -- remove
+    local t = {}
+    local a = table.remove(t)
+    is(a, nil, "function remove")
+    t = {'a','b','c','d','e'}
+    a = table.remove(t)
+    is(a, 'e')
+    is(table.concat(t, ','), 'a,b,c,d')
+    a = table.remove(t,3)
+    is(a, 'c')
+    is(table.concat(t, ','), 'a,b,d')
+    a = table.remove(t,1)
+    is(a, 'a')
+    is(table.concat(t, ','), 'b,d')
+
+    if _VERSION == 'Lua 5.1' then
+        todo("not with 5.1", 1)
+    end
+    error_like(function () table.remove(t,7) end,
+               "^[^:]+:%d+: bad argument #1 to 'remove' %(position out of bounds%)",
+               "function remove (out of bounds)")
+end
+
+-- setn obsolete
+if has_setn_obsolete then
+    local a = {}
+    error_like(function () table.setn(a, 10000) end,
+               "^[^:]+:%d+: 'setn' is obsolete",
+               "function setn")
+else
+    is(table.setn, nil, "no table.setn");
+end
+
+do -- sort
+    local lines = {
+        luaH_set = 10,
+        luaH_get = 24,
+        luaH_present = 48,
+    }
+
+    do
+        local a = {}
+        for n in pairs(lines) do a[#a + 1] = n end
+        table.sort(a)
+        local output = {}
+        for _, n in ipairs(a) do
+            table.insert(output, n)
+        end
+        eq_array(output, {'luaH_get', 'luaH_present', 'luaH_set'}, "function sort")
+    end
+
+    do
+        local function pairsByKeys (t, f)
+            local a = {}
+            for n in pairs(t) do a[#a + 1] = n end
+            table.sort(a, f)
+            local i = 0     -- iterator variable
+            return function ()  -- iterator function
+                i = i + 1
+                return a[i], t[a[i]]
+            end
+        end
+
+        local output = {}
+        for name, line in pairsByKeys(lines) do
+            table.insert(output, name)
+            table.insert(output, line)
+        end
+        eq_array(output, {'luaH_get', 24, 'luaH_present', 48, 'luaH_set', 10}, "function sort")
+
+        output = {}
+        for name, line in pairsByKeys(lines, function (a, b) return a < b end) do
+            table.insert(output, name)
+            table.insert(output, line)
+        end
+        eq_array(output, {'luaH_get', 24, 'luaH_present', 48, 'luaH_set', 10}, "function sort")
+    end
+
+    do
+        local function permgen (a, n)
+            n = n or #a
+            if n <= 1 then
+                coroutine.yield(a)
+            else
+                for i=1,n do
+                    a[n], a[i] = a[i], a[n]
+                    permgen(a, n - 1)
+                    a[n], a[i] = a[i], a[n]
+                end
+            end
+        end
+
+        local function permutations (a)
+            local co = coroutine.create(function () permgen(a) end)
+            return function ()
+                       local code, res = coroutine.resume(co)
+                       return res
+                    end
+        end
+
+        local t = {}
+        local output = {}
+        for _, v in ipairs{'a', 'b', 'c', 'd', 'e', 'f', 'g'} do
+            table.insert(t, v)
+            local ref = table.concat(t, ' ')
+            table.insert(output, ref)
+            local n = 0
+            for p in permutations(t) do
+                local c = {}
+                for i, vv in ipairs(p) do
+                    c[i] = vv
+                end
+                table.sort(c)
+                assert(ref == table.concat(c, ' '), table.concat(p, ' '))
+                n = n + 1
+            end
+            table.insert(output, n)
+        end
+
+        eq_array(output, {
+            'a', 1,
+            'a b', 2,
+            'a b c', 6,
+            'a b c d', 24,
+            'a b c d e', 120,
+            'a b c d e f', 720,
+            'a b c d e f g', 5040,
+        }, "function sort (all permutations)")
+    end
+
+    if _VERSION == 'Lua 5.1' and not jit then
+        todo("not with 5.1")
+    end
+    error_like(function ()
+                   local t = { 1 }
+                   table.sort( { t, t, t, t, }, function (a, b) return a[1] == b[1] end )
+               end,
+               "^[^:]+:%d+: invalid order function for sorting",
+               "function sort (bad func)")
+end
+
+-- unpack
+if has_unpack then
+    eq_array({table.unpack({})}, {}, "function unpack")
+    eq_array({table.unpack({'a'})}, {'a'})
+    eq_array({table.unpack({'a','b','c'})}, {'a','b','c'})
+    eq_array({(table.unpack({'a','b','c'}))}, {'a'})
+    eq_array({table.unpack({'a','b','c','d','e'},2,4)}, {'b','c','d'})
+    eq_array({table.unpack({'a','b','c'},2,4)}, {'b','c'})
+elseif has_alias_unpack then
+    is(table.unpack, unpack, "alias table.unpack");
+else
+    is(table.unpack, nil, "no table.unpack");
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/307-math.t b/test/lua-Harness-tests/307-math.t
new file mode 100755
index 0000000..8b51ed1
--- /dev/null
+++ b/test/lua-Harness-tests/307-math.t
@@ -0,0 +1,375 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Mathematic Library
+
+=head2 Synopsis
+
+    % prove 307-math.t
+
+=head2 Description
+
+Tests Lua Mathematic Library
+
+See section "Mathematical Functions" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.6>,
+L<https://www.lua.org/manual/5.2/manual.html#6.6>,
+L<https://www.lua.org/manual/5.3/manual.html#6.7>,
+L<https://www.lua.org/manual/5.4/manual.html#6.7>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local has_integer = _VERSION >= 'Lua 5.3' or (jit and jit.version:match'moonjit') or profile.integer
+local has_mathx = _VERSION < 'Lua 5.3' or profile.compat52 or profile.compat53 or profile.has_mathx
+local has_log10 = _VERSION < 'Lua 5.2' or profile.compat51 or profile.has_math_log10 or
+                  profile.compat52 or profile.compat53 or profile.has_mathx
+local has_log_with_base = _VERSION >= 'Lua 5.2' or profile.compat52
+local has_mod = profile.has_math_mod or ujit
+local nocvts2n = profile.nocvts2n or jit
+
+plan'no_plan'
+
+do -- abs
+    is(math.abs(-12.34), 12.34, "function abs (float)")
+    is(math.abs(12.34), 12.34)
+    if math.type then
+        is(math.type(math.abs(-12.34)), 'float')
+    end
+    is(math.abs(-12), 12, "function abs (integer)")
+    is(math.abs(12), 12)
+    if math.type then
+        is(math.type(math.abs(-12)), 'integer')
+    end
+end
+
+do -- acos
+    like(math.acos(0.5), '^1%.047', "function acos")
+end
+
+do -- asin
+    like(math.asin(0.5), '^0%.523', "function asin")
+end
+
+do -- atan
+    like(math.atan(0.5), '^0%.463', "function atan")
+end
+
+-- atan2
+if has_mathx then
+    like(math.atan2(1.0, 2.0), '^0%.463', "function atan2")
+else
+    is(math.atan2, nil, "function atan2 (removed)")
+end
+
+do -- ceil
+    is(math.ceil(12.34), 13, "function ceil")
+    is(math.ceil(-12.34), -12)
+    is(math.ceil(-12), -12)
+    if math.type then
+        is(math.type(math.ceil(-12.34)), 'integer')
+    end
+end
+
+do -- cos
+    like(math.cos(1.0), '^0%.540', "function cos")
+end
+
+-- cosh
+if has_mathx then
+    like(math.cosh(1.0), '^1%.543', "function cosh")
+else
+    is(math.cosh, nil, "function cosh (removed)")
+end
+
+do -- deg
+    is(math.deg(math.pi), 180, "function deg")
+end
+
+do -- exp
+    like(math.exp(1.0), '^2%.718', "function exp")
+end
+
+do -- floor
+    is(math.floor(12.34), 12, "function floor")
+    is(math.floor(-12.34), -13)
+    is(math.floor(-12), -12)
+    if math.type then
+        is(math.type(math.floor(-12.34)), 'integer')
+    end
+end
+
+do -- fmod
+    like(math.fmod(7.0001, 0.3), '^0%.100', "function fmod (float)")
+    like(math.fmod(-7.0001, 0.3), '^-0%.100')
+    like(math.fmod(-7.0001, -0.3), '^-0%.100')
+    if math.type then
+        is(math.type(math.fmod(7.0, 0.3)), 'float')
+    end
+    is(math.fmod(7, 3), 1, "function fmod (integer)")
+    is(math.fmod(-7, 3), -1)
+    is(math.fmod(-7, -1), 0)
+    if math.type then
+        is(math.type(math.fmod(7, 3)), 'integer')
+    end
+    if _VERSION >= 'Lua 5.3' then
+        error_like(function () math.fmod(7, 0) end,
+                   "^[^:]+:%d+: bad argument #2 to 'fmod' %(zero%)",
+                   "function fmod 0")
+    else
+        diag"fmod by zero -> nan"
+    end
+end
+
+-- frexp
+if has_mathx then
+    eq_array({math.frexp(1.5)}, {0.75, 1}, "function frexp")
+else
+    is(math.frexp, nil, "function frexp (removed)")
+end
+
+do -- huge
+    type_ok(math.huge, 'number', "variable huge")
+    if math.type then
+        is(math.type(math.huge), 'float')
+    end
+end
+
+-- ldexp
+if has_mathx then
+    is(math.ldexp(1.2, 3), 9.6, "function ldexp")
+else
+    is(math.ldexp, nil, "function ldexp (removed)")
+end
+
+do -- log
+    like(math.log(47), '^3%.85', "function log")
+    if has_log_with_base then
+        like(math.log(47, math.exp(1)), '^3%.85', "function log (base e)")
+        like(math.log(47, 2), '^5%.554', "function log (base 2)")
+        like(math.log(47, 10), '^1%.672', "function log (base 10)")
+    end
+end
+
+-- log10
+if has_log10 then
+    like(math.log10(47.0), '^1%.672', "function log10")
+else
+    is(math.log10, nil, "function log10 (removed)")
+end
+
+do --max
+    is(math.max(1), 1, "function max")
+    is(math.max(1, 2), 2)
+    is(math.max(1, 2, 3, -4), 3)
+
+    error_like(function () math.max() end,
+               "^[^:]+:%d+: bad argument #1 to 'max' %(.- expected",
+               "function max 0")
+end
+
+-- maxinteger
+if has_integer then
+    type_ok(math.maxinteger, 'number', "variable maxinteger")
+    if math.type then
+        is(math.type(math.maxinteger), 'integer')
+    end
+else
+    is(math.maxinteger, nil, "no maxinteger")
+end
+
+do --min
+    is(math.min(1), 1, "function min")
+    is(math.min(1, 2), 1)
+    is(math.min(1, 2, 3, -4), -4)
+
+    error_like(function () math.min() end,
+               "^[^:]+:%d+: bad argument #1 to 'min' %(.- expected",
+               "function min 0")
+end
+
+-- mininteger
+if has_integer then
+    type_ok(math.mininteger, 'number', "variable mininteger")
+    if math.type then
+        is(math.type(math.mininteger), 'integer')
+    end
+else
+    is(math.mininteger, nil, "no mininteger")
+end
+
+-- mod (compat50)
+if has_mod then
+    is(math.mod, math.fmod, "function mod (alias fmod)")
+else
+    is(math.mod, nil, "function mod (alias removed)")
+end
+
+do -- modf
+    eq_array({math.modf(2.25)}, {2, 0.25}, "function modf")
+    eq_array({math.modf(2)}, {2, 0.0})
+end
+
+do -- pi
+    like(tostring(math.pi), '^3%.14', "variable pi")
+end
+
+-- pow
+if has_mathx then
+    is(math.pow(-2, 3), -8, "function pow")
+else
+    is(math.pow, nil, "function pow (removed)")
+end
+
+do -- rad
+    like(math.rad(180), '^3%.14', "function rad")
+end
+
+do -- random
+    like(math.random(), '^0%.%d+', "function random no arg")
+    if math.type then
+        is(math.type(math.random()), 'float')
+    end
+    like(math.random(9), '^%d$', "function random 1 arg")
+    if math.type then
+        is(math.type(math.random(9)), 'integer')
+    end
+    like(math.random(10, 19), '^1%d$', "function random 2 arg")
+    if math.type then
+        is(math.type(math.random(10, 19)), 'integer')
+    end
+    like(math.random(-19, -10), '^-1%d$', "function random 2 arg")
+
+    if _VERSION >= 'Lua 5.4' then
+        like(math.random(0), '^%-?%d+$', "function random 0")
+    else
+        if jit then
+            todo("LuaJIT intentional. Don't check empty interval.")
+        end
+        error_like(function () math.random(0) end,
+                   "^[^:]+:%d+: bad argument #1 to 'random' %(interval is empty%)",
+                  "function random empty interval")
+    end
+
+    if jit then
+        todo("LuaJIT intentional. Don't check empty interval.", 2)
+    end
+    error_like(function () math.random(-9) end,
+               "^[^:]+:%d+: bad argument #%d to 'random' %(interval is empty%)",
+               "function random empty interval")
+
+    error_like(function () math.random(19, 10) end,
+               "^[^:]+:%d+: bad argument #%d to 'random' %(interval is empty%)",
+               "function random empty interval")
+
+    if jit then
+        todo("LuaJIT intentional. Don't care about extra arguments.")
+    end
+    error_like(function () math.random(1, 2, 3) end,
+               "^[^:]+:%d+: wrong number of arguments",
+               "function random too many arg")
+end
+
+do -- randomseed
+    math.randomseed(42)
+    local a = math.random()
+    math.randomseed(42)
+    local b = math.random()
+    is(a, b, "function randomseed")
+end
+
+do -- sin
+    like(math.sin(1.0), '^0%.841', "function sin")
+end
+
+-- sinh
+if has_mathx then
+    like(math.sinh(1), '^1%.175', "function sinh")
+else
+    is(math.sinh, nil, "function sinh (removed)")
+end
+
+do -- sqrt
+    like(math.sqrt(2), '^1%.414', "function sqrt")
+end
+
+do -- tan
+    like(math.tan(1.0), '^1%.557', "function tan")
+end
+
+-- tanh
+if has_mathx then
+    like(math.tanh(1), '^0%.761', "function tanh")
+else
+    is(math.tanh, nil, "function tanh (removed)")
+end
+
+-- tointeger
+if has_integer then
+    is(math.tointeger(-12), -12, "function tointeger (number)")
+    is(math.tointeger(-12.0), -12)
+    is(math.tointeger(-12.34), nil)
+    if nocvts2n then
+        is(math.tointeger('-12'), nil, "function tointeger (string)")
+        is(math.tointeger('-12.0'), nil)
+    else
+        is(math.tointeger('-12'), -12, "function tointeger (string)")
+        is(math.tointeger('-12.0'), -12)
+    end
+    is(math.tointeger('-12.34'), nil)
+    is(math.tointeger('bad'), nil)
+    is(math.tointeger(true), nil, "function tointeger (boolean)")
+    is(math.tointeger({}), nil, "function tointeger (table)")
+else
+    is(math.tointeger, nil, "no math.tointeger")
+end
+
+-- type
+if has_integer then
+    is(math.type(3), 'integer', "function type")
+    is(math.type(3.14), 'float')
+    is(math.type('3.14'), nil)
+else
+    is(math.type, nil, "no math.type")
+end
+
+-- ult
+if has_integer then
+    is(math.ult(2, 3), true, "function ult")
+    is(math.ult(2, 2), false)
+    is(math.ult(2, 1), false)
+
+    error_like(function () math.ult(3.14) end,
+               "^%S+ bad argument #1 to 'ult' %(number has no integer representation%)",
+               "function ult (float)")
+    error_like(function () math.ult(2, 3.14) end,
+               "^%S+ bad argument #2 to 'ult' %(number has no integer representation%)")
+    error_like(function () math.ult(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'ult' %(number expected, got boolean%)",
+               "function ult (boolean)")
+    error_like(function () math.ult(2, true) end,
+               "^[^:]+:%d+: bad argument #2 to 'ult' %(number expected, got boolean%)")
+else
+    is(math.ult, nil, "no math.ult")
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/308-io.t b/test/lua-Harness-tests/308-io.t
new file mode 100755
index 0000000..35d39c0
--- /dev/null
+++ b/test/lua-Harness-tests/308-io.t
@@ -0,0 +1,397 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Input/Output Library
+
+=head2 Synopsis
+
+    % prove 308-io.t
+
+=head2 Description
+
+Tests Lua Input/Output Library
+
+See section "Input and Output Facilities" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.7>,
+L<https://www.lua.org/manual/5.2/manual.html#6.8>,
+L<https://www.lua.org/manual/5.3/manual.html#6.8>,
+L<https://www.lua.org/manual/5.4/manual.html#6.8>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT')
+local has_write51 = _VERSION == 'Lua 5.1' and (not profile.luajit_compat52 or ujit)
+local has_lines52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_read52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_read53 = _VERSION >= 'Lua 5.3' or luajit21
+local has_meta53 = _VERSION >= 'Lua 5.3'
+local has_meta54 = _VERSION >= 'Lua 5.4'
+
+local lua = get_lua_binary_name()
+
+plan'no_plan'
+
+do -- stdin
+    like(io.stdin, '^file %(0?[Xx]?%x+%)$', "variable stdin")
+end
+
+do -- stdout
+    like(io.stdout, '^file %(0?[Xx]?%x+%)$', "variable stdout")
+end
+
+do -- stderr
+    like(io.stderr, '^file %(0?[Xx]?%x+%)$', "variable stderr")
+end
+
+do -- metatable
+    local f = io.tmpfile()
+    local mt = getmetatable(f)
+    type_ok(mt, 'table', "metatable")
+
+    type_ok(mt.__gc, 'function')
+    type_ok(mt.__tostring, 'function')
+    type_ok(mt.__index, 'table')
+
+    if has_meta53 then
+        is(mt.__name, 'FILE*')
+    else
+        is(mt.__name, nil)
+    end
+
+    if has_meta54 then
+        type_ok(mt.__close, 'function')
+        type_ok(mt.__index, 'table')
+        is(mt.close, nil)
+        is(mt.flush, nil)
+        is(mt.lines, nil)
+        is(mt.read, nil)
+        is(mt.seek, nil)
+        is(mt.setvbuf, nil)
+        is(mt.write, nil)
+    else
+        is(mt.__close, nil)
+        is(mt.__index, mt)
+        type_ok(mt.close, 'function')
+        type_ok(mt.flush, 'function')
+        type_ok(mt.lines, 'function')
+        type_ok(mt.read, 'function')
+        type_ok(mt.seek, 'function')
+        type_ok(mt.setvbuf, 'function')
+        type_ok(mt.write, 'function')
+    end
+
+    type_ok(mt.__index.close, 'function')
+    type_ok(mt.__index.flush, 'function')
+    type_ok(mt.__index.lines, 'function')
+    type_ok(mt.__index.read, 'function')
+    type_ok(mt.__index.seek, 'function')
+    type_ok(mt.__index.setvbuf, 'function')
+    type_ok(mt.__index.write, 'function')
+end
+
+do -- close
+    local r, msg = io.close(io.stderr)
+    is(r, nil, "close (std)")
+    is(msg, "cannot close standard file")
+end
+
+do -- flush
+    is(io.flush(), true, "function flush")
+end
+
+do -- open
+    os.remove('file-308.no')
+    local f, msg = io.open("file-308.no")
+    is(f, nil, "function open")
+    is(msg, "file-308.no: No such file or directory")
+
+    os.remove('file-308.txt')
+    f = io.open('file-308.txt', 'w')
+    f:write("file with text\n")
+    f:close()
+    f = io.open('file-308.txt')
+    like(f, '^file %(0?[Xx]?%x+%)$', "function open")
+
+    is(io.close(f), true, "function close")
+
+    error_like(function () io.close(f) end,
+               "^[^:]+:%d+: attempt to use a closed file",
+               "function close (closed)")
+
+    if _VERSION == 'Lua 5.1' then
+        todo("not with 5.1")
+    end
+    error_like(function () io.open('file-308.txt', 'baz') end,
+               "^[^:]+:%d+: bad argument #2 to 'open' %(invalid mode%)",
+               "function open (bad mode)")
+end
+
+do -- type
+    is(io.type("not a file"), nil, "function type")
+    local f = io.open('file-308.txt')
+    is(io.type(f), 'file')
+    like(tostring(f), '^file %(0?[Xx]?%x+%)$')
+    io.close(f)
+    is(io.type(f), 'closed file')
+    is(tostring(f), 'file (closed)')
+end
+
+do -- input
+    is(io.stdin, io.input(), "function input")
+    is(io.stdin, io.input(nil))
+    local f = io.stdin
+    like(io.input('file-308.txt'), '^file %(0?[Xx]?%x+%)$')
+    is(f, io.input(f))
+end
+
+do -- output
+    is(io.output(), io.stdout, "function output")
+    is(io.output(nil), io.stdout)
+    local f = io.stdout
+    like(io.output('output.new'), '^file %(0?[Xx]?%x+%)$')
+    is(f, io.output(f))
+    os.remove('output.new')
+end
+
+do -- popen
+    local r, f = pcall(io.popen, lua .. [[ -e "print 'standard output'"]])
+    if r then
+        is(io.type(f), 'file', "popen (read)")
+        is(f:read(), "standard output")
+        is(io.close(f), true)
+    else
+        diag("io.popen not supported")
+    end
+
+    r, f = pcall(io.popen, lua .. [[ -e "for line in io.lines() do print((line:gsub('e', 'a'))) end"]], 'w')
+    if r then
+        is(io.type(f), 'file', "popen (write)")
+        f:write("# hello\n") -- not tested : hallo
+        is(io.close(f), true)
+    else
+        diag("io.popen not supported")
+    end
+end
+
+do -- lines
+    for line in io.lines('file-308.txt') do
+        is(line, "file with text", "function lines(filename)")
+    end
+
+    error_like(function () io.lines('file-308.no') end,
+               "No such file or directory",
+               "function lines(no filename)")
+end
+
+do -- tmpfile
+    local  f = io.tmpfile()
+    is(io.type(f), 'file', "function tmpfile")
+    f:write("some text")
+    f:close()
+end
+
+do -- write
+    io.write() -- not tested
+    io.write('# text', 12, "\n") -- not tested :  # text12
+end
+
+do -- :close
+    local r, msg = io.stderr:close()
+    is(r, nil, "method close (std)")
+    is(msg, "cannot close standard file")
+
+    local f = io.open('file-308.txt')
+    is(f:close(), true, "method close")
+end
+
+do -- :flush
+    is(io.stderr:flush(), true, "method flush")
+
+    local f = io.open('file-308.txt')
+    f:close()
+    error_like(function () f:flush() end,
+               "^[^:]+:%d+: attempt to use a closed file",
+               "method flush (closed)")
+end
+
+do -- :read & :write
+    local f = io.open('file-308.txt')
+    f:close()
+    error_like(function () f:read() end,
+               "^[^:]+:%d+: attempt to use a closed file",
+               "method read (closed)")
+
+    f = io.open('file-308.txt')
+    local s = f:read()
+    is(s:len(), 14, "method read")
+    is(s, "file with text")
+    s = f:read()
+    is(s, nil)
+    f:close()
+
+    f = io.open('file-308.txt')
+    error_like(function () f:read('*z') end,
+               "^[^:]+:%d+: bad argument #1 to 'read' %(invalid %w+%)",
+               "method read (invalid)")
+    f:close()
+
+    f = io.open('file-308.txt')
+    local s1, s2 = f:read('*l', '*l')
+    is(s1:len(), 14, "method read *l")
+    is(s1, "file with text")
+    is(s2, nil)
+    f:close()
+
+    if has_read52 then
+        f = io.open('file-308.txt')
+        s1, s2 = f:read('*L', '*L')
+        is(s1:len(), 15, "method read *L")
+        is(s1, "file with text\n")
+        is(s2, nil)
+        f:close()
+    else
+        diag("no read *L")
+    end
+
+    f = io.open('file-308.txt')
+    local n1, n2 = f:read('*n', '*n')
+    is(n1, nil, "method read *n")
+    is(n2, nil)
+    f:close()
+
+    f = io.open('file-308.num', 'w')
+    f:write('1\n')
+    f:write('0xFF\n')
+    f:write(string.rep('012', 90) .. '\n')
+    f:close()
+
+    f = io.open('file-308.num')
+    n1, n2 = f:read('*n', '*n')
+    is(n1, 1, "method read *n")
+    is(n2, 255, "method read *n")
+    local n = f:read('*n')
+    if _VERSION < 'Lua 5.3' then
+        type_ok(n, 'number')
+    else
+        is(n, nil, "method read *n too long")
+    end
+    f:close()
+
+    os.remove('file-308.num') -- clean up
+
+    f = io.open('file-308.txt')
+    s = f:read('*a')
+    is(s:len(), 15, "method read *a")
+    is(s, "file with text\n")
+    f:close()
+
+    if has_read53 then
+        f = io.open('file-308.txt')
+        s = f:read('a')
+        is(s:len(), 15, "method read a")
+        is(s, "file with text\n")
+        f:close()
+    else
+        diag("* mandatory")
+    end
+
+    f = io.open('file-308.txt')
+    is(f:read(0), '', "method read number")
+    eq_array({f:read(5, 5, 15)}, {'file ', 'with ', "text\n"})
+    f:close()
+end
+
+do -- :lines
+    local f = io.open('file-308.txt')
+    for line in f:lines() do
+        is(line, "file with text", "method lines")
+    end
+    is(io.type(f), 'file')
+    f:close()
+    is(io.type(f), 'closed file')
+
+    if has_lines52 then
+        f = io.open('file-308.txt')
+        for two_char in f:lines(2) do
+            is(two_char, "fi", "method lines (with read option)")
+            break
+        end
+        f:close()
+    else
+        diag("no lines with option")
+    end
+end
+
+do -- :seek
+    local f = io.open('file-308.txt')
+    f:close()
+
+    error_like(function () f:seek('end', 0) end,
+               "^[^:]+:%d+: attempt to use a closed file",
+               "method seek (closed)")
+
+    f = io.open('file-308.txt')
+    error_like(function () f:seek('bad', 0) end,
+               "^[^:]+:%d+: bad argument #1 to 'seek' %(invalid option 'bad'%)",
+               "method seek (invalid)")
+
+    f = io.open('file-308.bin', 'w')
+    f:write('ABCDE')
+    f:close()
+    f = io.open('file-308.bin')
+    is(f:seek('end', 0), 5, "method seek")
+    f:close()
+    os.remove('file-308.bin') --clean up
+end
+
+do -- :setvbuf
+    local  f = io.open('file-308.txt')
+     is(f:setvbuf('no'), true, "method setvbuf 'no'")
+
+    is(f:setvbuf('full', 4096), true, "method setvbuf 'full'")
+
+    is(f:setvbuf('line', 132), true, "method setvbuf 'line'")
+    f:close()
+end
+
+os.remove('file-308.txt') -- clean up
+
+do -- :write
+    local  f = io.open('file-308.out', 'w')
+    f:close()
+    error_like(function () f:write('end') end,
+               "^[^:]+:%d+: attempt to use a closed file",
+               "method write (closed)")
+
+    f = io.open('file-308.out', 'w')
+    if has_write51 then
+        is(f:write('end'), true, "method write")
+    else
+        is(f:write('end'), f, "method write")
+    end
+    f:close()
+
+    os.remove('file-308.out') --clean up
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/309-os.t b/test/lua-Harness-tests/309-os.t
new file mode 100755
index 0000000..a787b14
--- /dev/null
+++ b/test/lua-Harness-tests/309-os.t
@@ -0,0 +1,271 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Operating System Library
+
+=head2 Synopsis
+
+    % prove 309-os.t
+
+=head2 Description
+
+Tests Lua Operating System Library
+
+See section "Operating System Facilities" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.8>,
+L<https://www.lua.org/manual/5.2/manual.html#6.9>,
+L<https://www.lua.org/manual/5.3/manual.html#6.9>,
+L<https://www.lua.org/manual/5.4/manual.html#6.9>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+local luajit20 = jit and (jit.version_num < 20100 and not jit.version:match'^RaptorJIT')
+local has_execute51 = _VERSION == 'Lua 5.1' and (not profile.luajit_compat52 or ujit)
+local lua = get_lua_binary_name()
+
+plan'no_plan'
+
+do -- clock
+    local clk = os.clock()
+    type_ok(clk, 'number', "function clock")
+    ok(clk <= os.clock())
+end
+
+do -- date
+    local d = os.date('!*t', 0)
+    is(d.year, 1970, "function date")
+    is(d.month, 1)
+    is(d.day, 1)
+    is(d.hour, 0)
+    is(d.min, 0)
+    is(d.sec, 0)
+    is(d.wday, 5)
+    is(d.yday, 1)
+    is(d.isdst, false)
+
+    is(os.date('!%d/%m/%y %H:%M:%S', 0), '01/01/70 00:00:00', "function date")
+
+    like(os.date('%H:%M:%S'), '^%d%d:%d%d:%d%d', "function date")
+
+    if (_VERSION == 'Lua 5.1' and not jit) or luajit20 then
+        todo("not with 5.1")
+    end
+    is(os.date('%Oy', 0), '70')
+
+    if _VERSION == 'Lua 5.1' then
+        todo("not with 5.1")
+    end
+    error_like(function () os.date('%Ja', 0) end,
+               "^[^:]+:%d+: bad argument #1 to 'date' %(invalid conversion specifier '%%Ja'%)",
+               "function date (invalid)")
+end
+
+do -- difftime
+    is(os.difftime(1234, 1200), 34, "function difftime")
+end
+
+do -- execute
+    if has_execute51 then
+        local res = os.execute()
+        is(res, 1, "function execute -> shell is available")
+
+        ok(os.execute('__IMPROBABLE__') > 0, "function execute __IMPROBABLE__")
+
+        local cmd = lua .. [[ -e "print '# hello from external Lua'"]]
+        is(os.execute(cmd), 0, "function execute")
+    else
+        local res = os.execute()
+        is(res, true, "function execute -> shell is available")
+
+        local r, s, n = os.execute('__IMPROBABLE__')
+        is(r, nil, "function execute __IMPROBABLE__")
+        is(s, 'exit')
+        type_ok(n, 'number')
+
+        local cmd = lua .. [[ -e "print '# hello from external Lua'"]]
+        r, s, n = os.execute(cmd)
+        is(r, true, "function execute")
+        is(s, 'exit')
+        is(n, 0)
+    end
+end
+
+do -- exit called with execute
+    if has_execute51 then
+        local cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(2)"]]
+        ok(os.execute(cmd) > 0, "function exit called with execute")
+    else
+        local cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(2)"]]
+        local r, s, n = os.execute(cmd)
+        is(r, nil, "function exit called with execute")
+        is(s, 'exit')
+        is(n, 2, "exit value")
+
+        cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(false)"]]
+        r, s, n = os.execute(cmd)
+        is(r, nil, "function exit called with execute")
+        is(s, 'exit')
+        is(n, 1, "exit value")
+
+        cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(true, true)"]]
+        r, s, n = os.execute(cmd)
+        is(r, true, "exit called with execute")
+        is(s, 'exit')
+        is(n, 0, "exit value")
+    end
+end
+
+do -- exit called with popen
+    local cmd = lua .. [[ -e "print 'reached'; os.exit(); print 'not reached';"]]
+    local res, f = pcall(io.popen, cmd)
+    if res then
+        is(f:read'*l', 'reached', "exit called with popen")
+        is(f:read'*l', nil)
+        if has_execute51 then
+            local code = f:close()
+            is(code, true, "exit code")
+        else
+            local r, s, n = f:close()
+            is(r, true)
+            is(s, 'exit', "exit code")
+            is(n, 0, "exit value")
+        end
+    else
+        diag("io.popen not supported")
+    end
+
+    cmd = lua .. [[ -e "print 'reached'; os.exit(3); print 'not reached';"]]
+    res, f = pcall(io.popen, cmd)
+    if res then
+        is(f:read'*l', 'reached', "exit called with popen")
+        is(f:read'*l', nil)
+        if has_execute51 then
+            local code = f:close()
+            is(code, true, "exit code")
+        else
+            local r, s, n = f:close()
+            is(r, nil)
+            is(s, 'exit', "exit code")
+            is(n, 3, "exit value")
+        end
+    else
+        diag("io.popen not supported")
+    end
+end
+
+do -- getenv
+    is(os.getenv('__IMPROBABLE__'), nil, "function getenv")
+
+    local user = os.getenv('LOGNAME') or os.getenv('USERNAME')
+    type_ok(user, 'string', "function getenv")
+end
+
+do -- remove
+    local f = io.open('file-309.rm', 'w')
+    f:write("file to remove")
+    f:close()
+    local r = os.remove("file-309.rm")
+    is(r, true, "function remove")
+
+    local msg
+    r, msg = os.remove('file-309.rm')
+    is(r, nil, "function remove")
+    like(msg, '^file%-309%.rm: No such file or directory')
+end
+
+do -- rename
+    local f = io.open('file-309.old', 'w')
+    f:write("file to rename")
+    f:close()
+    os.remove('file-309.new')
+    local r = os.rename('file-309.old', 'file-309.new')
+    is(r, true, "function rename")
+    os.remove('file-309.new') -- clean up
+
+    local msg
+    r, msg = os.rename('file-309.old', 'file-309.new')
+    is(r, nil, "function rename")
+    like(msg, 'No such file or directory')
+end
+
+do -- setlocale
+    is(os.setlocale('C', 'all'), 'C', "function setlocale")
+    is(os.setlocale(), 'C')
+    is(os.setlocale('unk_loc', 'all'), nil, "function setlocale (unknown locale)")
+end
+
+do -- time
+    like(os.time(), '^%d+%.?%d*$', "function time")
+    like(os.time(nil), '^%d+%.?%d*$', "function time")
+    like(os.time({
+        sec = 0,
+        min = 0,
+        hour = 0,
+        day = 1,
+        month = 1,
+        year = 2000,
+        isdst = false,
+    }), '^946%d+$', "function time")
+
+    error_like(function () os.time{} end,
+               "^[^:]+:%d+: field '%w+' missing in date table",
+               "function time (missing field)")
+
+    error_like(function () os.time({ day = 'bad', year = 'bad' }) end,
+               "^[^:]+:%d+: field '%w+'",
+               "function time (bad field)")
+
+    if _VERSION < 'Lua 5.3' then
+        todo("only with integer")
+    end
+    error_like(function () os.time({ day = 1.5, year = 1.5 }) end,
+               "^[^:]+:%d+: field '%w+' is not an integer",
+               "function time (not integer)")
+
+    if string.packsize and string.packsize('l') == 8 then
+        skip('64bit platforms')
+    else
+        if _VERSION < 'Lua 5.3' then
+            todo"only with 5.3"
+        end
+        error_like(function () os.time({
+            sec = 0,
+            min = 0,
+            hour = 0,
+            day = 1,
+            month = 1,
+            year = 1000,
+            isdst = false,
+        }) end,
+                   "^[^:]+:%d+: time result cannot be represented in this installation",
+                   "function time (invalid)")
+    end
+end
+
+do -- tmpname
+    local fname = os.tmpname()
+    type_ok(fname, 'string', "function tmpname")
+    ok(fname ~= os.tmpname())
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/310-debug.t b/test/lua-Harness-tests/310-debug.t
new file mode 100755
index 0000000..f78af03
--- /dev/null
+++ b/test/lua-Harness-tests/310-debug.t
@@ -0,0 +1,322 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Debug Library
+
+=head2 Synopsis
+
+    % prove 310-debug.t
+
+=head2 Description
+
+Tests Lua Debug Library
+
+See section "The Debug Library" in "Reference Manual"
+L<https://www.lua.org/manual/5.1/manual.html#5.9>,
+L<https://www.lua.org/manual/5.2/manual.html#6.10>,
+L<https://www.lua.org/manual/5.3/manual.html#6.10>,
+L<https://www.lua.org/manual/5.4/manual.html#6.10>
+
+=cut
+
+]]
+
+require 'tap'
+local profile = require'profile'
+local has_getfenv = _VERSION == 'Lua 5.1'
+local has_gethook54 = _VERSION >= 'Lua 5.4'
+local has_getlocal52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_getuservalue = _VERSION >= 'Lua 5.2' or profile.luajit_compat52
+local has_getuservalue54 = _VERSION >= 'Lua 5.4'
+local has_setcstacklimit = _VERSION >= 'Lua 5.4'
+local has_setmetatable52 = _VERSION >= 'Lua 5.2' or (profile.luajit_compat52 and not ujit)
+local has_upvalueid = _VERSION >= 'Lua 5.2' or jit
+local has_upvaluejoin = _VERSION >= 'Lua 5.2' or jit
+
+local debug = require 'debug'
+
+if not debug then
+    skip_all("no debug")
+end
+
+plan'no_plan'
+
+-- getfenv
+if has_getfenv then
+    is(debug.getfenv(3.14), nil, "function getfenv")
+    local function f () end
+    type_ok(debug.getfenv(f), 'table')
+    is(debug.getfenv(f), _G)
+    type_ok(debug.getfenv(print), 'table')
+    is(debug.getfenv(print), _G)
+
+    local a = coroutine.create(function () return 1 end)
+    type_ok(debug.getfenv(a), 'table', "function getfenv (thread)")
+    is(debug.getfenv(a), _G)
+else
+    is(debug.getfenv, nil, "no debug.getfenv (removed)")
+end
+
+do -- getinfo
+    local info = debug.getinfo(is)
+    type_ok(info, 'table', "function getinfo (function)")
+    is(info.func, is, " .func")
+
+    info = debug.getinfo(is, 'L')
+    type_ok(info, 'table', "function getinfo (function, opt)")
+    type_ok(info.activelines, 'table')
+
+    info = debug.getinfo(1)
+    type_ok(info, 'table', "function getinfo (level)")
+    like(info.func, "^function: [0]?[Xx]?%x+", " .func")
+
+    is(debug.getinfo(12), nil, "function getinfo (too depth)")
+
+    error_like(function () debug.getinfo('bad') end,
+               "bad argument #1 to 'getinfo' %(.- expected",
+               "function getinfo (bad arg)")
+
+    error_like(function () debug.getinfo(is, 'X') end,
+               "bad argument #2 to 'getinfo' %(invalid option%)",
+               "function getinfo (bad opt)")
+end
+
+do -- getlocal
+    local name, value = debug.getlocal(0, 1)
+    type_ok(name, 'string', "function getlocal (level)")
+    is(value, 0)
+
+    error_like(function () debug.getlocal(42, 1) end,
+               "bad argument #1 to 'getlocal' %(level out of range%)",
+               "function getlocal (out of range)")
+
+    if has_getlocal52 then
+        name, value = debug.getlocal(like, 1)
+        type_ok(name, 'string', "function getlocal (func)")
+        is(value, nil)
+    else
+        diag("no getlocal with function")
+    end
+end
+
+do -- getmetatable
+    local t = {}
+    is(debug.getmetatable(t), nil, "function getmetatable")
+    local t1 = {}
+    debug.setmetatable(t, t1)
+    is(debug.getmetatable(t), t1)
+
+    local a = true
+    is(debug.getmetatable(a), nil)
+    debug.setmetatable(a, t1)
+    is(debug.getmetatable(t), t1)
+
+    a = 3.14
+    is(debug.getmetatable(a), nil)
+    debug.setmetatable(a, t1)
+    is(debug.getmetatable(t), t1)
+end
+
+do -- getregistry
+    local reg = debug.getregistry()
+    type_ok(reg, 'table', "function getregistry")
+    type_ok(reg._LOADED, 'table')
+end
+
+do -- getupvalue
+    local name = debug.getupvalue(plan, 1)
+    type_ok(name, 'string', "function getupvalue")
+end
+
+do -- gethook
+    debug.sethook()
+    local hook, mask, count
+    if has_gethook54 then
+        hook = debug.gethook()
+        is(hook, nil, "function gethook")
+    else
+        hook, mask, count = debug.gethook()
+        is(hook, nil, "function gethook")
+        is(mask, '')
+        is(count, 0)
+    end
+    local function f () end
+    debug.sethook(f, 'c', 42)
+    hook , mask, count = debug.gethook()
+    is(hook, f, "function gethook")
+    is(mask, 'c')
+    is(count, 42)
+
+    local co = coroutine.create(function () print "thread" end)
+    hook = debug.gethook(co)
+    if jit then
+        type_ok(hook, 'function', "function gethook(thread)")
+    else
+        is(hook, nil, "function gethook(thread)")
+    end
+end
+
+do -- setlocal
+    local name = debug.setlocal(0, 1, 0)
+    type_ok(name, 'string', "function setlocal (level)")
+
+    name = debug.setlocal(0, 42, 0)
+    is(name, nil, "function setlocal (level)")
+
+    error_like(function () debug.setlocal(42, 1, true) end,
+               "bad argument #1 to 'setlocal' %(level out of range%)",
+               "function setlocal (out of range)")
+end
+
+-- setcstacklimit
+if has_setcstacklimit then
+    type_ok(debug.setcstacklimit(200), 'number', "function setcstacklimit")
+    is(debug.setcstacklimit(1000), 200)
+
+    error_like(function () debug.setcstacklimit('bad') end,
+               "^[^:]+:%d+: bad argument #1 to 'setcstacklimit' %(number expected, got string%)",
+               "function setcstacklimit (bad arg)")
+else
+    is(debug.setcstacklimit, nil, "no debug.setcstacklimit")
+end
+
+-- setfenv
+if has_getfenv then
+    local t = {}
+    local function f () end
+    is(debug.setfenv(f, t), f, "function setfenv")
+    type_ok(debug.getfenv(f), 'table')
+    is(debug.getfenv(f), t)
+    is(debug.setfenv(print, t), print)
+    type_ok(debug.getfenv(print), 'table')
+    is(debug.getfenv(print), t)
+
+    t = {}
+    local a = coroutine.create(function () return 1 end)
+    is(debug.setfenv(a, t), a, "function setfenv (thread)")
+    type_ok(debug.getfenv(a), 'table')
+    is(debug.getfenv(a), t)
+
+    error_like(function () t = {}; debug.setfenv(t, t) end,
+               "^[^:]+:%d+: 'setfenv' cannot change environment of given object",
+               "function setfenv (forbidden)")
+else
+    is(debug.setfenv, nil, "no debug.setfenv (removed)")
+end
+
+do -- setmetatable
+    local t = {}
+    local t1 = {}
+    if has_setmetatable52 then
+        is(debug.setmetatable(t, t1), t, "function setmetatable")
+    else
+        is(debug.setmetatable(t, t1), true, "function setmetatable")
+    end
+    is(getmetatable(t), t1)
+
+    error_like(function () debug.setmetatable(t, true) end,
+               "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected")
+end
+
+do -- setupvalue
+    local r, tb = pcall(require, 'Test.Builder')
+    local value = r and tb:new() or {}
+    local name = debug.setupvalue(plan, 1, value)
+    type_ok(name, 'string', "function setupvalue")
+
+    name = debug.setupvalue(plan, 42, true)
+    is(name, nil)
+end
+
+-- getuservalue / setuservalue
+if has_getuservalue54 then
+    local u = io.tmpfile()      -- lua_newuserdatauv(L, sizeof(LStream), 0);
+    is(debug.getuservalue(u, 0), nil, "function getuservalue")
+    is(debug.getuservalue(true), nil)
+
+    error_like(function () debug.getuservalue(u, 'foo') end,
+               "^[^:]+:%d+: bad argument #2 to 'getuservalue' %(number expected, got string%)")
+
+    local data = {}
+    is(debug.setuservalue(u, data, 42), nil, "function setuservalue")
+
+    error_like(function () debug.setuservalue({}, data) end,
+               "^[^:]+:%d+: bad argument #1 to 'setuservalue' %(userdata expected, got table%)")
+
+    error_like(function () debug.setuservalue(u, data, 'foo') end,
+               "^[^:]+:%d+: bad argument #3 to 'setuservalue' %(number expected, got string%)")
+elseif has_getuservalue then
+    local u = io.tmpfile()
+    local old = debug.getuservalue(u)
+    if jit then
+        type_ok(old, 'table', "function getuservalue")
+    else
+        is(old, nil, "function getuservalue")
+    end
+    is(debug.getuservalue(true), nil)
+
+    local data = {}
+    local r = debug.setuservalue(u, data)
+    is(r, u, "function setuservalue")
+    is(debug.getuservalue(u), data)
+    r = debug.setuservalue(u, old)
+    is(debug.getuservalue(u), old)
+
+    error_like(function () debug.setuservalue({}, data) end,
+               "^[^:]+:%d+: bad argument #1 to 'setuservalue' %(userdata expected, got table%)")
+else
+    is(debug.getuservalue, nil, "no getuservalue")
+    is(debug.setuservalue, nil, "no setuservalue")
+end
+
+do -- traceback
+    like(debug.traceback(), "^stack traceback:\n", "function traceback")
+
+    like(debug.traceback("message\n"), "^message\n\nstack traceback:\n", "function traceback with message")
+
+    like(debug.traceback(false), "false", "function traceback")
+end
+
+-- upvalueid
+if has_upvalueid then
+    local id = debug.upvalueid(plan, 1)
+    type_ok(id, 'userdata', "function upvalueid")
+else
+    is(debug.upvalueid, nil, "no upvalueid")
+end
+
+-- upvaluejoin
+if has_upvaluejoin and jit then
+    diag("jit upvaluejoin")
+    -- TODO
+elseif has_upvaluejoin then
+    debug.upvaluejoin(pass, 1, fail, 1)
+
+    error_like(function () debug.upvaluejoin(true, 1, nil, 1) end,
+               "bad argument #1 to 'upvaluejoin' %(function expected, got boolean%)",
+               "function upvaluejoin (bad arg)")
+
+    error_like(function () debug.upvaluejoin(pass, 1, true, 1) end,
+               "bad argument #3 to 'upvaluejoin' %(function expected, got boolean%)",
+               "function upvaluejoin (bad arg)")
+else
+    is(debug.upvaluejoin, nil, "no upvaluejoin")
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/311-bit32.t b/test/lua-Harness-tests/311-bit32.t
new file mode 100755
index 0000000..7023906
--- /dev/null
+++ b/test/lua-Harness-tests/311-bit32.t
@@ -0,0 +1,127 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2010-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Bitwise Library
+
+=head2 Synopsis
+
+    % prove 311-bit32.t
+
+=head2 Description
+
+Tests Lua Bitwise Library
+
+This library was introduced in Lua 5.2 and deprecated in Lua 5.3.
+
+See section "Bitwise Operations" in "Reference Manual"
+L<https://www.lua.org/manual/5.2/manual.html#6.7>
+
+=cut
+
+--]]
+
+require 'tap'
+local profile = require'profile'
+local has_bit32 = _VERSION == 'Lua 5.2' or profile.compat52 or profile.has_bit32
+
+if not bit32 then
+    plan(1)
+    nok(has_bit32, "no has_bit32")
+    os.exit(0)
+end
+
+plan(20)
+
+do -- arshift
+    is(bit32.arshift(0x06, 1), 0x03, "function arshift")
+    is(bit32.arshift(-3, 1), bit32.arshift(-6, 2), "function arshift")
+end
+
+do -- band
+    is(bit32.band(0x01, 0x03, 0x07), 0x01, "function band")
+end
+
+do -- bnot
+    if string.pack and #string.pack('n', 0) == 4 then
+        is(bit32.bnot(0x03), (-1 - 0x03), "function bnot")
+    else
+        is(bit32.bnot(0x03), (-1 - 0x03) % 2^32, "function bnot")
+    end
+end
+
+do -- bor
+    is(bit32.bor(0x01, 0x03, 0x07), 0x07, "function bor")
+end
+
+do -- btest
+    is(bit32.btest(0x01), true, "function btest")
+    is(bit32.btest(0x00), false, "function btest")
+end
+
+do -- bxor
+    is(bit32.bxor(0x01, 0x03, 0x07), 0x05, "function bxor")
+end
+
+do -- extract
+    is(bit32.extract(0xFFFF, 3, 3), 0x07, "function extract")
+
+    error_like(function () bit32.extract(0xFFFF, 99) end,
+               "^[^:]+:%d+: trying to access non%-existent bits",
+               "function extract (non-existent bits)")
+
+    error_like(function () bit32.extract(0xFFFF, -3) end,
+               "^[^:]+:%d+: bad argument #2 to 'extract' %(field cannot be negative%)",
+               "function extract (negatif field)")
+
+    error_like(function () bit32.extract(0xFFFF, 3, -3) end,
+               "^[^:]+:%d+: bad argument #3 to 'extract' %(width must be positive%)",
+               "function extract (negative width)")
+end
+
+do -- replace
+    is(bit32.replace(0x0000, 0xFFFF, 3, 3), 0x38, "function replace")
+
+    error_like(function () bit32.replace(0x0000, 0xFFFF, 99) end,
+               "^[^:]+:%d+: trying to access non%-existent bits",
+               "function replace (non-existent bits)")
+
+    error_like(function () bit32.replace(0x0000, 0xFFFF, -3) end,
+               "^[^:]+:%d+: bad argument #3 to 'replace' %(field cannot be negative%)",
+               "function replace (negatif field)")
+
+    error_like(function () bit32.replace(0x0000, 0xFFFF, 3, -3) end,
+               "^[^:]+:%d+: bad argument #4 to 'replace' %(width must be positive%)",
+               "function replace (negative width)")
+end
+
+do -- lrotate
+    is(bit32.lrotate(0x03, 2), 0x0C, "function lrotate")
+end
+
+do -- lshift
+    is(bit32.lshift(0x03, 2), 0x0C, "function lshift")
+end
+
+do -- rrotate
+    is(bit32.rrotate(0x06, 1), 0x03, "function rrotate")
+end
+
+do -- rshift
+    is(bit32.rshift(0x06, 1), 0x03, "function rshift")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/314-regex.t b/test/lua-Harness-tests/314-regex.t
new file mode 100755
index 0000000..ad4554c
--- /dev/null
+++ b/test/lua-Harness-tests/314-regex.t
@@ -0,0 +1,222 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Regex Compiler
+
+=head2 Synopsis
+
+    % prove 314-regex.t
+
+=head2 Description
+
+Tests Lua Regex
+
+Individual tests are stored in the C<rx_*> files in the same directory;
+There is one test per line: each test consists of the following
+columns (separated by one *or more* tabs):
+
+=over 4
+
+=item pattern
+
+The Lua regex to test.
+
+=item target
+
+The string that will be matched against the pattern. Use '' to indicate
+an empty string.
+
+=item result
+
+The expected result of the match.
+
+=item description
+
+Description of the test.
+
+=back
+
+=cut
+
+--]]
+
+require'tap'
+local loadstring = loadstring or load
+
+plan(162)
+
+local test_files = {
+    'rx_captures',
+    'rx_charclass',
+    'rx_metachars',
+}
+
+local todo_info = {}
+
+if _VERSION == 'Lua 5.1' then
+    if not jit then
+        todo_info[130] = "printable. %g"
+        --todo_info[131] = "printable. %g"
+        todo_info[132] = "not printable. %G"
+        --todo_info[133] = "not printable. %G"
+    end
+    todo_info[147] = "embedded nul. \\0"
+    todo_info[149] = "embedded nul. \\0"
+    todo_info[151] = "embedded nul. [^\\0]"
+    todo_info[153] = "embedded nul. [^\\0]"
+end
+
+local function split (line)
+    local pattern, target, result, desc = '', '', '', ''
+    local idx = 1
+    local c = line:sub(idx, idx)
+    while (c ~= '' and c ~= "\t") do
+        if (c == '"') then
+            pattern = pattern .. "\\\""
+        else
+            pattern = pattern .. c
+        end
+        idx = idx + 1
+        c = line:sub(idx, idx)
+    end
+    if pattern == "''" then
+        pattern = ''
+    end
+    while (c ~= '' and c == "\t") do
+        idx = idx + 1
+        c = line:sub(idx, idx)
+    end
+    while (c ~= '' and c ~= "\t") do
+        if (c == '"') then
+            target = target .. "\\\""
+        else
+            target = target .. c
+        end
+        idx = idx + 1
+        c = line:sub(idx, idx)
+    end
+    if target == "''" then
+        target = ''
+    end
+    while (c ~= '' and c == "\t") do
+        idx = idx + 1
+        c = line:sub(idx, idx)
+    end
+    while (c ~= '' and c ~= "\t") do
+        if c == "\\" then
+            idx = idx + 1
+            c = line:sub(idx, idx)
+            if     c == 'f' then
+                result = result .. "\f"
+            elseif c == 'n' then
+                result = result .. "\n"
+            elseif c == 'r' then
+                result = result .. "\r"
+            elseif c == 't' then
+                result = result .. "\t"
+            elseif c == '0' then
+                idx = idx + 1
+                c = line:sub(idx, idx)
+                if     c == '1' then
+                    result = result .. "\01"
+                elseif c == '2' then
+                    result = result .. "\02"
+                elseif c == '3' then
+                    result = result .. "\03"
+                elseif c == '4' then
+                    result = result .. "\04"
+                else
+                    result = result .. "\0" .. c
+                end
+            elseif c == "\t" then
+                result = result .. "\\"
+            else
+                result = result .. "\\" .. c
+            end
+        else
+            result = result .. c
+        end
+        idx = idx + 1
+        c = line:sub(idx, idx)
+    end
+    if result == "''" then
+        result = ''
+    end
+    while (c ~= '' and c == "\t") do
+        idx = idx + 1
+        c = line:sub(idx, idx)
+    end
+    while (c ~= '' and c ~= "\t") do
+        desc = desc .. c
+        idx = idx + 1
+        c = line:sub(idx, idx)
+    end
+    return pattern, target, result, desc
+end
+
+local test_number = 0
+local dirname = arg[0]:sub(1, arg[0]:find'314' -1)
+for _, filename in ipairs(test_files) do
+    local f, msg = io.open(dirname .. filename, 'r')
+    if f == nil then
+        diag(msg)
+        break
+    else
+        for line in f:lines() do
+            if line:len() == 0 then
+                break
+            end
+            local pattern, target, result, desc = split(line)
+            test_number = test_number + 1
+            if todo_info[test_number] then
+                todo(todo_info[test_number])
+            end
+            local code = [[
+                    local t = {string.match("]] .. target .. [[", "]] .. pattern .. [[")}
+                    if #t== 0 then
+                        return 'nil'
+                    else
+                        for i = 1, #t do
+                            t[i] = tostring(t[i])
+                        end
+                        return table.concat(t, "\t")
+                    end
+            ]]
+            local compiled
+            compiled, msg = loadstring(code)
+            if not compiled then
+                error("can't compile : " .. code .. "\n" .. msg)
+            end
+            if result:sub(1, 1) == '/' then
+                pattern = result:sub(2, result:len() - 1)
+                error_like(compiled, pattern, desc)
+            else
+                local r, out
+                r, msg = pcall(function () out = compiled() end)
+                if r then
+                    is(out, result, desc)
+                else
+                    fail(desc)
+                    diag(msg)
+                end
+            end
+        end
+        f:close()
+    end
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/320-stdin.t b/test/lua-Harness-tests/320-stdin.t
new file mode 100755
index 0000000..4828285
--- /dev/null
+++ b/test/lua-Harness-tests/320-stdin.t
@@ -0,0 +1,133 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 Lua Library
+
+=head2 Synopsis
+
+    % prove 320-stdin.t
+
+=head2 Description
+
+Tests Lua Basic & IO Libraries with stdin
+
+=cut
+
+--]]
+
+require'tap'
+
+local lua = get_lua_binary_name()
+
+if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
+    skip_all "io.popen not supported"
+end
+
+plan(12)
+
+do
+    local f = io.open('lib-320.lua', 'w')
+    f:write[[
+function norm (x, y)
+    return (x^2 + y^2)^0.5
+end
+
+function twice (x)
+    return 2*x
+end
+]]
+    f:close()
+
+    local cmd = lua .. [[ -e "dofile(); n = norm(3.4, 1.0); print(twice(n))" < lib-320.lua]]
+    f = io.popen(cmd)
+    like(f:read'*l', '^7%.088', "function dofile (stdin)")
+    f:close()
+
+    os.remove('lib-320.lua') -- clean up
+end
+
+do
+    local f = io.open('foo-320.lua', 'w')
+    f:write[[
+function foo (x)
+    return x
+end
+]]
+    f:close()
+
+    local cmd = lua .. [[ -e "f = loadfile(); print(foo); f(); print(foo('ok'))" < foo-320.lua]]
+    f = io.popen(cmd)
+    is(f:read'*l', 'nil', "function loadfile (stdin)")
+    is(f:read'*l', 'ok')
+    f:close()
+
+    os.remove('foo-320.lua') -- clean up
+end
+
+do
+    local f = io.open('file-320.txt', 'w')
+    f:write("file with text\n")
+    f:close()
+
+    local cmd = lua .. [[ -e "print(io.read'*l'); print(io.read'*l'); print(io.type(io.stdin))" < file-320.txt]]
+    f = io.popen(cmd)
+    is(f:read'*l', 'file with text', "function io.read *l")
+    is(f:read'*l', 'nil')
+    is(f:read'*l', 'file')
+    f:close()
+
+    cmd = lua .. [[ -e "for line in io.lines() do print(line) end" < file-320.txt]]
+    f = io.popen(cmd)
+    is(f:read'*l', 'file with text', "function io.lines")
+    is(f:read'*l', nil)
+    f:close()
+
+    os.remove('file-320.txt') -- clean up
+end
+
+do
+    local f = io.open('number-320.txt', 'w')
+    f:write("6.0     -3.23   15e3\n")
+    f:write("4.3     234     1000001\n")
+    f:close()
+
+    local cmd = lua .. [[ -e "while true do local n1, n2, n3 = io.read('*number', '*number', '*number'); if not n1 then break end; print(math.max(n1, n2, n3)) end" < number-320.txt]]
+    f = io.popen(cmd)
+    like(f:read'*l', '15000%.?', "function io:read *number")
+    is(f:read'*l', '1000001')
+    f:close()
+
+    os.remove('number-320.txt') -- clean up
+end
+
+do
+    local f = io.open('dbg-320.txt', 'w')
+    f:write("print 'ok'\n")
+    f:write("error 'dbg'\n")
+    f:write("cont\n")
+    f:close()
+
+    local cmd = lua .. [[ -e "debug.debug()" < dbg-320.txt]]
+    f = io.popen(cmd)
+    is(f:read'*l', 'ok', "function debug.debug")
+    is(f:read'*l', nil)
+    f:close()
+
+    os.remove('dbg-320.txt') -- clean up
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/401-bitop.t b/test/lua-Harness-tests/401-bitop.t
new file mode 100755
index 0000000..f95aebf
--- /dev/null
+++ b/test/lua-Harness-tests/401-bitop.t
@@ -0,0 +1,106 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 BitOp Library
+
+=head2 Synopsis
+
+    % prove 401-bitop.t
+
+=head2 Description
+
+See L<http://bitop.luajit.org/>.
+
+=cut
+
+--]]
+
+require 'tap'
+
+if not jit then
+    skip_all("only with LuaJIT")
+end
+
+plan(29)
+
+is(package.loaded.bit, _G.bit, "package.loaded")
+is(require'bit', bit, "require")
+
+do -- arshift
+    is(bit.arshift(256, 8), 1, "function arshift")
+    is(bit.arshift(-256, 8), -1)
+end
+
+do -- band
+    is(bit.band(0x12345678, 0xff), 0x00000078, "function band")
+end
+
+do -- bnot
+    is(bit.bnot(0), -1, "function bnot")
+    is(bit.bnot(-1), 0)
+    is(bit.bnot(0xffffffff), 0)
+end
+
+do -- bor
+    is(bit.bor(1, 2, 4, 8), 15, "function bor")
+end
+
+do -- bswap
+    is(bit.bswap(0x12345678), 0x78563412, "function bswap")
+    is(bit.bswap(0x78563412), 0x12345678)
+end
+
+do -- bxor
+    is(bit.bxor(0xa5a5f0f0, 0xaa55ff00), 0x0ff00ff0, "function bxor")
+end
+
+do -- lshift
+    is(bit.lshift(1, 0), 1, "function lshift")
+    is(bit.lshift(1, 8), 256)
+    is(bit.lshift(1, 40), 256)
+    is(bit.lshift(0x87654321, 12), 0x54321000)
+end
+
+do -- rol
+    is(bit.rol(0x12345678, 12), 0x45678123, "function rol")
+end
+
+do -- ror
+    is(bit.ror(0x12345678, 12), 0x67812345, "function ror")
+end
+
+do -- rshift
+    is(bit.rshift(256, 8), 1, "function rshift")
+    is(bit.rshift(-256, 8), 16777215)
+    is(bit.rshift(0x87654321, 12), 0x00087654)
+end
+
+do -- tobit
+    is(bit.tobit(0xffffffff + 1), 0, "function tobit")
+    is(bit.tobit(2^40 + 1234), 1234)
+end
+
+do -- tohex
+    is(bit.tohex(1), '00000001', "function tohex")
+    is(bit.tohex(-1), 'ffffffff')
+    is(bit.tohex(0xffffffff), 'ffffffff')
+    is(bit.tohex(-1, -8), 'FFFFFFFF')
+    is(bit.tohex(0x21, 4), '0021')
+    is(bit.tohex(0x87654321, 4), '4321')
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/402-ffi.t b/test/lua-Harness-tests/402-ffi.t
new file mode 100755
index 0000000..a2e32a5
--- /dev/null
+++ b/test/lua-Harness-tests/402-ffi.t
@@ -0,0 +1,142 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 FFI Library
+
+=head2 Synopsis
+
+    % prove 402-ffi.t
+
+=head2 Description
+
+See L<http://luajit.org/ext_ffi.html>.
+
+=cut
+
+--]]
+
+require 'tap'
+
+if not jit then
+    skip_all("only with LuaJIT")
+end
+
+if not pcall(require, 'ffi') then
+    plan(2)
+    is(_G.ffi, nil, "no FFI")
+    is(package.loaded.ffi, nil)
+    os.exit(0)
+end
+
+plan(33)
+
+is(_G.ffi, nil, "ffi not loaded by default")
+ffi = require'ffi'
+is(package.loaded.ffi, ffi, "package.loaded")
+is(require'ffi', ffi, "require")
+
+do -- C
+    type_ok(ffi.C, 'userdata', 'C')
+end
+
+do -- abi
+    type_ok(ffi.abi('32bit'), 'boolean', "abi")
+    type_ok(ffi.abi('64bit'), 'boolean')
+    type_ok(ffi.abi('le'), 'boolean')
+    type_ok(ffi.abi('be'), 'boolean')
+    type_ok(ffi.abi('fpu'), 'boolean')
+    type_ok(ffi.abi('softfp'), 'boolean')
+    type_ok(ffi.abi('hardfp'), 'boolean')
+    type_ok(ffi.abi('eabi'), 'boolean')
+    type_ok(ffi.abi('win'), 'boolean')
+    is(ffi.abi('bad'), false)
+    is(ffi.abi(0), false)
+
+    error_like(function () ffi.abi(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'abi' %(string expected, got boolean%)",
+               "function unpack missing size")
+end
+
+do -- alignof
+    type_ok(ffi.alignof, 'function', "alignof")
+end
+
+do -- arch
+    is(ffi.arch, jit.arch, "alias arch")
+end
+
+do -- cast
+    type_ok(ffi.cast, 'function', "cast")
+end
+
+do -- cdef
+    type_ok(ffi.cdef, 'function', "cdef")
+end
+
+do -- copy
+    type_ok(ffi.copy, 'function', "copy")
+end
+
+do -- errno
+    type_ok(ffi.errno, 'function', "errno")
+end
+
+do -- fill
+    type_ok(ffi.fill, 'function', "fill")
+end
+
+do -- gc
+    type_ok(ffi.gc, 'function', "gc")
+end
+
+do -- istype
+    type_ok(ffi.istype, 'function', "istype")
+end
+
+do -- load
+    type_ok(ffi.load, 'function', "load")
+end
+
+do -- metatype
+    type_ok(ffi.metatype, 'function', "metatype")
+end
+
+do -- new
+    type_ok(ffi.new, 'function', "new")
+end
+
+do -- offsetof
+    type_ok(ffi.offsetof, 'function', "offsetof")
+end
+
+do -- os
+    is(ffi.os, jit.os, "alias os")
+end
+
+do -- sizeof
+    type_ok(ffi.sizeof, 'function', "sizeof")
+end
+
+do -- string
+    type_ok(ffi.string, 'function', "string")
+end
+
+do -- typeof
+    type_ok(ffi.typeof, 'function', "typeof")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/403-jit.t b/test/lua-Harness-tests/403-jit.t
new file mode 100755
index 0000000..0073c90
--- /dev/null
+++ b/test/lua-Harness-tests/403-jit.t
@@ -0,0 +1,163 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 JIT Library
+
+=head2 Synopsis
+
+    % prove 403-jit.t
+
+=head2 Description
+
+See L<http://luajit.org/ext_jit.html>.
+
+=cut
+
+--]]
+
+require 'tap'
+local profile = require'profile'
+
+if not jit then
+    skip_all("only with LuaJIT")
+end
+
+local compiled_with_jit = jit.status()
+local luajit20 = jit.version_num < 20100 and not jit.version:match'RaptorJIT'
+local has_jit_opt = compiled_with_jit
+local has_jit_security = jit.security
+local has_jit_util = not ujit and not jit.version:match'RaptorJIT'
+
+plan'no_plan'
+
+is(package.loaded.jit, _G.jit, "package.loaded")
+is(require'jit', jit, "require")
+
+do -- arch
+    type_ok(jit.arch, 'string', "arch")
+end
+
+do -- flush
+    type_ok(jit.flush, 'function', "flush")
+end
+
+do -- off
+    jit.off()
+    is(jit.status(), false, "off")
+end
+
+-- on
+if compiled_with_jit then
+    jit.on()
+    is(jit.status(), true, "on")
+else
+    error_like(function () jit.on() end,
+               "^[^:]+:%d+: JIT compiler permanently disabled by build option",
+               "no jit.on")
+end
+
+-- opt
+if has_jit_opt then
+    type_ok(jit.opt, 'table', "opt.*")
+    type_ok(jit.opt.start, 'function', "opt.start")
+else
+    is(jit.opt, nil, "no jit.opt")
+end
+
+do -- os
+    type_ok(jit.os, 'string', "os")
+end
+
+-- prngstate
+if profile.openresty then
+    type_ok(jit.prngstate(), 'table', "prngstate")
+    local s1 = { 1, 2, 3, 4, 5, 6, 7, 8}
+    type_ok(jit.prngstate(s1), 'table')
+    local s2 = { 8, 7, 6, 5, 4, 3, 2, 1}
+    eq_array(jit.prngstate(s2), s1)
+    eq_array(jit.prngstate(), s2)
+
+    type_ok(jit.prngstate(32), 'table', "backward compat")
+    eq_array(jit.prngstate(5617), { 32, 0, 0, 0, 0, 0, 0, 0 })
+    eq_array(jit.prngstate(), { 5617, 0, 0, 0, 0, 0, 0, 0 })
+
+    error_like(function () jit.prngstate(-1) end,
+               "^[^:]+:%d+: bad argument #1 to 'prngstate' %(PRNG state must be an array with up to 8 integers or an integer%)")
+
+    error_like(function () jit.prngstate(false) end,
+               "^[^:]+:%d+: bad argument #1 to 'prngstate' %(table expected, got boolean%)")
+elseif jit.version:match'moonjit' then
+    is(jit.prngstate(), 0, "prngstate")
+else
+    is(jit.prngstate, nil, "no jit.prngstate");
+end
+
+-- security
+if has_jit_security then
+    type_ok(jit.security, 'function', "security")
+    type_ok(jit.security('prng'), 'number', "prng")
+    type_ok(jit.security('strhash'), 'number', "strhash")
+    type_ok(jit.security('strid'), 'number', "stdid")
+    type_ok(jit.security('mcode'), 'number', "mcode")
+
+    error_like(function () jit.security('foo') end,
+               "^[^:]+:%d+: bad argument #1 to 'security' %(invalid option 'foo'%)")
+else
+    is(jit.security, nil, "no jit.security")
+end
+
+do -- status
+    local status = { jit.status() }
+    type_ok(status[1], 'boolean', "status")
+    if compiled_with_jit then
+        for i = 2, #status do
+            type_ok(status[i], 'string', status[i])
+        end
+    else
+        is(#status, 1)
+    end
+end
+
+-- util
+if has_jit_util then
+    local jutil = require'jit.util'
+    type_ok(jutil, 'table', "util")
+    is(package.loaded['jit.util'], jutil)
+
+    if luajit20 then
+        is(jit.util, jutil, "util inside jit")
+    else
+        is(jit.util, nil, "no util inside jit")
+    end
+else
+    local r = pcall(require, 'jit.util')
+    is(r, false, "no jit.util")
+end
+
+do -- version
+    type_ok(jit.version, 'string', "version")
+    like(jit.version, '^%w+ %d%.%d%.%d')
+end
+
+do -- version_num
+    type_ok(jit.version_num, 'number', "version_num")
+    like(string.format("%06d", jit.version_num), '^0[12]0[012]%d%d$')
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/404-ext.t b/test/lua-Harness-tests/404-ext.t
new file mode 100755
index 0000000..22a52c7
--- /dev/null
+++ b/test/lua-Harness-tests/404-ext.t
@@ -0,0 +1,171 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2019-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 JIT Library extensions
+
+=head2 Synopsis
+
+    % prove 404-ext.t
+
+=head2 Description
+
+See L<http://luajit.org/ext_jit.html>.
+
+=cut
+
+--]]
+
+require 'tap'
+local profile = require'profile'
+
+local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT')
+if not luajit21 then
+    skip_all("only with LuaJIT 2.1")
+end
+
+plan'no_plan'
+
+do -- table.new
+    local r, new = pcall(require, 'table.new')
+    is(r, true, 'table.new')
+    type_ok(new, 'function')
+    is(package.loaded['table.new'], new)
+
+    type_ok(new(100, 0), 'table')
+    type_ok(new(0, 100), 'table')
+    type_ok(new(200, 200), 'table')
+
+    error_like(function () new(42) end,
+               "^[^:]+:%d+: bad argument #2 to 'new' %(number expected, got no value%)")
+end
+
+do -- table.clear
+    local r, clear = pcall(require, 'table.clear')
+    is(r, true, 'table.clear')
+    type_ok(clear, 'function')
+    is(package.loaded['table.clear'], clear)
+
+    local t = { 'foo', bar = 42 }
+    is(t[1], 'foo')
+    is(t.bar, 42)
+    clear(t)
+    is(t[1], nil)
+    is(t.bar, nil)
+
+    error_like(function () clear(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'clear' %(table expected, got number%)")
+end
+
+-- table.clone
+if profile.openresty then
+    local r, clone = pcall(require, 'table.clone')
+    is(r, true, 'table.clone')
+    type_ok(clone, 'function')
+    is(package.loaded['table.clone'], clone)
+
+    local mt = {}
+    local t = setmetatable({ 'foo', bar = 42 }, mt)
+    is(t[1], 'foo')
+    is(t.bar, 42)
+    local t2 = clone(t)
+    type_ok(t2, 'table')
+    isnt(t2, t)
+    is(getmetatable(t2), nil)
+    is(t2[1], 'foo')
+    is(t2.bar, 42)
+
+    error_like(function () clone(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'clone' %(table expected, got number%)")
+else
+    is(pcall(require, 'table.clone'), false, 'no table.clone')
+end
+
+-- table.isarray
+if profile.openresty then
+    local r, isarray = pcall(require, 'table.isarray')
+    is(r, true, 'table.isarray')
+    type_ok(isarray, 'function')
+    is(package.loaded['table.isarray'], isarray)
+
+    is(isarray({ [3] = 3, [5.3] = 4 }), false)
+    is(isarray({ [3] = 'a', [5] = true }), true)
+    is(isarray({ 'a', nil, true, 3.14 }), true)
+    is(isarray({}), true)
+    is(isarray({ ['1'] = 3, ['2'] = 4 }), false)
+    is(isarray({ ['dog'] = 3, ['cat'] = 4 }), false)
+    is(isarray({ 'dog', 'cat', true, ['bird'] = 3 }), false)
+
+    error_like(function () isarray(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'isarray' %(table expected, got number%)")
+else
+    is(pcall(require, 'table.isarray'), false, 'no table.isarray')
+end
+
+-- table.isempty
+if profile.openresty then
+    local r, isempty = pcall(require, 'table.isempty')
+    is(r, true, 'table.isempty')
+    type_ok(isempty, 'function')
+    is(package.loaded['table.isempty'], isempty)
+
+    is(isempty({}), true)
+    is(isempty({ nil }), true)
+    is(isempty({ dogs = nil }), true)
+    is(isempty({ 3.1 }), false)
+    is(isempty({ 'a', 'b' }), false)
+    is(isempty({ nil, false }), false)
+    is(isempty({ dogs = 3 }), false)
+    is(isempty({ dogs = 3, cats = 4 }), false)
+    is(isempty({ dogs = 3, 5 }), false)
+
+    error_like(function () isempty(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'isempty' %(table expected, got number%)")
+else
+    is(pcall(require, 'table.isempty'), false, 'no table.isempty')
+end
+
+-- table.nkeys
+if profile.openresty then
+    local r, nkeys = pcall(require, 'table.nkeys')
+    is(r, true, 'table.nkeys')
+    type_ok(nkeys, 'function')
+    is(package.loaded['table.nkeys'], nkeys)
+
+    is(nkeys({}), 0)
+    is(nkeys({ cats = 4 }), 1)
+    is(nkeys({ dogs = 3, cats = 4 }), 2)
+    is(nkeys({ dogs = nil, cats = 4 }), 1)
+    is(nkeys({ 'cats' }), 1)
+    is(nkeys({ 'dogs', 3, 'cats', 4 }), 4)
+    is(nkeys({ 'dogs', nil, 'cats', 4 }), 3)
+    is(nkeys({ cats = 4, 5, 6 }), 3)
+    is(nkeys({ nil, 'foo', dogs = 3, cats = 4 }), 3)
+
+    error_like(function () nkeys(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'nkeys' %(table expected, got number%)")
+else
+    is(pcall(require, 'table.nkeys'), false, 'no table.nkeys')
+end
+
+-- thread.exdata
+if pcall(require, 'ffi') and (profile.openresty or jit.version:match'moonjit') then
+    dofile'lexicojit/ext.t'
+end
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/411-luajit.t b/test/lua-Harness-tests/411-luajit.t
new file mode 100755
index 0000000..feb752e
--- /dev/null
+++ b/test/lua-Harness-tests/411-luajit.t
@@ -0,0 +1,211 @@
+#! /usr/bin/lua
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+--[[
+
+=head1 LuaJIT Stand-alone
+
+=head2 Synopsis
+
+    % prove 411-luajit.t
+
+=head2 Description
+
+See L<http://luajit.org/running.html>
+
+=cut
+
+--]]
+
+require'tap'
+local profile = require'profile'
+
+if not jit or ujit then
+    skip_all("only with LuaJIT")
+end
+
+local lua = get_lua_binary_name()
+
+if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
+    skip_all("io.popen not supported")
+end
+
+local compiled_with_jit = jit.status()
+local has_jutil = pcall(require, 'jit.util')
+local has_openresty_listing = profile.openresty or jit.version:match'moonjit'
+
+plan'no_plan'
+diag(lua)
+
+local f = io.open('hello-404.lua', 'w')
+f:write([[
+print 'Hello World'
+]])
+f:close()
+
+os.execute(lua .. " -b hello-404.lua hello-404.out")
+local cmd = lua .. " hello-404.out"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "-b")
+f:close()
+
+os.execute(lua .. " -bg hello-404.lua hello-404.out")
+cmd = lua .. " hello-404.out"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "-bg")
+f:close()
+
+os.execute(lua .. " -be 'print[[Hello World]]' hello-404.out")
+cmd = lua .. " hello-404.out"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "-be")
+f:close()
+
+os.remove('hello-404.out') -- clean up
+
+if has_jutil then
+    cmd = lua .. " -bl hello-404.lua"
+    f = io.popen(cmd)
+    like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bl hello.lua")
+    if has_openresty_listing then
+        like(f:read'*l', '^KGC    0')
+        like(f:read'*l', '^KGC    1')
+    end
+    like(f:read'*l', '^0001    %u[%u%d]+%s+')
+    like(f:read'*l', '^0002    %u[%u%d]+%s+')
+    like(f:read'*l', '^0003    %u[%u%d]+%s+')
+    f:close()
+
+    os.execute(lua .. " -bl hello-404.lua hello-404.txt")
+    f = io.open('hello-404.txt', 'r')
+    like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bl hello.lua hello.txt")
+    if has_openresty_listing then
+        like(f:read'*l', '^KGC    0')
+        like(f:read'*l', '^KGC    1')
+    end
+    like(f:read'*l', '^0001    %u[%u%d]+%s+')
+    like(f:read'*l', '^0002    %u[%u%d]+%s+')
+    like(f:read'*l', '^0003    %u[%u%d]+%s+')
+    f:close()
+end
+
+if has_openresty_listing then
+    cmd = lua .. " -bL hello-404.lua"
+    f = io.popen(cmd)
+    like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bL hello.lua")
+    like(f:read'*l', '^KGC    0')
+    like(f:read'*l', '^KGC    1')
+    like(f:read'*l', '^0001     %[1%]    %u[%u%d]+%s+')
+    like(f:read'*l', '^0002     %[1%]    %u[%u%d]+%s+')
+    like(f:read'*l', '^0003     %[1%]    %u[%u%d]+%s+')
+    f:close()
+
+    os.execute(lua .. " -bL hello-404.lua hello-404.txt")
+    f = io.open('hello-404.txt', 'r')
+    like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bL hello.lua hello.txt")
+    like(f:read'*l', '^KGC    0')
+    like(f:read'*l', '^KGC    1')
+    like(f:read'*l', '^0001     %[1%]    %u[%u%d]+%s+')
+    like(f:read'*l', '^0002     %[1%]    %u[%u%d]+%s+')
+    like(f:read'*l', '^0003     %[1%]    %u[%u%d]+%s+')
+    f:close()
+end
+
+os.remove('hello-404.txt') -- clean up
+
+os.execute(lua .. " -b hello-404.lua hello-404.c")
+f = io.open('hello-404.c', 'r')
+like(f:read'*l', '^#ifdef __?cplusplus$', "-b hello.lua hello.c")
+like(f:read'*l', '^extern "C"$')
+like(f:read'*l', '^#endif$')
+like(f:read'*l', '^#ifdef _WIN32$')
+like(f:read'*l', '^__declspec%(dllexport%)$')
+like(f:read'*l', '^#endif$')
+like(f:read'*l', '^const.- char luaJIT_BC_hello_404%[%] = {$')
+like(f:read'*l', '^%d+,%d+,%d+,')
+f:close()
+
+os.remove('hello-404.c') -- clean up
+
+os.execute(lua .. " -b hello-404.lua hello-404.h")
+f = io.open('hello-404.h', 'r')
+like(f:read'*l', '^#define luaJIT_BC_hello_404_SIZE %d+$', "-b hello.lua hello.h")
+like(f:read'*l', '^static const.- char luaJIT_BC_hello_404%[%] = {$')
+like(f:read'*l', '^%d+,%d+,%d+,')
+f:close()
+
+os.remove('hello-404.h') -- clean up
+
+cmd = lua .. " -j flush hello-404.lua"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "-j flush")
+f:close()
+
+cmd = lua .. " -joff hello-404.lua"
+f = io.popen(cmd)
+is(f:read'*l', 'Hello World', "-joff")
+f:close()
+
+cmd = lua .. " -jon hello-404.lua 2>&1"
+f = io.popen(cmd)
+if compiled_with_jit then
+    is(f:read'*l', 'Hello World', "-jon")
+else
+    like(f:read'*l', "^[^:]+: JIT compiler permanently disabled by build option", "no jit")
+end
+f:close()
+
+cmd = lua .. " -j bad hello-404.lua 2>&1"
+f = io.popen(cmd)
+like(f:read'*l', "^[^:]+: unknown luaJIT command or jit%.%* modules not installed", "-j bad")
+f:close()
+
+if compiled_with_jit then
+    cmd = lua .. " -O hello-404.lua"
+    f = io.popen(cmd)
+    is(f:read'*l', 'Hello World', "-O")
+    f:close()
+
+    cmd = lua .. " -O3 hello-404.lua"
+    f = io.popen(cmd)
+    is(f:read'*l', 'Hello World', "-O3")
+    f:close()
+
+    cmd = lua .. " -Ocse -O-dce -Ohotloop=10 hello-404.lua"
+    f = io.popen(cmd)
+    is(f:read'*l', 'Hello World', "-Ocse -O-dce -Ohotloop=10")
+    f:close()
+
+    cmd = lua .. " -O+cse,-dce,hotloop=10 hello-404.lua"
+    f = io.popen(cmd)
+    is(f:read'*l', 'Hello World', "-O+cse,-dce,hotloop=10")
+    f:close()
+
+    cmd = lua .. " -O+bad hello-404.lua 2>&1"
+    f = io.popen(cmd)
+    like(f:read'*l', "^[^:]+: unknown or malformed optimization flag '%+bad'", "-O+bad")
+    f:close()
+else
+    cmd = lua .. " -O0 hello-404.lua 2>&1"
+    f = io.popen(cmd)
+    like(f:read'*l', "^[^:]+: attempt to index a nil value")
+    f:close()
+end
+
+os.remove('hello-404.lua') -- clean up
+
+done_testing()
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
new file mode 100644
index 0000000..9b35e5a
--- /dev/null
+++ b/test/lua-Harness-tests/CMakeLists.txt
@@ -0,0 +1,49 @@
+# Test suite that has been added from lua-Harness test suite
+# in scope of https://github.com/tarantool/tarantool/issues/4473.
+
+# See the rationale in the root CMakeLists.txt
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+find_program(PROVE prove)
+if(NOT PROVE)
+  message(WARNING "`prove' is not found, so lua-Harness-tests target is not generated")
+  return()
+endif()
+
+set(LUA_TEST_FLAGS --failures --shuffle)
+if(CMAKE_VERBOSE_MAKEFILE)
+  list(APPEND LUA_TEST_FLAGS --verbose)
+endif()
+
+string(CONCAT LUA_PATH
+  "./?.lua\;"
+  "${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;"
+  "${LUAJIT_SOURCE_DIR}/?.lua\;"
+)
+
+string(CONCAT LUA_CPATH
+  "./?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
+  "${LUAJIT_SOURCE_DIR}/?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
+)
+
+add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY})
+
+add_custom_command(TARGET lua-Harness-tests
+  COMMENT "Running lua-Harness tests"
+  COMMAND
+  env
+    LUA_PATH="${LUA_PATH}\;"
+    LUA_CPATH="${LUA_CPATH}\;"
+    # Tarantool doesn't support LUA_INIT and most likely it
+    # never will.
+    # See https://github.com/tarantool/tarantool/issues/5744
+    # for more info.
+    # So use less preferable way for tests.
+    # See the root CMakeLists.txt for more info.
+    ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
+      --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
+      ${LUA_TEST_FLAGS}
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+# vim: expandtab tabstop=2 shiftwidth=2
diff --git a/test/lua-Harness-tests/lexico52/lexico.t b/test/lua-Harness-tests/lexico52/lexico.t
new file mode 100644
index 0000000..ff6bb99
--- /dev/null
+++ b/test/lua-Harness-tests/lexico52/lexico.t
@@ -0,0 +1,45 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2012-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+is("\x41", "A")
+is("\x3d", "=")
+is("\x3D", "=")
+
+do
+    local f, msg = load [[a = "A\xyz"]]
+    like(msg, "^[^:]+:%d+: .- near")
+
+    f, msg = load [[a = "A\Z"]]
+    like(msg, "^[^:]+:%d+: .- escape .- near")
+end
+
+do
+    local a = 'alo\n123"'
+    is("alo\n\z
+    123\"", a)
+
+    local f, msg = load [[a = " escape \z unauthorized
+new line" ]]
+    like(msg, "^[^:]+:%d+: unfinished string near")
+end
+
+is(0x0.1E, 0x1E / 0x100)        -- 0.1171875
+is(0xA23p-4, 0xA23 / (2^4))     -- 162.1875
+if string.pack and #string.pack('n', 0) == 4 then
+    diag('Small Lua')
+else
+    is(0X1.921FB54442D18P+1, (1 + 0x921FB54442D18/0x10000000000000) * 2)
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/boolean.t b/test/lua-Harness-tests/lexico53/boolean.t
new file mode 100644
index 0000000..693ac76
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/boolean.t
@@ -0,0 +1,43 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+error_like(function () return ~true end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "~true")
+
+error_like(function () return true // 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a boolean value",
+           "true // 3")
+
+error_like(function () return true & 7 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "true & 7")
+
+error_like(function () return true | 1 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "true | 1")
+
+error_like(function () return true ~ 4 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "true ~ 4")
+
+error_like(function () return true >> 5 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "true >> 5")
+
+error_like(function () return true << 2 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "true << 2")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/function.t b/test/lua-Harness-tests/lexico53/function.t
new file mode 100644
index 0000000..2471be6
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/function.t
@@ -0,0 +1,66 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+local f = function () return 1 end
+
+error_like(function () return ~f end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "~f")
+
+error_like(function () f = print; return ~f end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on")
+
+error_like(function () return f // 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "f // 3")
+
+error_like(function () f = print; return f // 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on")
+
+error_like(function () return f & 7 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "f & 7")
+
+error_like(function () f = print; return f & 7 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on")
+
+error_like(function () return f | 1 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "f | 1")
+
+error_like(function () f = print; return f | 1 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on")
+
+error_like(function () return f ~ 4 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "f ~ 4")
+
+error_like(function () f = print; return f ~ 4 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on")
+
+error_like(function () return f >> 5 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "f >> 5")
+
+error_like(function () f = print; return f >> 5 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on")
+
+error_like(function () return f << 2 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "f << 2")
+
+error_like(function () f = print; return f << 2 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/lexico.t b/test/lua-Harness-tests/lexico53/lexico.t
new file mode 100644
index 0000000..41b0d89
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/lexico.t
@@ -0,0 +1,30 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2015-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+is("\u{41}", "A")
+is("\u{20AC}", "\xE2\x82\xAC")
+is("\u{20ac}", "\xe2\x82\xac")
+
+do
+    local f, msg = load [[a = "A\u{yz}"]]
+    like(msg, "^[^:]+:%d+: .- near")
+
+    f, msg = load [[a = "A\u{41"]]
+    like(msg, "^[^:]+:%d+: .- near")
+
+    f, msg = load [[a = "A\u{FFFFFFFFFF}"]]
+    like(msg, "^[^:]+:%d+: .- near")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/nil.t b/test/lua-Harness-tests/lexico53/nil.t
new file mode 100644
index 0000000..a6438e2
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/nil.t
@@ -0,0 +1,43 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+error_like(function () return ~nil end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a nil value",
+           "~nil")
+
+error_like(function () return  nil // 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a nil value",
+           "nil // 3")
+
+error_like(function () return nil & 7 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a nil value",
+           "nil & 7")
+
+error_like(function () return nil | 1 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a nil value",
+           "nil | 1")
+
+error_like(function () return nil ~ 4 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a nil value",
+           "nil ~ 4")
+
+error_like(function () return nil >> 5 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a nil value",
+           "nil >> 5")
+
+error_like(function () return nil << 2 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a nil value",
+           "nil << 2")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/number.t b/test/lua-Harness-tests/lexico53/number.t
new file mode 100644
index 0000000..d205da3
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/number.t
@@ -0,0 +1,181 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+local profile = require'profile'
+
+is(~4, -5, "~4")
+
+error_like(function () return ~3.14 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "~3.14")
+
+is(25.5 // 3.5, 7.0, "25.5 // 3.5")
+
+is(25 // 3, 8, "25 // 3")
+
+is(25 // -3, -9, "25 // -3")
+
+is(1 // -1, -1, "1 // -1")
+
+type_ok(1.0 // 0, 'number', "1.0 // 0")
+
+error_like(function () return 1 // 0 end,
+           "^[^:]+:%d+: attempt to divide by zero",
+           "1 // 0")
+
+is(3 & 7, 3, "3 & 7")
+
+is(4 | 1, 5, "4 | 1")
+
+is(7 ~ 1, 6, "7 ~ 1")
+
+is(100 >> 5, 3, "100 >> 5")
+
+is(3 << 2, 12, "3 << 2")
+
+error_like(function () return 25 // {} end,
+           "^[^:]+:%d+: attempt to perform arithmetic on a table value",
+           "25 // {}")
+
+error_like(function () return 3 & true end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "3 & true")
+
+error_like(function () return 4 | true end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "4 | true")
+
+error_like(function () return 7 ~ true end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "7 ~ true")
+
+error_like(function () return 100 >> true end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "100 >> true")
+
+error_like(function () return 3 << true end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value",
+           "3 << true")
+
+error_like(function () return 25 // 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "25 // 'text'")
+
+error_like(function () return 3 & 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "3 & 'text'")
+
+error_like(function () return 4 | 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "4 | 'text'")
+
+error_like(function () return 7 ~ 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "7 ~ 'text'")
+
+error_like(function () return 100 >> 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "100 >> 'text'")
+
+error_like(function () return 3 << 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "3 << 'text'")
+
+if profile.nocvts2n then
+    error_like(function () return 25.5 // '3.5' end,
+               "^[^:]+:%d+: attempt to",
+               "25.5 // '3.5'")
+
+    error_like(function () return 25 // '3' end,
+               "^[^:]+:%d+: attempt to",
+               "25 // '3'")
+else
+    is(25.5 // '3.5', 7.0, "25.5 // '3.5'")
+
+    is(25 // '3', 8, "25 // '3'")
+end
+
+if profile.nocvts2n or _VERSION >= 'Lua 5.4' then
+    error_like(function () return 3 & '7' end,
+               "^[^:]+:%d+: attempt to",
+               "3 & '7'")
+
+    error_like(function () return 4 | '1' end,
+               "^[^:]+:%d+: attempt to",
+               "4 | '1'")
+
+    error_like(function () return 7 ~ '1' end,
+               "^[^:]+:%d+: attempt to",
+               "7 ~ '1'")
+
+    error_like(function () return 100 >> '5' end,
+               "^[^:]+:%d+: attempt to",
+               "100 >> '5'")
+
+    error_like(function () return 3 << '2' end,
+               "^[^:]+:%d+: attempt to",
+               "3 << '2'")
+else
+    is(3 & '7', 3, "3 & '7'")
+
+    is(4 | '1', 5, "4 | '1'")
+
+    is(7 ~ '1', 6, "7 ~ '1'")
+
+    is(100 >> '5', 3, "100 >> '5'")
+
+    is(3 << '2', 12, "3 << '2'")
+end
+
+error_like(function () return 3.5 & 7 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "3.5 & 7")
+
+error_like(function () return 3 & 7.5 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "3 & 7.5")
+
+error_like(function () return 4.5 | 1 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "4.5 | 1")
+
+error_like(function () return 4 | 1.5 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "4 | 1.5")
+
+error_like(function () return 7.5 ~ 1 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "7.5 ~ 1")
+
+error_like(function () return 7 ~ 1.5 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "7 ~ 1.5")
+
+error_like(function () return 100.5 >> 5 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "100.5 >> 5")
+
+error_like(function () return 100 >> 5.5 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "100 >> 5.5")
+
+error_like(function () return 3.5 << 2 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "3.5 << 2")
+
+error_like(function () return 3 << 2.5 end,
+           "^[^:]+:%d+: number has no integer representation",
+           "3 << 2.5")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/string.t b/test/lua-Harness-tests/lexico53/string.t
new file mode 100644
index 0000000..eb74064
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/string.t
@@ -0,0 +1,169 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+local profile = require'profile'
+
+if profile.nocvts2n or _VERSION >= 'Lua 5.4' then
+    error_like(function () return ~'4' end,
+               "^[^:]+:%d+: attempt to",
+               "~'4'")
+else
+    is(~'4', -5, "~'4'")
+end
+
+error_like(function () return ~'text' end,
+           "^[^:]+:%d+: attempt to",
+           "~'text'")
+
+if profile.nocvts2n then
+    error_like(function () return '25.5' // 3.5 end,
+               "^[^:]+:%d+: attempt to",
+               "'25.5' // 3.5")
+
+    error_like(function () return '25' // 3 end,
+               "^[^:]+:%d+: attempt to",
+               "'25' // 3")
+else
+    is('25.5' // 3.5, 7.0, "'25.5' // 3.5")
+
+    is('25' // 3, 8, "'25' // 3")
+end
+
+if profile.nocvts2n or _VERSION >= 'Lua 5.4' then
+    error_like(function () return '3' & 7 end,
+               "^[^:]+:%d+: attempt to",
+               "'3' & 7")
+
+    error_like(function () return '4' | 1 end,
+               "^[^:]+:%d+: attempt to",
+               "'4' | 1")
+
+    error_like(function () return '7' ~ 1 end,
+               "^[^:]+:%d+: attempt to",
+               "'7' ~ 1")
+
+    error_like(function () return '100' >> 5 end,
+               "^[^:]+:%d+: attempt to",
+               "'100' >> 5")
+
+    error_like(function () return '3' << 2 end,
+               "^[^:]+:%d+: attempt to",
+               "'3' << 2")
+else
+    is('3' & 7, 3, "'3' & 7")
+
+    is('4' | 1, 5, "'4' | 1")
+
+    is('7' ~ 1, 6, "'7' ~ 1")
+
+    is('100' >> 5, 3, "'100' >> 5")
+
+    is('3' << 2, 12, "'3' << 2")
+end
+
+error_like(function () return '25' // {} end,
+           "^[^:]+:%d+: attempt to",
+           "'25' // {}")
+
+error_like(function () return '3' & true end,
+           "^[^:]+:%d+: attempt to",
+           "'3' & true")
+
+error_like(function () return '4' | true end,
+           "^[^:]+:%d+: attempt to",
+           "'4' | true")
+
+error_like(function () return '7' ~ true end,
+           "^[^:]+:%d+: attempt to",
+           "'7' ~ true")
+
+error_like(function () return '100' >> true end,
+           "^[^:]+:%d+: attempt to",
+           "'100' >> true")
+
+error_like(function () return '3' << true end,
+           "^[^:]+:%d+: attempt to",
+           "'3' << true")
+
+error_like(function () return '25' // 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'25' // 'text'")
+
+error_like(function () return '3' & 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'3' & 'text'")
+
+error_like(function () return '4' | 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'4' | 'text'")
+
+error_like(function () return '7' ~ 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'7' ~ 'text'")
+
+error_like(function () return '100' >> 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'100' >> 'text'")
+
+error_like(function () return '3' << 'text' end,
+           "^[^:]+:%d+: attempt to",
+           "'3' << 'text'")
+
+if profile.nocvts2n then
+    error_like(function () return '25.5' // '3.5' end,
+               "^[^:]+:%d+: attempt to",
+               "'25.5' // '3.5'")
+
+    error_like(function () return '25' // '3' end,
+               "^[^:]+:%d+: attempt to",
+               "'25' // '3'")
+else
+    is('25.5' // '3.5', 7.0, "'25.5' // '3.5'")
+
+     is('25' // '3', 8, "'25' // '3'")
+end
+
+if profile.nocvts2n or _VERSION >= 'Lua 5.4' then
+    error_like(function () return '3' & '7' end,
+               "^[^:]+:%d+: attempt to",
+               "'3' & '7'")
+
+    error_like(function () return '4' | '1' end,
+               "^[^:]+:%d+: attempt to",
+               "'4' | '1'")
+
+    error_like(function () return '7' ~ '1' end,
+               "^[^:]+:%d+: attempt to",
+               "'7' ~ '1'")
+
+    error_like(function () return '100' >> '5' end,
+               "^[^:]+:%d+: attempt to",
+               "'100' >> '5'")
+
+    error_like(function () return '3' << '2' end,
+               "^[^:]+:%d+: attempt to",
+               "'3' << '2'")
+else
+    is('3' & '7', 3, "'3' & '7'")
+
+    is('4' | '1', 5, "'4' | '1'")
+
+    is('7' ~ '1', 6, "'7' ~ '1'")
+
+    is('100' >> '5', 3, "'100' >> '5'")
+
+    is('3' << '2', 12, "'3' << 2")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/table.t b/test/lua-Harness-tests/lexico53/table.t
new file mode 100644
index 0000000..007232d
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/table.t
@@ -0,0 +1,43 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+error_like(function () return ~{} end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a table value",
+           "~{}")
+
+error_like(function () return {} // 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "{} // 3")
+
+error_like(function () return {} & 7 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a table value",
+           "{} & 7")
+
+error_like(function () return {} | 1 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a table value",
+           "{} | 1")
+
+error_like(function () return {} ~ 4 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a table value",
+           "{} ~ 4")
+
+error_like(function () return {} >> 5 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a table value",
+           "{} >> 5")
+
+error_like(function () return {} << 2 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on a table value",
+           "{} << 2")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/thread.t b/test/lua-Harness-tests/lexico53/thread.t
new file mode 100644
index 0000000..ef9e57b
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/thread.t
@@ -0,0 +1,45 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+local co = coroutine.create(function () return 1 end)
+
+error_like(function () return ~co end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "~co")
+
+error_like(function () return co // 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "co // 3")
+
+error_like(function () return co & 7 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "co & 7")
+
+error_like(function () return co | 1 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "co | 1")
+
+error_like(function () return co ~ 4 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "co ~ 4")
+
+error_like(function () return co >> 5 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "co >> 5")
+
+error_like(function () return co << 2 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "co << 2")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/userdata.t b/test/lua-Harness-tests/lexico53/userdata.t
new file mode 100644
index 0000000..06b96f9
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/userdata.t
@@ -0,0 +1,45 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2009-2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+local u = io.stdin
+
+error_like(function () return ~u end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "~u")
+
+error_like(function () return u // 3 end,
+           "^[^:]+:%d+: attempt to perform arithmetic on",
+           "u // 3")
+
+error_like(function () return u & 7 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "u & 7")
+
+error_like(function () return u | 1 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "u | 1")
+
+error_like(function () return u ~ 4 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "u ~ 4")
+
+error_like(function () return u >> 5 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "u >> 5")
+
+error_like(function () return u << 2 end,
+           "^[^:]+:%d+: attempt to perform bitwise operation on",
+           "u << 2")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico53/utf8.t b/test/lua-Harness-tests/lexico53/utf8.t
new file mode 100644
index 0000000..87d3f6d
--- /dev/null
+++ b/test/lua-Harness-tests/lexico53/utf8.t
@@ -0,0 +1,179 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2014-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+local has_char54 = _VERSION >= 'Lua 5.4'
+local has_charpattern54 = _VERSION >= 'Lua 5.4'
+
+do -- char
+    is(utf8.char(65, 66, 67), 'ABC', "function char")
+    is(utf8.char(0x20AC), '\u{20AC}')
+    is(utf8.char(), '')
+
+    is(utf8.char(0):len(), 1)
+    is(utf8.char(0x7F):len(), 1)
+    is(utf8.char(0x80):len(), 2)
+    is(utf8.char(0x7FF):len(), 2)
+    is(utf8.char(0x800):len(), 3)
+    is(utf8.char(0xFFFF):len(), 3)
+    is(utf8.char(0x10000):len(), 4)
+    is(utf8.char(0x10FFFF):len(), 4)
+    if has_char54 then
+        is(utf8.char(0x1FFFFF):len(), 4)
+        is(utf8.char(0x200000):len(), 5)
+        is(utf8.char(0x3FFFFFF):len(), 5)
+        is(utf8.char(0x4000000):len(), 6)
+        is(utf8.char(0x7FFFFFFF):len(), 6)
+    else
+        error_like(function () utf8.char(0x110000) end,
+                   "^[^:]+:%d+: bad argument #1 to 'char' %(value out of ",
+                   "function char (out of range)")
+    end
+
+    error_like(function () utf8.char(0, -1) end,
+               "^[^:]+:%d+: bad argument #2 to 'char' %(value out of ",
+               "function char (out of range)")
+
+     error_like(function () utf8.char(0, 'bad') end,
+                "^[^:]+:%d+: bad argument #2 to 'char' %(number expected, got string%)",
+                "function char (bad)")
+end
+
+do -- charpattern
+    if has_charpattern54 then
+        is(utf8.charpattern, "[\0-\x7F\xC2-\xFD][\x80-\xBF]*", "charpattern")
+    else
+        is(utf8.charpattern, "[\0-\x7F\xC2-\xF4][\x80-\xBF]*", "charpattern")
+    end
+end
+
+do -- codes
+    local ap = {}
+    local ac = {}
+    for p, c in utf8.codes("A\u{20AC}3") do
+        ap[#ap+1] = p
+        ac[#ac+1] = c
+    end
+    eq_array(ap, {1, 2, 5}, "function codes")
+    eq_array(ac, {0x41, 0x20AC, 0x33})
+
+    local empty = true
+    for p, c in utf8.codes('') do
+        empty = false
+    end
+    ok(empty, "codes (empty)")
+
+    error_like(function () utf8.codes() end,
+               "^[^:]+:%d+: bad argument #1 to 'codes' %(string expected, got no value%)",
+               "function codes ()")
+
+    error_like(function () utf8.codes(true) end,
+               "^[^:]+:%d+: bad argument #1 to 'codes' %(string expected, got boolean%)",
+               "function codes (true)")
+
+    error_like(function () for p, c in utf8.codes('invalid\xFF') do end end,
+               "^[^:]+:%d+: invalid UTF%-8 code",
+               "function codes (invalid)")
+end
+
+do -- codepoints
+    is(utf8.codepoint("A\u{20AC}3"), 0x41, "function codepoint")
+    is(utf8.codepoint("A\u{20AC}3", 2), 0x20AC)
+    is(utf8.codepoint("A\u{20AC}3", -1), 0x33)
+    is(utf8.codepoint("A\u{20AC}3", 5), 0x33)
+    eq_array({utf8.codepoint("A\u{20AC}3", 1, 5)}, {0x41, 0x20AC, 0x33})
+    eq_array({utf8.codepoint("A\u{20AC}3", 1, 4)}, {0x41, 0x20AC})
+
+    error_like(function () utf8.codepoint("A\u{20AC}3", 6) end,
+               "^[^:]+:%d+: bad argument #3 to 'codepoint' %(out of ",
+               "function codepoint (out of range)")
+
+    error_like(function () utf8.codepoint("A\u{20AC}3", 8) end,
+               "^[^:]+:%d+: bad argument #3 to 'codepoint' %(out of ",
+               "function codepoint (out of range)")
+
+    error_like(function () utf8.codepoint("invalid\xFF", 8) end,
+               "^[^:]+:%d+: invalid UTF%-8 code",
+               "function codepoint (invalid)")
+end
+
+do -- len
+    is(utf8.len('A'), 1, "function len")
+    is(utf8.len(''), 0)
+    is(utf8.len("\u{41}\u{42}\u{43}"), 3)
+    is(utf8.len("A\u{20AC}3"), 3)
+
+    is(utf8.len('A', 1), 1)
+    is(utf8.len('A', 2), 0)
+    is(utf8.len('ABC', 1, 1), 1)
+    is(utf8.len('ABC', 2, 2), 1)
+    is(utf8.len('ABC', -1), 1)
+    is(utf8.len('ABC', -2), 2)
+
+    error_like(function () utf8.len('A', 3) end,
+               "^[^:]+:%d+: bad argument #2 to 'len' %(initial position out of ",
+               "function len (out of range)")
+
+    local len, pos = utf8.len('invalid\xFF')
+    is(len, nil, "function len (invalid)")
+    is(pos, 8)
+end
+
+do -- offset
+    is(utf8.offset("A\u{20AC}3", 1), 1, "function offset")
+    is(utf8.offset("A\u{20AC}3", 2), 2)
+    is(utf8.offset("A\u{20AC}3", 3), 5)
+    is(utf8.offset("A\u{20AC}3", 4), 6)
+    is(utf8.offset("A\u{20AC}3", 5), nil)
+    is(utf8.offset("A\u{20AC}3", 6), nil)
+    is(utf8.offset("A\u{20AC}3", -1), 5)
+    is(utf8.offset("A\u{20AC}3", 1, 2), 2)
+    is(utf8.offset("A\u{20AC}3", 2, 2), 5)
+    is(utf8.offset("A\u{20AC}3", 3, 2), 6)
+    is(utf8.offset("A\u{20AC}3", 4, 2), nil)
+    is(utf8.offset("A\u{20AC}3", -1, 2), 1)
+    is(utf8.offset("A\u{20AC}3", -2, 2), nil)
+    is(utf8.offset("A\u{20AC}3", 1, 5), 5)
+    is(utf8.offset("A\u{20AC}3", 2, 5), 6)
+    is(utf8.offset("A\u{20AC}3", 3, 5), nil)
+    is(utf8.offset("A\u{20AC}3", -1, 5), 2)
+    is(utf8.offset("A\u{20AC}3", -2, 5), 1)
+    is(utf8.offset("A\u{20AC}3", -3, 5), nil)
+    is(utf8.offset("A\u{20AC}3", 1, 6), 6)
+    is(utf8.offset("A\u{20AC}3", 2, 6), nil)
+    is(utf8.offset("A\u{20AC}3", 1, -1), 5)
+    is(utf8.offset("A\u{20AC}3", -1, -1), 2)
+    is(utf8.offset("A\u{20AC}3", -2, -1), 1)
+    is(utf8.offset("A\u{20AC}3", -3, -1), nil)
+    is(utf8.offset("A\u{20AC}3", 1, -4), 2)
+    is(utf8.offset("A\u{20AC}3", 2, -4), 5)
+    is(utf8.offset("A\u{20AC}3", -1, -4), 1)
+    is(utf8.offset("A\u{20AC}3", -2, -4), nil)
+
+    is(utf8.offset("A\u{20AC}3", 0, 1), 1)
+    is(utf8.offset("A\u{20AC}3", 0, 2), 2)
+    is(utf8.offset("A\u{20AC}3", 0, 3), 2)
+    is(utf8.offset("A\u{20AC}3", 0, 4), 2)
+    is(utf8.offset("A\u{20AC}3", 0, 5), 5)
+    is(utf8.offset("A\u{20AC}3", 0, 6), 6)
+
+    error_like(function () utf8.offset("A\u{20AC}3", 1, 7) end,
+               "^[^:]+:%d+: bad argument #3 to 'offset' %(position out of ",
+              "function offset (out of range)")
+
+    error_like(function () utf8.offset("\x80", 1) end,
+               "^[^:]+:%d+: initial position is a continuation byte",
+               "function offset (continuation byte)")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico54/lexico.t b/test/lua-Harness-tests/lexico54/lexico.t
new file mode 100644
index 0000000..4523a51
--- /dev/null
+++ b/test/lua-Harness-tests/lexico54/lexico.t
@@ -0,0 +1,19 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+is("\u{10000}", "\xF0\x90\x80\x80")
+is("\u{200000}", "\xF8\x88\x80\x80\x80")
+is("\u{4000000}", "\xFC\x84\x80\x80\x80\x80")
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico54/metatable.t b/test/lua-Harness-tests/lexico54/metatable.t
new file mode 100644
index 0000000..4685b34
--- /dev/null
+++ b/test/lua-Harness-tests/lexico54/metatable.t
@@ -0,0 +1,38 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2019-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+do -- toclose
+    local called = false
+    do
+        local foo <close> = setmetatable({}, { __close = function () called = true end })
+        type_ok(foo, 'table', "toclose")
+        is(called, false)
+    end
+    is(called, true)
+
+    error_like(function () do local foo <close> = {} end end,
+               "^[^:]+:%d+: variable 'foo' got a non%-closable value")
+
+    lives_ok(function ()
+        local var1 <const> = nil
+        local var2 <const> = nil
+        do
+            local var3 <close> = setmetatable({}, { __close = function () end })
+        end
+        local var4 = true
+        -- attempt to close non-closable variable 'var4'
+    end, "blocker bug 5.4.0-rc3")
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexico54/utf8.t b/test/lua-Harness-tests/lexico54/utf8.t
new file mode 100644
index 0000000..1aa70cc
--- /dev/null
+++ b/test/lua-Harness-tests/lexico54/utf8.t
@@ -0,0 +1,54 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2019, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+do -- codes
+    local ap = {}
+    local ac = {}
+    for p, c in utf8.codes("A\u{200000}3", true) do
+        ap[#ap+1] = p
+        ac[#ac+1] = c
+    end
+    eq_array(ap, {1, 2, 7}, "function codes lax")
+    eq_array(ac, {0x41, 0x200000, 0x33})
+
+    error_like(function () for _ in utf8.codes("A\u{200000}3", false) do end end,
+               "^[^:]+:%d+: invalid UTF%-8 code")
+
+    error_like(function () for _ in utf8.codes("A\u{200000}3") do end end,
+               "^[^:]+:%d+: invalid UTF%-8 code")
+end
+
+do -- codepoints
+    eq_array({utf8.codepoint("A\u{200000}3", 1, 7, true)}, {0x41, 0x200000, 0x33}, "function codepoint lax")
+
+    error_like(function () utf8.codepoint("A\u{200000}3", 1, 7, false) end,
+               "^[^:]+:%d+: invalid UTF%-8 code")
+
+    error_like(function () utf8.codepoint("A\u{200000}3", 1, 7) end,
+               "^[^:]+:%d+: invalid UTF%-8 code")
+end
+
+do -- len
+    is(utf8.len('A\u{200000}C', 1, -1, true), 3, "function len lax")
+
+    local len, pos = utf8.len('A\u{200000}C')
+    is(len, nil)
+    is(pos, 2)
+
+    len, pos = utf8.len('A\u{200000}C', 1, -1, false)
+    is(len, nil)
+    is(pos, 2)
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexicojit/basic.t b/test/lua-Harness-tests/lexicojit/basic.t
new file mode 100644
index 0000000..8ad3a59
--- /dev/null
+++ b/test/lua-Harness-tests/lexicojit/basic.t
@@ -0,0 +1,27 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+do -- tonumber
+    is(tonumber(42uLL), 42, "function tonumber (cdata)")
+    is(tonumber(42LL), 42)
+end
+
+do -- tostring
+    is(tostring(42uLL), '42ULL', "function tostring (cdata)")
+    is(tostring(42LL), '42LL')
+    is(tostring(1i), '0+1i')
+    is(tostring(12.5i), '0+12.5i')
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexicojit/ext.t b/test/lua-Harness-tests/lexicojit/ext.t
new file mode 100644
index 0000000..8c44b99
--- /dev/null
+++ b/test/lua-Harness-tests/lexicojit/ext.t
@@ -0,0 +1,52 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2019-2020, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+local profile = require'profile'
+
+do -- thread.exdata
+    local r, exdata = pcall(require, 'thread.exdata')
+    is(r, true, 'thread.exdata')
+    type_ok(exdata, 'function')
+    is(package.loaded['thread.exdata'], exdata)
+
+    local ffi = require'ffi'
+    local u64 = ffi.new('uintptr_t', 0xefdeaddeadbeefLL)
+    local ptr = ffi.cast('void *', u64)
+    exdata(u64)  -- set
+    is(exdata(), ptr) -- get
+
+    error_like(function () exdata(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'exdata' %(cdata expected, got number%)")
+end
+
+-- thread.exdata2
+if profile.openresty then
+    local r, exdata2 = pcall(require, 'thread.exdata2')
+    is(r, true, 'thread.exdata2')
+    type_ok(exdata2, 'function')
+    is(package.loaded['thread.exdata2'], exdata2)
+
+    local ffi = require'ffi'
+    local u64 = ffi.new('uintptr_t', 0xefdeaddeadbeefLL)
+    local ptr = ffi.cast('void *', u64)
+    exdata2(u64)  -- set
+    is(exdata2(), ptr) -- get
+
+    error_like(function () exdata2(42) end,
+               "^[^:]+:%d+: bad argument #1 to 'exdata2' %(cdata expected, got number%)")
+else
+    is(pcall(require, 'thread.exdata2'), false, 'no thread.exdata2')
+end
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/lexicojit/lexico.t b/test/lua-Harness-tests/lexicojit/lexico.t
new file mode 100644
index 0000000..1a973b5
--- /dev/null
+++ b/test/lua-Harness-tests/lexicojit/lexico.t
@@ -0,0 +1,32 @@
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+-- Copyright (C) 2018, Perrad Francois
+--
+-- This code is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
+
+type_ok(42LL, 'cdata', "42LL")
+type_ok(42ULL, 'cdata', "42ULL")
+type_ok(42uLL, 'cdata', "42uLL")
+type_ok(42ull, 'cdata', "42ull")
+
+type_ok(0x2aLL, 'cdata', "0x2aLL")
+type_ok(0x2aULL, 'cdata', "0x2aULL")
+type_ok(0x2auLL, 'cdata', "0x2auLL")
+type_ok(0x2aull, 'cdata', "0x2aull")
+
+type_ok(12.5i, 'cdata', '12.5i')
+type_ok(12.5I, 'cdata', '12.5I')
+type_ok(1i, 'cdata', '1i')
+type_ok(1I, 'cdata', '1I')
+type_ok(0i, 'cdata', '0i')
+type_ok(0I, 'cdata', '0I')
+
+-- Local Variables:
+--   mode: lua
+--   lua-indent-level: 4
+--   fill-column: 100
+-- End:
+-- vim: ft=lua expandtab shiftwidth=4:
diff --git a/test/lua-Harness-tests/profile.lua b/test/lua-Harness-tests/profile.lua
new file mode 100644
index 0000000..50c0c11
--- /dev/null
+++ b/test/lua-Harness-tests/profile.lua
@@ -0,0 +1,53 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = true,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = true,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua51.lua b/test/lua-Harness-tests/profile_lua51.lua
new file mode 100644
index 0000000..8625b23
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua51.lua
@@ -0,0 +1,46 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+-- [[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua51_strict.lua b/test/lua-Harness-tests/profile_lua51_strict.lua
new file mode 100644
index 0000000..d8d1efd
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua51_strict.lua
@@ -0,0 +1,46 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua52.lua b/test/lua-Harness-tests/profile_lua52.lua
new file mode 100644
index 0000000..fbc2fc4
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua52.lua
@@ -0,0 +1,46 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = true,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua52_strict.lua b/test/lua-Harness-tests/profile_lua52_strict.lua
new file mode 100644
index 0000000..d8d1efd
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua52_strict.lua
@@ -0,0 +1,46 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua53.lua b/test/lua-Harness-tests/profile_lua53.lua
new file mode 100644
index 0000000..ed1b91f
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua53.lua
@@ -0,0 +1,52 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = true,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua53_noconv.lua b/test/lua-Harness-tests/profile_lua53_noconv.lua
new file mode 100644
index 0000000..c4500b3
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua53_noconv.lua
@@ -0,0 +1,55 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = true,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    nocvtn2s = true,
+    nocvts2n = true,
+
+    compat53 = false,
+--[[
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua53_strict.lua b/test/lua-Harness-tests/profile_lua53_strict.lua
new file mode 100644
index 0000000..399282b
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua53_strict.lua
@@ -0,0 +1,52 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua54.lua b/test/lua-Harness-tests/profile_lua54.lua
new file mode 100644
index 0000000..ef4daa3
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua54.lua
@@ -0,0 +1,52 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = true,
+--[[
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua54_noconv.lua b/test/lua-Harness-tests/profile_lua54_noconv.lua
new file mode 100644
index 0000000..b9e17c3
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua54_noconv.lua
@@ -0,0 +1,55 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    nocvtn2s = true,
+    nocvts2n = true,
+
+    compat53 = true,
+--[[
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_lua54_strict.lua b/test/lua-Harness-tests/profile_lua54_strict.lua
new file mode 100644
index 0000000..9fcfb79
--- /dev/null
+++ b/test/lua-Harness-tests/profile_lua54_strict.lua
@@ -0,0 +1,53 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_luajit20.lua b/test/lua-Harness-tests/profile_luajit20.lua
new file mode 100644
index 0000000..75461c2
--- /dev/null
+++ b/test/lua-Harness-tests/profile_luajit20.lua
@@ -0,0 +1,53 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+-- [[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+-- [[ luajit
+    luajit_compat52 = false,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_luajit20_compat52.lua b/test/lua-Harness-tests/profile_luajit20_compat52.lua
new file mode 100644
index 0000000..7064470
--- /dev/null
+++ b/test/lua-Harness-tests/profile_luajit20_compat52.lua
@@ -0,0 +1,53 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = false,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+-- [[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_luajit21.lua b/test/lua-Harness-tests/profile_luajit21.lua
new file mode 100644
index 0000000..f24e85e
--- /dev/null
+++ b/test/lua-Harness-tests/profile_luajit21.lua
@@ -0,0 +1,53 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+-- [[ luajit
+    luajit_compat52 = false,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_luajit21_compat52.lua b/test/lua-Harness-tests/profile_luajit21_compat52.lua
new file mode 100644
index 0000000..7064470
--- /dev/null
+++ b/test/lua-Harness-tests/profile_luajit21_compat52.lua
@@ -0,0 +1,53 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = false,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+-- [[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_openresty.lua b/test/lua-Harness-tests/profile_openresty.lua
new file mode 100644
index 0000000..c151a39
--- /dev/null
+++ b/test/lua-Harness-tests/profile_openresty.lua
@@ -0,0 +1,53 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = false,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+-- [[ luajit
+    luajit_compat52 = true,
+    openresty = true,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_ravi.lua b/test/lua-Harness-tests/profile_ravi.lua
new file mode 100644
index 0000000..8cd2464
--- /dev/null
+++ b/test/lua-Harness-tests/profile_ravi.lua
@@ -0,0 +1,58 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+-- luacheck: globals _VERSION
+_VERSION = 'Lua 5.3'    -- instead of 'Ravi 5.3'
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = true,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = true,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    nocvtn2s = false,
+    nocvts2n = false,
+
+    compat53 = false,
+--[[
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+--[[ luajit
+    luajit_compat52 = true,
+    openresty = false,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/profile_tiny_fork.lua b/test/lua-Harness-tests/profile_tiny_fork.lua
new file mode 100644
index 0000000..f0df77b
--- /dev/null
+++ b/test/lua-Harness-tests/profile_tiny_fork.lua
@@ -0,0 +1,60 @@
+---
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+---
+
+require'compat53.math'
+-- luacheck: globals utf8
+utf8 = require'compat53.utf8'
+
+local profile = {
+
+--[[ compat 5.0
+    has_string_gfind = true,
+    has_math_mod = true,
+--]]
+
+    compat51 = false,
+--[[
+    has_unpack = true,
+    has_package_loaders = true,
+    has_math_log10 = true,
+    has_loadstring = true,
+    has_table_maxn = true,
+    has_module = true,
+    has_package_seeall = true,
+--]]
+
+    compat52 = false,
+--[[
+    has_mathx = true,
+    has_bit32 = true,
+    has_metamethod_ipairs = true,
+--]]
+
+    compat53 = false,
+--[[
+    has_math_log10 = true,
+    has_mathx = true,
+    has_metamethod_ipairs = true,
+--]]
+
+-- [[ luajit
+    luajit_compat52 = false,
+    openresty = false,
+    pack = true,
+    integer = true,
+    utf8 = true,
+--]]
+
+}
+
+package.loaded.profile = profile        -- prevents loading of default profile
+
+return profile
+
+--
+-- Copyright (c) 2018-2019 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
diff --git a/test/lua-Harness-tests/rx_captures b/test/lua-Harness-tests/rx_captures
new file mode 100644
index 0000000..e209d26
--- /dev/null
+++ b/test/lua-Harness-tests/rx_captures
@@ -0,0 +1,13 @@
+(a.)..(..)		zzzabcdefzzz	ab\tef			basic match
+(a(b(c))(d))		abcd		abcd\tbc\tc\td		nested match
+((%w+))			abcd		abcd\tabcd		nested match
+(a*(.)%w(%s*))		aa!b c		aa!b \t!\t 		nested match
+(a?)..			abcd		a			opt
+(A?)..			abcd		''			opt
+()aa()			flaaap		3\t5			empty capture
+(.)%1			bookkeeper	o			backreference
+(%w+)%s+%1		hello hello	hello			backreference
+(.*)x			123x		123			repeated dot capture
+$(%w+)			$abc=		abc			not escaped
+
+## vim: noexpandtab tabstop=4 shiftwidth=4
diff --git a/test/lua-Harness-tests/rx_charclass b/test/lua-Harness-tests/rx_charclass
new file mode 100644
index 0000000..af5cb45
--- /dev/null
+++ b/test/lua-Harness-tests/rx_charclass
@@ -0,0 +1,38 @@
+[c]			abcdef		c		character class
+^[a]			abcdef		a		anchored character class
+[^e]			abcdef		a		negated character class
+^[a]?			abcdef		a		anchored optional character class
+[^e]?			abcdef		a		negated optional character class
+^[^e]			abcdef		a		anchored negated character class
+^[^a]			abcdef		nil		anchored negated character class
+[b-d]			abcdef		b		character range
+[b-d]			abxxef		b		character range
+[b-d]			axcxef		c		character range
+[b-d]			axxdef		d		character range
+[b-d]			axxxef		nil		character range
+[^b-d]			abcdef		a		negated character range
+[^b-d]			bbccdd		nil		negated character range
+[-]			ab-def		-		unescaped hyphen
+[%-]			ab-def		-		escaped hyphen
+[%-]			abcdef		nil		escaped hyphen
+[^%-]			---x--		x		negated escaped hyphen
+[^%-]			------		nil		negated escaped hyphen
+[%-+]			ab-def		-		escaped hyphen in range
+[%-+]			ab+def		+		escaped hyphen in range
+[%-+]			abcdef		nil		escaped hyphen in range
+[+%-]			ab-def		-		escaped hyphen in range
+[+%-]			ab+def		+		escaped hyphen in range
+[+%-]			abcdef		nil		escaped hyphen in range
+[^%-+]			---x--		x		negated escaped hyphen in range
+[^%-+]			------		nil		negated escaped hyphen in range
+[^+%-]			---x--		x		negated escaped hyphen in range
+[^+%-]			------		nil		negated escaped hyphen in range
+["\\]			\\		\		escaped backslash
+[%]]			]		]		escaped close bracket
+[%]			\\]]		/malformed pattern %(missing ']'%)/	unescaped backslash (or no closing brace)
+ab\\cd			ab\092cd	ab\cd		literal match with backslash
+%?			ab<?		?		literal match with question mark
+[A-Z0-9]		abcdef		nil		two enumerated ranges
+[A-Z0-9]		abcDef		D		two enumerated ranges
+
+## vim: noexpandtab tabstop=4 shiftwidth=4
diff --git a/test/lua-Harness-tests/rx_metachars b/test/lua-Harness-tests/rx_metachars
new file mode 100644
index 0000000..8716ca1
--- /dev/null
+++ b/test/lua-Harness-tests/rx_metachars
@@ -0,0 +1,117 @@
+.			a		a		dot (.)
+.			\n		\n		dot (.)
+.			''		nil		dot (.)
+a%s+f			abcdef		nil		whitespace (%s)
+ab%s+cdef		ab  cdef	ab  cdef	whitespace (%s)
+a%S+f			abcdef		abcdef		not whitespace (%S)
+a%S+f			ab cdef		nil		not whitespace (%S)
+^abc			abcdef		abc		start and end of string (^)
+^abc			abc\ndef	abc		start and end of string (^)
+^abc			def\nabc	nil		start and end of string (^)
+def\n^abc		def\nabc	nil		start and end of string (^)
+def$			abcdef		def		start and end of string ($)
+def$			abc\ndef	def		start and end of string ($)
+def$			def\nabc	nil		start and end of string ($)
+def$\nabc		def\nabc	nil		start and end of string (^)
+abc\n$			abc\n		abc\n		end of string ($)
+abc$			abc\n		nil		end of string ($)
+c\nd			abc\ndef	c\nd		newline (\n)
+c\nd			abc\010def	c\nd		newline (\n)
+c\n+d			abc\n\ndef	c\n\nd		newline (\n)
+a\n+f			abcdef		nil		newline (\n)
+b\nc			abc\ndef	nil		newline (\n)
+c\td			abc\tdef	c\td		horizontal tab (\t)
+c\td			abc\09def	c\td		horizontal tab (\t)
+c\t+d			abc\t\tdef	c\t\td		horizontal tab (\t)
+a\t+f			abcdef		nil		horizontal tab (\t)
+b\tc			abc\tdef	nil		horizontal tab (\t)
+c\rd			abc\rdef	c\rd		return (\r)
+c\rd			abc\013def	c\rd		return (\r)
+c\r+d			abc\r\rdef	c\r\rd		return (\r)
+a\r+f			abcdef		nil		return (\r)
+b\rc			abc\rdef	nil		return (\r)
+c\fd			abc\fdef	c\fd		formfeed (\f)
+c\fd			abc\012def	c\fd		formfeed (\f)
+c\f+d			abc\f\fdef	c\f\fd		formfeed (\f)
+a\f+f			abcdef		nil		formfeed (\f)
+b\fc			abc\fdef	nil		formfeed (\f)
+c\033d			abc!def		c!d		dec (\0)
+c\033d			abc\033def	c!d		dec (\0)
+c\033+d			abc!!def	c!!d		dec (\0)
+a\033+f			abcdef		nil		dec (\0)
+b\033c			abc!def		nil		dec (\0)
+a%^d			a^d		a^d		escaped (useless)
+a^d			a^d		a^d		not escaped
+%^d			^d		^d		escaped
+a%$d			a$d		a$d		escaped (useless)
+a$d			a$d		a$d		not escaped
+a%$			a$		a$		escaped
+a%(d			a(d		a(d		escaped
+a%)d			a)d		a)d		escaped
+a%%d			a%d		a%d		escaped
+a%			a%		/malformed pattern %(ends with '%%'%)/	not escaped
+a%.d			a.d		a.d		escaped
+a%.d			abd		nil		escaped
+a%[d			a[d		a[d		escaped
+a%]d			a]d		a]d		escaped
+a%*d			a*d		a*d		escaped
+*ad			*ad		*ad		not escaped
+a%+d			a+d		a+d		escaped
+a%-d			a-d		a-d		escaped
+a%?d			a?d		a?d		escaped
+a%yd			ayd		ayd		escaped
+a%w+f			a=[ *f		nil		word character
+a%w+f			abcdef		abcdef		word character
+a%W+f			a&%- f		a&%- f		not word character
+a%W+f			abcdef		nil		not word character
+a%d+f			abcdef		nil		digit
+ab%d+cdef		ab42cdef	ab42cdef	digit
+a%D+f			abcdef		abcdef		not digit
+a%D+f			ab0cdef		nil		not digit
+a%l+f			aBCDEf		nil		lowercase letter
+a%l+f			abcdef		abcdef		lowercase letter
+a%L+f			a&2D f		a&2D f		not lowercase letter
+a%L+f			aBCdEf		nil		not lowercase letter
+a%u+f			abcdef		nil		uppercase letter
+a%u+f			aBCDEf		aBCDEf		uppercase letter
+a%U+f			a&2d f		a&2d f		not uppercase letter
+a%U+f			a&2D f		nil		not uppercase letter
+a%a+f			aBcDef		aBcDef		all letter
+a%a+f			a=[ *f		nil		all letter
+a%A+f			a&%- f		a&%- f		not all letter
+a%A+f			abcdef		nil		not all letter
+a%g+f			aBcDef		aBcDef		printable
+a%g+f			a=[ *f		nil		printable
+a%G+f			a \nf		a \nf		not printable
+a%G+f			abcdef		nil		not printable
+a%p+f			abcdef		nil		ponctuation
+a%p+f			a,;:!f		a,;:!f		ponctuation
+a%P+f			abcdef		abcdef		not ponctuation
+a%P+f			adc:ef		nil		not ponctuation
+a%c+f			abcdef		nil		control character
+a%c+f			a\04\03\02f	a\04\03\02f	control character
+a%C+f			abcdef		abcdef		not control character
+a%C+f			abc\01ef	nil		not control character
+a%x+f			axyzef		nil		hexadecimal
+a%x+f			ab3Def		ab3Def		hexadecimal
+a%X+f			abcdef		nil		not hexadecimal
+a%X+f			axy;Zf		axy;Zf		not hexadecimal
+a%z+f			abcdef		nil		zero (deprecated)
+a\0+f			abcdef		nil		zero
+a%z+f			a\0f		a\0f		zero (deprecated)
+a\0+f			a\0f		a\0f		zero
+a%Z+f			abcdef		abcdef		not zero (deprecated)
+a[^\0]+f		abcdef		abcdef		not zero
+a%Z+f			abc\0ef		nil		not zero (deprecated)
+a[^\0]+f		abc\0ef		nil		not zero
+a%b()f			a(bcde)f	a(bcde)f	balanced
+a%b()f			a(b(de)f	nil		balanced
+a%b()f			a(b(d)e)f	a(b(d)e)f	balanced
+a%b''f			a'bcde'f	a'bcde'f	balanced
+a%b""f			a"bcde"f	a"bcde"f	balanced
+%f[b]bc			abcdef		bc		frontier
+%f[b]c			abcdef		nil		frontier
+%f[^ab]c		abacdef		c		frontier
+%f[^ab]d		abacdef		nil		frontier
+
+## vim: noexpandtab tabstop=4 shiftwidth=4
diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
new file mode 100644
index 0000000..5ce95e6
--- /dev/null
+++ b/test/lua-Harness-tests/tap.lua
@@ -0,0 +1,212 @@
+
+--
+-- lua-Harness : <https://fperrad.frama.io/lua-Harness/>
+--
+
+--[[
+
+        Test Anything Protocol : minimalist version
+
+]]
+
+if pcall(require, 'Test.More') then
+    diag 'Test.More loaded'
+    return
+end
+
+local os = os
+local pcall = pcall
+local print = print
+local require = require
+local tostring = tostring
+local type = type
+
+local curr_test = 0
+local expected_tests = 0
+local todo_upto = 0
+local todo_reason
+
+function plan (arg)
+    if arg ~= 'no_plan' then
+        expected_tests = arg
+        print("1.." .. tostring(arg))
+    end
+end
+
+function done_testing ()
+    print("1.." .. tostring(curr_test))
+end
+
+function skip_all (reason)
+    out = "1..0"
+    if reason then
+        out = out .. " # SKIP " .. reason
+    end
+    print(out)
+    os.exit(0)
+end
+
+function ok (test, name)
+    curr_test = curr_test + 1
+    local out = ''
+    if not test then
+        out = "not "
+    end
+    out = out .. "ok " .. tostring(curr_test)
+    if name then
+        out = out .. " - " .. name
+    end
+    if todo_reason and todo_upto >= curr_test then
+        out = out .. " # TODO # " .. todo_reason
+    end
+    print(out)
+end
+
+function nok (test, name)
+    ok(not test, name)
+end
+
+function is (got, expected, name)
+    local pass = got == expected
+    ok(pass, name)
+    if not pass then
+        diag("         got: " .. tostring(got))
+        diag("    expected: " .. tostring(expected))
+    end
+end
+
+function isnt (got, not_expected, name)
+    local pass = got ~= not_expected
+    ok(pass, name)
+    if not pass then
+        diag("         got: " .. tostring(got))
+        diag("    expected: anything else")
+    end
+end
+
+function like (got, pattern, name)
+    local pass = tostring(got):match(pattern)
+    ok(pass, name)
+    if not pass then
+        diag("                  " .. tostring(got))
+        diag("    doesn't match '" .. tostring(pattern) .. "'")
+    end
+end
+
+function type_ok (val, t, name)
+    if type(val) == t then
+        ok(true, name)
+    else
+        ok(false, name)
+        diag("    " .. tostring(val) .. " isn't a '" .. t .."' it's '" .. type(val) .. "'")
+    end
+end
+
+function pass (name)
+    ok(true, name)
+end
+
+function fail (name)
+    ok(false, name)
+end
+
+function require_ok (mod)
+    local r, msg = pcall(require, mod)
+    ok(r, "require '" .. mod .. "'")
+    if not r then
+        diag("    " .. msg)
+    end
+    return r
+end
+
+function eq_array (got, expected, name)
+    for i = 1, #expected do
+        local v = expected[i]
+        local val = got[i]
+        if val ~= v then
+            ok(false, name)
+            diag("    at index: " .. tostring(i))
+            diag("         got: " .. tostring(val))
+            diag("    expected: " .. tostring(v))
+            return
+        end
+    end
+    local extra = #got - #expected
+    if extra ~= 0 then
+        ok(false, name)
+        diag("    " .. tostring(extra) .. " unexpected item(s)")
+    else
+        ok(true, name)
+    end
+end
+
+function error_is (code, expected, name)
+    local r, msg = pcall(code)
+    if r then
+        ok(false, name)
+        diag("    unexpected success")
+        diag("    expected: " .. tostring(pattern))
+    else
+        is(msg, expected, name)
+    end
+end
+
+function error_like (code, pattern, name)
+    local r, msg = pcall(code)
+    if r then
+        ok(false, name)
+        diag("    unexpected success")
+        diag("    expected: " .. tostring(pattern))
+    else
+        like(msg, pattern, name)
+    end
+end
+
+function lives_ok (code, name)
+    local r, msg = pcall(code)
+    ok(r, name)
+    if not r then
+        diag("    " .. msg)
+    end
+end
+
+function diag (msg)
+    print("# " .. msg)
+end
+
+function skip (reason, count)
+    count = count or 1
+    local name = "# skip"
+    if reason then
+        name = name .. " " ..reason
+    end
+    for i = 1, count do
+        ok(true, name)
+    end
+end
+
+function skip_rest (reason)
+    skip(reason, expected_tests - curr_test)
+end
+
+function todo (reason, count)
+    count = count or 1
+    todo_upto = curr_test + count
+    todo_reason = reason
+end
+
+-- The last arg element is guaranteed name of tested binary.
+function get_lua_binary_name ()
+    local i = 0
+    while arg[i] do
+        i = i - 1
+    end
+    return arg[i + 1]
+end
+
+--
+-- Copyright (c) 2009-2018 Francois Perrad
+--
+-- This library is licensed under the terms of the MIT/X11 license,
+-- like Lua itself.
+--
-- 
2.28.0



More information about the Tarantool-patches mailing list