* [Tarantool-patches] [PATCH luajit 1/6] test: add lua-Harness test suite
2021-03-12 5:27 [Tarantool-patches] [PATCH luajit 0/6] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
@ 2021-03-12 5:27 ` Sergey Kaplun via Tarantool-patches
2021-03-15 13:05 ` Igor Munkin via Tarantool-patches
2021-03-12 5:27 ` [Tarantool-patches] [PATCH luajit 2/6] test: adjust lua-Harness test suite for Tarantool Sergey Kaplun via Tarantool-patches
` (5 subsequent siblings)
6 siblings, 1 reply; 19+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-12 5:27 UTC (permalink / raw)
To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches
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@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
^ permalink raw reply [flat|nested] 19+ messages in thread