Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite
@ 2021-03-15 15:29 Sergey Kaplun via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 1/5] test: add " Sergey Kaplun via Tarantool-patches
                   ` (6 more replies)
  0 siblings, 7 replies; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 15:29 UTC (permalink / raw)
  To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches

In this patchset lua-Harness test suite is adapted for the LuaJIT fork
and Tarantool.

Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
Tarantool's branch for tests:
https://github.com/tarantool/tarantool/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
Issues:
* https://github.com/tarantool/tarantool/issues/5844
* https://github.com/tarantool/tarantool/issues/5473

Changes in v2:
* glanced commit message for the first patch
* dropped module renaming
* separate suite introduction and adjustment
* dropped unnecessary commits with disabled tests

Mergen Imeev (1):
  test: add lua-Harness test suite

Sergey Kaplun (4):
  test: adjust lua-Harness suite for LuaJIT
  test: adjust lua-Harness test suite for Tarantool
  test: disable 241-standalone of lua-Harness suite
  test: disable 411-luajit of lua-Harness suite

 .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           | 149 +++
 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 +++++++
 .../241-standalone.t.disabled                 | 269 ++++++
 test/lua-Harness-tests/242-luac.t             | 341 +++++++
 test/lua-Harness-tests/301-basic.t            | 860 ++++++++++++++++++
 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.disabled  | 211 +++++
 test/lua-Harness-tests/CMakeLists.txt         |  53 ++
 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, 12926 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.disabled
 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.disabled
 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

-- 
2.28.0


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
@ 2021-03-15 15:29 ` Sergey Kaplun via Tarantool-patches
  2021-03-15 17:37   ` Igor Munkin via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT Sergey Kaplun via Tarantool-patches
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 15:29 UTC (permalink / raw)
  To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches

This patch introduces lua-Harness test suite[1] into our LuaJIT
fork source tree.

Considering the different behaviour in the Tarantool runtime, several
tests need to be adjusted.

[1]: https://framagit.org/fperrad/lua-Harness/tree/a74be27/test_lua

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                | 203 +++++
 92 files changed, 12903 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..c99f324
--- /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 = arg[-3] or arg[-1]
+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..2d166e5
--- /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 = arg[-3] or arg[-1]
+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..e45599e
--- /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 = arg[-3] or arg[-1]
+
+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..cdbcb83
--- /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 = arg[-3] or arg[-1]
+
+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..e42fb53
--- /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 = arg[-3] or arg[-1]
+
+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..36528e8
--- /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 = arg[-3] or arg[-1]
+
+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..05111be
--- /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 = arg[-3] or arg[-1]
+
+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..08a99b8
--- /dev/null
+++ b/test/lua-Harness-tests/tap.lua
@@ -0,0 +1,203 @@
+
+--
+-- 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
+
+--
+-- 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] 30+ messages in thread

* [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT
  2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 1/5] test: add " Sergey Kaplun via Tarantool-patches
@ 2021-03-15 15:29 ` Sergey Kaplun via Tarantool-patches
  2021-03-15 17:39   ` Igor Munkin via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool Sergey Kaplun via Tarantool-patches
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 15:29 UTC (permalink / raw)
  To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches

LUAJIT_TEST_COMMAND always extends an amount of line argument by two
causing child test failures.
So, a new universal way to detect program name is required.

This patch introduces the new function `get_lua_binary_name()` inside
lua-Harness tap.lua module to get binary for test execution correctly.

The following tests are adjusted with the new function:
* 241-standalone.t
* 242-luac.t
* 301-basic.t
* 308-io.t
* 309-os.t
* 320-stdin.t
* 411-luajit.t

Part of tarantool/tarantool#5844
Part of tarantool/tarantool#4473
---
 test/lua-Harness-tests/241-standalone.t | 2 +-
 test/lua-Harness-tests/242-luac.t       | 2 +-
 test/lua-Harness-tests/301-basic.t      | 2 +-
 test/lua-Harness-tests/308-io.t         | 2 +-
 test/lua-Harness-tests/309-os.t         | 2 +-
 test/lua-Harness-tests/320-stdin.t      | 2 +-
 test/lua-Harness-tests/411-luajit.t     | 2 +-
 test/lua-Harness-tests/tap.lua          | 9 +++++++++
 8 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/test/lua-Harness-tests/241-standalone.t b/test/lua-Harness-tests/241-standalone.t
index c99f324..c5237ee 100755
--- a/test/lua-Harness-tests/241-standalone.t
+++ b/test/lua-Harness-tests/241-standalone.t
@@ -41,7 +41,7 @@ elseif ravi then
     banner = '^Ravi %d%.%d%.%d'
 end
 
-local lua = arg[-3] or arg[-1]
+local lua = get_lua_binary_name()
 local luac = jit and lua or (lua .. 'c')
 
 if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
diff --git a/test/lua-Harness-tests/242-luac.t b/test/lua-Harness-tests/242-luac.t
index 2d166e5..a95a334 100755
--- a/test/lua-Harness-tests/242-luac.t
+++ b/test/lua-Harness-tests/242-luac.t
@@ -38,7 +38,7 @@ if ravi then
     skip_all("ravi")
 end
 
-local lua = arg[-3] or arg[-1]
+local lua = get_lua_binary_name()
 local luac = lua .. 'c'
 
 if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
diff --git a/test/lua-Harness-tests/301-basic.t b/test/lua-Harness-tests/301-basic.t
index e45599e..f4f9235 100755
--- a/test/lua-Harness-tests/301-basic.t
+++ b/test/lua-Harness-tests/301-basic.t
@@ -48,7 +48,7 @@ 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 = arg[-3] or arg[-1]
+local lua = get_lua_binary_name()
 
 plan'no_plan'
 
diff --git a/test/lua-Harness-tests/308-io.t b/test/lua-Harness-tests/308-io.t
index cdbcb83..35d39c0 100755
--- a/test/lua-Harness-tests/308-io.t
+++ b/test/lua-Harness-tests/308-io.t
@@ -40,7 +40,7 @@ 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 = arg[-3] or arg[-1]
+local lua = get_lua_binary_name()
 
 plan'no_plan'
 
diff --git a/test/lua-Harness-tests/309-os.t b/test/lua-Harness-tests/309-os.t
index e42fb53..a787b14 100755
--- a/test/lua-Harness-tests/309-os.t
+++ b/test/lua-Harness-tests/309-os.t
@@ -34,7 +34,7 @@ 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 = arg[-3] or arg[-1]
+local lua = get_lua_binary_name()
 
 plan'no_plan'
 
diff --git a/test/lua-Harness-tests/320-stdin.t b/test/lua-Harness-tests/320-stdin.t
index 36528e8..4828285 100755
--- a/test/lua-Harness-tests/320-stdin.t
+++ b/test/lua-Harness-tests/320-stdin.t
@@ -26,7 +26,7 @@ Tests Lua Basic & IO Libraries with stdin
 
 require'tap'
 
-local lua = arg[-3] or arg[-1]
+local lua = get_lua_binary_name()
 
 if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
     skip_all "io.popen not supported"
diff --git a/test/lua-Harness-tests/411-luajit.t b/test/lua-Harness-tests/411-luajit.t
index 05111be..feb752e 100755
--- a/test/lua-Harness-tests/411-luajit.t
+++ b/test/lua-Harness-tests/411-luajit.t
@@ -31,7 +31,7 @@ if not jit or ujit then
     skip_all("only with LuaJIT")
 end
 
-local lua = arg[-3] or arg[-1]
+local lua = get_lua_binary_name()
 
 if not pcall(io.popen, lua .. [[ -e "a=1"]]) then
     skip_all("io.popen not supported")
diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
index 08a99b8..5ce95e6 100644
--- a/test/lua-Harness-tests/tap.lua
+++ b/test/lua-Harness-tests/tap.lua
@@ -195,6 +195,15 @@ function todo (reason, 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
 --
-- 
2.28.0


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool
  2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 1/5] test: add " Sergey Kaplun via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT Sergey Kaplun via Tarantool-patches
@ 2021-03-15 15:29 ` Sergey Kaplun via Tarantool-patches
  2021-03-15 17:44   ` Igor Munkin via Tarantool-patches
  2021-03-15 19:12   ` Igor Munkin via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 4/5] test: disable 241-standalone of lua-Harness suite Sergey Kaplun via Tarantool-patches
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 15:29 UTC (permalink / raw)
  To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches

This patch makes it possible to run lua-Harness test suite using
Tarantool.

203-lexico.t and 301-basic.t is adjusted to valid working with
out-of-source build in Tarantool CI.

Inside Tarantool's GitHub-CI there is no defined variable LOGNAME nor
USERNAME. This leads to test failure inside CI, because a string is
expected. So, now USERNAME is set manually via CMake.

Part of tarantool/tarantool#5844
Part of tarantool/tarantool#4473
---
 test/lua-Harness-tests/203-lexico.t   | 14 ++++++++++----
 test/lua-Harness-tests/301-basic.t    |  6 +++++-
 test/lua-Harness-tests/CMakeLists.txt |  4 ++++
 3 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/test/lua-Harness-tests/203-lexico.t b/test/lua-Harness-tests/203-lexico.t
index c1abebf..5f79b3f 100755
--- a/test/lua-Harness-tests/203-lexico.t
+++ b/test/lua-Harness-tests/203-lexico.t
@@ -117,20 +117,26 @@ do
     like(msg, "^[^:]+:%d+: unfinished long comment .-near")
 end
 
+-- XXX: If this test is run out of the tests source tree, the
+-- relative paths below become invalid. Hence, we need to
+-- prepend the directory from the script (i.e. test) name to
+-- the auxiliary files to be loaded and executed.
+local test_srcdir = arg[0]:gsub('([^/]+)%.t$', '')
+
 if _VERSION >= 'Lua 5.2' or jit then
-    dofile'lexico52/lexico.t'
+    dofile(test_srcdir .. 'lexico52/lexico.t')
 end
 
 if _VERSION >= 'Lua 5.3' or luajit21 then
-    dofile'lexico53/lexico.t'
+    dofile(test_srcdir .. 'lexico53/lexico.t')
 end
 
 if _VERSION >= 'Lua 5.4' then
-    dofile'lexico54/lexico.t'
+    dofile(test_srcdir .. 'lexico54/lexico.t')
 end
 
 if jit and pcall(require, 'ffi') then
-    dofile'lexicojit/lexico.t'
+    dofile(test_srcdir .. 'lexicojit/lexico.t')
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/301-basic.t b/test/lua-Harness-tests/301-basic.t
index f4f9235..c4ab594 100755
--- a/test/lua-Harness-tests/301-basic.t
+++ b/test/lua-Harness-tests/301-basic.t
@@ -843,7 +843,11 @@ do -- xpcall
 end
 
 if jit and pcall(require, 'ffi') then
-    dofile'lexicojit/basic.t'
+    -- XXX: If this test is run out of the tests source tree, the
+    -- relative paths below become invalid. Hence, we need to
+    -- prepend the directory from the script (i.e. test) name to
+    -- the auxiliary files to be loaded and executed.
+    dofile(arg[0]:gsub('([^/]+)%.t$', '') .. '/lexicojit/basic.t')
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
index 9b35e5a..bac279f 100644
--- a/test/lua-Harness-tests/CMakeLists.txt
+++ b/test/lua-Harness-tests/CMakeLists.txt
@@ -40,6 +40,10 @@ add_custom_command(TARGET lua-Harness-tests
     # for more info.
     # So use less preferable way for tests.
     # See the root CMakeLists.txt for more info.
+    # XXX: 309-os.t checks os.getenv() function by examine of
+    # USERNAME or LOGNAME enviroment variable. It is not present
+    # inside CI by itself, so it is set here manually.
+    USERNAME="fperrad"
     ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
       --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
       ${LUA_TEST_FLAGS}
-- 
2.28.0


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [Tarantool-patches] [PATCH v2 luajit 4/5] test: disable 241-standalone of lua-Harness suite
  2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
                   ` (2 preceding siblings ...)
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool Sergey Kaplun via Tarantool-patches
@ 2021-03-15 15:29 ` Sergey Kaplun via Tarantool-patches
  2021-03-16 14:51   ` Sergey Ostanevich via Tarantool-patches
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 5/5] test: disable 411-luajit " Sergey Kaplun via Tarantool-patches
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 15:29 UTC (permalink / raw)
  To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches

This patch disables 241-standalone.t from the lua-Harness test suite,
because some flags in Tarantool and LuaJIT work differently, or they are
not present at all in Tarantool. For example, -i, -b, -j.
See tarantool/tarantool#5541.

Part of tarantool/tarantool#5844
Part of tarantool/tarantool#4473
---
 .../{241-standalone.t => 241-standalone.t.disabled}               | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename test/lua-Harness-tests/{241-standalone.t => 241-standalone.t.disabled} (100%)

diff --git a/test/lua-Harness-tests/241-standalone.t b/test/lua-Harness-tests/241-standalone.t.disabled
similarity index 100%
rename from test/lua-Harness-tests/241-standalone.t
rename to test/lua-Harness-tests/241-standalone.t.disabled
-- 
2.28.0


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [Tarantool-patches] [PATCH v2 luajit 5/5] test: disable 411-luajit of lua-Harness suite
  2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
                   ` (3 preceding siblings ...)
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 4/5] test: disable 241-standalone of lua-Harness suite Sergey Kaplun via Tarantool-patches
@ 2021-03-15 15:29 ` Sergey Kaplun via Tarantool-patches
  2021-03-16 14:52   ` Sergey Ostanevich via Tarantool-patches
  2021-03-17  0:46 ` [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Igor Munkin via Tarantool-patches
  2021-03-17 16:49 ` Igor Munkin via Tarantool-patches
  6 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 15:29 UTC (permalink / raw)
  To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches

This patch disables 411-luajit.t from the lua-Harness test suite,
because Tarantool does not support -b and -j flags.
See tarantool/tarantool#5541.

Part of tarantool/tarantool#5844
Part of tarantool/tarantool#4473
---
 test/lua-Harness-tests/{411-luajit.t => 411-luajit.t.disabled} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename test/lua-Harness-tests/{411-luajit.t => 411-luajit.t.disabled} (100%)

diff --git a/test/lua-Harness-tests/411-luajit.t b/test/lua-Harness-tests/411-luajit.t.disabled
similarity index 100%
rename from test/lua-Harness-tests/411-luajit.t
rename to test/lua-Harness-tests/411-luajit.t.disabled
-- 
2.28.0


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 1/5] test: add " Sergey Kaplun via Tarantool-patches
@ 2021-03-15 17:37   ` Igor Munkin via Tarantool-patches
  2021-03-15 18:10     ` Sergey Kaplun via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-15 17:37 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

Thanks for the patch!

On 15.03.21, Sergey Kaplun wrote:
> This patch introduces lua-Harness test suite[1] into our LuaJIT
> fork source tree.

The suite has been taken intact. To check this I used the following
recipe:
| $ pwd
| /lua-Harness/test_lua
| $ git remote -v
| origin  https://framagit.org/fperrad/lua-Harness.git (fetch)
| origin  https://framagit.org/fperrad/lua-Harness.git (push)
| $ git lo -1
| a74be27 (HEAD -> master, origin/master, origin/HEAD) Makefile for lua-5.4.3-rc1
| $ find . -type f | sort | xargs md5sum > ~/vanilla
| <...>
| $ pwd
| /tarantool-luajit/test/lua-Harness-tests
| $ git remote -v
| origin  git@github.com:tarantool/luajit (fetch)
| origin  git@github.com:tarantool/luajit (push)
| $ git lo -1
| aeb693b1 (HEAD) test: add lua-Harness test suite
| $ find . -type f | sort | xargs md5sum > ~/tarantool
| $ diff ~/vanilla ~/tarantool
| 50a51
| > 6b2c7f2b647e0e3f72fd1426520c80a5  ./CMakeLists.txt
| 68d68
| < 221b08fe5c896c109f9bf22a65f52c07  ./Makefile

> 
> Considering the different behaviour in the Tarantool runtime, several
> tests need to be adjusted.
> 
> [1]: https://framagit.org/fperrad/lua-Harness/tree/a74be27/test_lua
> 
> 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                | 203 +++++
>  92 files changed, 12903 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
> 

<snipped>

> 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)

Why did you choose this order?

>  
>  add_custom_target(${PROJECT_NAME}-test DEPENDS
> +  lua-Harness-tests
>    LuaJIT-tests
>    tarantool-tests
>  )

<snipped>

> 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)

Why did you drop TEST_DEPS variable containing the dependencies?

> +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\;"
> +)

There is not a word regarding such complex LUA_PATH configuration.

> +
> +string(CONCAT LUA_CPATH
> +  "./?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> +  "${LUAJIT_SOURCE_DIR}/?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> +)

Ditto.

> +
> +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.

Why do you need this comment here? You're using LUAJIT_TEST_COMMAND
here, so if you need to explain its usage, it's better to leave a
comment with the rationale right before its definition rather than each
place it is used with prove.

> +    ${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

<snipped>

> -- 
> 2.28.0
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT Sergey Kaplun via Tarantool-patches
@ 2021-03-15 17:39   ` Igor Munkin via Tarantool-patches
  2021-03-15 18:33     ` Sergey Kaplun via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-15 17:39 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

Thanks for the patch!

This is why it's so important to take the suite intact at first: I
didn't even notice these changes in the previous series and now I regret
a bit regarding the solution with LUAJIT_TEST_INIT: for this case it
occurs to be ugly a little. Nevertheless, I believe Francois would be
interested in this use case, so it's worth to file a bug against
lua-Harness, IMHO.

On 15.03.21, Sergey Kaplun wrote:
> LUAJIT_TEST_COMMAND always extends an amount of line argument by two
> causing child test failures.

I don't get the line above. I guess you mind something similar to this:
| LUAJIT_TEST_COMMAND always extends <arg> table containing command line
| arguments by two. It leads to child test failures, since Lua
| interpreter name is misfetched from the table.

> So, a new universal way to detect program name is required.
> 
> This patch introduces the new function `get_lua_binary_name()` inside
> lua-Harness tap.lua module to get binary for test execution correctly.

Side note: I doubt the function location is right, but I guess there is
no other place that is required by all test chunks.

> 
> The following tests are adjusted with the new function:
> * 241-standalone.t
> * 242-luac.t
> * 301-basic.t
> * 308-io.t
> * 309-os.t
> * 320-stdin.t
> * 411-luajit.t
> 
> Part of tarantool/tarantool#5844
> Part of tarantool/tarantool#4473
> ---
>  test/lua-Harness-tests/241-standalone.t | 2 +-
>  test/lua-Harness-tests/242-luac.t       | 2 +-
>  test/lua-Harness-tests/301-basic.t      | 2 +-
>  test/lua-Harness-tests/308-io.t         | 2 +-
>  test/lua-Harness-tests/309-os.t         | 2 +-
>  test/lua-Harness-tests/320-stdin.t      | 2 +-
>  test/lua-Harness-tests/411-luajit.t     | 2 +-
>  test/lua-Harness-tests/tap.lua          | 9 +++++++++
>  8 files changed, 16 insertions(+), 7 deletions(-)
> 

<snipped>

> diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
> index 08a99b8..5ce95e6 100644
> --- a/test/lua-Harness-tests/tap.lua
> +++ b/test/lua-Harness-tests/tap.lua
> @@ -195,6 +195,15 @@ function todo (reason, count)
>      todo_reason = reason
>  end
>  
> +-- The last arg element is guaranteed name of tested binary.

Typo: s/last/least/.
Typo: s/guaranteed name of tested/guaranteed to be the name of the tested/.

> +function get_lua_binary_name ()
> +    local i = 0
> +    while arg[i] do

You make an excess lookup to a _G for each iteration. It's better to
pass <arg> as an argument to this function. Furthermore, it makes the
signature clearer, so user knows you're using <arg> to detect the
interpreter name.

> +        i = i - 1
> +    end
> +    return arg[i + 1]
> +end
> +
>  --
>  -- Copyright (c) 2009-2018 Francois Perrad
>  --
> -- 
> 2.28.0
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool Sergey Kaplun via Tarantool-patches
@ 2021-03-15 17:44   ` Igor Munkin via Tarantool-patches
  2021-03-16  6:01     ` Sergey Kaplun via Tarantool-patches
  2021-03-15 19:12   ` Igor Munkin via Tarantool-patches
  1 sibling, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-15 17:44 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

This is ridiculous: you split two similar renames required by the one
issue into *two* separate commits, but leaving the changes *totally
unrelated to each other* within a single commit. Please, split this
patch into two: one for the test directory tweak and another with
mocking environment variable in CMake.

On 15.03.21, Sergey Kaplun wrote:
> This patch makes it possible to run lua-Harness test suite using
> Tarantool.
> 
> 203-lexico.t and 301-basic.t is adjusted to valid working with
> out-of-source build in Tarantool CI.

This is done not only for Tarantool CI, but also for LuaJIT out of
source build.

> 
> Inside Tarantool's GitHub-CI there is no defined variable LOGNAME nor
> USERNAME. This leads to test failure inside CI, because a string is
> expected. So, now USERNAME is set manually via CMake.

You mix up "the symptom" and "the root cause" here again. Problem is not
in CI, but in the test. See the comment at the end.

> 
> Part of tarantool/tarantool#5844
> Part of tarantool/tarantool#4473
> ---
>  test/lua-Harness-tests/203-lexico.t   | 14 ++++++++++----
>  test/lua-Harness-tests/301-basic.t    |  6 +++++-
>  test/lua-Harness-tests/CMakeLists.txt |  4 ++++
>  3 files changed, 19 insertions(+), 5 deletions(-)
> 

<snipped>

> diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
> index 9b35e5a..bac279f 100644
> --- a/test/lua-Harness-tests/CMakeLists.txt
> +++ b/test/lua-Harness-tests/CMakeLists.txt
> @@ -40,6 +40,10 @@ add_custom_command(TARGET lua-Harness-tests
>      # for more info.
>      # So use less preferable way for tests.
>      # See the root CMakeLists.txt for more info.
> +    # XXX: 309-os.t checks os.getenv() function by examine of
> +    # USERNAME or LOGNAME enviroment variable. It is not present
> +    # inside CI by itself, so it is set here manually.

Strictly saying, the issue was found in CI, but it doesn't relate
directly to CI: this can be done via `unset USERNAME` in you bash. This
is nothing else, but just a bad test. You can ask Francois to adjust the
test using a bit more popular variable (such as PWD or HOME). For now I
propose to change the comment the way below and adjust the commit
message regarding the changes made.

s/It is not present inside CI by itself/These might not be set in the environment/.

> +    USERNAME="fperrad"
>      ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
>        --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
>        ${LUA_TEST_FLAGS}
> -- 
> 2.28.0
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-15 17:37   ` Igor Munkin via Tarantool-patches
@ 2021-03-15 18:10     ` Sergey Kaplun via Tarantool-patches
  2021-03-15 21:06       ` Igor Munkin via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 18:10 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

Thanks for the review!

On 15.03.21, Igor Munkin wrote:
> Sergey,
> 
> Thanks for the patch!
> 
> On 15.03.21, Sergey Kaplun wrote:
> > This patch introduces lua-Harness test suite[1] into our LuaJIT
> > fork source tree.
> 
> The suite has been taken intact. To check this I used the following
> recipe:
> | $ pwd
> | /lua-Harness/test_lua
> | $ git remote -v
> | origin  https://framagit.org/fperrad/lua-Harness.git (fetch)
> | origin  https://framagit.org/fperrad/lua-Harness.git (push)
> | $ git lo -1
> | a74be27 (HEAD -> master, origin/master, origin/HEAD) Makefile for lua-5.4.3-rc1
> | $ find . -type f | sort | xargs md5sum > ~/vanilla
> | <...>
> | $ pwd
> | /tarantool-luajit/test/lua-Harness-tests
> | $ git remote -v
> | origin  git@github.com:tarantool/luajit (fetch)
> | origin  git@github.com:tarantool/luajit (push)
> | $ git lo -1
> | aeb693b1 (HEAD) test: add lua-Harness test suite
> | $ find . -type f | sort | xargs md5sum > ~/tarantool
> | $ diff ~/vanilla ~/tarantool
> | 50a51
> | > 6b2c7f2b647e0e3f72fd1426520c80a5  ./CMakeLists.txt
> | 68d68
> | < 221b08fe5c896c109f9bf22a65f52c07  ./Makefile
> 
> > 
> > Considering the different behaviour in the Tarantool runtime, several
> > tests need to be adjusted.
> > 
> > [1]: https://framagit.org/fperrad/lua-Harness/tree/a74be27/test_lua
> > 
> > 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                | 203 +++++
> >  92 files changed, 12903 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
> > 
> 
> <snipped>
> 
> > 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)
> 
> Why did you choose this order?

Alphabetically, like in `ls` output. Feel free to propose your own.

> 
> >  
> >  add_custom_target(${PROJECT_NAME}-test DEPENDS
> > +  lua-Harness-tests
> >    LuaJIT-tests
> >    tarantool-tests
> >  )
> 
> <snipped>
> 
> > 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)
> 
> Why did you drop TEST_DEPS variable containing the dependencies?

Sorry, don't get it. What do you mean?

> 
> > +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\;"
> > +)
> 
> There is not a word regarding such complex LUA_PATH configuration.

Ok, it can be the one long string, but, in my opinion, this format is
more readable, plus, as a bonus, with it line length is less than 120
characters. I'll join these lines into one if you insist.

> 
> > +
> > +string(CONCAT LUA_CPATH
> > +  "./?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> > +  "${LUAJIT_SOURCE_DIR}/?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> > +)
> 
> Ditto.
> 
> > +
> > +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.
> 
> Why do you need this comment here? You're using LUAJIT_TEST_COMMAND
> here, so if you need to explain its usage, it's better to leave a
> comment with the rationale right before its definition rather than each
> place it is used with prove.

Ok, dropped. See the iterative patch below. Branch is force-pushed.

===================================================================
diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
index 9b35e5a..f8611ce 100644
--- a/test/lua-Harness-tests/CMakeLists.txt
+++ b/test/lua-Harness-tests/CMakeLists.txt
@@ -34,12 +34,6 @@ add_custom_command(TARGET lua-Harness-tests
   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}
===================================================================

> 
> > +    ${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
> 
> <snipped>
> 
> > -- 
> > 2.28.0
> > 
> 
> -- 
> Best regards,
> IM

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT
  2021-03-15 17:39   ` Igor Munkin via Tarantool-patches
@ 2021-03-15 18:33     ` Sergey Kaplun via Tarantool-patches
  2021-03-15 21:27       ` Igor Munkin via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-15 18:33 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

Thanks for the review!

On 15.03.21, Igor Munkin wrote:
> Sergey,
> 
> Thanks for the patch!
> 
> This is why it's so important to take the suite intact at first: I
> didn't even notice these changes in the previous series and now I regret
> a bit regarding the solution with LUAJIT_TEST_INIT: for this case it
> occurs to be ugly a little. Nevertheless, I believe Francois would be
> interested in this use case, so it's worth to file a bug against
> lua-Harness, IMHO.

I don't think so -- usage [1] declares the way to launch the suite.
It is our problem, that we don't use it.

> 
> On 15.03.21, Sergey Kaplun wrote:
> > LUAJIT_TEST_COMMAND always extends an amount of line argument by two
> > causing child test failures.
> 
> I don't get the line above. I guess you mind something similar to this:
> | LUAJIT_TEST_COMMAND always extends <arg> table containing command line
> | arguments by two. It leads to child test failures, since Lua
> | interpreter name is misfetched from the table.

Updated commit message considering your proposal.

> 
> > So, a new universal way to detect program name is required.
> > 
> > This patch introduces the new function `get_lua_binary_name()` inside
> > lua-Harness tap.lua module to get binary for test execution correctly.
> 
> Side note: I doubt the function location is right, but I guess there is
> no other place that is required by all test chunks.
> 
> > 
> > The following tests are adjusted with the new function:
> > * 241-standalone.t
> > * 242-luac.t
> > * 301-basic.t
> > * 308-io.t
> > * 309-os.t
> > * 320-stdin.t
> > * 411-luajit.t
> > 
> > Part of tarantool/tarantool#5844
> > Part of tarantool/tarantool#4473
> > ---
> >  test/lua-Harness-tests/241-standalone.t | 2 +-
> >  test/lua-Harness-tests/242-luac.t       | 2 +-
> >  test/lua-Harness-tests/301-basic.t      | 2 +-
> >  test/lua-Harness-tests/308-io.t         | 2 +-
> >  test/lua-Harness-tests/309-os.t         | 2 +-
> >  test/lua-Harness-tests/320-stdin.t      | 2 +-
> >  test/lua-Harness-tests/411-luajit.t     | 2 +-
> >  test/lua-Harness-tests/tap.lua          | 9 +++++++++
> >  8 files changed, 16 insertions(+), 7 deletions(-)
> > 
> 
> <snipped>
> 
> > diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
> > index 08a99b8..5ce95e6 100644
> > --- a/test/lua-Harness-tests/tap.lua
> > +++ b/test/lua-Harness-tests/tap.lua
> > @@ -195,6 +195,15 @@ function todo (reason, count)
> >      todo_reason = reason
> >  end
> >  
> > +-- The last arg element is guaranteed name of tested binary.
> 
> Typo: s/last/least/.
> Typo: s/guaranteed name of tested/guaranteed to be the name of the tested/.

Thanks, update the branch. See the iterative patch below.
===================================================================
diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
index 5ce95e6..e527687 100644
--- a/test/lua-Harness-tests/tap.lua
+++ b/test/lua-Harness-tests/tap.lua
@@ -195,7 +195,8 @@ function todo (reason, count)
     todo_reason = reason
 end
 
--- The last arg element is guaranteed name of tested binary.
+-- The least arg element is guaranteed to be the name
+-- of the tested binary.
 function get_lua_binary_name ()
     local i = 0
     while arg[i] do
===================================================================

> 
> > +function get_lua_binary_name ()
> > +    local i = 0
> > +    while arg[i] do
> 
> You make an excess lookup to a _G for each iteration. It's better to
> pass <arg> as an argument to this function. Furthermore, it makes the
> signature clearer, so user knows you're using <arg> to detect the
> interpreter name.

This economy looks unnecessary -- there are only 6 calls to this
function from the whole suite. You can provide time measurement
to prove me wrong.
I disagreed that it makes signature clearer, because there is no way to
use something instead `arg` variable anyway. Please, give me an
example, when usage of custom array is preferable than usage `arg`
variable. If this function *always* uses `arg` variable only, why we
should move it outside this function?

> 
> > +        i = i - 1
> > +    end
> > +    return arg[i + 1]
> > +end
> > +
> >  --
> >  -- Copyright (c) 2009-2018 Francois Perrad
> >  --
> > -- 
> > 2.28.0
> > 
> 
> -- 
> Best regards,
> IM

[1]: https://fperrad.frama.io/lua-Harness/usage/

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool Sergey Kaplun via Tarantool-patches
  2021-03-15 17:44   ` Igor Munkin via Tarantool-patches
@ 2021-03-15 19:12   ` Igor Munkin via Tarantool-patches
  1 sibling, 0 replies; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-15 19:12 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

On 15.03.21, Sergey Kaplun wrote:
> This patch makes it possible to run lua-Harness test suite using
> Tarantool.
> 
> 203-lexico.t and 301-basic.t is adjusted to valid working with
> out-of-source build in Tarantool CI.
> 
> Inside Tarantool's GitHub-CI there is no defined variable LOGNAME nor
> USERNAME. This leads to test failure inside CI, because a string is
> expected. So, now USERNAME is set manually via CMake.
> 
> Part of tarantool/tarantool#5844
> Part of tarantool/tarantool#4473
> ---
>  test/lua-Harness-tests/203-lexico.t   | 14 ++++++++++----
>  test/lua-Harness-tests/301-basic.t    |  6 +++++-
>  test/lua-Harness-tests/CMakeLists.txt |  4 ++++
>  3 files changed, 19 insertions(+), 5 deletions(-)
> 
> diff --git a/test/lua-Harness-tests/203-lexico.t b/test/lua-Harness-tests/203-lexico.t
> index c1abebf..5f79b3f 100755
> --- a/test/lua-Harness-tests/203-lexico.t
> +++ b/test/lua-Harness-tests/203-lexico.t
> @@ -117,20 +117,26 @@ do
>      like(msg, "^[^:]+:%d+: unfinished long comment .-near")
>  end
>  
> +-- XXX: If this test is run out of the tests source tree, the
> +-- relative paths below become invalid. Hence, we need to
> +-- prepend the directory from the script (i.e. test) name to
> +-- the auxiliary files to be loaded and executed.

On the second thought, my fix is bad and inconvenient, considering you
have missed a couple of other occurrences (just grep <dofile> in
lua-Harness-tests directory). Hence, I propose to introduce a new
routine in tap.lua implementing kinda Perlish "goto &" to the Lua file
in lua-Harness source tree to enclose this hack within the new function.

> +local test_srcdir = arg[0]:gsub('([^/]+)%.t$', '')
> +
>  if _VERSION >= 'Lua 5.2' or jit then
> -    dofile'lexico52/lexico.t'
> +    dofile(test_srcdir .. 'lexico52/lexico.t')
>  end
>  
>  if _VERSION >= 'Lua 5.3' or luajit21 then
> -    dofile'lexico53/lexico.t'
> +    dofile(test_srcdir .. 'lexico53/lexico.t')
>  end
>  
>  if _VERSION >= 'Lua 5.4' then
> -    dofile'lexico54/lexico.t'
> +    dofile(test_srcdir .. 'lexico54/lexico.t')
>  end
>  
>  if jit and pcall(require, 'ffi') then
> -    dofile'lexicojit/lexico.t'
> +    dofile(test_srcdir .. 'lexicojit/lexico.t')
>  end
>  
>  done_testing()

<snipped>

> -- 
> 2.28.0
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-15 18:10     ` Sergey Kaplun via Tarantool-patches
@ 2021-03-15 21:06       ` Igor Munkin via Tarantool-patches
  2021-03-16  9:38         ` Sergey Kaplun via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-15 21:06 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

On 15.03.21, Sergey Kaplun wrote:
> Igor,
> 
> Thanks for the review!
> 
> On 15.03.21, Igor Munkin wrote:
> > Sergey,
> > 
> > Thanks for the patch!
> > 
> > On 15.03.21, Sergey Kaplun wrote:

<snipped>

> > > 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)
> > 
> > Why did you choose this order?
> 
> Alphabetically, like in `ls` output. Feel free to propose your own.

To conform the alphabetical sort order LuaJIT-tests directory should go
before lua-Harness-tests directory.

> 

<snipped>

> > > 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)
> > 
> > Why did you drop TEST_DEPS variable containing the dependencies?
> 
> Sorry, don't get it. What do you mean?

If you look onto my iterative patch in the first review iteration,
you'll find TEST_DEPS variable similar to the one in tarantool-tests
CMakeLists.txt. I forgot to add it into CMakeLists.txt for LuaJIT-tests
and remembered about it in this patch.

> 
> > 
> > > +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\;"
> > > +)
> > 
> > There is not a word regarding such complex LUA_PATH configuration.
> 
> Ok, it can be the one long string, but, in my opinion, this format is
> more readable, plus, as a bonus, with it line length is less than 120
> characters. I'll join these lines into one if you insist.

This is not the issue (and might be much better that my approach in
tarantool-tests and I will patch the test runners to make it conform to
one style later). I'm talking about the purpose for each entry. E.g. why
do you need both "./?.lua" and "${CMAKE_CURRENT_SOURCE_DIR}/?.lua"?  If
you need "${LUAJIT_SOURCE_DIR}/?.lua" for jit.* modules, then why it's
not required for other suites? Mention this explicitly, please.

> 
> > 
> > > +
> > > +string(CONCAT LUA_CPATH
> > > +  "./?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> > > +  "${LUAJIT_SOURCE_DIR}/?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> > > +)
> > 
> > Ditto.
> > 

<snipped>

> > > -- 
> > > 2.28.0
> > > 
> > 
> > -- 
> > Best regards,
> > IM
> 
> -- 
> Best regards,
> Sergey Kaplun

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT
  2021-03-15 18:33     ` Sergey Kaplun via Tarantool-patches
@ 2021-03-15 21:27       ` Igor Munkin via Tarantool-patches
  2021-03-16 14:25         ` Sergey Ostanevich via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-15 21:27 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

On 15.03.21, Sergey Kaplun wrote:
> Igor,
> 
> Thanks for the review!
> 
> On 15.03.21, Igor Munkin wrote:
> > Sergey,
> > 
> > Thanks for the patch!
> > 
> > This is why it's so important to take the suite intact at first: I
> > didn't even notice these changes in the previous series and now I regret
> > a bit regarding the solution with LUAJIT_TEST_INIT: for this case it
> > occurs to be ugly a little. Nevertheless, I believe Francois would be
> > interested in this use case, so it's worth to file a bug against
> > lua-Harness, IMHO.
> 
> I don't think so -- usage [1] declares the way to launch the suite.
> It is our problem, that we don't use it.

OK, I'll do it myself then.

> 

<snipped>

> > > diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
> > > index 08a99b8..5ce95e6 100644
> > > --- a/test/lua-Harness-tests/tap.lua
> > > +++ b/test/lua-Harness-tests/tap.lua
> > > @@ -195,6 +195,15 @@ function todo (reason, count)
> > >      todo_reason = reason
> > >  end
> > >  
> > > +-- The last arg element is guaranteed name of tested binary.
> > 
> > Typo: s/last/least/.
> > Typo: s/guaranteed name of tested/guaranteed to be the name of the tested/.
> 
> Thanks, update the branch. See the iterative patch below.
> ===================================================================
> diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
> index 5ce95e6..e527687 100644
> --- a/test/lua-Harness-tests/tap.lua
> +++ b/test/lua-Harness-tests/tap.lua
> @@ -195,7 +195,8 @@ function todo (reason, count)
>      todo_reason = reason
>  end
>  
> --- The last arg element is guaranteed name of tested binary.
> +-- The least arg element is guaranteed to be the name
> +-- of the tested binary.
>  function get_lua_binary_name ()
>      local i = 0
>      while arg[i] do
> ===================================================================
> 
> > 
> > > +function get_lua_binary_name ()
> > > +    local i = 0
> > > +    while arg[i] do
> > 
> > You make an excess lookup to a _G for each iteration. It's better to
> > pass <arg> as an argument to this function. Furthermore, it makes the
> > signature clearer, so user knows you're using <arg> to detect the
> > interpreter name.
> 
> This economy looks unnecessary -- there are only 6 calls to this
> function from the whole suite. You can provide time measurement
> to prove me wrong.
> I disagreed that it makes signature clearer, because there is no way to
> use something instead `arg` variable anyway. Please, give me an
> example, when usage of custom array is preferable than usage `arg`
> variable. If this function *always* uses `arg` variable only, why we
> should move it outside this function?

I forgot to add "feel free to ignore" here. You can write the code you
like and I can't make you to do it another way alone. For this purpose
there are two reviewers. I'll postpone my LGTM a bit for this change.

Regarding "no way to use something instead arg": nobody can stop you
from parsing shebang.

> 
> > 
> > > +        i = i - 1
> > > +    end
> > > +    return arg[i + 1]
> > > +end
> > > +
> > >  --
> > >  -- Copyright (c) 2009-2018 Francois Perrad
> > >  --
> > > -- 
> > > 2.28.0
> > > 
> > 
> > -- 
> > Best regards,
> > IM
> 
> [1]: https://fperrad.frama.io/lua-Harness/usage/
> 
> -- 
> Best regards,
> Sergey Kaplun

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool
  2021-03-15 17:44   ` Igor Munkin via Tarantool-patches
@ 2021-03-16  6:01     ` Sergey Kaplun via Tarantool-patches
  2021-03-16 10:51       ` Igor Munkin via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-16  6:01 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

Thanks for the review!

On 15.03.21, Igor Munkin wrote:
> Sergey,
> 
> This is ridiculous: you split two similar renames required by the one
> issue into *two* separate commits, but leaving the changes *totally
> unrelated to each other* within a single commit. Please, split this
> patch into two: one for the test directory tweak and another with
> mocking environment variable in CMake.

Sorry, but why then you said nothing about commits separation/joining
for this [1] draft series, as I asked for?

Offline we came to the agreement that we should use 3 commits for each
test suite. The first to onboard it, the second to adjust for LuaJIT,
the third to adjust it for Tarantool.
Later your asked me to send Mergens changes as is.

I specially send draft to discuss the commits content, order and so on.
You said only about separating patchset for different test suites and
merged LuaJIT test suite, so I thought that commit order is OK for you.
I'd merged changes with Tarantool-related one.

If it is not comfortable for you getting WIP series and discussing them
let's decline this practise.

Back to business, I've split the patch into two, considering your
proposal, see them below (their order is the same).

> 
> On 15.03.21, Sergey Kaplun wrote:
> > This patch makes it possible to run lua-Harness test suite using
> > Tarantool.
> > 
> > 203-lexico.t and 301-basic.t is adjusted to valid working with
> > out-of-source build in Tarantool CI.
> 
> This is done not only for Tarantool CI, but also for LuaJIT out of
> source build.
> 
> > 
> > Inside Tarantool's GitHub-CI there is no defined variable LOGNAME nor
> > USERNAME. This leads to test failure inside CI, because a string is
> > expected. So, now USERNAME is set manually via CMake.
> 
> You mix up "the symptom" and "the root cause" here again. Problem is not
> in CI, but in the test. See the comment at the end.
> 
> > 
> > Part of tarantool/tarantool#5844
> > Part of tarantool/tarantool#4473
> > ---
> >  test/lua-Harness-tests/203-lexico.t   | 14 ++++++++++----
> >  test/lua-Harness-tests/301-basic.t    |  6 +++++-
> >  test/lua-Harness-tests/CMakeLists.txt |  4 ++++
> >  3 files changed, 19 insertions(+), 5 deletions(-)
> > 
> 
> <snipped>
> 
> > diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
> > index 9b35e5a..bac279f 100644
> > --- a/test/lua-Harness-tests/CMakeLists.txt
> > +++ b/test/lua-Harness-tests/CMakeLists.txt
> > @@ -40,6 +40,10 @@ add_custom_command(TARGET lua-Harness-tests
> >      # for more info.
> >      # So use less preferable way for tests.
> >      # See the root CMakeLists.txt for more info.
> > +    # XXX: 309-os.t checks os.getenv() function by examine of
> > +    # USERNAME or LOGNAME enviroment variable. It is not present
> > +    # inside CI by itself, so it is set here manually.
> 
> Strictly saying, the issue was found in CI, but it doesn't relate
> directly to CI: this can be done via `unset USERNAME` in you bash. This
> is nothing else, but just a bad test. You can ask Francois to adjust the
> test using a bit more popular variable (such as PWD or HOME). For now I
> propose to change the comment the way below and adjust the commit
> message regarding the changes made.
> 
> s/It is not present inside CI by itself/These might not be set in the environment/.
> 
> > +    USERNAME="fperrad"
> >      ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
> >        --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
> >        ${LUA_TEST_FLAGS}
> > -- 
> > 2.28.0
> > 
> 
> -- 
> Best regards,
> IM

Patch for test directory tweak. Adjusted considering [2].

===================================================================
commit a84980334dce27243a25508e3bb8fd491689e552
Author: Sergey Kaplun <skaplun@tarantool.org>
Date:   Mon Mar 15 16:24:07 2021 +0300

    test: adjust lua-Harness tests that using dofile

    This patch makes out-of-source execution lua-Harness suite tests that
    using `dofile()` correct.

    There are the following files that used `dofile()` function
    on file in test sources directory:
    * 101-boolean.t
    * 102-function.t
    * 103-nil.t
    * 104-number.t
    * 105-string.t
    * 106-table.t
    * 107-thread.t
    * 108-userdata.t
    * 203-lexico.t
    * 231-metatable.t
    * 301-basic.t
    * 305-utf8.t
    * 404-ext.t

    `dofile()` looks for files to execute in the current working directory,
    that might be not the same as the test source directory.

    This patch introduces the new function `dofile_fullpath()` that
    evaluates full path to file considering arg[0] (i.e. test filename)
    value.

    Part of tarantool/tarantool#5844
    Part of tarantool/tarantool#4473

diff --git a/test/lua-Harness-tests/101-boolean.t b/test/lua-Harness-tests/101-boolean.t
index 0033eff..b9a769f 100755
--- a/test/lua-Harness-tests/101-boolean.t
+++ b/test/lua-Harness-tests/101-boolean.t
@@ -114,7 +114,7 @@ error_like(function () local a = true; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile'lexico53/boolean.t'
+    dofile_fullpath'lexico53/boolean.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/102-function.t b/test/lua-Harness-tests/102-function.t
index 48ed814..2858640 100755
--- a/test/lua-Harness-tests/102-function.t
+++ b/test/lua-Harness-tests/102-function.t
@@ -193,7 +193,7 @@ t[print] = true
 ok(t[print])
 
 if has_op53 then
-    dofile'lexico53/function.t'
+    dofile_fullpath'lexico53/function.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/103-nil.t b/test/lua-Harness-tests/103-nil.t
index 561b101..1e7c134 100755
--- a/test/lua-Harness-tests/103-nil.t
+++ b/test/lua-Harness-tests/103-nil.t
@@ -114,7 +114,7 @@ error_like(function () local a = nil; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile'lexico53/nil.t'
+    dofile_fullpath'lexico53/nil.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/104-number.t b/test/lua-Harness-tests/104-number.t
index 0d4d3fd..affd1a4 100755
--- a/test/lua-Harness-tests/104-number.t
+++ b/test/lua-Harness-tests/104-number.t
@@ -233,7 +233,7 @@ error_like(function () local a = 3.14; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile'lexico53/number.t'
+    dofile_fullpath'lexico53/number.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/105-string.t b/test/lua-Harness-tests/105-string.t
index cd8c88b..f571520 100755
--- a/test/lua-Harness-tests/105-string.t
+++ b/test/lua-Harness-tests/105-string.t
@@ -264,7 +264,7 @@ error_like(function () a = 'text'; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile'lexico53/string.t'
+    dofile_fullpath'lexico53/string.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/106-table.t b/test/lua-Harness-tests/106-table.t
index 0c0ba49..b1a1027 100755
--- a/test/lua-Harness-tests/106-table.t
+++ b/test/lua-Harness-tests/106-table.t
@@ -122,7 +122,7 @@ error_like(function () t = {}; t[0/0] = 42 end,
            "table index is NaN")
 
 if has_op53 then
-    dofile'lexico53/table.t'
+    dofile_fullpath'lexico53/table.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/107-thread.t b/test/lua-Harness-tests/107-thread.t
index 3d4af18..2f332d7 100755
--- a/test/lua-Harness-tests/107-thread.t
+++ b/test/lua-Harness-tests/107-thread.t
@@ -122,7 +122,7 @@ t[co] = true
 ok(t[co])
 
 if has_op53 then
-    dofile'lexico53/thread.t'
+    dofile_fullpath'lexico53/thread.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/108-userdata.t b/test/lua-Harness-tests/108-userdata.t
index b1e3641..cc4134b 100755
--- a/test/lua-Harness-tests/108-userdata.t
+++ b/test/lua-Harness-tests/108-userdata.t
@@ -119,7 +119,7 @@ t[u] = true
 ok(t[u])
 
 if has_op53 then
-    dofile'lexico53/userdata.t'
+    dofile_fullpath'lexico53/userdata.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/203-lexico.t b/test/lua-Harness-tests/203-lexico.t
index c1abebf..e5e89ed 100755
--- a/test/lua-Harness-tests/203-lexico.t
+++ b/test/lua-Harness-tests/203-lexico.t
@@ -118,19 +118,19 @@ do
 end
 
 if _VERSION >= 'Lua 5.2' or jit then
-    dofile'lexico52/lexico.t'
+    dofile_fullpath('lexico52/lexico.t')
 end
 
 if _VERSION >= 'Lua 5.3' or luajit21 then
-    dofile'lexico53/lexico.t'
+    dofile_fullpath('lexico53/lexico.t')
 end
 
 if _VERSION >= 'Lua 5.4' then
-    dofile'lexico54/lexico.t'
+    dofile_fullpath('lexico54/lexico.t')
 end
 
 if jit and pcall(require, 'ffi') then
-    dofile'lexicojit/lexico.t'
+    dofile_fullpath('lexicojit/lexico.t')
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/231-metatable.t b/test/lua-Harness-tests/231-metatable.t
index a2c6499..c5684d2 100755
--- a/test/lua-Harness-tests/231-metatable.t
+++ b/test/lua-Harness-tests/231-metatable.t
@@ -589,7 +589,7 @@ do
 end
 
 if has_anno_toclose then
-    dofile'lexico54/metatable.t'
+    dofile_fullpath'lexico54/metatable.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/301-basic.t b/test/lua-Harness-tests/301-basic.t
index f4f9235..460a02f 100755
--- a/test/lua-Harness-tests/301-basic.t
+++ b/test/lua-Harness-tests/301-basic.t
@@ -843,7 +843,7 @@ do -- xpcall
 end
 
 if jit and pcall(require, 'ffi') then
-    dofile'lexicojit/basic.t'
+    dofile_fullpath('lexicojit/basic.t')
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/305-utf8.t b/test/lua-Harness-tests/305-utf8.t
index 4304b6c..18c57d8 100755
--- a/test/lua-Harness-tests/305-utf8.t
+++ b/test/lua-Harness-tests/305-utf8.t
@@ -40,9 +40,9 @@ if not utf8 then
     nok(has_utf8, "no has_utf8")
 else
     plan'no_plan'
-    dofile'lexico53/utf8.t'
+    dofile_fullpath'lexico53/utf8.t'
     if _VERSION >= 'Lua 5.4' then
-        dofile'lexico54/utf8.t'
+        dofile_fullpath'lexico54/utf8.t'
     end
     done_testing()
 end
diff --git a/test/lua-Harness-tests/404-ext.t b/test/lua-Harness-tests/404-ext.t
index 22a52c7..e48d91a 100755
--- a/test/lua-Harness-tests/404-ext.t
+++ b/test/lua-Harness-tests/404-ext.t
@@ -158,7 +158,7 @@ end
 
 -- thread.exdata
 if pcall(require, 'ffi') and (profile.openresty or jit.version:match'moonjit') then
-    dofile'lexicojit/ext.t'
+    dofile_fullpath'lexicojit/ext.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
index e527687..37b9df7 100644
--- a/test/lua-Harness-tests/tap.lua
+++ b/test/lua-Harness-tests/tap.lua
@@ -205,6 +205,14 @@ function get_lua_binary_name ()
     return arg[i + 1]
 end
 
+-- XXX: If tests is run out of the tests source tree, the
+-- relative paths below become invalid. Hence, we need to
+-- prepend the directory from the script (i.e. test) name to
+-- the auxiliary files to be loaded and executed.
+function dofile_fullpath (filename)
+    return dofile(arg[0]:gsub('([^/]+)%.t$', '') .. filename)
+end
+
 --
 -- Copyright (c) 2009-2018 Francois Perrad
 --
===================================================================

Patch for mocking environment variable in CMake.

===================================================================
commit 483508b0a7863efabcde6d232ab9af2033e0011f
Author: Sergey Kaplun <skaplun@tarantool.org>
Date:   Mon Mar 15 22:08:07 2021 +0300

    test: forcify set USERNAME env var for lua-Harness

    309-os.t checks `os.getenv()` function by examining of
    USERNAME or LOGNAME environment variable.
    These variables might not be set in the environment, that leads to test
    failure.

    This patchs sets manually USERNAME environment variable for
    lua-Harness-tests target.

    Part of tarantool/tarantool#5844
    Part of tarantool/tarantool#4473

diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
index f8611ce..b844788 100644
--- a/test/lua-Harness-tests/CMakeLists.txt
+++ b/test/lua-Harness-tests/CMakeLists.txt
@@ -34,6 +34,11 @@ add_custom_command(TARGET lua-Harness-tests
   env
     LUA_PATH="${LUA_PATH}\;"
     LUA_CPATH="${LUA_CPATH}\;"
+    # XXX: 309-os.t checks os.getenv() function by examining of
+    # USERNAME or LOGNAME environment variable.
+    # These variables might not be set in the environment, so
+    # set one of them manually.
+    USERNAME="fperrad"
     ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
       --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
       ${LUA_TEST_FLAGS}
===================================================================

[1]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022563.html
[2]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022710.html

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-15 21:06       ` Igor Munkin via Tarantool-patches
@ 2021-03-16  9:38         ` Sergey Kaplun via Tarantool-patches
  2021-03-16 11:08           ` Igor Munkin via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-16  9:38 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

On 16.03.21, Igor Munkin wrote:
> Sergey,
> 
> On 15.03.21, Sergey Kaplun wrote:
> > Igor,
> > 
> > Thanks for the review!
> > 
> > On 15.03.21, Igor Munkin wrote:
> > > Sergey,
> > > 
> > > Thanks for the patch!
> > > 
> > > On 15.03.21, Sergey Kaplun wrote:
> 
> <snipped>
> 
> > > > 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)
> > > 
> > > Why did you choose this order?
> > 
> > Alphabetically, like in `ls` output. Feel free to propose your own.
> 
> To conform the alphabetical sort order LuaJIT-tests directory should go
> before lua-Harness-tests directory.

Agree. See the iteractive patch below. Branch is force-pushed.

===================================================================
diff --git a/.luacheckrc b/.luacheckrc
index a5f90b9..4e5dbdf 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -8,6 +8,6 @@ read_globals = { 'misc' }
 exclude_files = {
   'dynasm/',
   'src/',
-  'test/lua-Harness-tests/',
   'test/LuaJIT-tests/',
+  'test/lua-Harness-tests/',
 }
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 3a42f41..02fb2ed 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -43,13 +43,13 @@ endif()
 set(LUAJIT_TEST_COMMAND "${LUAJIT_TEST_BINARY} -e dofile[[${LUAJIT_TEST_INIT}]]")
 separate_arguments(LUAJIT_TEST_COMMAND)
 
-add_subdirectory(lua-Harness-tests)
 add_subdirectory(LuaJIT-tests)
+add_subdirectory(lua-Harness-tests)
 add_subdirectory(tarantool-tests)
 
 add_custom_target(${PROJECT_NAME}-test DEPENDS
-  lua-Harness-tests
   LuaJIT-tests
+  lua-Harness-tests
   tarantool-tests
 )
 
===================================================================

> 
> > 
> 
> <snipped>
> 
> > > > 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)
> > > 
> > > Why did you drop TEST_DEPS variable containing the dependencies?
> > 
> > Sorry, don't get it. What do you mean?
> 
> If you look onto my iterative patch in the first review iteration,
> you'll find TEST_DEPS variable similar to the one in tarantool-tests
> CMakeLists.txt. I forgot to add it into CMakeLists.txt for LuaJIT-tests
> and remembered about it in this patch.

Sorry, I missed it while looks through your patch -- I supposed that
it does two things:
* removes tap renaming
* removes list of test usage, as far as 5040 is resolved

For now I don't understand, why do we need this TEST_DEPS?
What is its mission?

> 
> > 
> > > 
> > > > +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\;"
> > > > +)
> > > 
> > > There is not a word regarding such complex LUA_PATH configuration.
> > 
> > Ok, it can be the one long string, but, in my opinion, this format is
> > more readable, plus, as a bonus, with it line length is less than 120
> > characters. I'll join these lines into one if you insist.
> 
> This is not the issue (and might be much better that my approach in
> tarantool-tests and I will patch the test runners to make it conform to
> one style later). I'm talking about the purpose for each entry. E.g. why
> do you need both "./?.lua" and "${CMAKE_CURRENT_SOURCE_DIR}/?.lua"?  If
> you need "${LUAJIT_SOURCE_DIR}/?.lua" for jit.* modules, then why it's
> not required for other suites? Mention this explicitly, please.

Got it now, thanks!
Looks like it really is not necessary. See the iterative patch below:
Checked result in CI -- it is green, except known freebsd issue.

===================================================================
diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
index b844788..fd5c8ce 100644
--- a/test/lua-Harness-tests/CMakeLists.txt
+++ b/test/lua-Harness-tests/CMakeLists.txt
@@ -15,16 +15,7 @@ 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}\;"
-)
+set(LUA_PATH "./?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;")
 
 add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY})
 
@@ -33,7 +24,6 @@ add_custom_command(TARGET lua-Harness-tests
   COMMAND
   env
     LUA_PATH="${LUA_PATH}\;"
-    LUA_CPATH="${LUA_CPATH}\;"
     # XXX: 309-os.t checks os.getenv() function by examining of
     # USERNAME or LOGNAME environment variable.
     # These variables might not be set in the environment, so
===================================================================

> 
> > 
> > > 
> > > > +
> > > > +string(CONCAT LUA_CPATH
> > > > +  "./?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> > > > +  "${LUAJIT_SOURCE_DIR}/?${CMAKE_SHARED_LIBRARY_SUFFIX}\;"
> > > > +)
> > > 
> > > Ditto.
> > > 
> 
> <snipped>
> 
> > > > -- 
> > > > 2.28.0
> > > > 
> > > 
> > > -- 
> > > Best regards,
> > > IM
> > 
> > -- 
> > Best regards,
> > Sergey Kaplun
> 
> -- 
> Best regards,
> IM

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool
  2021-03-16  6:01     ` Sergey Kaplun via Tarantool-patches
@ 2021-03-16 10:51       ` Igor Munkin via Tarantool-patches
  2021-03-16 14:51         ` Sergey Ostanevich via Tarantool-patches
  2021-03-16 14:59         ` Sergey Kaplun via Tarantool-patches
  0 siblings, 2 replies; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-16 10:51 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

On 16.03.21, Sergey Kaplun wrote:
> Igor,
> 
> Thanks for the review!
> 
> On 15.03.21, Igor Munkin wrote:
> > Sergey,
> > 
> > This is ridiculous: you split two similar renames required by the one
> > issue into *two* separate commits, but leaving the changes *totally
> > unrelated to each other* within a single commit. Please, split this
> > patch into two: one for the test directory tweak and another with
> > mocking environment variable in CMake.
> 
> Sorry, but why then you said nothing about commits separation/joining
> for this [1] draft series, as I asked for?

I mentioned it here[1] and you decided to left everything intact (that's
OK for me). This commit is a new one and you created it from two
separate commits in the previous version. So it's just a new feedback
for the new changes.

> 
> Offline we came to the agreement that we should use 3 commits for each
> test suite. The first to onboard it, the second to adjust for LuaJIT,
> the third to adjust it for Tarantool.

I remember only 3 bullets on which we have explicitly agreed:
* The suite should be taken intact in the first commit despite the fact
  tests can be broken.
* LuaJIT related changes should be separated from Tarantool related
  ones to ease their further maintenance. Furthermore, every change
  should be mentioned in our GitHub queue.
* All tests should be run in a unified way via both LuaJIT and Tarantool
  testing machinery. It means test chunk or test case is either run or
  not despite the testing environment.

Regarding everything else I was open to discuss it on review, since it's
too hard (at least for me) to consider all issues faced while adopting
these suites and create the most unified way to handle them. I believe,
this is the purpose of review process: to see what is done and think
whether it can be done in a better way (better doesn't mean *you* made
it wrong, but *we* chose a bad solution).

> Later your asked me to send Mergens changes as is.
> 
> I specially send draft to discuss the commits content, order and so on.
> You said only about separating patchset for different test suites and
> merged LuaJIT test suite, so I thought that commit order is OK for you.
> I'd merged changes with Tarantool-related one.

I hope you remember that I've asked a couple of times to polish and send
LuaJIT-test-cleanup patchset. The last time I was asking was right
before you sent WIP series. LuaJIT related patches per se were ready to
be merged; the only issue was disabling strict for it. Additionally I've
adjusted tarantool-tests runner to use LUAJIT_TEST_COMMAND to make all
tests be run by unified way.

Then I asked you to split two remaining suites into two series so I can
look on them separately. Hence, I was OK with the general approach, but
was afraid to miss some details.

> 
> If it is not comfortable for you getting WIP series and discussing them
> let's decline this practise.

I'm totally fine with WIP series: e.g. LUAJIT_TEST_INIT has been done
after I've glanced all the patches with tests you've sent.

> 
> Back to business, I've split the patch into two, considering your
> proposal, see them below (their order is the same).

Nice, thanks a lot!

> 

<snipped>

> 
> Patch for test directory tweak. Adjusted considering [2].
> 
> ===================================================================
> commit a84980334dce27243a25508e3bb8fd491689e552
> Author: Sergey Kaplun <skaplun@tarantool.org>
> Date:   Mon Mar 15 16:24:07 2021 +0300
> 
>     test: adjust lua-Harness tests that using dofile
> 
>     This patch makes out-of-source execution lua-Harness suite tests that
>     using `dofile()` correct.

Minor: There are other tests using <dofile>, but they are fine. The root
problem relates to the approach used in the patched tests: the .t files
are kinda wrapper, containing the basic checks (or not, e.g. UTF-8 test
chunk), and some specific checks are moved to the auxiliary chunks
"dofiled" in .t script.

> 
>     There are the following files that used `dofile()` function
>     on file in test sources directory:
>     * 101-boolean.t
>     * 102-function.t
>     * 103-nil.t
>     * 104-number.t
>     * 105-string.t
>     * 106-table.t
>     * 107-thread.t
>     * 108-userdata.t
>     * 203-lexico.t
>     * 231-metatable.t
>     * 301-basic.t
>     * 305-utf8.t
>     * 404-ext.t
> 
>     `dofile()` looks for files to execute in the current working directory,
>     that might be not the same as the test source directory.
> 
>     This patch introduces the new function `dofile_fullpath()` that

What does "fullpath" mean? If this is absolute path, then naming is
ambiguous; and I guess nothing stops one from using relative paths (but
not symlink, I think) here. Furthermore, the naming doesn't represent
the purpose: as I mentioned above this dofile is needed to implement
specific checks, so you can adjust the naming to more verbose one:
<test_more> or <make_specific_checks>. Thoughts?

>     evaluates full path to file considering arg[0] (i.e. test filename)

It's worth to check and mention the caveat with symlinks. If the issue
exists, then the paths should be resolved in CMake the way similar to
the one used for luacheck target.

>     value.
> 
>     Part of tarantool/tarantool#5844
>     Part of tarantool/tarantool#4473
> 

<snipped>

> ===================================================================
> 
> Patch for mocking environment variable in CMake.
> 
> ===================================================================
> commit 483508b0a7863efabcde6d232ab9af2033e0011f
> Author: Sergey Kaplun <skaplun@tarantool.org>
> Date:   Mon Mar 15 22:08:07 2021 +0300
> 
>     test: forcify set USERNAME env var for lua-Harness

Strictly saying, you do not force, but just set. Furthermore, I doubt
about word formation you applied to "force".

> 
>     309-os.t checks `os.getenv()` function by examining of

Typo: examine <smth>, not examine of <smth>[2].

>     USERNAME or LOGNAME environment variable.
>     These variables might not be set in the environment, that leads to test
>     failure.
> 
>     This patchs sets manually USERNAME environment variable for

Typo: s/manually/explicitly/.

>     lua-Harness-tests target.
> 
>     Part of tarantool/tarantool#5844
>     Part of tarantool/tarantool#4473
> 
> diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
> index f8611ce..b844788 100644
> --- a/test/lua-Harness-tests/CMakeLists.txt
> +++ b/test/lua-Harness-tests/CMakeLists.txt
> @@ -34,6 +34,11 @@ add_custom_command(TARGET lua-Harness-tests
>    env
>      LUA_PATH="${LUA_PATH}\;"
>      LUA_CPATH="${LUA_CPATH}\;"
> +    # XXX: 309-os.t checks os.getenv() function by examining of

Typo: examine <smth>, not examine of <smth>[2].

> +    # USERNAME or LOGNAME environment variable.
> +    # These variables might not be set in the environment, so
> +    # set one of them manually.
> +    USERNAME="fperrad"
>      ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
>        --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
>        ${LUA_TEST_FLAGS}
> ===================================================================
> 
> [1]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022563.html
> [2]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022710.html
> 
> -- 
> Best regards,
> Sergey Kaplun

[1]: https://lists.tarantool.org/tarantool-patches/16E39C08-397B-4A38-953A-B9EB85CD9C8B@tarantool.org/T/#m9de07af72e06ac22b7540741b9e1c4ac485688bb
[2]: https://dictionary.cambridge.org/dictionary/english/examine

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-16  9:38         ` Sergey Kaplun via Tarantool-patches
@ 2021-03-16 11:08           ` Igor Munkin via Tarantool-patches
  2021-03-16 12:02             ` Sergey Kaplun via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-16 11:08 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

Thanks for the fixes!

On 16.03.21, Sergey Kaplun wrote:
> Igor,
> 
> On 16.03.21, Igor Munkin wrote:
> > Sergey,
> > 

<snipped>

> > 
> > > > > 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)
> > > > 
> > > > Why did you drop TEST_DEPS variable containing the dependencies?
> > > 
> > > Sorry, don't get it. What do you mean?
> > 
> > If you look onto my iterative patch in the first review iteration,
> > you'll find TEST_DEPS variable similar to the one in tarantool-tests
> > CMakeLists.txt. I forgot to add it into CMakeLists.txt for LuaJIT-tests
> > and remembered about it in this patch.
> 
> Sorry, I missed it while looks through your patch -- I supposed that
> it does two things:
> * removes tap renaming
> * removes list of test usage, as far as 5040 is resolved

Yeah, that's my fault.

> 
> For now I don't understand, why do we need this TEST_DEPS?
> What is its mission?

To control the target dependencies: the binary and test chunks. However,
it was required when *-tests targets were not .PHONY, and now it's more
for self-check that nothing global is broken.

> 
> > 
> > > 
> > > > 
> > > > > +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\;"
> > > > > +)
> > > > 
> > > > There is not a word regarding such complex LUA_PATH configuration.
> > > 
> > > Ok, it can be the one long string, but, in my opinion, this format is
> > > more readable, plus, as a bonus, with it line length is less than 120
> > > characters. I'll join these lines into one if you insist.
> > 
> > This is not the issue (and might be much better that my approach in
> > tarantool-tests and I will patch the test runners to make it conform to
> > one style later). I'm talking about the purpose for each entry. E.g. why
> > do you need both "./?.lua" and "${CMAKE_CURRENT_SOURCE_DIR}/?.lua"?  If
> > you need "${LUAJIT_SOURCE_DIR}/?.lua" for jit.* modules, then why it's
> > not required for other suites? Mention this explicitly, please.
> 
> Got it now, thanks!
> Looks like it really is not necessary. See the iterative patch below:
> Checked result in CI -- it is green, except known freebsd issue.
> 
> ===================================================================
> diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
> index b844788..fd5c8ce 100644
> --- a/test/lua-Harness-tests/CMakeLists.txt
> +++ b/test/lua-Harness-tests/CMakeLists.txt
> @@ -15,16 +15,7 @@ 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}\;"
> -)
> +set(LUA_PATH "./?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;")

Still not a word, why do you need both "./?.lua" and
"${CMAKE_CURRENT_SOURCE_DIR}/?.lua".

>  
>  add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY})
>  
> @@ -33,7 +24,6 @@ add_custom_command(TARGET lua-Harness-tests
>    COMMAND
>    env
>      LUA_PATH="${LUA_PATH}\;"
> -    LUA_CPATH="${LUA_CPATH}\;"
>      # XXX: 309-os.t checks os.getenv() function by examining of
>      # USERNAME or LOGNAME environment variable.
>      # These variables might not be set in the environment, so
> ===================================================================
> 

<snipped>

> 
> -- 
> Best regards,
> Sergey Kaplun

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-16 11:08           ` Igor Munkin via Tarantool-patches
@ 2021-03-16 12:02             ` Sergey Kaplun via Tarantool-patches
  2021-03-16 13:50               ` Sergey Ostanevich via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-16 12:02 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

Thanks for the feedback!

On 16.03.21, Igor Munkin wrote:
> Sergey,
> 
> Thanks for the fixes!
> 
> On 16.03.21, Sergey Kaplun wrote:
> > Igor,
> > 
> > On 16.03.21, Igor Munkin wrote:
> > > Sergey,
> > > 
> 
> <snipped>
> 
> > > 
> > > > > > 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)
> > > > > 
> > > > > Why did you drop TEST_DEPS variable containing the dependencies?
> > > > 
> > > > Sorry, don't get it. What do you mean?
> > > 
> > > If you look onto my iterative patch in the first review iteration,
> > > you'll find TEST_DEPS variable similar to the one in tarantool-tests
> > > CMakeLists.txt. I forgot to add it into CMakeLists.txt for LuaJIT-tests
> > > and remembered about it in this patch.
> > 
> > Sorry, I missed it while looks through your patch -- I supposed that
> > it does two things:
> > * removes tap renaming
> > * removes list of test usage, as far as 5040 is resolved
> 
> Yeah, that's my fault.
> 
> > 
> > For now I don't understand, why do we need this TEST_DEPS?
> > What is its mission?
> 
> To control the target dependencies: the binary and test chunks. However,
> it was required when *-tests targets were not .PHONY, and now it's more
> for self-check that nothing global is broken.

OK, looks like we came to agreement offline so I just repeate this here:

* All test chunks are `.PHONY`, so all tests will rerun always,
  even without test sources changing. That's why we need only build
  dependencies here.
* We are planing to make all test suites more consistent,
  so TEST_DEPS will be removed from Tarantool's suite too later.

> 
> > 
> > > 
> > > > 
> > > > > 
> > > > > > +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\;"
> > > > > > +)
> > > > > 
> > > > > There is not a word regarding such complex LUA_PATH configuration.
> > > > 
> > > > Ok, it can be the one long string, but, in my opinion, this format is
> > > > more readable, plus, as a bonus, with it line length is less than 120
> > > > characters. I'll join these lines into one if you insist.
> > > 
> > > This is not the issue (and might be much better that my approach in
> > > tarantool-tests and I will patch the test runners to make it conform to
> > > one style later). I'm talking about the purpose for each entry. E.g. why
> > > do you need both "./?.lua" and "${CMAKE_CURRENT_SOURCE_DIR}/?.lua"?  If
> > > you need "${LUAJIT_SOURCE_DIR}/?.lua" for jit.* modules, then why it's
> > > not required for other suites? Mention this explicitly, please.
> > 
> > Got it now, thanks!
> > Looks like it really is not necessary. See the iterative patch below:
> > Checked result in CI -- it is green, except known freebsd issue.
> > 
> > ===================================================================
> > diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
> > index b844788..fd5c8ce 100644
> > --- a/test/lua-Harness-tests/CMakeLists.txt
> > +++ b/test/lua-Harness-tests/CMakeLists.txt
> > @@ -15,16 +15,7 @@ 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}\;"
> > -)
> > +set(LUA_PATH "./?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;")
> 
> Still not a word, why do you need both "./?.lua" and
> "${CMAKE_CURRENT_SOURCE_DIR}/?.lua".

Sorry, add corresponding comment:
===================================================================
diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
index a639553..336dc03 100644
--- a/test/lua-Harness-tests/CMakeLists.txt
+++ b/test/lua-Harness-tests/CMakeLists.txt
@@ -15,6 +15,9 @@ if(CMAKE_VERBOSE_MAKEFILE)
   list(APPEND LUA_TEST_FLAGS --verbose)
 endif()
 
+# Tests create temporary files (see 303-package.t for example)
+# to require. Also, they require some files from original
+# test source directory.
 set(LUA_PATH "./?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;")
 
 add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY})
===================================================================

> 
> >  
> >  add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY})
> >  
> > @@ -33,7 +24,6 @@ add_custom_command(TARGET lua-Harness-tests
> >    COMMAND
> >    env
> >      LUA_PATH="${LUA_PATH}\;"
> > -    LUA_CPATH="${LUA_CPATH}\;"
> >      # XXX: 309-os.t checks os.getenv() function by examining of
> >      # USERNAME or LOGNAME environment variable.
> >      # These variables might not be set in the environment, so
> > ===================================================================
> > 
> 
> <snipped>
> 
> > 
> > -- 
> > Best regards,
> > Sergey Kaplun
> 
> -- 
> Best regards,
> IM

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 1/5] test: add lua-Harness test suite
  2021-03-16 12:02             ` Sergey Kaplun via Tarantool-patches
@ 2021-03-16 13:50               ` Sergey Ostanevich via Tarantool-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Sergey Ostanevich via Tarantool-patches @ 2021-03-16 13:50 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

[-- Attachment #1: Type: text/plain, Size: 6181 bytes --]

Hi!

Thanks for the patch!

LGTM.

Sergos

> On 16 Mar 2021, at 15:02, Sergey Kaplun <skaplun@tarantool.org> wrote:
> 
> Igor,
> 
> Thanks for the feedback!
> 
> On 16.03.21, Igor Munkin wrote:
>> Sergey,
>> 
>> Thanks for the fixes!
>> 
>> On 16.03.21, Sergey Kaplun wrote:
>>> Igor,
>>> 
>>> On 16.03.21, Igor Munkin wrote:
>>>> Sergey,
>>>> 
>> 
>> <snipped>
>> 
>>>> 
>>>>>>> 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)
>>>>>> 
>>>>>> Why did you drop TEST_DEPS variable containing the dependencies?
>>>>> 
>>>>> Sorry, don't get it. What do you mean?
>>>> 
>>>> If you look onto my iterative patch in the first review iteration,
>>>> you'll find TEST_DEPS variable similar to the one in tarantool-tests
>>>> CMakeLists.txt. I forgot to add it into CMakeLists.txt for LuaJIT-tests
>>>> and remembered about it in this patch.
>>> 
>>> Sorry, I missed it while looks through your patch -- I supposed that
>>> it does two things:
>>> * removes tap renaming
>>> * removes list of test usage, as far as 5040 is resolved
>> 
>> Yeah, that's my fault.
>> 
>>> 
>>> For now I don't understand, why do we need this TEST_DEPS?
>>> What is its mission?
>> 
>> To control the target dependencies: the binary and test chunks. However,
>> it was required when *-tests targets were not .PHONY, and now it's more
>> for self-check that nothing global is broken.
> 
> OK, looks like we came to agreement offline so I just repeate this here:
> 
> * All test chunks are `.PHONY`, so all tests will rerun always,
>  even without test sources changing. That's why we need only build
>  dependencies here.
> * We are planing to make all test suites more consistent,
>  so TEST_DEPS will be removed from Tarantool's suite too later.
> 
>> 
>>> 
>>>> 
>>>>> 
>>>>>> 
>>>>>>> +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\;"
>>>>>>> +)
>>>>>> 
>>>>>> There is not a word regarding such complex LUA_PATH configuration.
>>>>> 
>>>>> Ok, it can be the one long string, but, in my opinion, this format is
>>>>> more readable, plus, as a bonus, with it line length is less than 120
>>>>> characters. I'll join these lines into one if you insist.
>>>> 
>>>> This is not the issue (and might be much better that my approach in
>>>> tarantool-tests and I will patch the test runners to make it conform to
>>>> one style later). I'm talking about the purpose for each entry. E.g. why
>>>> do you need both "./?.lua" and "${CMAKE_CURRENT_SOURCE_DIR}/?.lua"?  If
>>>> you need "${LUAJIT_SOURCE_DIR}/?.lua" for jit.* modules, then why it's
>>>> not required for other suites? Mention this explicitly, please.
>>> 
>>> Got it now, thanks!
>>> Looks like it really is not necessary. See the iterative patch below:
>>> Checked result in CI -- it is green, except known freebsd issue.
>>> 
>>> ===================================================================
>>> diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
>>> index b844788..fd5c8ce 100644
>>> --- a/test/lua-Harness-tests/CMakeLists.txt
>>> +++ b/test/lua-Harness-tests/CMakeLists.txt
>>> @@ -15,16 +15,7 @@ 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}\;"
>>> -)
>>> +set(LUA_PATH "./?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;")
>> 
>> Still not a word, why do you need both "./?.lua" and
>> "${CMAKE_CURRENT_SOURCE_DIR}/?.lua".
> 
> Sorry, add corresponding comment:
> ===================================================================
> diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
> index a639553..336dc03 100644
> --- a/test/lua-Harness-tests/CMakeLists.txt
> +++ b/test/lua-Harness-tests/CMakeLists.txt
> @@ -15,6 +15,9 @@ if(CMAKE_VERBOSE_MAKEFILE)
>   list(APPEND LUA_TEST_FLAGS --verbose)
> endif()
> 
> +# Tests create temporary files (see 303-package.t for example)
> +# to require. Also, they require some files from original
> +# test source directory.
> set(LUA_PATH "./?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;")
> 
> add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY})
> ===================================================================
> 
>> 
>>> 
>>> add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY})
>>> 
>>> @@ -33,7 +24,6 @@ add_custom_command(TARGET lua-Harness-tests
>>>   COMMAND
>>>   env
>>>     LUA_PATH="${LUA_PATH}\;"
>>> -    LUA_CPATH="${LUA_CPATH}\;"
>>>     # XXX: 309-os.t checks os.getenv() function by examining of
>>>     # USERNAME or LOGNAME environment variable.
>>>     # These variables might not be set in the environment, so
>>> ===================================================================
>>> 
>> 
>> <snipped>
>> 
>>> 
>>> -- 
>>> Best regards,
>>> Sergey Kaplun
>> 
>> -- 
>> Best regards,
>> IM
> 
> -- 
> Best regards,
> Sergey Kaplun


[-- Attachment #2: Type: text/html, Size: 32519 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT
  2021-03-15 21:27       ` Igor Munkin via Tarantool-patches
@ 2021-03-16 14:25         ` Sergey Ostanevich via Tarantool-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Sergey Ostanevich via Tarantool-patches @ 2021-03-16 14:25 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

[-- Attachment #1: Type: text/plain, Size: 4027 bytes --]

Hi!

Thanks for the patch and review!


> On 16 Mar 2021, at 00:27, Igor Munkin <imun@tarantool.org> wrote:
> 
> Sergey,
> 
> On 15.03.21, Sergey Kaplun wrote:
>> Igor,
>> 
>> Thanks for the review!
>> 
>> On 15.03.21, Igor Munkin wrote:
>>> Sergey,
>>> 
>>> Thanks for the patch!
>>> 
>>> This is why it's so important to take the suite intact at first: I
>>> didn't even notice these changes in the previous series and now I regret
>>> a bit regarding the solution with LUAJIT_TEST_INIT: for this case it
>>> occurs to be ugly a little. Nevertheless, I believe Francois would be
>>> interested in this use case, so it's worth to file a bug against
>>> lua-Harness, IMHO.
>> 
>> I don't think so -- usage [1] declares the way to launch the suite.
>> It is our problem, that we don't use it.
> 
> OK, I'll do it myself then.
> 
>> 
> 
> <snipped>
> 
>>>> diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
>>>> index 08a99b8..5ce95e6 100644
>>>> --- a/test/lua-Harness-tests/tap.lua
>>>> +++ b/test/lua-Harness-tests/tap.lua
>>>> @@ -195,6 +195,15 @@ function todo (reason, count)
>>>>     todo_reason = reason
>>>> end
>>>> 
>>>> +-- The last arg element is guaranteed name of tested binary.
>>> 
>>> Typo: s/last/least/.
>>> Typo: s/guaranteed name of tested/guaranteed to be the name of the tested/.
>> 
>> Thanks, update the branch. See the iterative patch below.
>> ===================================================================
>> diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
>> index 5ce95e6..e527687 100644
>> --- a/test/lua-Harness-tests/tap.lua
>> +++ b/test/lua-Harness-tests/tap.lua
>> @@ -195,7 +195,8 @@ function todo (reason, count)
>>     todo_reason = reason
>> end
>> 
>> --- The last arg element is guaranteed name of tested binary.
>> +-- The least arg element is guaranteed to be the name
>> +-- of the tested binary.
>> function get_lua_binary_name ()
>>     local i = 0
>>     while arg[i] do
>> ===================================================================
>> 
>>> 
>>>> +function get_lua_binary_name ()
>>>> +    local i = 0
>>>> +    while arg[i] do
>>> 
>>> You make an excess lookup to a _G for each iteration. It's better to
>>> pass <arg> as an argument to this function. Furthermore, it makes the
>>> signature clearer, so user knows you're using <arg> to detect the
>>> interpreter name.
>> 
>> This economy looks unnecessary -- there are only 6 calls to this
>> function from the whole suite. You can provide time measurement
>> to prove me wrong.
>> I disagreed that it makes signature clearer, because there is no way to
>> use something instead `arg` variable anyway. Please, give me an
>> example, when usage of custom array is preferable than usage `arg`
>> variable. If this function *always* uses `arg` variable only, why we
>> should move it outside this function?
> 
> I forgot to add "feel free to ignore" here. You can write the code you
> like and I can't make you to do it another way alone. For this purpose
> there are two reviewers. I'll postpone my LGTM a bit for this change.
> 
> Regarding "no way to use something instead arg": nobody can stop you
> from parsing shebang.
> 

I believe the comment to the get_lua_binary_name tells exactly how the
binary is detected. Other than that - you will need to access the arg 
outside the function, hence if the code is not in a trace you’ll have
to pass it on the stack, and if it is in a trace the optimizer will
CSE the arg access from within the function?

LGTM.

Sergos


>> 
>>> 
>>>> +        i = i - 1
>>>> +    end
>>>> +    return arg[i + 1]
>>>> +end
>>>> +
>>>> --
>>>> -- Copyright (c) 2009-2018 Francois Perrad
>>>> --
>>>> -- 
>>>> 2.28.0
>>>> 
>>> 
>>> -- 
>>> Best regards,
>>> IM
>> 
>> [1]: https://fperrad.frama.io/lua-Harness/usage/
>> 
>> -- 
>> Best regards,
>> Sergey Kaplun
> 
> -- 
> Best regards,
> IM


[-- Attachment #2: Type: text/html, Size: 19227 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool
  2021-03-16 10:51       ` Igor Munkin via Tarantool-patches
@ 2021-03-16 14:51         ` Sergey Ostanevich via Tarantool-patches
  2021-03-16 14:59         ` Sergey Kaplun via Tarantool-patches
  1 sibling, 0 replies; 30+ messages in thread
From: Sergey Ostanevich via Tarantool-patches @ 2021-03-16 14:51 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

[-- Attachment #1: Type: text/plain, Size: 8888 bytes --]

Hi!

Thanks for patch and review!

With all comments below fixed the patch is LGTM.

My proposal on dofile_fullpath() naming:
- split the functions, it’ll ease reading. Keep dofile() in the place of use, 
  wrap the name with additional function
- pick a name that echo what function does: delivers a filename relative to the
  test itself e.g. relative_to_test()
This results in

    dofile(relative_to_test('lexico53/boolean.t’))

regards,
Sergos


> On 16 Mar 2021, at 13:51, Igor Munkin <imun@tarantool.org> wrote:
> 
> Sergey,
>  
> On 16.03.21, Sergey Kaplun wrote:
>> Igor,
>> 
>> Thanks for the review!
>> 
>> On 15.03.21, Igor Munkin wrote:
>>> Sergey,
>>> 
>>> This is ridiculous: you split two similar renames required by the one
>>> issue into *two* separate commits, but leaving the changes *totally
>>> unrelated to each other* within a single commit. Please, split this
>>> patch into two: one for the test directory tweak and another with
>>> mocking environment variable in CMake.
>> 
>> Sorry, but why then you said nothing about commits separation/joining
>> for this [1] draft series, as I asked for?
> 
> I mentioned it here[1] and you decided to left everything intact (that's
> OK for me). This commit is a new one and you created it from two
> separate commits in the previous version. So it's just a new feedback
> for the new changes.
> 
>> 
>> Offline we came to the agreement that we should use 3 commits for each
>> test suite. The first to onboard it, the second to adjust for LuaJIT,
>> the third to adjust it for Tarantool.
> 
> I remember only 3 bullets on which we have explicitly agreed:
> * The suite should be taken intact in the first commit despite the fact
>  tests can be broken.
> * LuaJIT related changes should be separated from Tarantool related
>  ones to ease their further maintenance. Furthermore, every change
>  should be mentioned in our GitHub queue.
> * All tests should be run in a unified way via both LuaJIT and Tarantool
>  testing machinery. It means test chunk or test case is either run or
>  not despite the testing environment.
> 
> Regarding everything else I was open to discuss it on review, since it's
> too hard (at least for me) to consider all issues faced while adopting
> these suites and create the most unified way to handle them. I believe,
> this is the purpose of review process: to see what is done and think
> whether it can be done in a better way (better doesn't mean *you* made
> it wrong, but *we* chose a bad solution).
> 
>> Later your asked me to send Mergens changes as is.
>> 
>> I specially send draft to discuss the commits content, order and so on.
>> You said only about separating patchset for different test suites and
>> merged LuaJIT test suite, so I thought that commit order is OK for you.
>> I'd merged changes with Tarantool-related one.
> 
> I hope you remember that I've asked a couple of times to polish and send
> LuaJIT-test-cleanup patchset. The last time I was asking was right
> before you sent WIP series. LuaJIT related patches per se were ready to
> be merged; the only issue was disabling strict for it. Additionally I've
> adjusted tarantool-tests runner to use LUAJIT_TEST_COMMAND to make all
> tests be run by unified way.
> 
> Then I asked you to split two remaining suites into two series so I can
> look on them separately. Hence, I was OK with the general approach, but
> was afraid to miss some details.
> 
>> 
>> If it is not comfortable for you getting WIP series and discussing them
>> let's decline this practise.
> 
> I'm totally fine with WIP series: e.g. LUAJIT_TEST_INIT has been done
> after I've glanced all the patches with tests you've sent.
> 
>> 
>> Back to business, I've split the patch into two, considering your
>> proposal, see them below (their order is the same).
> 
> Nice, thanks a lot!
> 
>> 
> 
> <snipped>
> 
>> 
>> Patch for test directory tweak. Adjusted considering [2].
>> 
>> ===================================================================
>> commit a84980334dce27243a25508e3bb8fd491689e552
>> Author: Sergey Kaplun <skaplun@tarantool.org <mailto:skaplun@tarantool.org>>
>> Date:   Mon Mar 15 16:24:07 2021 +0300
>> 
>>    test: adjust lua-Harness tests that using dofile
>> 
>>    This patch makes out-of-source execution lua-Harness suite tests that
>>    using `dofile()` correct.
> 
> Minor: There are other tests using <dofile>, but they are fine. The root
> problem relates to the approach used in the patched tests: the .t files
> are kinda wrapper, containing the basic checks (or not, e.g. UTF-8 test
> chunk), and some specific checks are moved to the auxiliary chunks
> "dofiled" in .t script.
> 
>> 
>>    There are the following files that used `dofile()` function
>>    on file in test sources directory:
>>    * 101-boolean.t
>>    * 102-function.t
>>    * 103-nil.t
>>    * 104-number.t
>>    * 105-string.t
>>    * 106-table.t
>>    * 107-thread.t
>>    * 108-userdata.t
>>    * 203-lexico.t
>>    * 231-metatable.t
>>    * 301-basic.t
>>    * 305-utf8.t
>>    * 404-ext.t
>> 
>>    `dofile()` looks for files to execute in the current working directory,
>>    that might be not the same as the test source directory.
>> 
>>    This patch introduces the new function `dofile_fullpath()` that
> 
> What does "fullpath" mean? If this is absolute path, then naming is
> ambiguous; and I guess nothing stops one from using relative paths (but
> not symlink, I think) here. Furthermore, the naming doesn't represent
> the purpose: as I mentioned above this dofile is needed to implement
> specific checks, so you can adjust the naming to more verbose one:
> <test_more> or <make_specific_checks>. Thoughts?
> 
>>    evaluates full path to file considering arg[0] (i.e. test filename)
> 
> It's worth to check and mention the caveat with symlinks. If the issue
> exists, then the paths should be resolved in CMake the way similar to
> the one used for luacheck target.
> 
>>    value.
>> 
>>    Part of tarantool/tarantool#5844
>>    Part of tarantool/tarantool#4473
>> 
> 
> <snipped>
> 
>> ===================================================================
>> 
>> Patch for mocking environment variable in CMake.
>> 
>> ===================================================================
>> commit 483508b0a7863efabcde6d232ab9af2033e0011f
>> Author: Sergey Kaplun <skaplun@tarantool.org <mailto:skaplun@tarantool.org>>
>> Date:   Mon Mar 15 22:08:07 2021 +0300
>> 
>>    test: forcify set USERNAME env var for lua-Harness
> 
> Strictly saying, you do not force, but just set. Furthermore, I doubt
> about word formation you applied to "force".
> 
>> 
>>    309-os.t checks `os.getenv()` function by examining of
> 
> Typo: examine <smth>, not examine of <smth>[2].
> 
>>    USERNAME or LOGNAME environment variable.
>>    These variables might not be set in the environment, that leads to test
>>    failure.
>> 
>>    This patchs sets manually USERNAME environment variable for
> 
> Typo: s/manually/explicitly/.
> 
>>    lua-Harness-tests target.
>> 
>>    Part of tarantool/tarantool#5844
>>    Part of tarantool/tarantool#4473
>> 
>> diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
>> index f8611ce..b844788 100644
>> --- a/test/lua-Harness-tests/CMakeLists.txt
>> +++ b/test/lua-Harness-tests/CMakeLists.txt
>> @@ -34,6 +34,11 @@ add_custom_command(TARGET lua-Harness-tests
>>   env
>>     LUA_PATH="${LUA_PATH}\;"
>>     LUA_CPATH="${LUA_CPATH}\;"
>> +    # XXX: 309-os.t checks os.getenv() function by examining of
> 
> Typo: examine <smth>, not examine of <smth>[2].
> 
>> +    # USERNAME or LOGNAME environment variable.
>> +    # These variables might not be set in the environment, so
>> +    # set one of them manually.
>> +    USERNAME="fperrad"
>>     ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
>>       --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
>>       ${LUA_TEST_FLAGS}
>> ===================================================================
>> 
>> [1]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022563.html
>> [2]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022710.html
>> 
>> -- 
>> Best regards,
>> Sergey Kaplun
> 
> [1]: https://lists.tarantool.org/tarantool-patches/16E39C08-397B-4A38-953A-B9EB85CD9C8B@tarantool.org/T/#m9de07af72e06ac22b7540741b9e1c4ac485688bb <https://lists.tarantool.org/tarantool-patches/16E39C08-397B-4A38-953A-B9EB85CD9C8B@tarantool.org/T/#m9de07af72e06ac22b7540741b9e1c4ac485688bb>
> [2]: https://dictionary.cambridge.org/dictionary/english/examine <https://dictionary.cambridge.org/dictionary/english/examine>
> 
> -- 
> Best regards,
> IM


[-- Attachment #2: Type: text/html, Size: 72450 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 4/5] test: disable 241-standalone of lua-Harness suite
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 4/5] test: disable 241-standalone of lua-Harness suite Sergey Kaplun via Tarantool-patches
@ 2021-03-16 14:51   ` Sergey Ostanevich via Tarantool-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Sergey Ostanevich via Tarantool-patches @ 2021-03-16 14:51 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

LGTM.

> On 15 Mar 2021, at 18:29, Sergey Kaplun <skaplun@tarantool.org> wrote:
> 
> This patch disables 241-standalone.t from the lua-Harness test suite,
> because some flags in Tarantool and LuaJIT work differently, or they are
> not present at all in Tarantool. For example, -i, -b, -j.
> See tarantool/tarantool#5541.
> 
> Part of tarantool/tarantool#5844
> Part of tarantool/tarantool#4473
> ---
> .../{241-standalone.t => 241-standalone.t.disabled}               | 0
> 1 file changed, 0 insertions(+), 0 deletions(-)
> rename test/lua-Harness-tests/{241-standalone.t => 241-standalone.t.disabled} (100%)
> 
> diff --git a/test/lua-Harness-tests/241-standalone.t b/test/lua-Harness-tests/241-standalone.t.disabled
> similarity index 100%
> rename from test/lua-Harness-tests/241-standalone.t
> rename to test/lua-Harness-tests/241-standalone.t.disabled
> -- 
> 2.28.0
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 5/5] test: disable 411-luajit of lua-Harness suite
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 5/5] test: disable 411-luajit " Sergey Kaplun via Tarantool-patches
@ 2021-03-16 14:52   ` Sergey Ostanevich via Tarantool-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Sergey Ostanevich via Tarantool-patches @ 2021-03-16 14:52 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

LGTM.

> On 15 Mar 2021, at 18:29, Sergey Kaplun <skaplun@tarantool.org> wrote:
> 
> This patch disables 411-luajit.t from the lua-Harness test suite,
> because Tarantool does not support -b and -j flags.
> See tarantool/tarantool#5541.
> 
> Part of tarantool/tarantool#5844
> Part of tarantool/tarantool#4473
> ---
> test/lua-Harness-tests/{411-luajit.t => 411-luajit.t.disabled} | 0
> 1 file changed, 0 insertions(+), 0 deletions(-)
> rename test/lua-Harness-tests/{411-luajit.t => 411-luajit.t.disabled} (100%)
> 
> diff --git a/test/lua-Harness-tests/411-luajit.t b/test/lua-Harness-tests/411-luajit.t.disabled
> similarity index 100%
> rename from test/lua-Harness-tests/411-luajit.t
> rename to test/lua-Harness-tests/411-luajit.t.disabled
> -- 
> 2.28.0
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool
  2021-03-16 10:51       ` Igor Munkin via Tarantool-patches
  2021-03-16 14:51         ` Sergey Ostanevich via Tarantool-patches
@ 2021-03-16 14:59         ` Sergey Kaplun via Tarantool-patches
  1 sibling, 0 replies; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-16 14:59 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

On 16.03.21, Igor Munkin wrote:
> Sergey,
> 
> On 16.03.21, Sergey Kaplun wrote:
> > Igor,
> > 
> > Thanks for the review!
> > 
> > On 15.03.21, Igor Munkin wrote:
> > > Sergey,
> > > 

OK, thanks for clarification!

<snipped>

> > 
> > Patch for test directory tweak. Adjusted considering [2].
> > 
> > ===================================================================
> > commit a84980334dce27243a25508e3bb8fd491689e552
> > Author: Sergey Kaplun <skaplun@tarantool.org>
> > Date:   Mon Mar 15 16:24:07 2021 +0300
> > 
> >     test: adjust lua-Harness tests that using dofile
> > 
> >     This patch makes out-of-source execution lua-Harness suite tests that
> >     using `dofile()` correct.
> 
> Minor: There are other tests using <dofile>, but they are fine. The root
> problem relates to the approach used in the patched tests: the .t files
> are kinda wrapper, containing the basic checks (or not, e.g. UTF-8 test
> chunk), and some specific checks are moved to the auxiliary chunks
> "dofiled" in .t script.

Reformulate like the following:

| This patch makes out-of-source execution lua-Harness suite tests that
| using `dofile()` for specific checks mentioned in corresponding
| *.t files correct.

> 
> > 
> >     There are the following files that used `dofile()` function
> >     on file in test sources directory:
> >     * 101-boolean.t
> >     * 102-function.t
> >     * 103-nil.t
> >     * 104-number.t
> >     * 105-string.t
> >     * 106-table.t
> >     * 107-thread.t
> >     * 108-userdata.t
> >     * 203-lexico.t
> >     * 231-metatable.t
> >     * 301-basic.t
> >     * 305-utf8.t
> >     * 404-ext.t
> > 
> >     `dofile()` looks for files to execute in the current working directory,
> >     that might be not the same as the test source directory.
> > 
> >     This patch introduces the new function `dofile_fullpath()` that
> 
> What does "fullpath" mean? If this is absolute path, then naming is
> ambiguous; and I guess nothing stops one from using relative paths (but
> not symlink, I think) here. Furthermore, the naming doesn't represent
> the purpose: as I mentioned above this dofile is needed to implement
> specific checks, so you can adjust the naming to more verbose one:
> <test_more> or <make_specific_checks>. Thoughts?

`make_specific_checks()` is good for me. See the iterative patch below:

===================================================================
diff --git a/test/lua-Harness-tests/101-boolean.t b/test/lua-Harness-tests/101-boolean.t
index b9a769f..c26b276 100755
--- a/test/lua-Harness-tests/101-boolean.t
+++ b/test/lua-Harness-tests/101-boolean.t
@@ -114,7 +114,7 @@ error_like(function () local a = true; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile_fullpath'lexico53/boolean.t'
+    make_specific_checks'lexico53/boolean.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/102-function.t b/test/lua-Harness-tests/102-function.t
index 2858640..c49afc5 100755
--- a/test/lua-Harness-tests/102-function.t
+++ b/test/lua-Harness-tests/102-function.t
@@ -193,7 +193,7 @@ t[print] = true
 ok(t[print])
 
 if has_op53 then
-    dofile_fullpath'lexico53/function.t'
+    make_specific_checks'lexico53/function.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/103-nil.t b/test/lua-Harness-tests/103-nil.t
index 1e7c134..87a1c3b 100755
--- a/test/lua-Harness-tests/103-nil.t
+++ b/test/lua-Harness-tests/103-nil.t
@@ -114,7 +114,7 @@ error_like(function () local a = nil; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile_fullpath'lexico53/nil.t'
+    make_specific_checks'lexico53/nil.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/104-number.t b/test/lua-Harness-tests/104-number.t
index affd1a4..f5b81e3 100755
--- a/test/lua-Harness-tests/104-number.t
+++ b/test/lua-Harness-tests/104-number.t
@@ -233,7 +233,7 @@ error_like(function () local a = 3.14; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile_fullpath'lexico53/number.t'
+    make_specific_checks'lexico53/number.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/105-string.t b/test/lua-Harness-tests/105-string.t
index f571520..184deab 100755
--- a/test/lua-Harness-tests/105-string.t
+++ b/test/lua-Harness-tests/105-string.t
@@ -264,7 +264,7 @@ error_like(function () a = 'text'; a[1] = 1; end,
            "index")
 
 if has_op53 then
-    dofile_fullpath'lexico53/string.t'
+    make_specific_checks'lexico53/string.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/106-table.t b/test/lua-Harness-tests/106-table.t
index b1a1027..667b9c8 100755
--- a/test/lua-Harness-tests/106-table.t
+++ b/test/lua-Harness-tests/106-table.t
@@ -122,7 +122,7 @@ error_like(function () t = {}; t[0/0] = 42 end,
            "table index is NaN")
 
 if has_op53 then
-    dofile_fullpath'lexico53/table.t'
+    make_specific_checks'lexico53/table.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/107-thread.t b/test/lua-Harness-tests/107-thread.t
index 2f332d7..5c5bf22 100755
--- a/test/lua-Harness-tests/107-thread.t
+++ b/test/lua-Harness-tests/107-thread.t
@@ -122,7 +122,7 @@ t[co] = true
 ok(t[co])
 
 if has_op53 then
-    dofile_fullpath'lexico53/thread.t'
+    make_specific_checks'lexico53/thread.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/108-userdata.t b/test/lua-Harness-tests/108-userdata.t
index cc4134b..48a5f60 100755
--- a/test/lua-Harness-tests/108-userdata.t
+++ b/test/lua-Harness-tests/108-userdata.t
@@ -119,7 +119,7 @@ t[u] = true
 ok(t[u])
 
 if has_op53 then
-    dofile_fullpath'lexico53/userdata.t'
+    make_specific_checks'lexico53/userdata.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/203-lexico.t b/test/lua-Harness-tests/203-lexico.t
index e5e89ed..a4f06a3 100755
--- a/test/lua-Harness-tests/203-lexico.t
+++ b/test/lua-Harness-tests/203-lexico.t
@@ -118,19 +118,19 @@ do
 end
 
 if _VERSION >= 'Lua 5.2' or jit then
-    dofile_fullpath('lexico52/lexico.t')
+    make_specific_checks('lexico52/lexico.t')
 end
 
 if _VERSION >= 'Lua 5.3' or luajit21 then
-    dofile_fullpath('lexico53/lexico.t')
+    make_specific_checks('lexico53/lexico.t')
 end
 
 if _VERSION >= 'Lua 5.4' then
-    dofile_fullpath('lexico54/lexico.t')
+    make_specific_checks('lexico54/lexico.t')
 end
 
 if jit and pcall(require, 'ffi') then
-    dofile_fullpath('lexicojit/lexico.t')
+    make_specific_checks('lexicojit/lexico.t')
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/231-metatable.t b/test/lua-Harness-tests/231-metatable.t
index c5684d2..97ac542 100755
--- a/test/lua-Harness-tests/231-metatable.t
+++ b/test/lua-Harness-tests/231-metatable.t
@@ -589,7 +589,7 @@ do
 end
 
 if has_anno_toclose then
-    dofile_fullpath'lexico54/metatable.t'
+    make_specific_checks'lexico54/metatable.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/301-basic.t b/test/lua-Harness-tests/301-basic.t
index 460a02f..f92d744 100755
--- a/test/lua-Harness-tests/301-basic.t
+++ b/test/lua-Harness-tests/301-basic.t
@@ -843,7 +843,7 @@ do -- xpcall
 end
 
 if jit and pcall(require, 'ffi') then
-    dofile_fullpath('lexicojit/basic.t')
+    make_specific_checks('lexicojit/basic.t')
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/305-utf8.t b/test/lua-Harness-tests/305-utf8.t
index 18c57d8..6c12538 100755
--- a/test/lua-Harness-tests/305-utf8.t
+++ b/test/lua-Harness-tests/305-utf8.t
@@ -40,9 +40,9 @@ if not utf8 then
     nok(has_utf8, "no has_utf8")
 else
     plan'no_plan'
-    dofile_fullpath'lexico53/utf8.t'
+    make_specific_checks'lexico53/utf8.t'
     if _VERSION >= 'Lua 5.4' then
-        dofile_fullpath'lexico54/utf8.t'
+        make_specific_checks'lexico54/utf8.t'
     end
     done_testing()
 end
diff --git a/test/lua-Harness-tests/404-ext.t b/test/lua-Harness-tests/404-ext.t
index e48d91a..a799c75 100755
--- a/test/lua-Harness-tests/404-ext.t
+++ b/test/lua-Harness-tests/404-ext.t
@@ -158,7 +158,7 @@ end
 
 -- thread.exdata
 if pcall(require, 'ffi') and (profile.openresty or jit.version:match'moonjit') then
-    dofile_fullpath'lexicojit/ext.t'
+    make_specific_checks'lexicojit/ext.t'
 end
 
 done_testing()
diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua
index 37b9df7..a8454ae 100644
--- a/test/lua-Harness-tests/tap.lua
+++ b/test/lua-Harness-tests/tap.lua
@@ -209,7 +209,7 @@ end
 -- relative paths below become invalid. Hence, we need to
 -- prepend the directory from the script (i.e. test) name to
 -- the auxiliary files to be loaded and executed.
-function dofile_fullpath (filename)
+function make_specific_checks (filename)
     return dofile(arg[0]:gsub('([^/]+)%.t$', '') .. filename)
 end
 
===================================================================

> 
> >     evaluates full path to file considering arg[0] (i.e. test filename)
> 
> It's worth to check and mention the caveat with symlinks. If the issue
> exists, then the paths should be resolved in CMake the way similar to
> the one used for luacheck target.

Looks like all is fine:

| $ pwd
| /home/burii/builds_workspace/luajit/gh-5844-adapt-lua-harness-test-suite
| $ rm -rf third_party/luajit/
| $ cd third_party/
| $ ln -s $HOME/builds_workspace/luajit/gh-5844-adapt-lua-harness-test-suite/ ~/builds_workspace/tarantool/gh-5844-adapt-lua-harness-test-suite/third_party/luajit
| $ cd ../build/
| $ cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_BACKTRACE=ON .. && make -j && make LuaJIT-test
| <snipped>
| All tests successful.

> 
> >     value.
> > 
> >     Part of tarantool/tarantool#5844
> >     Part of tarantool/tarantool#4473
> > 
> 
> <snipped>
> 
> > ===================================================================
> > 
> > Patch for mocking environment variable in CMake.
> > 
> > ===================================================================
> > commit 483508b0a7863efabcde6d232ab9af2033e0011f
> > Author: Sergey Kaplun <skaplun@tarantool.org>
> > Date:   Mon Mar 15 22:08:07 2021 +0300
> > 
> >     test: forcify set USERNAME env var for lua-Harness
> 
> Strictly saying, you do not force, but just set. Furthermore, I doubt
> about word formation you applied to "force".

Removed confusing "forcify". See the whole patch below.

> 
> > 
> >     309-os.t checks `os.getenv()` function by examining of
> 
> Typo: examine <smth>, not examine of <smth>[2].

Fixed.

> 
> >     USERNAME or LOGNAME environment variable.
> >     These variables might not be set in the environment, that leads to test
> >     failure.
> > 
> >     This patchs sets manually USERNAME environment variable for
> 
> Typo: s/manually/explicitly/.

Fixed.

> 
> >     lua-Harness-tests target.
> > 
> >     Part of tarantool/tarantool#5844
> >     Part of tarantool/tarantool#4473
> > 
> > diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
> > index f8611ce..b844788 100644
> > --- a/test/lua-Harness-tests/CMakeLists.txt
> > +++ b/test/lua-Harness-tests/CMakeLists.txt
> > @@ -34,6 +34,11 @@ add_custom_command(TARGET lua-Harness-tests
> >    env
> >      LUA_PATH="${LUA_PATH}\;"
> >      LUA_CPATH="${LUA_CPATH}\;"
> > +    # XXX: 309-os.t checks os.getenv() function by examining of
> 
> Typo: examine <smth>, not examine of <smth>[2].

Fixed. See the full commit below:

===================================================================
commit 6f42397be1bd1a4d96a639d92da658180f270091 (HEAD)
Author: Sergey Kaplun <skaplun@tarantool.org>
Date:   Mon Mar 15 22:08:07 2021 +0300

    test: set USERNAME env var for lua-Harness

    309-os.t checks `os.getenv()` function by examining
    USERNAME or LOGNAME environment variable.
    These variables might not be set in the environment, that leads to test
    failure.

    This patchs sets explicitly USERNAME environment variable for
    lua-Harness-tests target.

    Part of tarantool/tarantool#5844
    Part of tarantool/tarantool#4473

diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt
index 336dc03..1061c79 100644
--- a/test/lua-Harness-tests/CMakeLists.txt
+++ b/test/lua-Harness-tests/CMakeLists.txt
@@ -27,6 +27,11 @@ add_custom_command(TARGET lua-Harness-tests
   COMMAND
   env
     LUA_PATH="${LUA_PATH}\;"
+    # XXX: 309-os.t checks os.getenv() function by examining
+    # USERNAME or LOGNAME environment variable.
+    # These variables might not be set in the environment, so
+    # set one of them manually.
+    USERNAME="fperrad"
     ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
       --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
       ${LUA_TEST_FLAGS}
===================================================================

> 
> > +    # USERNAME or LOGNAME environment variable.
> > +    # These variables might not be set in the environment, so
> > +    # set one of them manually.
> > +    USERNAME="fperrad"
> >      ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR}
> >        --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21'
> >        ${LUA_TEST_FLAGS}
> > ===================================================================
> > 
> > [1]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022563.html
> > [2]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022710.html
> > 
> > -- 
> > Best regards,
> > Sergey Kaplun
> 
> [1]: https://lists.tarantool.org/tarantool-patches/16E39C08-397B-4A38-953A-B9EB85CD9C8B@tarantool.org/T/#m9de07af72e06ac22b7540741b9e1c4ac485688bb
> [2]: https://dictionary.cambridge.org/dictionary/english/examine
> 
> -- 
> Best regards,
> IM

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite
  2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
                   ` (4 preceding siblings ...)
  2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 5/5] test: disable 411-luajit " Sergey Kaplun via Tarantool-patches
@ 2021-03-17  0:46 ` Igor Munkin via Tarantool-patches
  2021-03-17  7:32   ` Sergey Kaplun via Tarantool-patches
  2021-03-17 16:49 ` Igor Munkin via Tarantool-patches
  6 siblings, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-17  0:46 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

Thanks for the series! I've looked onto the updated version on your
branch and it is almost cool! I've polished it a bit: commit message,
typos, etc -- you can see the changes on my branch[1] (CI is green[2]).
If you're OK with them, I'll push the changeset to the trunk.

Speaking about the changes in Tarantool, I almost OK with them except
the test/luajit-test-init.lua. Consider the comments below.

================================================================================

diff --git a/cmake/luajit.cmake b/cmake/luajit.cmake
index 1c05e085b..3d37164e8 100644
--- a/cmake/luajit.cmake
+++ b/cmake/luajit.cmake
@@ -40,16 +40,19 @@ set(LUAJIT_TEST_BINARY $<TARGET_FILE:tarantool> CACHE STRING
 set(LUAJIT_USE_TEST OFF CACHE BOOL
     "Generate <test> target" FORCE)
 
-# Enable internal LuaJIT assertions for Tarantool Debug build.
 # XXX: There is <strict> module enabled by default in Tarantool
 # built in Debug, so we need to tweak LuaJIT testing environment.
+# XXX: Also, this script "unloads" internal Tarantool's modules
+# and remove globals conflicting with LuaJIT test suites.
+set(LUAJIT_TEST_INIT "${PROJECT_SOURCE_DIR}/test/luajit-test-init.lua"
+    CACHE STRING "Lua code need to be run before tests are started" FORCE)
+
+# Enable internal LuaJIT assertions for Tarantool Debug build.
 if(CMAKE_BUILD_TYPE STREQUAL "Debug")
     set(LUAJIT_USE_APICHECK ON CACHE BOOL
         "Assertions for the Lua/C API" FORCE)
     set(LUAJIT_USE_ASSERT ON CACHE BOOL
         "Assertions for the whole LuaJIT VM" FORCE)
-    set(LUAJIT_TEST_INIT "${PROJECT_SOURCE_DIR}/test/luajit-test-init.lua"
-        CACHE STRING "Lua code need to be run before tests are started" FORCE)
 endif()
 
 # Valgrind can be used only with the system allocator. For more
diff --git a/test/luajit-test-init.lua b/test/luajit-test-init.lua
index bc4af9748..d3f637156 100644
--- a/test/luajit-test-init.lua
+++ b/test/luajit-test-init.lua
@@ -1,2 +1,16 @@
 -- Disable strict for Tarantool.
 require("strict").off()
+
+-- XXX: lua-Harness test suite uses it's own tap.lua module
+-- that conflicts with the Tarantool's one.
+package.loaded.tap = nil
+-- XXX: lua-Harness test suite checks that utf8 module presents
+-- only in Lua5.3 or moonjit.
+utf8 = nil
+
+-- Add `strict.off()` to `progname` command, that runs child tests

# If only strict.off is required for child processes, please mention why
# others are not.

+-- in some LuaJIT test suites to disable strict there too.
+-- Quotes type is important.
+-- XXX: luacheck thinks that `arg` is read-only global variable.
+-- luacheck: no global
+arg[-1] = arg[-1]..' -e "require[[strict]].off()"'

# Please, mention how Tarantool parses CLI arguments and why arg[-1]
# contains the binary name despite the given flags.

# Furthermore, you can get the file path via `debug.getinfo(1).source`,
# so you can reassemble LUAJIT_TEST_COMMAND. However, if this is
# unnecessary, then nevermind.

================================================================================

On 15.03.21, Sergey Kaplun wrote:
> In this patchset lua-Harness test suite is adapted for the LuaJIT fork
> and Tarantool.
> 
> Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> Tarantool's branch for tests:
> https://github.com/tarantool/tarantool/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> Issues:
> * https://github.com/tarantool/tarantool/issues/5844
> * https://github.com/tarantool/tarantool/issues/5473
> 
> Changes in v2:
> * glanced commit message for the first patch
> * dropped module renaming
> * separate suite introduction and adjustment
> * dropped unnecessary commits with disabled tests
> 
> Mergen Imeev (1):
>   test: add lua-Harness test suite
> 
> Sergey Kaplun (4):
>   test: adjust lua-Harness suite for LuaJIT
>   test: adjust lua-Harness test suite for Tarantool
>   test: disable 241-standalone of lua-Harness suite
>   test: disable 411-luajit of lua-Harness suite
> 

<snipped>

> 
> -- 
> 2.28.0

[1]: https://github.com/tarantool/luajit/tree/imun/gh-5844-adapt-lua-harness-test-suite
[2]: https://github.com/tarantool/tarantool/tree/imun/gh-5844-adapt-lua-harness-test-suite

> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite
  2021-03-17  0:46 ` [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Igor Munkin via Tarantool-patches
@ 2021-03-17  7:32   ` Sergey Kaplun via Tarantool-patches
  2021-03-17 10:27     ` Igor Munkin via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-17  7:32 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

Thanks for the review!

On 17.03.21, Igor Munkin wrote:
> Sergey,
> 
> Thanks for the series! I've looked onto the updated version on your
> branch and it is almost cool! I've polished it a bit: commit message,
> typos, etc -- you can see the changes on my branch[1] (CI is green[2]).
> If you're OK with them, I'll push the changeset to the trunk.

LGTM.
What's about Sergos'es naming proposal here [1]?

> 
> Speaking about the changes in Tarantool, I almost OK with them except
> the test/luajit-test-init.lua. Consider the comments below.

Sorry, I don't get how exactly to consider them, so I answer your
questions here. If it necessary I'll push them to the branch (yours or
mine).

> 
> ================================================================================
> 
> diff --git a/cmake/luajit.cmake b/cmake/luajit.cmake
> index 1c05e085b..3d37164e8 100644
> --- a/cmake/luajit.cmake
> +++ b/cmake/luajit.cmake

<snipped>

> diff --git a/test/luajit-test-init.lua b/test/luajit-test-init.lua
> index bc4af9748..d3f637156 100644
> --- a/test/luajit-test-init.lua
> +++ b/test/luajit-test-init.lua
> @@ -1,2 +1,16 @@
>  -- Disable strict for Tarantool.
>  require("strict").off()
> +
> +-- XXX: lua-Harness test suite uses it's own tap.lua module
> +-- that conflicts with the Tarantool's one.
> +package.loaded.tap = nil
> +-- XXX: lua-Harness test suite checks that utf8 module presents
> +-- only in Lua5.3 or moonjit.
> +utf8 = nil
> +
> +-- Add `strict.off()` to `progname` command, that runs child tests
> 
> # If only strict.off is required for child processes, please mention why
> # others are not.

Other changes are required only for parent process, looks obviously
as far as they are not added.

> 
> +-- in some LuaJIT test suites to disable strict there too.
> +-- Quotes type is important.
> +-- XXX: luacheck thinks that `arg` is read-only global variable.
> +-- luacheck: no global
> +arg[-1] = arg[-1]..' -e "require[[strict]].off()"'
> 
> # Please, mention how Tarantool parses CLI arguments and why arg[-1]
> # contains the binary name despite the given flags.

Tarantool stores the script name at index 0 in arg variable and
interpreter name at index -1, ignoring other CLI arguments between them.

> 
> # Furthermore, you can get the file path via `debug.getinfo(1).source`,
> # so you can reassemble LUAJIT_TEST_COMMAND. However, if this is
> # unnecessary, then nevermind.

Looks unnecessary and not such easy to configure, ignoring for now.

> 
> ================================================================================
> 
> On 15.03.21, Sergey Kaplun wrote:
> > In this patchset lua-Harness test suite is adapted for the LuaJIT fork
> > and Tarantool.
> > 
> > Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> > Tarantool's branch for tests:
> > https://github.com/tarantool/tarantool/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> > Issues:
> > * https://github.com/tarantool/tarantool/issues/5844
> > * https://github.com/tarantool/tarantool/issues/5473
> > 
> > Changes in v2:
> > * glanced commit message for the first patch
> > * dropped module renaming
> > * separate suite introduction and adjustment
> > * dropped unnecessary commits with disabled tests
> > 
> > Mergen Imeev (1):
> >   test: add lua-Harness test suite
> > 
> > Sergey Kaplun (4):
> >   test: adjust lua-Harness suite for LuaJIT
> >   test: adjust lua-Harness test suite for Tarantool
> >   test: disable 241-standalone of lua-Harness suite
> >   test: disable 411-luajit of lua-Harness suite
> > 
> 
> <snipped>
> 
> > 
> > -- 
> > 2.28.0
> 
> [1]: https://github.com/tarantool/luajit/tree/imun/gh-5844-adapt-lua-harness-test-suite
> [2]: https://github.com/tarantool/tarantool/tree/imun/gh-5844-adapt-lua-harness-test-suite
> 
> > 
> 
> -- 
> Best regards,
> IM

[1]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022733.html

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite
  2021-03-17  7:32   ` Sergey Kaplun via Tarantool-patches
@ 2021-03-17 10:27     ` Igor Munkin via Tarantool-patches
  2021-03-17 10:31       ` Sergey Kaplun via Tarantool-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-17 10:27 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

On 17.03.21, Sergey Kaplun wrote:
> Igor,
> 
> Thanks for the review!
> 
> On 17.03.21, Igor Munkin wrote:
> > Sergey,
> > 
> > Thanks for the series! I've looked onto the updated version on your
> > branch and it is almost cool! I've polished it a bit: commit message,
> > typos, etc -- you can see the changes on my branch[1] (CI is green[2]).
> > If you're OK with them, I'll push the changeset to the trunk.
> 
> LGTM.
> What's about Sergos'es naming proposal here [1]?

Discussed offline: Sergos is OK with the current solution.

> 
> > 
> > Speaking about the changes in Tarantool, I almost OK with them except
> > the test/luajit-test-init.lua. Consider the comments below.
> 
> Sorry, I don't get how exactly to consider them, so I answer your
> questions here. If it necessary I'll push them to the branch (yours or
> mine).

Good, thanks! Considering your answers, I've polished the commit in
Tarantool repo. See the patch below:

================================================================================

From 2fa0e10e45f799419c341befba745286273d0c08 Mon Sep 17 00:00:00 2001
Message-Id: <2fa0e10e45f799419c341befba745286273d0c08.1615976372.git.imun@tarantool.org>
From: Sergey Kaplun <skaplun@tarantool.org>
Date: Thu, 11 Mar 2021 12:00:44 +0300
Subject: [PATCH] luajit: bump new version

LuaJIT submodule is bumped to introduce the following changes:
* test: disable 411-luajit of lua-Harness suite
* test: disable 241-standalone of lua-Harness suite
* test: set USERNAME env var for lua-Harness suite
* test: adjust lua-Harness tests that use dofile
* test: adjust lua-Harness suite to CMake machinery
* test: add lua-Harness test suite

Within this changeset lua-Harness suite[1] is added to Tarantool
testing. Considering Tarantool specific changes in runtime the suite
itself is adjusted in LuaJIT submodule.

However, Tarantool provides and unconditionally loads TAP module
conflicting with the one used in the new suite. Hence, the Tarantool
built-in module is "unloaded" in test/luajit-test-init.lua.

Furthermore, Tarantool provides UTF-8 support via another built-in
module. Its interfaces differ from the ones implemented in Lua5.3 and
moonjit. At the same time our LuaJIT fork provides no UTF-8 support, so
lua-Harness UTF-8 detector is simply confused with non-nil utf8 global
variable. As a result, utf8 is set to nil in test/luajit-test-init.lua.

There are also some tests launching Lua interpreter, so strict need to
be disabled for their child tests too. Hence `strict.off()` is added to
`progname` (i.e. arg[-1] considering the way Tarantool parses its CLI
arguments)  command used in these tests.

[1]: https://framagit.org/fperrad/lua-Harness/tree/a74be27/test_lua

Closes #5844
Part of #4473

Reviewed-by: Sergey Ostanevich <sergos@tarantool.org>
Reviewed-by: Igor Munkin <imun@tarantool.org>
---
 cmake/luajit.cmake        |  9 ++++++---
 test/luajit-test-init.lua | 22 ++++++++++++++++++++++
 third_party/luajit        |  2 +-
 3 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/cmake/luajit.cmake b/cmake/luajit.cmake
index 1c05e085b..3d37164e8 100644
--- a/cmake/luajit.cmake
+++ b/cmake/luajit.cmake
@@ -40,16 +40,19 @@ set(LUAJIT_TEST_BINARY $<TARGET_FILE:tarantool> CACHE STRING
 set(LUAJIT_USE_TEST OFF CACHE BOOL
     "Generate <test> target" FORCE)
 
-# Enable internal LuaJIT assertions for Tarantool Debug build.
 # XXX: There is <strict> module enabled by default in Tarantool
 # built in Debug, so we need to tweak LuaJIT testing environment.
+# XXX: Also, this script "unloads" internal Tarantool's modules
+# and remove globals conflicting with LuaJIT test suites.
+set(LUAJIT_TEST_INIT "${PROJECT_SOURCE_DIR}/test/luajit-test-init.lua"
+    CACHE STRING "Lua code need to be run before tests are started" FORCE)
+
+# Enable internal LuaJIT assertions for Tarantool Debug build.
 if(CMAKE_BUILD_TYPE STREQUAL "Debug")
     set(LUAJIT_USE_APICHECK ON CACHE BOOL
         "Assertions for the Lua/C API" FORCE)
     set(LUAJIT_USE_ASSERT ON CACHE BOOL
         "Assertions for the whole LuaJIT VM" FORCE)
-    set(LUAJIT_TEST_INIT "${PROJECT_SOURCE_DIR}/test/luajit-test-init.lua"
-        CACHE STRING "Lua code need to be run before tests are started" FORCE)
 endif()
 
 # Valgrind can be used only with the system allocator. For more
diff --git a/test/luajit-test-init.lua b/test/luajit-test-init.lua
index bc4af9748..6d9b058eb 100644
--- a/test/luajit-test-init.lua
+++ b/test/luajit-test-init.lua
@@ -1,2 +1,24 @@
 -- Disable strict for Tarantool.
 require("strict").off()
+
+-- XXX: lua-Harness test suite uses it's own tap.lua module
+-- that conflicts with the Tarantool's one.
+package.loaded.tap = nil
+-- XXX: lua-Harness test suite checks that utf8 module presents
+-- only in Lua5.3 or moonjit.
+utf8 = nil
+
+-- There are some tests launching Lua interpreter, so strict need
+-- to be disabled for the child tests too. Hence `strict.off()` is
+-- added to `progname` command used in these tests.
+-- Unlike LuaJIT, Tarantool doesn't store the given CLI flags in
+-- `arg`, so the table has the following layout:
+-- * arg[-1] -- the binary name
+-- * arg[0]  -- the script name
+-- * arg[N]  -- the script argument for all N in [1, #arg]
+-- The former one can be used to adjust the command to be used in
+-- child tests.
+-- XXX: Quotes types are important.
+-- XXX: luacheck thinks that `arg` is read-only global variable.
+-- luacheck: no global
+arg[-1] = arg[-1]..' -e "require[[strict]].off()"'
diff --git a/third_party/luajit b/third_party/luajit
index 75e6e90dd..eefe18886 160000
--- a/third_party/luajit
+++ b/third_party/luajit
@@ -1 +1 @@
-Subproject commit 75e6e90ddfbebbb5ff36d99afc1becf9e53249d6
+Subproject commit eefe18886813ab0872471588f02b277eb370d25d
-- 
2.25.0

================================================================================

Furthermore, I've squashed two last commits in LuaJIT repo into one.
Here is the patch:

================================================================================

From eefe18886813ab0872471588f02b277eb370d25d Mon Sep 17 00:00:00 2001
Message-Id: <eefe18886813ab0872471588f02b277eb370d25d.1615976764.git.imun@tarantool.org>
From: Sergey Kaplun <skaplun@tarantool.org>
Date: Tue, 2 Mar 2021 18:15:37 +0300
Subject: [PATCH] test: disable LuaJIT CLI tests in lua-Harness suite

This patch disables 241-standalone.t and 411-luajit.t from lua-Harness
test suite, because some flags in LuaJIT and Tarantool work differently,
or they are not supported in Tarantool at all. For example, -i, -b, -j.
See tarantool/tarantool#5541.

Resolves tarantool/tarantool#5844
Part of tarantool/tarantool#4473

Reviewed-by: Sergey Ostanevich <sergos@tarantool.org>
Reviewed-by: Igor Munkin <imun@tarantool.org>
---
 .../{241-standalone.t => 241-standalone.t.disabled}               | 0
 test/lua-Harness-tests/{411-luajit.t => 411-luajit.t.disabled}    | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename test/lua-Harness-tests/{241-standalone.t => 241-standalone.t.disabled} (100%)
 rename test/lua-Harness-tests/{411-luajit.t => 411-luajit.t.disabled} (100%)

diff --git a/test/lua-Harness-tests/241-standalone.t b/test/lua-Harness-tests/241-standalone.t.disabled
similarity index 100%
rename from test/lua-Harness-tests/241-standalone.t
rename to test/lua-Harness-tests/241-standalone.t.disabled
diff --git a/test/lua-Harness-tests/411-luajit.t b/test/lua-Harness-tests/411-luajit.t.disabled
similarity index 100%
rename from test/lua-Harness-tests/411-luajit.t
rename to test/lua-Harness-tests/411-luajit.t.disabled
-- 
2.25.0


================================================================================

If you're OK with everything above, I'll push the series to the trunk.

> 

<snipped>

> > 
> > On 15.03.21, Sergey Kaplun wrote:
> > > In this patchset lua-Harness test suite is adapted for the LuaJIT fork
> > > and Tarantool.
> > > 
> > > Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> > > Tarantool's branch for tests:
> > > https://github.com/tarantool/tarantool/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> > > Issues:
> > > * https://github.com/tarantool/tarantool/issues/5844
> > > * https://github.com/tarantool/tarantool/issues/5473
> > > 
> > > Changes in v2:
> > > * glanced commit message for the first patch
> > > * dropped module renaming
> > > * separate suite introduction and adjustment
> > > * dropped unnecessary commits with disabled tests
> > > 
> > > Mergen Imeev (1):
> > >   test: add lua-Harness test suite
> > > 
> > > Sergey Kaplun (4):
> > >   test: adjust lua-Harness suite for LuaJIT
> > >   test: adjust lua-Harness test suite for Tarantool
> > >   test: disable 241-standalone of lua-Harness suite
> > >   test: disable 411-luajit of lua-Harness suite
> > > 
> > 
> > <snipped>
> > 
> > > 
> > > -- 
> > > 2.28.0
> > 
> > [1]: https://github.com/tarantool/luajit/tree/imun/gh-5844-adapt-lua-harness-test-suite
> > [2]: https://github.com/tarantool/tarantool/tree/imun/gh-5844-adapt-lua-harness-test-suite
> > 
> > > 
> > 
> > -- 
> > Best regards,
> > IM
> 
> [1]: https://lists.tarantool.org/pipermail/tarantool-patches/2021-March/022733.html
> 
> -- 
> Best regards,
> Sergey Kaplun

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite
  2021-03-17 10:27     ` Igor Munkin via Tarantool-patches
@ 2021-03-17 10:31       ` Sergey Kaplun via Tarantool-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-17 10:31 UTC (permalink / raw)
  To: Igor Munkin; +Cc: tarantool-patches

Igor,

LGTM.

-- 
Best regards,
Sergey Kaplun

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite
  2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
                   ` (5 preceding siblings ...)
  2021-03-17  0:46 ` [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Igor Munkin via Tarantool-patches
@ 2021-03-17 16:49 ` Igor Munkin via Tarantool-patches
  6 siblings, 0 replies; 30+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2021-03-17 16:49 UTC (permalink / raw)
  To: Sergey Kaplun; +Cc: tarantool-patches

Sergey,

I've checked the series into all long-term branches in tarantool/luajit
and bumped a new version in 1.10, 2.6, 2.7 and master.

On 15.03.21, Sergey Kaplun wrote:
> In this patchset lua-Harness test suite is adapted for the LuaJIT fork
> and Tarantool.
> 
> Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> Tarantool's branch for tests:
> https://github.com/tarantool/tarantool/tree/skaplun/gh-5844-adapt-lua-harness-test-suite
> Issues:
> * https://github.com/tarantool/tarantool/issues/5844
> * https://github.com/tarantool/tarantool/issues/5473
> 
> Changes in v2:
> * glanced commit message for the first patch
> * dropped module renaming
> * separate suite introduction and adjustment
> * dropped unnecessary commits with disabled tests
> 
> Mergen Imeev (1):
>   test: add lua-Harness test suite
> 
> Sergey Kaplun (4):
>   test: adjust lua-Harness suite for LuaJIT
>   test: adjust lua-Harness test suite for Tarantool
>   test: disable 241-standalone of lua-Harness suite
>   test: disable 411-luajit of lua-Harness suite
> 

<snipped>

> 
> -- 
> 2.28.0
> 

-- 
Best regards,
IM

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2021-03-17 16:49 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-15 15:29 [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Sergey Kaplun via Tarantool-patches
2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 1/5] test: add " Sergey Kaplun via Tarantool-patches
2021-03-15 17:37   ` Igor Munkin via Tarantool-patches
2021-03-15 18:10     ` Sergey Kaplun via Tarantool-patches
2021-03-15 21:06       ` Igor Munkin via Tarantool-patches
2021-03-16  9:38         ` Sergey Kaplun via Tarantool-patches
2021-03-16 11:08           ` Igor Munkin via Tarantool-patches
2021-03-16 12:02             ` Sergey Kaplun via Tarantool-patches
2021-03-16 13:50               ` Sergey Ostanevich via Tarantool-patches
2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 2/5] test: adjust lua-Harness suite for LuaJIT Sergey Kaplun via Tarantool-patches
2021-03-15 17:39   ` Igor Munkin via Tarantool-patches
2021-03-15 18:33     ` Sergey Kaplun via Tarantool-patches
2021-03-15 21:27       ` Igor Munkin via Tarantool-patches
2021-03-16 14:25         ` Sergey Ostanevich via Tarantool-patches
2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 3/5] test: adjust lua-Harness test suite for Tarantool Sergey Kaplun via Tarantool-patches
2021-03-15 17:44   ` Igor Munkin via Tarantool-patches
2021-03-16  6:01     ` Sergey Kaplun via Tarantool-patches
2021-03-16 10:51       ` Igor Munkin via Tarantool-patches
2021-03-16 14:51         ` Sergey Ostanevich via Tarantool-patches
2021-03-16 14:59         ` Sergey Kaplun via Tarantool-patches
2021-03-15 19:12   ` Igor Munkin via Tarantool-patches
2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 4/5] test: disable 241-standalone of lua-Harness suite Sergey Kaplun via Tarantool-patches
2021-03-16 14:51   ` Sergey Ostanevich via Tarantool-patches
2021-03-15 15:29 ` [Tarantool-patches] [PATCH v2 luajit 5/5] test: disable 411-luajit " Sergey Kaplun via Tarantool-patches
2021-03-16 14:52   ` Sergey Ostanevich via Tarantool-patches
2021-03-17  0:46 ` [Tarantool-patches] [PATCH v2 luajit 0/5] Adapt lua-Harness test suite Igor Munkin via Tarantool-patches
2021-03-17  7:32   ` Sergey Kaplun via Tarantool-patches
2021-03-17 10:27     ` Igor Munkin via Tarantool-patches
2021-03-17 10:31       ` Sergey Kaplun via Tarantool-patches
2021-03-17 16:49 ` Igor Munkin via Tarantool-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox