From: Sergey Kaplun via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: Sergey Ostanevich <sergos@tarantool.org>, Igor Munkin <imun@tarantool.org> Cc: tarantool-patches@dev.tarantool.org Subject: [Tarantool-patches] [PATCH luajit 1/6] test: add lua-Harness test suite Date: Fri, 12 Mar 2021 08:27:29 +0300 [thread overview] Message-ID: <639a4804ee9c20ac3b8cd58540c612d0bcf693ad.1615470667.git.skaplun@tarantool.org> (raw) In-Reply-To: <cover.1615470667.git.skaplun@tarantool.org> This patch adds lua-Harness test suite: https://fperrad.frama.io/lua-Harness/ For lua binary name detection the new function `get_lua_binary_name()` is introduced. It is necessary because LUAJIT_TEST_COMMAND always extends an amount of line argument by two and a new universal way to detect program name is required. Some tests may fail after this commit. They will be disabled or adapted in the next patches. Part of tarantool/tarantool#5844 Part of tarantool/tarantool#4473 --- Author: Mergen Imeev <imeevma@gmail.com> .luacheckrc | 1 + test/CMakeLists.txt | 4 +- test/lua-Harness-tests/000-sanity.t | 54 ++ test/lua-Harness-tests/001-if.t | 88 ++ test/lua-Harness-tests/002-table.t | 67 ++ test/lua-Harness-tests/011-while.t | 89 ++ test/lua-Harness-tests/012-repeat.t | 85 ++ test/lua-Harness-tests/014-fornum.t | 151 +++ test/lua-Harness-tests/015-forlist.t | 111 +++ test/lua-Harness-tests/090-tap.t | 37 + test/lua-Harness-tests/091-profile.t | 45 + test/lua-Harness-tests/101-boolean.t | 127 +++ test/lua-Harness-tests/102-function.t | 206 +++++ test/lua-Harness-tests/103-nil.t | 127 +++ test/lua-Harness-tests/104-number.t | 246 +++++ test/lua-Harness-tests/105-string.t | 277 ++++++ test/lua-Harness-tests/106-table.t | 135 +++ test/lua-Harness-tests/107-thread.t | 135 +++ test/lua-Harness-tests/108-userdata.t | 132 +++ test/lua-Harness-tests/200-examples.t | 104 +++ test/lua-Harness-tests/201-assign.t | 150 +++ test/lua-Harness-tests/202-expr.t | 157 ++++ test/lua-Harness-tests/203-lexico.t | 143 +++ test/lua-Harness-tests/204-grammar.t | 233 +++++ test/lua-Harness-tests/211-scope.t | 86 ++ test/lua-Harness-tests/212-function.t | 288 ++++++ test/lua-Harness-tests/213-closure.t | 98 ++ test/lua-Harness-tests/214-coroutine.t | 244 +++++ test/lua-Harness-tests/221-table.t | 120 +++ test/lua-Harness-tests/222-constructor.t | 119 +++ test/lua-Harness-tests/223-iterator.t | 203 +++++ test/lua-Harness-tests/231-metatable.t | 602 ++++++++++++ test/lua-Harness-tests/232-object.t | 314 +++++++ test/lua-Harness-tests/241-standalone.t | 269 ++++++ test/lua-Harness-tests/242-luac.t | 341 +++++++ test/lua-Harness-tests/301-basic.t | 856 ++++++++++++++++++ test/lua-Harness-tests/303-package.t | 290 ++++++ test/lua-Harness-tests/304-string.t | 633 +++++++++++++ test/lua-Harness-tests/305-utf8.t | 55 ++ test/lua-Harness-tests/306-table.t | 372 ++++++++ test/lua-Harness-tests/307-math.t | 375 ++++++++ test/lua-Harness-tests/308-io.t | 397 ++++++++ test/lua-Harness-tests/309-os.t | 271 ++++++ test/lua-Harness-tests/310-debug.t | 322 +++++++ test/lua-Harness-tests/311-bit32.t | 127 +++ test/lua-Harness-tests/314-regex.t | 222 +++++ test/lua-Harness-tests/320-stdin.t | 133 +++ test/lua-Harness-tests/401-bitop.t | 106 +++ test/lua-Harness-tests/402-ffi.t | 142 +++ test/lua-Harness-tests/403-jit.t | 163 ++++ test/lua-Harness-tests/404-ext.t | 171 ++++ test/lua-Harness-tests/411-luajit.t | 211 +++++ test/lua-Harness-tests/CMakeLists.txt | 49 + test/lua-Harness-tests/lexico52/lexico.t | 45 + test/lua-Harness-tests/lexico53/boolean.t | 43 + test/lua-Harness-tests/lexico53/function.t | 66 ++ test/lua-Harness-tests/lexico53/lexico.t | 30 + test/lua-Harness-tests/lexico53/nil.t | 43 + test/lua-Harness-tests/lexico53/number.t | 181 ++++ test/lua-Harness-tests/lexico53/string.t | 169 ++++ test/lua-Harness-tests/lexico53/table.t | 43 + test/lua-Harness-tests/lexico53/thread.t | 45 + test/lua-Harness-tests/lexico53/userdata.t | 45 + test/lua-Harness-tests/lexico53/utf8.t | 179 ++++ test/lua-Harness-tests/lexico54/lexico.t | 19 + test/lua-Harness-tests/lexico54/metatable.t | 38 + test/lua-Harness-tests/lexico54/utf8.t | 54 ++ test/lua-Harness-tests/lexicojit/basic.t | 27 + test/lua-Harness-tests/lexicojit/ext.t | 52 ++ test/lua-Harness-tests/lexicojit/lexico.t | 32 + test/lua-Harness-tests/profile.lua | 53 ++ test/lua-Harness-tests/profile_lua51.lua | 46 + .../profile_lua51_strict.lua | 46 + test/lua-Harness-tests/profile_lua52.lua | 46 + .../profile_lua52_strict.lua | 46 + test/lua-Harness-tests/profile_lua53.lua | 52 ++ .../profile_lua53_noconv.lua | 55 ++ .../profile_lua53_strict.lua | 52 ++ test/lua-Harness-tests/profile_lua54.lua | 52 ++ .../profile_lua54_noconv.lua | 55 ++ .../profile_lua54_strict.lua | 53 ++ test/lua-Harness-tests/profile_luajit20.lua | 53 ++ .../profile_luajit20_compat52.lua | 53 ++ test/lua-Harness-tests/profile_luajit21.lua | 53 ++ .../profile_luajit21_compat52.lua | 53 ++ test/lua-Harness-tests/profile_openresty.lua | 53 ++ test/lua-Harness-tests/profile_ravi.lua | 58 ++ test/lua-Harness-tests/profile_tiny_fork.lua | 60 ++ test/lua-Harness-tests/rx_captures | 13 + test/lua-Harness-tests/rx_charclass | 38 + test/lua-Harness-tests/rx_metachars | 117 +++ test/lua-Harness-tests/tap.lua | 212 +++++ 92 files changed, 12912 insertions(+), 1 deletion(-) create mode 100755 test/lua-Harness-tests/000-sanity.t create mode 100755 test/lua-Harness-tests/001-if.t create mode 100755 test/lua-Harness-tests/002-table.t create mode 100755 test/lua-Harness-tests/011-while.t create mode 100755 test/lua-Harness-tests/012-repeat.t create mode 100755 test/lua-Harness-tests/014-fornum.t create mode 100755 test/lua-Harness-tests/015-forlist.t create mode 100755 test/lua-Harness-tests/090-tap.t create mode 100755 test/lua-Harness-tests/091-profile.t create mode 100755 test/lua-Harness-tests/101-boolean.t create mode 100755 test/lua-Harness-tests/102-function.t create mode 100755 test/lua-Harness-tests/103-nil.t create mode 100755 test/lua-Harness-tests/104-number.t create mode 100755 test/lua-Harness-tests/105-string.t create mode 100755 test/lua-Harness-tests/106-table.t create mode 100755 test/lua-Harness-tests/107-thread.t create mode 100755 test/lua-Harness-tests/108-userdata.t create mode 100755 test/lua-Harness-tests/200-examples.t create mode 100755 test/lua-Harness-tests/201-assign.t create mode 100755 test/lua-Harness-tests/202-expr.t create mode 100755 test/lua-Harness-tests/203-lexico.t create mode 100755 test/lua-Harness-tests/204-grammar.t create mode 100755 test/lua-Harness-tests/211-scope.t create mode 100755 test/lua-Harness-tests/212-function.t create mode 100755 test/lua-Harness-tests/213-closure.t create mode 100755 test/lua-Harness-tests/214-coroutine.t create mode 100755 test/lua-Harness-tests/221-table.t create mode 100755 test/lua-Harness-tests/222-constructor.t create mode 100755 test/lua-Harness-tests/223-iterator.t create mode 100755 test/lua-Harness-tests/231-metatable.t create mode 100755 test/lua-Harness-tests/232-object.t create mode 100755 test/lua-Harness-tests/241-standalone.t create mode 100755 test/lua-Harness-tests/242-luac.t create mode 100755 test/lua-Harness-tests/301-basic.t create mode 100755 test/lua-Harness-tests/303-package.t create mode 100755 test/lua-Harness-tests/304-string.t create mode 100755 test/lua-Harness-tests/305-utf8.t create mode 100755 test/lua-Harness-tests/306-table.t create mode 100755 test/lua-Harness-tests/307-math.t create mode 100755 test/lua-Harness-tests/308-io.t create mode 100755 test/lua-Harness-tests/309-os.t create mode 100755 test/lua-Harness-tests/310-debug.t create mode 100755 test/lua-Harness-tests/311-bit32.t create mode 100755 test/lua-Harness-tests/314-regex.t create mode 100755 test/lua-Harness-tests/320-stdin.t create mode 100755 test/lua-Harness-tests/401-bitop.t create mode 100755 test/lua-Harness-tests/402-ffi.t create mode 100755 test/lua-Harness-tests/403-jit.t create mode 100755 test/lua-Harness-tests/404-ext.t create mode 100755 test/lua-Harness-tests/411-luajit.t create mode 100644 test/lua-Harness-tests/CMakeLists.txt create mode 100644 test/lua-Harness-tests/lexico52/lexico.t create mode 100644 test/lua-Harness-tests/lexico53/boolean.t create mode 100644 test/lua-Harness-tests/lexico53/function.t create mode 100644 test/lua-Harness-tests/lexico53/lexico.t create mode 100644 test/lua-Harness-tests/lexico53/nil.t create mode 100644 test/lua-Harness-tests/lexico53/number.t create mode 100644 test/lua-Harness-tests/lexico53/string.t create mode 100644 test/lua-Harness-tests/lexico53/table.t create mode 100644 test/lua-Harness-tests/lexico53/thread.t create mode 100644 test/lua-Harness-tests/lexico53/userdata.t create mode 100644 test/lua-Harness-tests/lexico53/utf8.t create mode 100644 test/lua-Harness-tests/lexico54/lexico.t create mode 100644 test/lua-Harness-tests/lexico54/metatable.t create mode 100644 test/lua-Harness-tests/lexico54/utf8.t create mode 100644 test/lua-Harness-tests/lexicojit/basic.t create mode 100644 test/lua-Harness-tests/lexicojit/ext.t create mode 100644 test/lua-Harness-tests/lexicojit/lexico.t create mode 100644 test/lua-Harness-tests/profile.lua create mode 100644 test/lua-Harness-tests/profile_lua51.lua create mode 100644 test/lua-Harness-tests/profile_lua51_strict.lua create mode 100644 test/lua-Harness-tests/profile_lua52.lua create mode 100644 test/lua-Harness-tests/profile_lua52_strict.lua create mode 100644 test/lua-Harness-tests/profile_lua53.lua create mode 100644 test/lua-Harness-tests/profile_lua53_noconv.lua create mode 100644 test/lua-Harness-tests/profile_lua53_strict.lua create mode 100644 test/lua-Harness-tests/profile_lua54.lua create mode 100644 test/lua-Harness-tests/profile_lua54_noconv.lua create mode 100644 test/lua-Harness-tests/profile_lua54_strict.lua create mode 100644 test/lua-Harness-tests/profile_luajit20.lua create mode 100644 test/lua-Harness-tests/profile_luajit20_compat52.lua create mode 100644 test/lua-Harness-tests/profile_luajit21.lua create mode 100644 test/lua-Harness-tests/profile_luajit21_compat52.lua create mode 100644 test/lua-Harness-tests/profile_openresty.lua create mode 100644 test/lua-Harness-tests/profile_ravi.lua create mode 100644 test/lua-Harness-tests/profile_tiny_fork.lua create mode 100644 test/lua-Harness-tests/rx_captures create mode 100644 test/lua-Harness-tests/rx_charclass create mode 100644 test/lua-Harness-tests/rx_metachars create mode 100644 test/lua-Harness-tests/tap.lua diff --git a/.luacheckrc b/.luacheckrc index 1a76108..a5f90b9 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -8,5 +8,6 @@ read_globals = { 'misc' } exclude_files = { 'dynasm/', 'src/', + 'test/lua-Harness-tests/', 'test/LuaJIT-tests/', } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 99471db..3a42f41 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -43,10 +43,12 @@ endif() set(LUAJIT_TEST_COMMAND "${LUAJIT_TEST_BINARY} -e dofile[[${LUAJIT_TEST_INIT}]]") separate_arguments(LUAJIT_TEST_COMMAND) -add_subdirectory(tarantool-tests) +add_subdirectory(lua-Harness-tests) add_subdirectory(LuaJIT-tests) +add_subdirectory(tarantool-tests) add_custom_target(${PROJECT_NAME}-test DEPENDS + lua-Harness-tests LuaJIT-tests tarantool-tests ) diff --git a/test/lua-Harness-tests/000-sanity.t b/test/lua-Harness-tests/000-sanity.t new file mode 100755 index 0000000..e039153 --- /dev/null +++ b/test/lua-Harness-tests/000-sanity.t @@ -0,0 +1,54 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua test suite + +=head2 Synopsis + + % prove 000-sanity.t + +=head2 Description + +=cut + +]] + +function f (n) + return n + 1 +end + +function g (m, p) + return m + p +end + +print('1..9') +print("ok 1 -") +print('ok', 2, "- list") +print("ok " .. tostring(3) .. " - concatenation") +i = 4 +print("ok " .. tostring(i) .. " - var") +i = i + 1 +print("ok " .. tostring(i) .. " - var incr") +print("ok " .. tostring(i+1) .. " - expr") +j = f(i + 1) +print("ok " .. tostring(j) .. " - call f") +k = g(i, 3) +print("ok " .. tostring(k) .. " - call g") +local print = print +print("ok 9 - local") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/001-if.t b/test/lua-Harness-tests/001-if.t new file mode 100755 index 0000000..b84e331 --- /dev/null +++ b/test/lua-Harness-tests/001-if.t @@ -0,0 +1,88 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua if statement + +=head2 Synopsis + + % prove 001-if.t + +=head2 Description + +See section "Control Structures" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.4.4>, +L<https://www.lua.org/manual/5.2/manual.html#3.3.4>, +L<https://www.lua.org/manual/5.3/manual.html#3.3.4>, +L<https://www.lua.org/manual/5.4/manual.html#3.3.4> + +=cut + +]] + +print("1..6") + +if true then + print("ok 1") +else + print("not ok 1") +end + +if not true then + print("not ok 2") +else + print("ok 2") +end + +a = 12 +b = 34 +if a < b then + print("ok 3") +else + print("not ok 3") +end + +a = 0 +b = 4 +if a < b then + print("ok 4") +elseif a == b then + print("not ok 4") +else + print("not ok 4") +end + +a = 5 +b = 5 +if a < b then + print("not ok 5") +elseif a == b then + print("ok 5") +else + print("not ok 5") +end + +a = 10 +b = 6 +if a < b then + print("not ok 6") +elseif a == b then + print("not ok 6") +else + print("ok 6") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/002-table.t b/test/lua-Harness-tests/002-table.t new file mode 100755 index 0000000..b84afd6 --- /dev/null +++ b/test/lua-Harness-tests/002-table.t @@ -0,0 +1,67 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua table + +=head2 Synopsis + + % prove 002-table.t + +=head2 Description + +See section "Tables" in "Programming in Lua". + +=cut + +]] + +print("1..8") + +a = {"ok 1", "ok 2", "ok 3"} +print(a[1]) +i = 2 +print(a[i]) +print(a[i+1]) +if #a == 3 then + print("ok 4 - len") +else + print("not ok 4") +end +if a[7] == nil then + print("ok 5") +else + print("not ok 5") +end + +t = {a=10, b=100} +if t['a'] == 10 then + print("ok 6") +else + print("not ok 6") +end +if t.b == 100 then + print("ok 7") +else + print("not ok 7") +end +if t.z == nil then + print("ok 8") +else + print("not ok 8") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/011-while.t b/test/lua-Harness-tests/011-while.t new file mode 100755 index 0000000..8ba4c6b --- /dev/null +++ b/test/lua-Harness-tests/011-while.t @@ -0,0 +1,89 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua while statement + +=head2 Synopsis + + % prove 011-while.t + +=head2 Description + +See section "Control Structures" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.4.4>, +L<https://www.lua.org/manual/5.2/manual.html#3.3.4>, +L<https://www.lua.org/manual/5.3/manual.html#3.3.4>, +L<https://www.lua.org/manual/5.4/manual.html#3.3.4> + +=cut + +]] + +print("1..11") + +do + local a = {} + local i = 1 + while a[i] do + i = i + 1 + end + if i == 1 then + print("ok 1 - while empty") + else + print("not ok 1 - " .. i) + end +end + +do + local a = {"ok 2 - while ", "ok 3", "ok 4"} + local i = 1 + while a[i] do + print(a[i]) + i = i + 1 + end +end + +do + local a = {"ok 5 - with break", "ok 6", "stop", "more"} + local i = 1 + while a[i] do + if a[i] == 'stop' then break end + print(a[i]) + i = i + 1 + end + if i == 3 then + print("ok 7 - break") + else + print("not ok 7 - " .. i) + end +end + +do + local x = 3 + local i = 1 + while i<=x do + print("ok " .. tostring(7+i)) + i = i + 1 + end + if i == 4 then + print("ok 11") + else + print("not ok 11 - " .. tostring(i)) + end +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/012-repeat.t b/test/lua-Harness-tests/012-repeat.t new file mode 100755 index 0000000..527db63 --- /dev/null +++ b/test/lua-Harness-tests/012-repeat.t @@ -0,0 +1,85 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua repeat statement + +=head2 Synopsis + + % prove 012-repeat.t + +=head2 Description + +See section "Control Structures" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.4.4>, +L<https://www.lua.org/manual/5.2/manual.html#3.3.4>, +L<https://www.lua.org/manual/5.3/manual.html#3.3.4>, +L<https://www.lua.org/manual/5.4/manual.html#3.3.4> + +=cut + +]] + +print("1..8") + +do + local a = {"ok 1 - repeat", "ok 2", "ok 3"} + local i = 0 + repeat + i = i + 1 + if a[i] then + print(a[i]) + end + until not a[i] + if i == 4 then + print("ok 4") + else + print("not ok 4 - " .. i) + end +end + +do + local a = {"ok 5 - with break", "ok 6", 'stop', 'more'} + local i = 0 + repeat + i = i + 1 + if a[i] == 'stop' then break end + print(a[i]) + until not a[i] + if a[i] == 'stop' then + print("ok 7 - break") + else + print("not ok 7 - " .. a[i]) + end +end + +do + local function f () return true end + + local i = 1 + repeat + local v = f() + if i == 1 then + print("ok 8 - scope") + else + print("not ok") + break + end + i = i + 1 + until v +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/014-fornum.t b/test/lua-Harness-tests/014-fornum.t new file mode 100755 index 0000000..3f6d1b1 --- /dev/null +++ b/test/lua-Harness-tests/014-fornum.t @@ -0,0 +1,151 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua for statement + +=head2 Synopsis + + % prove 014-fornum.t + +=head2 Description + +See section "For Statement" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.4.5>, +L<https://www.lua.org/manual/5.2/manual.html#3.3.5>, +L<https://www.lua.org/manual/5.3/manual.html#3.3.5>, +L<https://www.lua.org/manual/5.4/manual.html#3.3.5> + +=cut + +--]] + +print("1..36") + +for i = 1.0, 3.0, 0.5 do + print("ok " .. tostring(2*i-1) .. " - for 1.0, 3.0, 0.5") +end + +for i = 1.0, 3.0, 0.5 do + local function f () + print("ok " .. tostring(2*i+4) .. " - for 1.0, 3.0, 0.5 lex") + end + f() +end + +local function f (i) + print("ok " .. tostring(2*i+9) .. " - for 1.0, 3.0, 0.5 !lex") +end +for i = 1.0, 3.0, 0.5 do + f(i) +end + +for i = 3, 5 do + print("ok " .. tostring(13+i) .. " - for 3, 5") + i = i + 1 +end + +for i = 5, 1, -1 do + print("ok " .. tostring(24-i) .. " - for 5, 1, -1") +end + +for i = 5, 5 do + print("ok " .. tostring(19+i) .. " - for 5, 5") +end + +for i = 5, 5, -1 do + print("ok " .. tostring(20+i) .. " - for 5, 5, -1") +end + +do + local v = false + for i = 5, 3 do + v = true + end + if v then + print("not ok 26 - for 5, 3") + else + print("ok 26 - for 5, 3") + end +end + +do + local v = false + for i = 5, 7, -1 do + v = true + end + if v then + print("not ok 27 - for 5, 7, -1") + else + print("ok 27 - for 5, 7, -1") + end +end + +do + local v = false + if _VERSION <= 'Lua 5.3' then + for i = 5, 7, 0 do + v = true + break -- avoid infinite loop with LuaJIT + end + end + if jit then + print("not ok 28 - for 5, 7, 0 # TODO # LuaJIT intentional.") + elseif v then + print("not ok 28 - for 5, 7, 0") + else + print("ok 28 - for 5, 7, 0") + end +end + +do + local v = nil + for i = 1, 10, 2 do + if i > 4 then break end + print("ok " .. tostring((i+57)/2) .. " - for break") + v = i + end + if v == 3 then + print("ok 31 - break") + else + print("not ok 31 - " .. v) + end +end + +do + local function first() return 1 end + local function limit() return 8 end + local function step() return 2 end + for i = first(), limit(), step() do + print("ok " .. tostring((i+63)/2) .. " - with functions") + end +end + +do + local a = {} + for i = 1, 10 do + a[i] = function () return i end + end + local v = a[5]() + if v == 5 then + print("ok 36 - for & upval") + else + print("not ok 36 - for & upval") + print("#", v) + end +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/015-forlist.t b/test/lua-Harness-tests/015-forlist.t new file mode 100755 index 0000000..cd9db61 --- /dev/null +++ b/test/lua-Harness-tests/015-forlist.t @@ -0,0 +1,111 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua for statement + +=head2 Synopsis + + % prove 015-forlist.t + +=head2 Description + +See section "For Statement" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.4.5>, +L<https://www.lua.org/manual/5.2/manual.html#3.3.5>, +L<https://www.lua.org/manual/5.3/manual.html#3.3.5>, +L<https://www.lua.org/manual/5.4/manual.html#3.3.5> + +=cut + +--]] + +print("1..18") + +do + local a = {"ok 1 - for ipairs", "ok 2 - for ipairs", "ok 3 - for ipairs"} + + for _, v in ipairs(a) do + print(v) + end + + for i, v in ipairs(a) do + print("ok " .. tostring(3+i) .. " - for ipairs") + end + + for k in pairs(a) do + print("ok " .. tostring(6+k) .. " - for pairs") + end +end + +do + local r = false + local t = {a=10, b=100} + + for i, v in ipairs(t) do + print(i, v) + r = true + end + if r then + print("not ok 10 - for ipairs (hash)") + else + print("ok 10 - for ipairs (hash)") + end + + local i = 1 + for k in pairs(t) do + if k == 'a' or k == 'b' then + print("ok " .. tostring(10+i) .. " - for pairs (hash)") + else + print("not ok " .. tostring(10+i) .. " - " .. k) + end + i = i + 1 + end +end + +do + local a = {"ok 13 - for break", "ok 14 - for break", "stop", "more"} + local i + for _, v in ipairs(a) do + if v == "stop" then break end + print(v) + i = _ + end + if i == 2 then + print("ok 15 - break") + else + print("not ok 15 - " .. i) + end +end + +do + local a = {"ok 16 - for & upval", "ok 17 - for & upval", "ok 18 - for & upval"} + local b = {} + for i, v in ipairs(a) do + b[i] = function () return v end + end + for i, v in ipairs(a) do + local r = b[i]() + if r == a[i] then + print(r) + else + print("not " .. a[i]) + print("#", r) + end + end +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/090-tap.t b/test/lua-Harness-tests/090-tap.t new file mode 100755 index 0000000..92f04d8 --- /dev/null +++ b/test/lua-Harness-tests/090-tap.t @@ -0,0 +1,37 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua test suite + +=head2 Synopsis + + % prove 090-tap.t + +=head2 Description + +=cut + +]] + +require'tap' + +plan(3) +ok( true, 'ok' ) +is( 42, 42, '42 == 42' ) +pass( 'pass' ) + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/091-profile.t b/test/lua-Harness-tests/091-profile.t new file mode 100755 index 0000000..db47438 --- /dev/null +++ b/test/lua-Harness-tests/091-profile.t @@ -0,0 +1,45 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua test suite + +=head2 Synopsis + + % prove 091-profile.t + +=head2 Description + +=cut + +]] + +require'tap' + +plan'no_plan' + +type_ok(_VERSION, 'string', "variable _VERSION") +like(_VERSION, '^Lua 5%.%d$') + +if jit then + type_ok(jit.version_num, 'number', "variable jit.version_num") +end + +local profile = require_ok'profile' + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/101-boolean.t b/test/lua-Harness-tests/101-boolean.t new file mode 100755 index 0000000..0033eff --- /dev/null +++ b/test/lua-Harness-tests/101-boolean.t @@ -0,0 +1,127 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua boolean & coercion + +=head2 Synopsis + + % prove 101-boolean.t + +=head2 Description + +=cut + +]] + +require'tap' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +error_like(function () return -true end, + "^[^:]+:%d+: attempt to perform arithmetic on a %w+ value", + "-true") + +error_like(function () return #true end, + "^[^:]+:%d+: attempt to get length of a boolean value", + "#true") + +is(not false, true, "not false") + +error_like(function () return true + 10 end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "true + 10") + +error_like(function () return true - 2 end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "true - 2") + +error_like(function () return true * 3.14 end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "true * 3.14") + +error_like(function () return true / -7 end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "true / -7") + +error_like(function () return true % 4 end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "true % 4") + +error_like(function () return true ^ 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "true ^ 3") + +error_like(function () return true .. 'end' end, + "^[^:]+:%d+: attempt to concatenate a boolean value", + "true .. 'end'") + +is(true == true, true, "true == true") + +is(true ~= false, true, "true ~= false") + +is(true == 1, false, "true == 1") + +is(true ~= 1, true, "true ~= 1") + +error_like(function () return true < false end, + "^[^:]+:%d+: attempt to compare two boolean values", + "true < false") + +error_like(function () return true <= false end, + "^[^:]+:%d+: attempt to compare two boolean values", + "true <= false") + +error_like(function () return true > false end, + "^[^:]+:%d+: attempt to compare two boolean values", + "true > false") + +error_like(function () return true >= false end, + "^[^:]+:%d+: attempt to compare two boolean values", + "true >= false") + +error_like(function () return true < 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "true < 0") + +error_like(function () return true <= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "true <= 0") + +error_like(function () return true > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "true > 0") + +error_like(function () return true >= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "true >= 0") + +error_like(function () local a = true; local b = a[1]; end, + "^[^:]+:%d+: attempt to index", + "index") + +error_like(function () local a = true; a[1] = 1; end, + "^[^:]+:%d+: attempt to index", + "index") + +if has_op53 then + dofile'lexico53/boolean.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/102-function.t b/test/lua-Harness-tests/102-function.t new file mode 100755 index 0000000..48ed814 --- /dev/null +++ b/test/lua-Harness-tests/102-function.t @@ -0,0 +1,206 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua function & coercion + +=head2 Synopsis + + % prove 102-function.t + +=head2 Description + +=cut + +--]] + +require'tap' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +local f = function () return 1 end + +error_like(function () return -f end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "-f") + +error_like(function () f = print; return -f end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return #f end, + "^[^:]+:%d+: attempt to get length of", + "#f") + +error_like(function () f = print; return #f end, + "^[^:]+:%d+: attempt to get length of") + +is(not f, false, "not f") + +is(not print, false) + +error_like(function () return f + 10 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "f + 10") + +error_like(function () f = print; return f + 10 end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return f - 2 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "f - 2") + +error_like(function () f = print; return f - 2 end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return f * 3.14 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "f * 3.14") + +error_like(function () f = print; return f * 3.14 end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return f / -7 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "f / -7") + +error_like(function () f = print; return f / -7 end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return f % 4 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "f % 4") + +error_like(function () f = print; return f % 4 end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return f ^ 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "f ^ 3") + +error_like(function () f = print; return f ^ 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return f .. 'end' end, + "^[^:]+:%d+: attempt to concatenate", + "f .. 'end'") + +error_like(function () f = print; return f .. 'end' end, + "^[^:]+:%d+: attempt to concatenate") + +local g = f +is(f == g, true, "f == f") + +g = print +is(g == print, true) + +g = function () return 2 end +is(f ~= g, true, "f ~= g") +local h = type +is(f ~= h, true) + +is(print ~= g, true) +is(print ~= h, true) + +is(f == 1, false, "f == 1") + +is(print == 1, false) + +is(f ~= 1, true, "f ~= 1") + +is(print ~= 1, true) + +error_like(function () return f < g end, + "^[^:]+:%d+: attempt to compare two function values", + "f < g") + +error_like(function () f = print; g = type; return f < g end, + "^[^:]+:%d+: attempt to compare two function values") + +error_like(function () return f <= g end, + "^[^:]+:%d+: attempt to compare two function values", + "f <= g") + +error_like(function () f = print; g = type; return f <= g end, + "^[^:]+:%d+: attempt to compare two function values") + +error_like(function () return f > g end, + "^[^:]+:%d+: attempt to compare two function values", + "f > g") + +error_like(function () f = print; g = type; return f > g end, + "^[^:]+:%d+: attempt to compare two function values") + +error_like(function () return f >= g end, + "^[^:]+:%d+: attempt to compare two function values", + "f >= g") + +error_like(function () f = print; g = type; return f >= g end, + "^[^:]+:%d+: attempt to compare two function values") + +error_like(function () return f < 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "f < 0") + +error_like(function () f = print; return f < 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+") + +error_like(function () return f <= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "f <= 0") + +error_like(function () f = print; return f <= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+") + +error_like(function () return f > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "f > 0") + +error_like(function () f = print; return f > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+") + +error_like(function () return f > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "f >= 0") + +error_like(function () f = print; return f >= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+") + +error_like(function () local a = f; local b = a[1]; end, + "^[^:]+:%d+: attempt to index", + "index") + +error_like(function () local a = print; local b = a[1]; end, + "^[^:]+:%d+: attempt to index") + +error_like(function () local a = f; a[1] = 1; end, + "^[^:]+:%d+: attempt to index", + "index") + +error_like(function () local a = print; a[1] = 1; end, + "^[^:]+:%d+: attempt to index") + +local t = {} +t[print] = true +ok(t[print]) + +if has_op53 then + dofile'lexico53/function.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/103-nil.t b/test/lua-Harness-tests/103-nil.t new file mode 100755 index 0000000..561b101 --- /dev/null +++ b/test/lua-Harness-tests/103-nil.t @@ -0,0 +1,127 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua nil & coercion + +=head2 Synopsis + + % prove 103-nil.t + +=head2 Description + +=cut + +--]] + +require'tap' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +error_like(function () return -nil end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "-nil") + +error_like(function () return #nil end, + "^[^:]+:%d+: attempt to get length of a nil value", + "#nil") + +is(not nil, true, "not nil") + +error_like(function () return nil + 10 end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "nil + 10") + +error_like(function () return nil - 2 end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "nil - 2") + +error_like(function () return nil * 3.14 end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "nil * 3.14") + +error_like(function () return nil / -7 end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "nil / -7") + +error_like(function () return nil % 4 end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "nil % 4") + +error_like(function () return nil ^ 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "nil ^ 3") + +error_like(function () return nil .. 'end' end, + "^[^:]+:%d+: attempt to concatenate a nil value", + "nil .. 'end'") + +is(nil == nil, true, "nil == nil") + +is(nil ~= nil, false, "nil ~= nil") + +is(nil == 1, false, "nil == 1") + +is(nil ~= 1, true, "nil ~= 1") + +error_like(function () return nil < nil end, + "^[^:]+:%d+: attempt to compare two nil values", + "nil < nil") + +error_like(function () return nil <= nil end, + "^[^:]+:%d+: attempt to compare two nil values", + "nil <= nil") + +error_like(function () return nil > nil end, + "^[^:]+:%d+: attempt to compare two nil values", + "nil > nil") + +error_like(function () return nil > nil end, + "^[^:]+:%d+: attempt to compare two nil values", + "nil >= nil") + +error_like(function () return nil < 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "nil < 0") + +error_like(function () return nil <= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "nil <= 0") + +error_like(function () return nil > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "nil > 0") + +error_like(function () return nil >= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "nil >= 0") + +error_like(function () local a = nil; local b = a[1]; end, + "^[^:]+:%d+: attempt to index", + "index") + +error_like(function () local a = nil; a[1] = 1; end, + "^[^:]+:%d+: attempt to index", + "index") + +if has_op53 then + dofile'lexico53/nil.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/104-number.t b/test/lua-Harness-tests/104-number.t new file mode 100755 index 0000000..0d4d3fd --- /dev/null +++ b/test/lua-Harness-tests/104-number.t @@ -0,0 +1,246 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua number & coercion + +=head2 Synopsis + + % prove 104-number.t + +=head2 Description + +=cut + +--]] + +require'tap' +local profile = require'profile' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +is(-1, -(1), "-1") + +is(not 1, false, "not 1") + +is(10 + 2, 12, "10 + 2") + +is(2 - 10.5, -8.5, "2 - 10.5") + +is(2 * 3, 6, "2 * 3") + +is(3.14 * 1, 3.14, "3.14 * 1") + +is(-7 / 0.5, -14, "-7 / 0.5") + +type_ok(1.0 / 0.0, 'number', "1.0 / 0.0") + +is(-25 % 3, 2, "-25 % 3") + +if _VERSION >= 'Lua 5.3' then + error_like(function () return 1 % 0 end, + "^[^:]+:%d+: attempt to perform 'n%%0'", + "1 % 0") +else + type_ok(1 % 0, 'number', "1 % 0") +end + +error_like(function () return 10 + true end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "10 + true") + +error_like(function () return 2 - nil end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "2 - nil") + +error_like(function () return 2 * {} end, + "^[^:]+:%d+: attempt to perform arithmetic on a table value", + "2 * {}") + +error_like(function () return 3.14 * false end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "3.14 * false") + +error_like(function () return -7 / {} end, + "^[^:]+:%d+: attempt to perform arithmetic on a table value", + "-7 / {}") + +error_like(function () return 3 ^ true end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "3 ^ true") + +error_like(function () return -25 % false end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "-25 % false") + +error_like(function () return 10 + 'text' end, + "^[^:]+:%d+: attempt to", + "10 + 'text'") + +error_like(function () return 2 - 'text' end, + "^[^:]+:%d+: attempt to", + "2 - 'text'") + +error_like(function () return 2 * 'text' end, + "^[^:]+:%d+: attempt to", + "2 * 'text'") + +error_like(function () return 3.14 * 'text' end, + "^[^:]+:%d+: attempt to", + "3.14 * 'text'") + +error_like(function () return -7 / 'text' end, + "^[^:]+:%d+: attempt to", + "-7 / 'text'") + +error_like(function () return 25 % 'text' end, + "^[^:]+:%d+: attempt to", + "25 % 'text'") + +error_like(function () return 3 ^ 'text' end, + "^[^:]+:%d+: attempt to", + "3 ^ 'text'") + +if profile.nocvts2n then + error_like(function () return 10 + '2' end, + "^[^:]+:%d+: attempt to", + "10 + '2'") + + error_like(function () return 2 - '10.5' end, + "^[^:]+:%d+: attempt to", + "2 - '10.5'") + + error_like(function () return 2 * '3' end, + "^[^:]+:%d+: attempt to", + "2 * '3'") + + error_like(function () return 3.14 * '1' end, + "^[^:]+:%d+: attempt to", + "3.14 * '1'") + + error_like(function () return -7 / '0.5' end, + "^[^:]+:%d+: attempt to", + "-7 / '0.5'") + + error_like(function () return -25 % '3' end, + "^[^:]+:%d+: attempt to", + "-25 % '3'") + + error_like(function () return 3 ^ '3' end, + "^[^:]+:%d+: attempt to", + "3 ^ '3'") +else + is(10 + '2', 12, "10 + '2'") + + is(2 - '10.5', -8.5, "2 - '10.5'") + + is(2 * '3', 6, "2 * '3'") + + is(3.14 * '1', 3.14, "3.14 * '1'") + + is(-7 / '0.5', -14, "-7 / '0.5'") + + is(-25 % '3', 2, "-25 % '3'") + + is(3 ^ '3', 27, "3 ^ '3'") +end + +if profile.nocvtn2s then + error_like(function () return 1 .. 'end' end, + "^[^:]+:%d+: attempt to concatenate a number value", + "1 .. 'end'") + + error_like(function () return 1 .. 2 end, + "^[^:]+:%d+: attempt to concatenate a number value", + "1 .. 2") +else + is(1 .. 'end', '1end', "1 .. 'end'") + + is(1 .. 2, '12', "1 .. 2") +end + +error_like(function () return 1 .. true end, + "^[^:]+:%d+: attempt to concatenate a %w+ value", + "1 .. true") + +is(1.0 == 1, true, "1.0 == 1") + +is(1 ~= 2, true, "1 ~= 2") + +is(1 == true, false, "1 == true") + +is(1 ~= nil, true, "1 ~= nil") + +is(1 == '1', false, "1 == '1'") + +is(1 ~= '1', true, "1 ~= '1'") + +is(1 < 0, false, "1 < 0") + +is(1 <= 0, false, "1 <= 0") + +is(1 > 0, true, "1 > 0") + +is(1 >= 0, true, "1 >= 0") + +error_like(function () return 1 < false end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 < false") + +error_like(function () return 1 <= nil end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 <= nil") + +error_like(function () return 1 > true end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 > true") + +error_like(function () return 1 >= {} end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 >= {}") + +error_like(function () return 1 < '0' end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 < '0'") + +error_like(function () return 1 <= '0' end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 <= '0'") + +error_like(function () return 1 > '0' end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 > '0'") + +error_like(function () return 1 >= '0' end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "1 >= '0'") + +error_like(function () local a= 3.14; local b = a[1]; end, + "^[^:]+:%d+: attempt to index", + "index") + +error_like(function () local a = 3.14; a[1] = 1; end, + "^[^:]+:%d+: attempt to index", + "index") + +if has_op53 then + dofile'lexico53/number.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/105-string.t b/test/lua-Harness-tests/105-string.t new file mode 100755 index 0000000..cd8c88b --- /dev/null +++ b/test/lua-Harness-tests/105-string.t @@ -0,0 +1,277 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua string & coercion + +=head2 Synopsis + + % prove 105-string.t + +=head2 Description + +=cut + +--]] + +require'tap' +local profile = require'profile' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +if profile.nocvts2n then + error_like(function () return - '1' end, + "^[^:]+:%d+: attempt to", + "-'1'") +else + is(- '1', -1, "-'1'") +end + +error_like(function () return - 'text' end, + "^[^:]+:%d+: attempt to", + "-'text'") + +is(# 'text', 4, "#'text'") + +is(not 'text', false, "not 'text'") + +if profile.nocvts2n then + error_like(function () return '10' + 2 end, + "^[^:]+:%d+: attempt to", + "'10' + 2") + + error_like(function () return '2' - 10.5 end, + "^[^:]+:%d+: attempt to", + "'2' - 10.5") + + error_like(function () return '2' * 3 end, + "^[^:]+:%d+: attempt to", + "'2' * 3") + + error_like(function () return '3.14' * 1 end, + "^[^:]+:%d+: attempt to", + "'3.14' * 1") + + error_like(function () return '-7' / 0.5 end, + "^[^:]+:%d+: attempt to", + "'-7' / 0.5") + + error_like(function () return '-25' % 3 end, + "^[^:]+:%d+: attempt to", + "'-25' % 3") + + error_like(function () return '3' ^ 3 end, + "^[^:]+:%d+: attempt to", + "'3' ^ 3") +else + is('10' + 2, 12, "'10' + 2") + + is('2' - 10.5, -8.5, "'2' - 10.5") + + is('2' * 3, 6, "'2' * 3") + + is('3.14' * 1, 3.14, "'3.14' * 1") + + is('-7' / 0.5, -14, "'-7' / 0.5") + + is('-25' % 3, 2, "'-25' % 3") + + is('3' ^ 3, 27, "'3' ^ 3") +end + +error_like(function () return '10' + true end, + "^[^:]+:%d+: attempt to", + "'10' + true") + +error_like(function () return '2' - nil end, + "^[^:]+:%d+: attempt to", + "'2' - nil") + +error_like(function () return '2' * {} end, + "^[^:]+:%d+: attempt to", + "'2' * {}") + +error_like(function () return '3.14' * false end, + "^[^:]+:%d+: attempt to", + "'3.14' * false") + +error_like(function () return '-7' / {} end, + "^[^:]+:%d+: attempt to", + "'-7' / {}") + +error_like(function () return '-25' % false end, + "^[^:]+:%d+: attempt to", + "'-25' % false") + +error_like(function () return '3' ^ true end, + "^[^:]+:%d+: attempt to", + "'3' ^ true") + +error_like(function () return '10' + 'text' end, + "^[^:]+:%d+: attempt to", + "'10' + 'text'") + +error_like(function () return '2' - 'text' end, + "^[^:]+:%d+: attempt to", + "'2' - 'text'") + +error_like(function () return '3.14' * 'text' end, + "^[^:]+:%d+: attempt to", + "'3.14' * 'text'") + +error_like(function () return '-7' / 'text' end, + "^[^:]+:%d+: attempt to", + "'-7' / 'text'") + +error_like(function () return '-25' % 'text' end, + "^[^:]+:%d+: attempt to", + "'-25' % 'text'") + +error_like(function () return '3' ^ 'text' end, + "^[^:]+:%d+: attempt to", + "'3' ^ 'text'") + +if profile.nocvts2n then + error_like(function () return '10' + '2' end, + "^[^:]+:%d+: attempt to", + "'10' + '2'") + + error_like(function () return '2' - '10.5' end, + "^[^:]+:%d+: attempt to", + "'2' - '10.5'") + + error_like(function () return '2' * '3' end, + "^[^:]+:%d+: attempt to", + "'2' * '3'") + + error_like(function () return '3.14' * '1' end, + "^[^:]+:%d+: attempt to", + "'3.14' * '1'") + + error_like(function () return '-7' / '0.5' end, + "^[^:]+:%d+: attempt to", + "'-7' / '0.5'") + + error_like(function () return '-25' % '3' end, + "^[^:]+:%d+: attempt to", + "'-25' % '3'") + + error_like(function () return '3' ^ '3' end, + "^[^:]+:%d+: attempt to", + "'3' ^ '3'") +else + is('10' + '2', 12, "'10' + '2'") + + is('2' - '10.5', -8.5, "'2' - '10.5'") + + is('2' * '3', 6, "'2' * '3'") + + is('3.14' * '1', 3.14, "'3.14' * '1'") + + is('-7' / '0.5', -14, "'-7' / '0.5'") + + is('-25' % '3', 2, "'-25' % '3'") + + is('3' ^ '3', 27, "'3' ^ '3'") +end + +is('1' .. 'end', '1end', "'1' .. 'end'") + +if profile.nocvtn2s then + error_like(function () return '1' .. 2 end, + "^[^:]+:%d+: attempt to concatenate a number value", + "'1' .. 2") +else + is('1' .. 2, '12', "'1' .. 2") +end + +error_like(function () return '1' .. true end, + "^[^:]+:%d+: attempt to concatenate a boolean value", + "'1' .. true") + +is('foo\0bar' <= 'foo\0baz', true, "'foo\\0bar' <= 'foo\\0baz'") + +is('foo\0bar' ~= 'foo', true, "'foo\\0bar' ~= 'foo'") + +is('foo\0bar' >= 'foo', true, "'foo\\0bar' >= 'foo'") + +is('1.0' == '1', false, "'1.0' == '1'") + +is('1' ~= '2', true, "'1' ~= '2'") + +is('1' == true, false, "'1' == true") + +is('1' ~= nil, true, "'1' ~= nil") + +is('1' == 1, false, "'1' == 1") + +is('1' ~= 1, true, "'1' ~= 1") + +is('1' < '0', false, "'1' < '0'") + +is('1' <= '0', false, "'1' <= '0'") + +is('1' > '0', true, "'1' > '0'") + +is('1' >= '0', true, "'1' >= '0'") + +error_like(function () return '1' < false end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' < false") + +error_like(function () return '1' <= nil end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' <= nil") + +error_like(function () return '1' > true end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' > true") + +error_like(function () return '1' >= {} end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' >= {}") + +error_like(function () return '1' < 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' < 0") + +error_like(function () return '1' <= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' <= 0") + +error_like(function () return '1' > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' > 0") + +error_like(function () return '1' > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "'1' >== 0") + +local a = 'text' +is(a[1], nil, "index") + +error_like(function () a = 'text'; a[1] = 1; end, + "^[^:]+:%d+: attempt to index", + "index") + +if has_op53 then + dofile'lexico53/string.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/106-table.t b/test/lua-Harness-tests/106-table.t new file mode 100755 index 0000000..0c0ba49 --- /dev/null +++ b/test/lua-Harness-tests/106-table.t @@ -0,0 +1,135 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua table & coercion + +=head2 Synopsis + + % prove 106-table.t + +=head2 Description + +=cut + +--]] + +require'tap' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +error_like(function () return -{} end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "-{}") + +is(# {}, 0, "#{}") +is(# {4,5,6}, 3) + +is(not {}, false, "not {}") + +error_like(function () return {} + 10 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "{} + 10") + +error_like(function () return {} - 2 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "{} - 2") + +error_like(function () return {} * 3.14 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "{} * 3.14") + +error_like(function () return {} / 7 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "{} / 7") + +error_like(function () return {} % 4 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "{} % 4") + +error_like(function () return {} ^ 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "{} ^ 3") + +error_like(function () return {} .. 'end' end, + "^[^:]+:%d+: attempt to concatenate", + "{} .. 'end'") + +is({} == {}, false, "{} == {}") + +local t1 = {} +local t2 = {} +is(t1 == t1, true, "t1 == t1") +is(t1 == t2, false, "t1 == t2") +is(t1 ~= t2, true, "t1 ~= t2") + +is({} == 1, false, "{} == 1") + +is({} ~= 1, true, "{} ~= 1") + +error_like(function () return t1 < t2 end, + "^[^:]+:%d+: attempt to compare two table values", + "t1 < t2") + +error_like(function () return t1 <= t2 end, + "^[^:]+:%d+: attempt to compare two table values", + "t1 <= t2") + +error_like(function () return t1 > t2 end, + "^[^:]+:%d+: attempt to compare two table values", + "t1 > t2") + +error_like(function () return t1 >= t2 end, + "^[^:]+:%d+: attempt to compare two table values", + "t1 >= t2") + +error_like(function () return {} < 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "{} < 0") + +error_like(function () return {} <= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "{} <= 0") + +error_like(function () return {} > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "{} > 0") + +error_like(function () return {} >= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "{} >= 0") + +local t = {} +is( t[1], nil, "index" ) +t[1] = 42 +is( t[1], 42, "index" ) + +error_like(function () t = {}; t[nil] = 42 end, + "^[^:]+:%d+: table index is nil", + "table index is nil") + +error_like(function () t = {}; t[0/0] = 42 end, + "^[^:]+:%d+: table index is NaN", + "table index is NaN") + +if has_op53 then + dofile'lexico53/table.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/107-thread.t b/test/lua-Harness-tests/107-thread.t new file mode 100755 index 0000000..3d4af18 --- /dev/null +++ b/test/lua-Harness-tests/107-thread.t @@ -0,0 +1,135 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua thread & coercion + +=head2 Synopsis + + % prove 107-thread.t + +=head2 Description + +=cut + +--]] + +require'tap' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +local co = coroutine.create(function () return 1 end) + +error_like(function () return -co end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "-co") + +error_like(function () return #co end, + "^[^:]+:%d+: attempt to get length of", + "#co") + +is(not co, false, "not co") + +error_like(function () return co + 10 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "co + 10") + +error_like(function () return co - 2 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "co - 2") + +error_like(function () return co * 3.14 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "co * 3.14") + +error_like(function () return co / 7 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "co / 7") + +error_like(function () return co % 4 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "co % 4") + +error_like(function () return co ^ 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "co ^ 3") + +error_like(function () return co .. 'end' end, + "^[^:]+:%d+: attempt to concatenate", + "co .. 'end'") + +is(co == co, true, "co == co") + +local co1 = coroutine.create(function () return 1 end) +local co2 = coroutine.create(function () return 2 end) +is(co1 ~= co2, true, "co1 ~= co2") + +is(co == 1, false, "co == 1") + +is(co ~= 1, true, "co ~= 1") + +error_like(function () return co1 < co2 end, + "^[^:]+:%d+: attempt to compare two thread values", + "co1 < co2") + +error_like(function () return co1 <= co2 end, + "^[^:]+:%d+: attempt to compare two thread values", + "co1 <= co2") + +error_like(function () return co1 > co2 end, + "^[^:]+:%d+: attempt to compare two thread values", + "co1 > co2") + +error_like(function () return co1 >= co2 end, + "^[^:]+:%d+: attempt to compare two thread values", + "co1 >= co2") + +error_like(function () return co < 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "co < 0") + +error_like(function () return co <= 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "co <= 0") + +error_like(function () return co > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "co > 0") + +error_like(function () return co > 0 end, + "^[^:]+:%d+: attempt to compare %w+ with %w+", + "co >= 0") + +error_like(function () local a = co[1] end, + "^[^:]+:%d+: attempt to index", + "index") + +error_like(function () co[1] = 1 end, + "^[^:]+:%d+: attempt to index", + "index") + +local t = {} +t[co] = true +ok(t[co]) + +if has_op53 then + dofile'lexico53/thread.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/108-userdata.t b/test/lua-Harness-tests/108-userdata.t new file mode 100755 index 0000000..b1e3641 --- /dev/null +++ b/test/lua-Harness-tests/108-userdata.t @@ -0,0 +1,132 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua userdata & coercion + +=head2 Synopsis + + % prove 108-userdata.t + +=head2 Description + +=cut + +--]] + +require'tap' +local has_op53 = _VERSION >= 'Lua 5.3' + +plan'no_plan' + +local u = io.stdin + +error_like(function () return -u end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "-u") + +error_like(function () return #u end, + "^[^:]+:%d+: attempt to get length of", + "#u") + +is(not u, false, "not u") + +error_like(function () return u + 10 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "u + 10") + +error_like(function () return u - 2 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "u - 2") + +error_like(function () return u * 3.14 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "u * 3.14") + +error_like(function () return u / 7 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "u / 7") + +error_like(function () return u % 4 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "u % 4") + +error_like(function () return u ^ 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "u ^ 3") + +error_like(function () return u .. 'end' end, + "^[^:]+:%d+: attempt to concatenate", + "u .. 'end'") + +is(u == u, true, "u == u") + +local v = io.stdout +is(u ~= v, true, "u ~= v") + +is(u == 1, false, "u == 1") + +is(u ~= 1, true, "u ~= 1") + +error_like(function () return u < v end, + "^[^:]+:%d+: attempt to compare two", + "u < v") + +error_like(function () return u <= v end, + "^[^:]+:%d+: attempt to compare two", + "u <= v") + +error_like(function () return u > v end, + "^[^:]+:%d+: attempt to compare two", + "u > v") + +error_like(function () return u >= v end, + "^[^:]+:%d+: attempt to compare two", + "u >= v") + +error_like(function () return u < 0 end, + "^[^:]+:%d+: attempt to compare", + "u < 0") + +error_like(function () return u <= 0 end, + "^[^:]+:%d+: attempt to compare", + "u <= 0") + +error_like(function () return u > 0 end, + "^[^:]+:%d+: attempt to compare", + "u > 0") + +error_like(function () return u > 0 end, + "^[^:]+:%d+: attempt to compare", + "u >= 0") + +is(u[1], nil, "index") + +error_like(function () u[1] = 1 end, + "^[^:]+:%d+: attempt to index", + "index") + +local t = {} +t[u] = true +ok(t[u]) + +if has_op53 then + dofile'lexico53/userdata.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/200-examples.t b/test/lua-Harness-tests/200-examples.t new file mode 100755 index 0000000..362aae3 --- /dev/null +++ b/test/lua-Harness-tests/200-examples.t @@ -0,0 +1,104 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 some Lua code examples + +=head2 Synopsis + + % prove 200-examples.t + +=head2 Description + +First tests in order to check infrastructure. + +=cut + +--]] + +require'tap' + +plan(5) + +function factorial (n) + if n == 0 then + return 1 + else + return n * factorial(n-1) + end +end +is(factorial(7), 5040, "factorial (recursive)") + +local function local_factorial (n) + if n == 0 then + return 1 + else + return n * local_factorial(n-1) + end +end +is(local_factorial(7), 5040, "factorial (recursive)") + +local function loop_factorial (n) + local a = 1 + for i = 1, n, 1 do + a = a*i + end + return a +end +is(loop_factorial(7), 5040, "factorial (loop)") + +local function iter_factorial (n) + local function iter (product, counter) + if counter > n then + return product + else + return iter(counter*product, counter+1) + end + end + return iter(1, 1) +end +is(iter_factorial(7), 5040, "factorial (iter)") + +--[[ + + Knuth's "man or boy" test. + See http://en.wikipedia.org/wiki/Man_or_boy_test + +]] + +local function A (k, x1, x2, x3, x4, x5) + local function B () + k = k - 1 + return A(k, B, x1, x2, x3, x4) + end + if k <= 0 then + return x4() + x5() + else + return B() + end +end + +is(A(10, + function () return 1 end, + function () return -1 end, + function () return -1 end, + function () return 1 end, + function () return 0 end), + -67, + "man or boy" +) + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/201-assign.t b/test/lua-Harness-tests/201-assign.t new file mode 100755 index 0000000..7d023d8 --- /dev/null +++ b/test/lua-Harness-tests/201-assign.t @@ -0,0 +1,150 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua assignment + +=head2 Synopsis + + % prove 201-assign.t + +=head2 Description + +See section "Assignment" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.4.3>, +L<https://www.lua.org/manual/5.2/manual.html#3.3.3>, +L<https://www.lua.org/manual/5.3/manual.html#3.3.3>, +L<https://www.lua.org/manual/5.4/manual.html#3.3.3> + +=cut + +--]] + +require'tap' +local has_env = _VERSION >= 'Lua 5.2' + +plan'no_plan' + +do + is(b, nil, "global variable") + b = 10 + is(b, 10) + if has_env then + is(_ENV.b, 10, "_ENV") + is(_G, _ENV, "_G") + error_like([[ _ENV = nil; b = 20 ]], + "attempt to ") + else + is(_ENV, nil, "no _ENV"); + end + b = nil + is(b, nil) +end + +do + local a = {} + local i = 3 + i, a[i] = i+1, 20 + -- this behavior is undefined + -- see http://lua-users.org/lists/lua-l/2006-06/msg00378.html + is(i, 4, "check eval") + is(a[3], 20) +end + +do + local x = 1. + local y = 2. + x, y = y, x -- swap + is(x, 2, "check swap") + is(y, 1) +end + +do + local a, b, c = 0, 1 + is(a, 0, "check padding") + is(b, 1) + is(c, nil) + a, b = a+1, b+1, a+b + is(a, 1) + is(b, 2) + a, b, c = 0 + is(a, 0) + is(b, nil) + is(c, nil) +end + +do + local function f() return 1, 2 end + local a, b, c, d = f() + is(a, 1, "adjust with function") + is(b, 2) + is(c, nil) + is(d, nil) +end + +do + local function f() print('# f') end + local a = 2 + local b, c + a, b, c = f(), 3 + is(a, nil, "padding with function") + is(b, 3) + is(c, nil) +end + +do + local my_i = 1 + is(my_i, 1, "local variable") + local my_i = 2 + is(my_i, 2) +end + +do + local i = 1 + local j = i + is(i, 1, "local variable") + is(j, 1) + j = 2 + is(i, 1) + is(j, 2) +end + +do + local function f(x) return 2*x end + is(f(2), 4, "param & result of function") + local a = 2 + a = f(a) + is(a, 4) + local b = 2 + b = f(b) + is(b, 4) +end + +do + local n1 = 1 + local n2 = 2 + local n3 = 3 + local n4 = 4 + n1,n2,n3,n4 = n4,n3,n2,n1 + is(n1, 4, "assignment list swap values") + is(n2, 3) + is(n3, 2) + is(n4, 1) +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/202-expr.t b/test/lua-Harness-tests/202-expr.t new file mode 100755 index 0000000..2576750 --- /dev/null +++ b/test/lua-Harness-tests/202-expr.t @@ -0,0 +1,157 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua expression + +=head2 Synopsis + + % prove 202-expr.t + +=head2 Description + +See section "Expressions" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.5>, +L<https://www.lua.org/manual/5.2/manual.html#3.4>, +L<https://www.lua.org/manual/5.3/manual.html#3.4>, +L<https://www.lua.org/manual/5.4/manual.html#3.4> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local nocvtn2s = profile.nocvtn2s +local nocvts2n = profile.nocvts2n + +plan'no_plan' + +local x = math.pi +is(tostring(x - x%0.0001), tostring(3.1415), "modulo") + +local a = {}; a.x = 1; a.y = 0; +local b = {}; b.x = 1; b.y = 0; +local c = a +is(a == c, true, "relational op (by reference)") +is(a ~= b, true) + +is('0' == 0, false, "relational op") +is(2 < 15, true) +is('2' < '15', false) + +error_like(function () return 2 < '15' end, + "compare", + "relational op") + +error_like(function () return '2' < 15 end, + "compare", + "relational op") + +is(4 and 5, 5, "logical op") +is(nil and 13, nil) +is(false and 13, false) +is(4 or 5, 4) +is(false or 5, 5) +is(false or 'text', 'text') + +is(10 or 20, 10, "logical op") +is(10 or error(), 10) +is(nil or 'a', 'a') +is(nil and 10, nil) +is(false and error(), false) +is(false and nil, false) +is(false or nil, nil) +is(10 and 20, 20) + +is(not nil, true, "logical not") +is(not false, true) +is(not 0, false) +is(not not nil, false) +is(not 'text', false) +a = {} +is(not a, false) +is(not (a == a), false) +is(not (a ~= a), true) + +is("Hello " .. "World", "Hello World", "concatenation") +if not nocvtn2s then + is(0 .. 1, '01') +end +a = "Hello" +is(a .. " World", "Hello World") +is(a, "Hello") + +if not nocvts2n then + is('10' + 1, 11, "coercion") + is('-5.3' * '2', -10.6) +end +is(tostring(10), '10') +if not nocvtn2s then + is(10 .. 20, '1020') + is(10 .. '', '10') +end + +error_like(function () return 'hello' + 1 end, + ((not nocvts2n and _VERSION >= 'Lua 5.4') or ravi) and "attempt to add" or "perform arithmetic", + "no coercion") + +error_like(function () + local function first() return end + local function limit() return 2 end + local function step() return 1 end + for i = first(), limit(), step() do + print(i) + end + end, + "^[^:]+:%d+:.- 'for' initial value", + "for tonumber") + +error_like(function () + local function first() return 1 end + local function limit() return end + local function step() return 2 end + for i = first(), limit(), step() do + print(i) + end + end, + "^[^:]+:%d+:.- 'for' limit", + "for tonumber") + +error_like(function () + local function first() return 1 end + local function limit() return 2 end + local function step() return end + for i = first(), limit(), step() do + print(i) + end + end, + "^[^:]+:%d+:.- 'for' step", + "for tonumber") + +if _VERSION >= 'Lua 5.4' then + error_like(function () + for i = 1, 10, 0 do + print(i) + end + end, + "^[^:]+:%d+: 'for' step is zero", + "for step zero") +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/203-lexico.t b/test/lua-Harness-tests/203-lexico.t new file mode 100755 index 0000000..c1abebf --- /dev/null +++ b/test/lua-Harness-tests/203-lexico.t @@ -0,0 +1,143 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2010-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Lexicography + +=head2 Synopsis + + % prove 203-lexico.t + +=head2 Description + +See "Lua 5.3 Reference Manual", section 3.1 "Lexical Conventions", +L<http://www.lua.org/manual/5.3/manual.html#3.1>. + +See section "Lexical Conventions" +L<https://www.lua.org/manual/5.1/manual.html#2.1>, +L<https://www.lua.org/manual/5.2/manual.html#3.1>, +L<https://www.lua.org/manual/5.3/manual.html#3.1>, +L<https://www.lua.org/manual/5.4/manual.html#3.1> + +=cut + +--]] + +require'tap' +local loadstring = loadstring or load +local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT') + +plan'no_plan' + +is("\65", "A") +is("\065", "A") + +is(string.byte("\a"), 7) +is(string.byte("\b"), 8) +is(string.byte("\f"), 12) +is(string.byte("\n"), 10) +is(string.byte("\r"), 13) +is(string.byte("\t"), 9) +is(string.byte("\v"), 11) +is(string.byte("\\"), 92) + +is(string.len("A\0B"), 3) + +do + local f, msg = loadstring [[a = "A\300"]] + if _VERSION == 'Lua 5.1' then + like(msg, "^[^:]+:%d+: .- near") + else + like(msg, "^[^:]+:%d+: .- escape .- near") + end + + f, msg = loadstring [[a = " unfinished string ]] + like(msg, "^[^:]+:%d+: unfinished string near") + + f, msg = loadstring [[a = " unfinished string +]] + like(msg, "^[^:]+:%d+: unfinished string near") + + f, msg = loadstring [[a = " unfinished string \ +]] + like(msg, "^[^:]+:%d+: unfinished string near") + + f, msg = loadstring [[a = " unfinished string \]] + like(msg, "^[^:]+:%d+: unfinished string near") + + f, msg = loadstring "a = [[ unfinished long string " + like(msg, "^[^:]+:%d+: unfinished long string .-near") + + f, msg = loadstring "a = [== invalid long string delimiter " + like(msg, "^[^:]+:%d+: invalid long string delimiter near") +end + +do + local a = 'alo\n123"' + is('alo\n123"', a) + is("alo\n123\"", a) + is('\97lo\10\04923"', a) + is([[alo +123"]], a) + is([==[ +alo +123"]==], a) +end + +is(3.0, 3) +is(314.16e-2, 3.1416) +is(0.31416E1, 3.1416) +is(.3, 0.3) +is(0xff, 255) +is(0x56, 86) + +do + local f, msg = loadstring [[a = 12e34e56]] + like(msg, "^[^:]+:%d+: malformed number near") +end + +--[===[ +--[[ +--[=[ + nested long comments +--]=] +--]] +--]===] + +do + local f, msg = loadstring " --[[ unfinished long comment " + like(msg, "^[^:]+:%d+: unfinished long comment .-near") +end + +if _VERSION >= 'Lua 5.2' or jit then + dofile'lexico52/lexico.t' +end + +if _VERSION >= 'Lua 5.3' or luajit21 then + dofile'lexico53/lexico.t' +end + +if _VERSION >= 'Lua 5.4' then + dofile'lexico54/lexico.t' +end + +if jit and pcall(require, 'ffi') then + dofile'lexicojit/lexico.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/204-grammar.t b/test/lua-Harness-tests/204-grammar.t new file mode 100755 index 0000000..d9ae3a6 --- /dev/null +++ b/test/lua-Harness-tests/204-grammar.t @@ -0,0 +1,233 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2010-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Grammar + +=head2 Synopsis + + % prove 204-grammar.t + +=head2 Description + +See section "The Complete Syntax of Lua" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#8>, +L<https://www.lua.org/manual/5.2/manual.html#9>, +L<https://www.lua.org/manual/5.3/manual.html#9>, +L<https://www.lua.org/manual/5.4/manual.html#9> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local has_goto = _VERSION >= 'Lua 5.2' or jit +local has_attr = _VERSION >= 'Lua 5.4' +local loadstring = loadstring or load + +plan'no_plan' + +do --[[ empty statement ]] + local f, msg = loadstring [[; a = 1]] + if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then + like(msg, "^[^:]+:%d+: unexpected symbol near ';'", "empty statement") + else + type_ok(f, 'function', "empty statement") + end + + f = loadstring [[a = 1; a = 2]] + type_ok(f, 'function') + + f, msg = loadstring [[a = 1;;; a = 2]] + if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then + like(msg, "^[^:]+:%d+: unexpected symbol near ';'") + else + type_ok(f, 'function') + end +end + +do --[[ orphan break ]] + local f, msg = loadstring [[ +function f() + print "before" + do + print "inner" + break + end + print "after" +end +]] + if _VERSION == 'Lua 5.1' then + like(msg, "^[^:]+:%d+: no loop to break", "orphan break") + elseif _VERSION <= 'Lua 5.3' then + like(msg, "^[^:]+:%d+: <break> at line 5 not inside a loop", "orphan break") + else + like(msg, "^[^:]+:%d+: break outside loop at line 5", "orphan break") + end +end + +do --[[ break anywhere ]] + local f, msg = loadstring [[ +function f() + print "before" + while true do + print "inner" + break + print "break" + end + print "after" +end +]] + if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then + like(msg, "^[^:]+:%d+: 'end' expected %(to close 'while' at line 3%) near 'print'", "break anywhere") + else + type_ok(f, 'function', "break anywhere") + end + + f, msg = loadstring [[ +function f() + print "before" + while true do + print "inner" + if cond then + break + print "break" + end + end + print "after" +end +]] + if _VERSION == 'Lua 5.1' and not profile.luajit_compat52 then + like(msg, "^[^:]+:%d+: 'end' expected %(to close 'if' at line 5%) near 'print'", "break anywhere") + else + type_ok(f, 'function', "break anywhere") + end +end + +--[[ goto ]] +if has_goto then + local f, msg = loadstring [[ +::label:: + goto unknown +]] + if jit then + like(msg, ":%d+: undefined label 'unknown'", "unknown goto") + else + like(msg, ":%d+: no visible label 'unknown' for <goto> at line %d+", "unknown goto") + end + + f, msg = loadstring [[ +::label:: + goto label +::label:: +]] + if jit then + like(msg, ":%d+: duplicate label 'label'", "duplicate label") + else + like(msg, ":%d+: label 'label' already defined on line %d+", "duplicate label") + end + + f, msg = loadstring [[ +::e:: + goto f + local x +::f:: + goto e +]] + if jit then + like(msg, ":%d+: <goto f> jumps into the scope of local 'x'", "bad goto") + else + like(msg, ":%d+: <goto f> at line %d+ jumps into the scope of local 'x'", "bad goto") + end + + f= loadstring [[ +do +::s1:: ; + goto s2 + +::s2:: + goto s3 + +::s3:: +end +]] + type_ok(f, 'function', "goto") +else + diag("no goto") +end + +do --[[ syntax error ]] + local f, msg = loadstring [[a = { 1, 2, 3)]] + like(msg, ":%d+: '}' expected near '%)'", "constructor { }") + + f, msg = loadstring [[a = (1 + 2}]] + like(msg, ":%d+: '%)' expected near '}'", "expr ( )") + + f, msg = loadstring [[a = f(1, 2}]] + like(msg, ":%d+: '%)' expected near '}'", "expr ( )") + + f, msg = loadstring [[function f () return 1]] + like(msg, ":%d+: 'end' expected near '?<eof>'?", "function end") + + f, msg = loadstring [[do local a = f()]] + like(msg, ":%d+: 'end' expected near '?<eof>'?", "do end") + + f, msg = loadstring [[for i = 1, 2 do print(i)]] + like(msg, ":%d+: 'end' expected near '?<eof>'?", "for end") + + f, msg = loadstring [[if true then f()]] + like(msg, ":%d+: 'end' expected near '?<eof>'?", "if end") + + f, msg = loadstring [[while true do f()]] + like(msg, ":%d+: 'end' expected near '?<eof>'?", "while end") + + f, msg = loadstring [[repeat f()]] + like(msg, ":%d+: 'until' expected near '?<eof>'?", "repeat until") + + f, msg = loadstring [[function f (a, 2) return a * 2 end]] + like(msg, ":%d+: <name> or '...' expected near '2'", "function parameter list") + + f, msg = loadstring [[a = o:m[1, 2)]] + like(msg, ":%d+: function arguments expected near '%['", "function argument list") + + f, msg = loadstring [[for i do print(i) end]] + like(msg, ":%d+: '=' or 'in' expected near 'do'", "for init") + + f, msg = loadstring [[for i = 1, 2 print(i) end]] + like(msg, ":%d+: 'do' expected near 'print'", "for do") + + f, msg = loadstring [[if true f() end]] + like(msg, ":%d+: 'then' expected near 'f'", "if then") + + f, msg = loadstring [[while true f() end]] + like(msg, ":%d+: 'do' expected near 'f", "while do") +end + +if has_attr then + local f, msg = load [[local foo < bar > = 'bar']] + like(msg, "^[^:]+:%d+: unknown attribute 'bar'") + + f, msg = load [[local foo <const> = 'bar'; foo = 'baz']] + like(msg, "^[^:]+:%d+: attempt to assign to const variable 'foo'") + + f, msg = load [[local foo <close> = 'bar'; foo = 'baz']] + like(msg, "^[^:]+:%d+: attempt to assign to const variable 'foo'") +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/211-scope.t b/test/lua-Harness-tests/211-scope.t new file mode 100755 index 0000000..64eed52 --- /dev/null +++ b/test/lua-Harness-tests/211-scope.t @@ -0,0 +1,86 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua scope + +=head2 Synopsis + + % prove 211-scope.t + +=head2 Description + +See section "Visibility Rules" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.6>, +L<https://www.lua.org/manual/5.2/manual.html#3.5>, +L<https://www.lua.org/manual/5.3/manual.html#3.5>, +L<https://www.lua.org/manual/5.4/manual.html#3.5> + +See section "Local Variables and Blocks" in "Programming in Lua". + +=cut + +--]] + +require'tap' + +plan(10) + +--[[ scope ]] +x = 10 +do + local x = x + is(x, 10, "scope") + x = x + 1 + do + local x = x + 1 + is(x, 12) + end + is(x, 11) +end +is(x, 10) + +--[[ scope ]] +x = 10 +local i = 1 + +while i<=x do + local x = i*2 +-- print(x) + i = i + 1 +end + +if i > 20 then + local x + x = 20 + nok("scope") +else + is(x, 10, "scope") +end + +is(x, 10) + +--[[ scope ]] +local a, b = 1, 10 +if a < b then + is(a, 1, "scope") + local a + is(a, nil) +end +is(a, 1) +is(b, 10) + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/212-function.t b/test/lua-Harness-tests/212-function.t new file mode 100755 index 0000000..2851053 --- /dev/null +++ b/test/lua-Harness-tests/212-function.t @@ -0,0 +1,288 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua functions + +=head2 Synopsis + + % prove 212-function.t + +=head2 Description + +See section "Function Definitions" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.5.9>, +L<https://www.lua.org/manual/5.2/manual.html#3.4.10>, +L<https://www.lua.org/manual/5.3/manual.html#3.4.11>, +L<https://www.lua.org/manual/5.4/manual.html#3.4.11> + +See section "Functions" in "Programming in Lua". + +=cut + +--]] + +require'tap' +local loadstring = loadstring or load + +plan(68) + +do --[[ add ]] + local function add (a) + local sum = 0 + for i,v in ipairs(a) do + sum = sum + v + end + return sum + end + + local t = { 10, 20, 30, 40 } + is(add(t), 100, "add") +end + +do --[[ f ]] + local function f(a, b) return a or b end + + is(f(3), 3, "f") + is(f(3, 4), 3) + is(f(3, 4, 5), 3) +end + +do --[[ incCount ]] + local count = 0 + + local function incCount (n) + n = n or 1 + count = count + n + end + + is(count, 0, "inCount") + incCount() + is(count, 1) + incCount(2) + is(count, 3) + incCount(1) + is(count, 4) +end + +do --[[ maximum ]] + local function maximum (a) + local mi = 1 -- maximum index + local m = a[mi] -- maximum value + for i,val in ipairs(a) do + if val > m then + mi = i + m = val + end + end + return m, mi + end + + local m, mi = maximum({8,10,23,12,5}) + is(m, 23, "maximum") + is(mi, 3) +end + +do --[[ call by value ]] + local function f (n) + n = n - 1 + return n + end + + local a = 12 + is(a, 12, "call by value") + local b = f(a) + is(b, 11) + is(a, 12) + local c = f(12) + is(c, 11) + is(a, 12) +end + +do --[[ call by ref ]] + local function f (t) + t[#t+1] = 'end' + return t + end + + local a = { 'a', 'b', 'c' } + is(table.concat(a, ','), 'a,b,c', "call by ref") + local b = f(a) + is(table.concat(b, ','), 'a,b,c,end') + is(table.concat(a, ','), 'a,b,c,end') +end + +do --[[ var args ]] + local function g1(a, b, ...) + local arg = {...} + is(a, 3, "vararg") + is(b, nil) + is(#arg, 0) + is(arg[1], nil) + end + g1(3) + + local function g2(a, b, ...) + local arg = {...} + is(a, 3) + is(b, 4) + is(#arg, 0) + is(arg[1], nil) + end + g2(3, 4) + + local function g3(a, b, ...) + local arg = {...} + is(a, 3) + is(b, 4) + is(#arg, 2) + is(arg[1], 5) + is(arg[2], 8) + end + g3(3, 4, 5, 8) +end + +do --[[ var args ]] + local function g1(a, b, ...) + local c, d, e = ... + is(a, 3, "var args") + is(b, nil) + is(c, nil) + is(d, nil) + is(e, nil) + end + g1(3) + + local function g2(a, b, ...) + local c, d, e = ... + is(a, 3) + is(b, 4) + is(c, nil) + is(d, nil) + is(e, nil) + end + g2(3, 4) + + local function g3(a, b, ...) + local c, d, e = ... + is(a, 3) + is(b, 4) + is(c, 5) + is(d, 8) + is(e, nil) + end + g3(3, 4, 5, 8) +end + +do --[[ var args ]] + local function g1(a, b, ...) + is(#{a, b, ...}, 1, "varargs") + end + g1(3) + + local function g2(a, b, ...) + is(#{a, b, ...}, 2) + end + g2(3, 4) + + local function g3(a, b, ...) + is(#{a, b, ...}, 4) + end + g3(3, 4, 5, 8) +end + +do --[[ var args ]] + local function f() return 1, 2 end + local function g() return 'a', f() end + local function h() return f(), 'b' end + local function k() return 'c', (f()) end + + local x, y = f() + is(x, 1, "var args") + is(y, 2) + local z + x, y, z = g() + is(x, 'a') + is(y, 1) + is(z, 2) + x, y = h() + is(x, 1) + is(y, 'b') + x, y, z = k() + is(x, 'c') + is(y, 1) + is(z, nil) +end + +do --[[ invalid var args ]] + local f, msg = loadstring [[ +function f () + print(...) +end +]] + like(msg, "^[^:]+:%d+: cannot use '...' outside a vararg function", "invalid var args") +end + +do --[[ tail call ]] + local output = {} + local function foo (n) + output[#output+1] = n + if n > 0 then + return foo(n -1) + end + return 'end', 0 + end + + eq_array({foo(3)}, {'end', 0}, "tail call") + eq_array(output, {3, 2, 1, 0}) +end + +do --[[ no tail call ]] + local output = {} + local function foo (n) + output[#output+1] = n + if n > 0 then + return (foo(n -1)) + end + return 'end', 0 + end + + is(foo(3), 'end', "no tail call") + eq_array(output, {3, 2, 1, 0}) +end + +do --[[ no tail call ]] + local output = {} + local function foo (n) + output[#output+1] = n + if n > 0 then + foo(n -1) + end + end + + is(foo(3), nil, "no tail call") + eq_array(output, {3, 2, 1, 0}) +end + +do --[[ sub name ]] + local function f () return 1 end + is(f(), 1, "sub name") + + function f () return 2 end + is(f(), 2) +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/213-closure.t b/test/lua-Harness-tests/213-closure.t new file mode 100755 index 0000000..fc3bd29 --- /dev/null +++ b/test/lua-Harness-tests/213-closure.t @@ -0,0 +1,98 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua closures + +=head2 Synopsis + + % prove 213-closure.t + +=head2 Description + +See section "Closures" in "Programming in Lua". + +=cut + +--]] + +require'tap' + +plan(15) + +do --[[ inc ]] + local counter = 0 + + local function inc (x) + counter = counter + x + return counter + end + + is(inc(1), 1, "inc") + is(inc(2), 3) +end + +do --[[ newCounter ]] + local function newCounter () + local i = 0 + return function () -- anonymous function + i = i + 1 + return i + end + end + + local c1 = newCounter() + is(c1(), 1, "newCounter") + is(c1(), 2) + + local c2 = newCounter() + is(c2(), 1) + is(c1(), 3) + is(c2(), 2) +end + +do --[[ +The loop creates ten closures (that is, ten instances of the anonymous +function). Each of these closures uses a different y variable, while all +of them share the same x. +]] + local a = {} + local x = 20 + for i=1,10 do + local y = 0 + a[i] = function () y=y+1; return x+y end + end + + is(a[1](), 21, "ten closures") + is(a[1](), 22) + is(a[2](), 21) +end + +do --[[ add ]] + local function add(x) + return function (y) return (x + y) end + end + + local f = add(2) + type_ok(f, 'function', "add") + is(f(10), 12) + local g = add(5) + is(g(1), 6) + is(g(10), 15) + is(f(1), 3) +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/214-coroutine.t b/test/lua-Harness-tests/214-coroutine.t new file mode 100755 index 0000000..92929e1 --- /dev/null +++ b/test/lua-Harness-tests/214-coroutine.t @@ -0,0 +1,244 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua coroutines + +=head2 Synopsis + + % prove 214-coroutine.t + +=head2 Description + +See section "Coroutines" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.11>, +L<https://www.lua.org/manual/5.2/manual.html#2.6>, +L<https://www.lua.org/manual/5.3/manual.html#2.6>, +L<https://www.lua.org/manual/5.4/manual.html#2.6> + +See section "Coroutines" in "Programming in Lua". + +=cut + +--]] + +require'tap' +local profile = require'profile' +local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT') +local has_coroutine52 = _VERSION >= 'Lua 5.2' or jit +local has_running52 = _VERSION >= 'Lua 5.2' or (profile.luajit_compat52 and not ujit) +local has_isyieldable = _VERSION >= 'Lua 5.3' or luajit21 +local has_close = _VERSION >= 'Lua 5.4' + +plan'no_plan' + +do + local output = {} + + local function foo1 (a) + output[#output+1] = "foo " .. tostring(a) + return coroutine.yield(2*a) + end + + local co = coroutine.create(function (a,b) + local r, s + output[#output+1] = "co-body " .. tostring(a) .." " .. tostring(b) + r = foo1(a+1) + output[#output+1] = "co-body " .. r + r, s = coroutine.yield(a+b, a-b) + output[#output+1] = "co-body " .. r .. " " .. s + return b, 'end' + end) + + eq_array({coroutine.resume(co, 1, 10)}, {true, 4}, "foo1") + eq_array({coroutine.resume(co, 'r')}, {true, 11, -9}) + eq_array({coroutine.resume(co, "x", "y")}, {true, 10, 'end'}) + eq_array({coroutine.resume(co, "x", "y")}, {false, "cannot resume dead coroutine"}) + eq_array(output, { + 'co-body 1 10', + 'foo 2', + 'co-body r', + 'co-body x y', + }) +end + +do + local output = '' + local co = coroutine.create(function () + output = 'hi' + end) + like(co, '^thread: 0?[Xx]?%x+$', "basics") + + is(coroutine.status(co), 'suspended') + coroutine.resume(co) + is(output, 'hi') + is(coroutine.status(co), 'dead') + + error_like(function () coroutine.create(true) end, + "^[^:]+:%d+: bad argument #1 to 'create' %(.- expected") + + error_like(function () coroutine.resume(true) end, + "^[^:]+:%d+: bad argument #1 to 'resume' %(.- expected") + + error_like(function () coroutine.status(true) end, + "^[^:]+:%d+: bad argument #1 to 'status' %(.- expected") +end + +do + local output = {} + local co = coroutine.create(function () + for i=1,10 do + output[#output+1] = i + coroutine.yield() + end + end) + + coroutine.resume(co) + if has_running52 then + local thr, ismain = coroutine.running() + type_ok(thr, 'thread', "running") + is(ismain, true, "running") + else + local thr = coroutine.running() + is(thr, nil, "main thread") + end + is(coroutine.status(co), 'suspended', "basics") + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + coroutine.resume(co) + eq_array({coroutine.resume(co)}, {false, 'cannot resume dead coroutine'}) + eq_array(output, {1,2,3,4,5,6,7,8,9,10}) +end + +do + local co = coroutine.create(function (a,b) + coroutine.yield(a + b, a - b) + end) + + eq_array({coroutine.resume(co, 20, 10)}, {true, 30, 10}, "basics") +end + +do + local co = coroutine.create(function () + return 6, 7 + end) + + eq_array({coroutine.resume(co)}, {true, 6, 7}, "basics") +end + +if has_coroutine52 then + local co = coroutine.wrap(function(...) + return pcall(function(...) + return coroutine.yield(...) + end, ...) + end) + eq_array({co("Hello")}, {"Hello"}) + eq_array({co("World")}, {true, "World"}) +end + +if has_coroutine52 then + local co = coroutine.wrap(function(...) + local function backtrace () + return 'not a back trace' + end + return xpcall(function(...) + return coroutine.yield(...) + end, backtrace, ...) + end) + eq_array({co("Hello")}, {"Hello"}) + eq_array({co("World")}, {true, "World"}) +end + +if has_coroutine52 then + local output = {} + local co = coroutine.wrap(function() + while true do + local t = setmetatable({}, { + __eq = function(...) + return coroutine.yield(...) + end} + ) + local t2 = setmetatable({}, getmetatable(t)) + output[#output+1] = t == t2 + end + end) + co() + co(true) + co(false) + eq_array(output, {true, false}) +end + +if has_coroutine52 then + local co = coroutine.wrap(print) + type_ok(co, 'function') + + error_like(function () coroutine.wrap(true) end, + "^[^:]+:%d+: bad argument #1 to 'wrap' %(function expected, got boolean%)") + + co = coroutine.wrap(function () error"in coro" end) + error_like(function () co() end, + "^[^:]+:%d+: [^:]+:%d+: in coro$") +end + +do + local co = coroutine.create(function () + error "in coro" + end) + local r, msg = coroutine.resume(co) + is(r, false) + like(msg, "^[^:]+:%d+: in coro$") +end + +do + error_like(function () coroutine.yield() end, + "attempt to yield") + + if has_isyieldable then + is(coroutine.isyieldable(), false, "isyieldable") + else + is(coroutine.isyieldable, nil, "no coroutine.isyieldable") + end +end + +-- close +if has_close then + local output = '' + local co = coroutine.create(function () + output = 'hi' + end) + is(coroutine.close(co), true, "close") + is(coroutine.status(co), 'dead') + is(coroutine.close(co), true, "close again") + + error_like(function () coroutine.close(coroutine.running()) end, + "^[^:]+:%d+: cannot close a running coroutine") + + error_like(function () coroutine.close(42) end, + "^[^:]+:%d+: bad argument #1 to 'close' %(thread expected, got number%)") +else + is(coroutine.close, nil, "no coroutine.close") +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/221-table.t b/test/lua-Harness-tests/221-table.t new file mode 100755 index 0000000..c064a33 --- /dev/null +++ b/test/lua-Harness-tests/221-table.t @@ -0,0 +1,120 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua tables + +=head2 Synopsis + + % prove 221-table.t + +=head2 Description + +See section "Tables" in "Programming in Lua". + +=cut + +--]] + +require'tap' + +plan(25) + +do + local a = {} + local k = 'x' + a[k] = 10 + a[20] = 'great' + is(a['x'], 10) + k = 20 + is(a[k], 'great') + a['x'] = a ['x'] + 1 + is(a['x'], 11) +end + +do + local a = {} + a['x'] = 10 + local b = a + is(b['x'], 10) + b['x'] = 20 + is(a['x'], 20) + a = nil + b = nil +end + +do + local a = {} + for i=1,1000 do a[i] = i*2 end + is(a[9], 18) + a['x'] = 10 + is(a['x'], 10) + is(a['y'], nil) +end + +do + local a = {} + local x = 'y' + a[x] = 10 + is(a[x], 10) + is(a.x, nil) + is(a.y, 10) +end + +do + local i = 10; local j = '10'; local k = '+10' + local a = {} + a[i] = "one value" + a[j] = "another value" + a[k] = "yet another value" + is(a[j], "another value") + is(a[k], "yet another value") + is(a[tonumber(j)], "one value") + is(a[tonumber(k)], "one value") +end + +do + local t = { {'a','b','c'}, 10 } + is(t[2], 10) + is(t[1][3], 'c') + t[1][1] = 'A' + is(table.concat(t[1],','), 'A,b,c') +end + +do + local tt = { {'a','b','c'}, 10 } + is(tt[2], 10) + is(tt[1][3], 'c') + tt[1][1] = 'A' + is(table.concat(tt[1],','), 'A,b,c') +end + +do + local a = {} + error_like(function () a() end, + "^[^:]+:%d+: .- call") +end + +do + local tt = { {'a','b','c'}, 10 } + is((tt)[2], 10) + is((tt[1])[3], 'c'); + (tt)[1][2] = 'B' + (tt[1])[3] = 'C' + is(table.concat(tt[1],','), 'a,B,C') +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/222-constructor.t b/test/lua-Harness-tests/222-constructor.t new file mode 100755 index 0000000..a01be2e --- /dev/null +++ b/test/lua-Harness-tests/222-constructor.t @@ -0,0 +1,119 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Table Constructors + +=head2 Synopsis + + % prove 222-constructor.t + +=head2 Description + +See section "Table Constructors" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.5.7>, +L<https://www.lua.org/manual/5.2/manual.html#3.4.8>, +L<https://www.lua.org/manual/5.3/manual.html#3.4.9>, +L<https://www.lua.org/manual/5.4/manual.html#3.4.9> + +See section "Table Constructors" in "Programming in Lua". + +=cut + +--]] + +require'tap' + +plan(16) + +do --[[ list-style init ]] + local days = {'Sunday', 'Monday', 'Tuesday', 'Wednesday', + 'Thursday', 'Friday', 'Saturday'} + is(days[4], 'Wednesday', "list-style init") + is(#days, 7) +end + +do + local large = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 } + is(#large, 100) + large = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 } + is(#large, 200) +end + +do --[[ record-style init ]] + local a = {x=0, y=0} + is(a.x, 0, "record-style init") + is(a.y, 0) +end + +do + local w = {x=0, y=0, label='console'} + local x = {0, 1, 2} + w[1] = "another field" + x.f = w + is(w['x'], 0, "ctor") + is(w[1], "another field") + is(x.f[1], "another field") + w.x = nil +end + +do --[[ mix record-style and list-style init ]] + local polyline = {color='blue', thickness=2, npoints=4, + {x=0, y=0}, + {x=-10, y=0}, + {x=-10, y=1}, + {x=0, y=1} + } + is(polyline[2].x, -10, "mix record-style and list-style init") +end + +do + local opnames = {['+'] = 'add', ['-'] = 'sub', + ['*'] = 'mul', ['/'] = 'div'} + local i = 20; local s = '-' + local a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s} + is(opnames[s], 'sub', "ctor") + is(a[22], '---') +end + +do + local function f() return 10, 20 end + + eq_array({f()}, {10, 20}, "ctor") + eq_array({'a', f()}, {'a', 10, 20}) + eq_array({f(), 'b'}, {10, 'b'}) + eq_array({'c', (f())}, {'c', 10}) +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/223-iterator.t b/test/lua-Harness-tests/223-iterator.t new file mode 100755 index 0000000..777ad73 --- /dev/null +++ b/test/lua-Harness-tests/223-iterator.t @@ -0,0 +1,203 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua iterators + +=head2 Synopsis + + % prove 223-iterator.t + +=head2 Description + +See section "Iterators and the Generic for" and +section "Coroutines as Iterators" in "Programming in Lua". + +=cut + +--]] + +require'tap' + +plan(8) + +do --[[ list_iter ]] + local function list_iter (t) + local i = 0 + local n = #t + return function () + i = i + 1 + if i <= n then + return t[i] + else + return nil + end + end + end + + local t = {10, 20, 30} + local output = {} + for element in list_iter(t) do + output[#output+1] = element + end + eq_array(output, t, "list_iter") +end + +do --[[ values ]] + local function values (t) + local i = 0 + return function () + i = i + 1 + return t[i] + end + end + + local t = {10, 20, 30} + local output = {} + for element in values(t) do + output[#output+1] = element + end + eq_array(output, t, "values") +end + +do --[[ emul ipairs ]] + local function iter (a, i) + i = i + 1 + local v = a[i] + if v then + return i, v + end + end + + local function my_ipairs (a) + return iter, a, 0 + end + + local a = {'one', 'two', 'three'} + local output = {} + for i, v in my_ipairs(a) do + output[#output+1] = i + output[#output+1] = v + end + eq_array(output, {1, 'one', 2, 'two', 3, 'three'}, "emul ipairs") +end + +do --[[ emul pairs ]] + local function my_pairs (t) + return next, t, nil + end + + local a = {'one', 'two', 'three'} + local output = {} + for k, v in my_pairs(a) do + output[#output+1] = k + output[#output+1] = v + end + eq_array(output, {1, 'one', 2, 'two', 3, 'three'}, "emul ipairs") +end + +do --[[ with next ]] + local t = {'one', 'two', 'three'} + local output = {} + for k, v in next, t do + output[#output+1] = k + output[#output+1] = v + end + eq_array(output, {1, 'one', 2, 'two', 3, 'three'}, "with next") +end + +do --[[ permutations ]] + local function permgen (a, n) + n = n or #a -- default for 'n' is size of 'a' + if n <= 1 then -- nothing to change? + coroutine.yield(a) + else + for i=1,n do + -- put i-th element as the last one + a[n], a[i] = a[i], a[n] + -- generate all permutations of the other elements + permgen(a, n - 1) + -- restore i-th element + a[n], a[i] = a[i], a[n] + end + end + end + + local function permutations (a) + local co = coroutine.create(function () permgen(a) end) + return function () -- iterator + local code, res = coroutine.resume(co) + return res + end + end + + local output = {} + for p in permutations{'a', 'b', 'c'} do + output[#output+1] = table.concat(p, ' ') + end + eq_array(output, {'b c a','c b a','c a b','a c b','b a c','a b c'}, "permutations") +end + +do --[[ permutations with wrap ]] + local function permgen (a, n) + n = n or #a -- default for 'n' is size of 'a' + if n <= 1 then -- nothing to change? + coroutine.yield(a) + else + for i=1,n do + -- put i-th element as the last one + a[n], a[i] = a[i], a[n] + -- generate all permutations of the other elements + permgen(a, n - 1) + -- restore i-th element + a[n], a[i] = a[i], a[n] + end + end + end + + local function permutations (a) + return coroutine.wrap(function () permgen(a) end) + end + + local output = {} + for p in permutations{'a', 'b', 'c'} do + output[#output+1] = table.concat(p, ' ') + end + eq_array(output, {'b c a','c b a','c a b','a c b','b a c','a b c'}, "permutations with wrap") +end + +do --[[ fibo ]] + local function fibogen () + local x, y = 0, 1 + while true do + coroutine.yield(x) + x, y = y, x + y + end + end + + local function fibo () + return coroutine.wrap(function () fibogen() end) + end + + local output = {} + for n in fibo() do + output[#output+1] = n + if n > 30 then break end + end + eq_array(output, {0, 1, 1, 2, 3, 5, 8, 13, 21, 34}, "fibo") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/231-metatable.t b/test/lua-Harness-tests/231-metatable.t new file mode 100755 index 0000000..a2c6499 --- /dev/null +++ b/test/lua-Harness-tests/231-metatable.t @@ -0,0 +1,602 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua metatables + +=head2 Synopsis + + % prove 231-metatable.t + +=head2 Description + +See section "Metatables and Metamethods" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#2.8>, +L<https://www.lua.org/manual/5.2/manual.html#2.4>, +L<https://www.lua.org/manual/5.3/manual.html#2.4>, +L<https://www.lua.org/manual/5.4/manual.html#2.4> + +See section "Metatables and Metamethods" in "Programming in Lua". + +=cut + +--]] + +require'tap' +local profile = require'profile' +local has_metamethod52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_metamethod_ipairs = _VERSION == 'Lua 5.2' or profile.compat52 or profile.luajit_compat52 +local has_metamethod_le_emulated = _VERSION <= 'Lua 5.3' or profile.compat53 +local has_metamethod_pairs = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_metamethod_tostring53 = _VERSION >= 'Lua 5.3' +local has_metamethod_tostring54 = _VERSION >= 'Lua 5.4' +local has_anno_toclose = _VERSION >= 'Lua 5.4' + +plan'no_plan' + +do + local t = {} + is(getmetatable(t), nil, "metatable") + local t1 = {} + is(setmetatable(t, t1), t) + is(getmetatable(t), t1) + is(setmetatable(t, nil), t) + error_like(function () setmetatable(t, true) end, + "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected") + + local mt = {} + mt.__metatable = "not your business" + setmetatable(t, mt) + is(getmetatable(t), "not your business", "protected metatable") + error_like(function () setmetatable(t, {}) end, + "^[^:]+:%d+: cannot change a protected metatable") + + is(getmetatable('').__index, string, "metatable for string") + + is(getmetatable(nil), nil, "metatable for nil") + is(getmetatable(false), nil, "metatable for boolean") + is(getmetatable(2), nil, "metatable for number") + is(getmetatable(print), nil, "metatable for function") +end + +do + local t = {} + local mt = { __tostring=function () return '__TABLE__' end } + setmetatable(t, mt) + is(tostring(t), '__TABLE__', "__tostring") +end + +do + local t = {} + local mt = {} + local a = nil + function mt.__tostring () a = "return nothing" end + setmetatable(t, mt) + if has_metamethod_tostring53 then + error_like(function () tostring(t) end, + "^[^:]+:%d+: '__tostring' must return a string") + is(a, "return nothing") + if has_metamethod_tostring54 then + error_like(function () print(t) end, + "^[^:]+:%d+: '__tostring' must return a string") + else + error_is(function () print(t) end, + "'__tostring' must return a string") + end + else + is(tostring(t), nil, "__tostring no-output") + is(a, "return nothing") + error_like(function () print(t) end, + "^[^:]+:%d+: 'tostring' must return a string to 'print'") + end + + mt.__tostring = function () return '__FIRST__', 2 end + setmetatable(t, mt) + is(tostring(t), '__FIRST__', "__tostring too-many-output") +end + +do + local t = {} + t.mt = {} + setmetatable(t, t.mt) + t.mt.__tostring = "not a function" + error_like(function () tostring(t) end, + "attempt to call", + "__tostring invalid") +end + +do + local t = {} + local mt = { __len=function () return 42 end } + setmetatable(t, mt) + if has_metamethod52 then + is(#t, 42, "__len") + else + is(#t, 0, "__len 5.1") + end +end + +if has_metamethod52 then + local t = {} + local mt = { __len=function () return nil end } + setmetatable(t, mt) + if jit then + todo("not with LuaJIT") + end + error_like(function () print(table.concat(t)) end, + "object length is not a.-er", + "__len invalid") +end + +do + local t = {} + local mt = { + __tostring=function () return 't' end, + __concat=function (op1, op2) + return tostring(op1) .. '|' .. tostring(op2) + end, + } + setmetatable(t, mt) + is(t .. t .. t ..'end' .. '.', "t|t|t|end.", "__concat") +end + +do --[[ Cplx ]] + local Cplx = {} + Cplx.mt = {} + local tointeger = math.tointeger or math.floor + + function Cplx.new (re, im) + local c = {} + setmetatable(c, Cplx.mt) + c.re = tonumber(re) + if im == nil then + c.im = 0.0 + else + c.im = tonumber(im) + end + return c + end + + function Cplx.mt.__tostring (c) + return '(' .. tostring(tointeger(c.re)) .. ',' .. tostring(tointeger(c.im)) .. ')' + end + + function Cplx.mt.__add (a, b) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + if type(b) ~= 'table' then + b = Cplx.new(b, 0) + end + local r = Cplx.new(a.re + b.re, a.im + b.im) + return r + end + + local c1 = Cplx.new(1, 3) + local c2 = Cplx.new(2, -1) + + is(tostring(c1 + c2), '(3,2)', "cplx __add") + is(tostring(c1 + 3), '(4,3)') + is(tostring(-2 + c1), '(-1,3)') + is(tostring(c1 + '3'), '(4,3)') + is(tostring('-2' + c1), '(-1,3)') + + function Cplx.mt.__sub (a, b) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + if type(b) ~= 'table' then + b = Cplx.new(b, 0) + end + local r = Cplx.new(a.re - b.re, a.im - b.im) + return r + end + + is(tostring(c1 - c2), '(-1,4)', "cplx __sub") + is(tostring(c1 - 3), '(-2,3)') + is(tostring(-2 - c1), '(-3,-3)') + is(tostring(c1 - '3'), '(-2,3)') + is(tostring('-2' - c1), '(-3,-3)') + + function Cplx.mt.__mul (a, b) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + if type(b) ~= 'table' then + b = Cplx.new(b, 0) + end + local r = Cplx.new(a.re*b.re - a.im*b.im, + a.re*b.im + a.im*b.re) + return r + end + + is(tostring(c1 * c2), '(5,5)', "cplx __mul") + is(tostring(c1 * 3), '(3,9)') + is(tostring(-2 * c1), '(-2,-6)') + is(tostring(c1 * '3'), '(3,9)') + is(tostring('-2' * c1), '(-2,-6)') + + function Cplx.mt.__div (a, b) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + if type(b) ~= 'table' then + b = Cplx.new(b, 0) + end + local n = b.re*b.re + b.im*b.im + local inv = Cplx.new(b.re/n, b.im/n) + local r = Cplx.new(a.re*inv.re - a.im*inv.im, + a.re*inv.im + a.im*inv.re) + return r + end + + c1 = Cplx.new(2, 6) + c2 = Cplx.new(2, 0) + + is(tostring(c1 / c2), '(1,3)', "cplx __div") + is(tostring(c1 / 2), '(1,3)') + is(tostring(-4 / c2), '(-2,0)') + is(tostring(c1 / '2'), '(1,3)') + is(tostring('-4' / c2), '(-2,0)') + + function Cplx.mt.__unm (a) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + local r = Cplx.new(-a.re, -a.im) + return r + end + + c1 = Cplx.new(1, 3) + is(tostring(- c1), '(-1,-3)', "cplx __unm") + + function Cplx.mt.__len (a) + return math.sqrt(a.re*a.re + a.im*a.im) + end + + c1 = Cplx.new(3, 4) + if has_metamethod52 then + is( #c1, 5, "cplx __len") + else + is( #c1, 0, "__len 5.1") + end + + function Cplx.mt.__eq (a, b) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + if type(b) ~= 'table' then + b = Cplx.new(b, 0) + end + return (a.re == b.re) and (b.im == b.im) + end + + c1 = Cplx.new(2, 0) + c2 = Cplx.new(1, 3) + local c3 = Cplx.new(2, 0) + + is(c1 ~= c2, true, "cplx __eq") + is(c1 == c3, true) + is(c1 == 2, false) + is(Cplx.mt.__eq(c1, 2), true) + + function Cplx.mt.__lt (a, b) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + if type(b) ~= 'table' then + b = Cplx.new(b, 0) + end + local ra = a.re*a.re + a.im*a.im + local rb = b.re*b.re + b.im*b.im + return ra < rb + end + + is(c1 < c2, true, "cplx __lt") + is(c1 < c3, false) + if has_metamethod_le_emulated then + is(c1 <= c3, true) + end + if has_metamethod52 then + is(c1 < 1, false) + is(c1 < 4, true) + end + + function Cplx.mt.__le (a, b) + if type(a) ~= 'table' then + a = Cplx.new(a, 0) + end + if type(b) ~= 'table' then + b = Cplx.new(b, 0) + end + local ra = a.re*a.re + a.im*a.im + local rb = b.re*b.re + b.im*b.im + return ra <= rb + end + + is(c1 < c2, true, "cplx __lt __le") + is(c1 < c3, false) + is(c1 <= c3, true) + + local a = nil + function Cplx.mt.__call (obj) + a = "Cplx.__call " .. tostring(obj) + return true + end + + c1 = Cplx.new(2, 0) + local r = c1() + is(r, true, "cplx __call (without args)") + is(a, "Cplx.__call (2,0)") + + function Cplx.mt.__call (obj, ...) + a = "Cplx.__call " .. tostring(obj) .. ", " .. table.concat({...}, ", ") + return true + end + + is(c1(), true, "cplx __call (with args)") + is(a, "Cplx.__call (2,0), ") + is(c1('a'), true) + is(a, "Cplx.__call (2,0), a") + is(c1('a', 'b', 'c'), true) + is(a, "Cplx.__call (2,0), a, b, c") +end + +--[[ delegate ]] +if has_metamethod_pairs then + local t = { + _VALUES = { + a = 1, + b = 'text', + c = true, + } + } + local mt = { + __pairs = function (op) + return next, op._VALUES + end + } + setmetatable(t, mt) + + local r = {} + for k in pairs(t) do + r[#r+1] = k + end + table.sort(r) + is( table.concat(r, ','), 'a,b,c', "__pairs" ) +end +if has_metamethod_ipairs then + local t = { + _VALUES = { 'a', 'b', 'c' } + } + local mt = { + __ipairs = function (op) + return ipairs(op._VALUES) + end + } + setmetatable(t, mt) + + local r = '' + for i, v in ipairs(t) do + r = r .. v + end + is( r, 'abc', "__ipairs" ) +end + +do --[[ Window ]] + -- create a namespace + local Window = {} + -- create a prototype with default values + Window.prototype = {x=0, y=0, width=100, heigth=100, } + -- create a metatable + Window.mt = {} + -- declare the constructor function + function Window.new (o) + setmetatable(o, Window.mt) + return o + end + + Window.mt.__index = function (table, key) + return Window.prototype[key] + end + + local w = Window.new{x=10, y=20} + is(w.x, 10, "table-access") + is(w.width, 100) + is(rawget(w, 'x'), 10) + is(rawget(w, 'width'), nil) + + Window.mt.__index = Window.prototype -- just a table + w = Window.new{x=10, y=20} + is(w.x, 10, "table-access") + is(w.width, 100) + is(rawget(w, 'x'), 10) + is(rawget(w, 'width'), nil) +end + +do --[[ tables with default values ]] + local function setDefault_1 (t, d) + local mt = {__index = function () return d end} + setmetatable (t, mt) + end + + local tab = {x=10, y=20} + is(tab.x, 10, "tables with default values") + is(tab.z, nil) + setDefault_1(tab, 0) + is(tab.x, 10) + is(tab.z, 0) +end + +do --[[ tables with default values ]] + local mt = {__index = function (t) return t.___ end} + local function setDefault_2 (t, d) + t.___ = d + setmetatable (t, mt) + end + + local tab = {x=10, y=20} + is(tab.x, 10, "tables with default values") + is(tab.z, nil) + setDefault_2(tab, 0) + is(tab.x, 10) + is(tab.z, 0) +end + +do --[[ tables with default values ]] + local key = {} + local mt = {__index = function (t) return t[key] end} + local function setDefault_3 (t, d) + t[key] = d + setmetatable (t, mt) + end + + local tab = {x=10, y=20} + is(tab.x, 10, "tables with default values") + is(tab.z, nil) + setDefault_3(tab, 0) + is(tab.x, 10) + is(tab.z, 0) +end + +do --[[ private access ]] + local t = {} -- original table + -- keep a private access to original table + local _t = t + -- create proxy + t = {} + + local w = nil + local r = nil + -- create metatable + local mt = { + __index = function (t,k) + r = "*access to element " .. tostring(k) + return _t[k] -- access the original table + end, + + __newindex = function (t,k,v) + w = "*update of element " .. tostring(k) .. + " to " .. tostring(v) + _t[k] = v -- update original table + end + } + setmetatable(t, mt) + + t[2] = 'hello' + is(t[2], 'hello', "tracking table accesses") + is(w, "*update of element 2 to hello") + is(r, "*access to element 2") +end + +do --[[ private access ]] + -- create private index + local index = {} + + local w = nil + local r = nil + -- create metatable + local mt = { + __index = function (t,k) + r = "*access to element " .. tostring(k) + return t[index][k] -- access the original table + end, + + __newindex = function (t,k,v) + w = "*update of element " .. tostring(k) .. + " to " .. tostring(v) + t[index][k] = v -- update original table + end + } + local function track (t) + local proxy = {} + proxy[index] = t + setmetatable(proxy, mt) + return proxy + end + + local t = {} + t = track(t) + + t[2] = 'hello' + is(t[2], 'hello', "tracking table accesses") + is(w, "*update of element 2 to hello") + is(r, "*access to element 2") +end + +do --[[ read-only table ]] + local function readOnly (t) + local proxy = {} + local mt = { + __index = t, + __newindex = function (_t,k,v) + error("attempt to update a read-only table", 2) + end + } + setmetatable(proxy, mt) + return proxy + end + + local days = readOnly{'Sunday', 'Monday', 'Tuesday', 'Wednesday', + 'Thurday', 'Friday', 'Saturday'} + + is(days[1], 'Sunday', "read-only tables") + + error_like(function () days[2] = 'Noday' end, + "^[^:]+:%d+: attempt to update a read%-only table") +end + +do --[[ declare global ]] + local function declare (name, initval) + rawset(_G, name, initval or false) + end + + setmetatable(_G, { + __newindex = function (_, n) + error("attempt to write to undeclared variable " .. n, 2) + end, + __index = function (_, n) + error("attempt to read undeclared variable" .. n, 2) + end, + }) + + error_like(function () new_a = 1 end, + "^[^:]+:%d+: attempt to write to undeclared variable new_a", + "declaring global variables") + + declare 'new_a' + new_a = 1 + is(new_a, 1) +end + +do + local newindex = {} + -- create metatable + local mt = { + __newindex = newindex + } + local t = setmetatable({}, mt) + t[1] = 42 + is(newindex[1], 42, "__newindex") +end + +if has_anno_toclose then + dofile'lexico54/metatable.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/232-object.t b/test/lua-Harness-tests/232-object.t new file mode 100755 index 0000000..0d87572 --- /dev/null +++ b/test/lua-Harness-tests/232-object.t @@ -0,0 +1,314 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua object + +=head2 Synopsis + + % prove 232-object.t + +=head2 Description + +See section "Object-Oriented Programming" in "Programming in Lua". + +=cut + +--]] + +require'tap' + +plan(18) + +do --[[ object ]] + local Account = {balance = 0} + + function Account.withdraw (self, v) + self.balance = self.balance - v + end + + local a1 = Account; Account = nil + a1.withdraw(a1, 100.00) + is(a1.balance, -100, "object") + + local a2 = {balance = 0, withdraw = a1.withdraw} + a2.withdraw(a2, 260.00) + is(a2.balance, -260) +end + +do --[[ object ]] + local Account = {balance = 0} + + function Account:withdraw (v) + self.balance = self.balance - v + end + + local a = Account + a:withdraw(100.00) + is(a.balance, -100, "object") + + Account = { balance = 0, + withdraw = function (self, v) + self.balance = self.balance -v + end + } + function Account:deposit (v) + self.balance = self.balance + v + end + + Account.deposit(Account, 200.00) + is(Account.balance, 200, "object") + Account:withdraw(100.00) + is(Account.balance, 100) +end + +do --[[ class ]] + local Account = {balance = 0} + + function Account:new (o) + o = o or {} + setmetatable(o, self) + self.__index = self + return o + end + + function Account:deposit (v) + self.balance = self.balance + v + end + + function Account:withdraw (v) + self.balance = self.balance - v + end + + local a = Account:new{balance = 0} + a:deposit(100.00) + is(a.balance, 100, "classe") + + local b = Account:new() + is(b.balance, 0) + b:deposit(200.00) + is(b.balance, 200) +end + +do --[[ inheritance ]] + local Account = {balance = 0} + + function Account:new (o) + -- print "Account:new" + o = o or {} + setmetatable(o, self) + self.__index = self + return o + end + + function Account:deposit (v) + -- print "Account:deposit" + self.balance = self.balance + v + end + + function Account:withdraw (v) + -- print "Account:withdraw" + if v > self.balance then error"insuficient funds" end + self.balance = self.balance - v + end + + local a = Account:new() + is(a.balance, 0, "inheritance") + -- r, msg = pcall(Account.withdraw, a, 100) + -- print(msg) + + local SpecialAccount = Account:new() + + function SpecialAccount:withdraw (v) + -- print "SpecialAccount:withdraw" + if self.balance - v <= -self:getLimit() then + error"insuficient funds" + end + self.balance = self.balance - v + end + + function SpecialAccount:getLimit () + -- print "SpecialAccount:getLimit" + return self.limit or 0 + end + + local s = SpecialAccount:new{limit=1000.00} + + s:deposit(100.00) + is(s.balance, 100) + + s:withdraw(200.00) + is(s.balance, -100) +end + +do --[[ multiple inheritance ]] + -- look up for 'k' in list of tables 'plist' + local function search (k, plist) + for i=1, #plist do + local v = plist[i][k] -- try 'i'-th superclass + if v then return v end + end + end + + local function createClass (...) + local c = {} -- new class + local arg = {...} + + -- class will search for each method in the list of its + -- parents ('arg' is the list of parents) + setmetatable(c, {__index = function (t, k) + return search(k, arg) + end}) + + -- prepare 'c' to be the metatable of its instance + c.__index = c + + -- define a new constructor for this new class + function c:new (o) + o = o or {} + setmetatable(o, c) + return o + end + + -- return new class + return c + end + + local Account = {balance = 0} + function Account:deposit (v) + self.balance = self.balance + v + end + function Account:withdraw (v) + self.balance = self.balance - v + end + + local Named = {} + function Named:getname () + return self.name + end + function Named:setname (n) + self.name = n + end + + local NamedAccount = createClass(Account, Named) + + local account = NamedAccount:new{name = "Paul"} + is(account:getname(), 'Paul', "multiple inheritance") + account:deposit(100.00) + is(account.balance, 100) +end + +do --[[ multiple inheritance (patched) ]] + -- look up for 'k' in list of tables 'plist' + local function search (k, plist) + for i=1, #plist do + local v = plist[i][k] -- try 'i'-th superclass + if v then return v end + end + end + + local function createClass (...) + local c = {} -- new class + local arg = {...} + + -- class will search for each method in the list of its + -- parents ('arg' is the list of parents) + setmetatable(c, {__index = function (t, k) + -- return search(k, arg) + return (search(k, arg)) + end}) + + -- prepare 'c' to be the metatable of its instance + c.__index = c + + -- define a new constructor for this new class + function c:new (o) + o = o or {} + setmetatable(o, c) + return o + end + + -- return new class + return c + end + + local Account = {balance = 0} + function Account:deposit (v) + self.balance = self.balance + v + end + function Account:withdraw (v) + self.balance = self.balance - v + end + + local Named = {} + function Named:getname () + return self.name + end + function Named:setname (n) + self.name = n + end + + local NamedAccount = createClass(Account, Named) + + local account = NamedAccount:new{name = "Paul"} + is(account:getname(), 'Paul', "multiple inheritance (patched)") + account:deposit(100.00) + is(account.balance, 100) +end + +do --[[ privacy ]] + local function newAccount (initialBalance) + local self = {balance = initialBalance} + + local withdraw = function (v) + self.balance = self.balance - v + end + + local deposit = function (v) + self.balance = self.balance + v + end + + local getBalance = function () return self.balance end + + return { + withdraw = withdraw, + deposit = deposit, + getBalance = getBalance + } + end + + local acc1 = newAccount(100.00) + acc1.withdraw(40.00) + is(acc1.getBalance(), 60, "privacy") +end + +do --[[ single-method approach ]] + local function newObject (value) + return function (action, v) + if action == 'get' then return value + elseif action == 'set' then value = v + else error("invalid action") + end + end + end + + local d = newObject(0) + is(d('get'), 0, "single-method approach") + d('set', 10) + is(d('get'), 10) +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/241-standalone.t b/test/lua-Harness-tests/241-standalone.t new file mode 100755 index 0000000..c5237ee --- /dev/null +++ b/test/lua-Harness-tests/241-standalone.t @@ -0,0 +1,269 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Stand-alone + +=head2 Synopsis + + % prove 241-standalone.t + +=head2 Description + +See section "Lua Stand-alone" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#6>, +L<https://www.lua.org/manual/5.2/manual.html#7>, +L<https://www.lua.org/manual/5.3/manual.html#7>, +L<https://www.lua.org/manual/5.4/manual.html#7> + +=cut + +--]] + +require'tap' +local has_bytecode = not ujit and not ravi +local has_error52 = _VERSION >= 'Lua 5.2' +local has_error53 = _VERSION >= 'Lua 5.3' +local has_opt_E = _VERSION >= 'Lua 5.2' or jit +local has_opt_W = _VERSION >= 'Lua 5.4' +local banner = '^[%w%s%-%.]-Copyright %(C%) %d%d%d%d' +if jit and jit.version:match'^RaptorJIT' then + banner = '^[%w%s%.]- %-%- ' +elseif ravi then + banner = '^Ravi %d%.%d%.%d' +end + +local lua = get_lua_binary_name() +local luac = jit and lua or (lua .. 'c') + +if not pcall(io.popen, lua .. [[ -e "a=1"]]) then + skip_all "io.popen not supported" +end + +plan'no_plan' +diag(lua) + +local f = io.open('hello-241.lua', 'w') +f:write([[ +print 'Hello World' +]]) +f:close() + +local cmd = lua .. " hello-241.lua" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "file") +f:close() + +cmd = lua .. " -- hello-241.lua" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "-- file") +f:close() + +cmd = lua .. " no_file-241.lua 2>&1" +f = io.popen(cmd) +like(f:read'*l', "^[^:]+: cannot open no_file%-241%.lua", "no file") +f:close() + +if has_bytecode then + if jit then + os.execute(lua .. " -b hello-241.lua hello-241.luac") + else + os.execute(luac .. " -s -o hello-241.luac hello-241.lua") + end + cmd = lua .. " hello-241.luac" + f = io.popen(cmd) + is(f:read'*l', 'Hello World', "bytecode") + f:close() + os.remove('hello-241.luac') -- clean up + + if not jit then + os.execute(luac .. " -s -o hello-hello-241.luac hello-241.lua hello-241.lua") + cmd = lua .. " hello-hello-241.luac" + f = io.popen(cmd) + is(f:read'*l', 'Hello World', "combine 1") + is(f:read'*l', 'Hello World', "combine 2") + f:close() + os.remove('hello-hello-241.luac') -- clean up + end +end + +cmd = lua .. " < hello-241.lua" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "redirect") +f:close() + +cmd = lua .. " - < hello-241.lua" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "redirect") +f:close() + +cmd = lua .. " -i hello-241.lua < hello-241.lua 2>&1" +f = io.popen(cmd) +like(f:read'*l', banner, "-i") +if ujit then + like(f:read'*l', '^JIT:') +end +if ravi then + like(f:read'*l', '^Copyright %(C%)') + like(f:read'*l', '^Portions Copyright %(C%)') + like(f:read'*l', '^Options') +end +is(f:read'*l', 'Hello World') +f:close() + +cmd = lua .. [[ -e"a=1" -e "print(a)"]] +f = io.popen(cmd) +is(f:read'*l', '1', "-e") +f:close() + +cmd = lua .. [[ -e "error('msg')" 2>&1]] +f = io.popen(cmd) +is(f:read'*l', lua .. [[: (command line):1: msg]], "error") +is(f:read'*l', "stack traceback:", "backtrace") +f:close() + +cmd = lua .. [[ -e "error(setmetatable({}, {__tostring=function() return 'MSG' end}))" 2>&1]] +f = io.popen(cmd) +if has_error52 or jit then + is(f:read'*l', lua .. [[: MSG]], "error with object") +else + is(f:read'*l', lua .. [[: (error object is not a string)]], "error with object") +end +if jit then + is(f:read'*l', "stack traceback:", "backtrace") +else + is(f:read'*l', nil, "not backtrace") +end +f:close() + +cmd = lua .. [[ -e "error{}" 2>&1]] +f = io.popen(cmd) +if has_error53 then + is(f:read'l', lua .. [[: (error object is a table value)]], "error") + is(f:read'l', "stack traceback:", "backtrace") +elseif has_error52 then + is(f:read'*l', lua .. [[: (no error message)]], "error") + is(f:read'*l', nil, "not backtrace") +else + is(f:read'*l', lua .. [[: (error object is not a string)]], "error") + is(f:read'*l', nil, "not backtrace") +end +f:close() + +cmd = lua .. [[ -e"a=1" -e "print(a)" hello-241.lua]] +f = io.popen(cmd) +is(f:read'*l', '1', "-e & script") +is(f:read'*l', 'Hello World') +f:close() + +cmd = lua .. [[ -e"a=1" -i < hello-241.lua 2>&1]] +f = io.popen(cmd) +like(f:read'*l', banner, "-e & -i") +f:close() + +cmd = lua .. [[ -e "?syntax error?" 2>&1]] +f = io.popen(cmd) +like(f:read'*l', "^.-%d: unexpected symbol near '%?'", "-e bad") +f:close() + +cmd = lua .. [[ -e 2>&1]] +f = io.popen(cmd) +if _VERSION ~= 'Lua 5.1' then + like(f:read'*l', "^[^:]+: '%-e' needs argument", "no file") +end +like(f:read'*l', "^usage: ", "no file") +f:close() + +cmd = lua .. [[ -v 2>&1]] +f = io.popen(cmd) +like(f:read'*l', banner, "-v") +f:close() + +cmd = lua .. [[ -v hello-241.lua 2>&1]] +f = io.popen(cmd) +like(f:read'*l', banner, "-v & script") +if ravi then + like(f:read'*l', '^Copyright %(C%)') + like(f:read'*l', '^Portions Copyright %(C%)') + like(f:read'*l', '^Options') +end +is(f:read'*l', 'Hello World') +f:close() + +cmd = lua .. [[ -v -- 2>&1]] +f = io.popen(cmd) +like(f:read'*l', banner, "-v --") +f:close() + +if has_opt_E then + cmd = lua .. [[ -E hello-241.lua 2>&1]] + f = io.popen(cmd) + is(f:read'*l', 'Hello World', "-E") + f:close() +else + diag("no -E") +end + +cmd = lua .. [[ -u 2>&1]] +f = io.popen(cmd) +if _VERSION ~= 'Lua 5.1' then + like(f:read'*l', "^[^:]+: unrecognized option '%-u'", "unknown option") +end +like(f:read'*l', "^usage: ", "no file") +f:close() + +cmd = lua .. [[ --u 2>&1]] +f = io.popen(cmd) +if _VERSION ~= 'Lua 5.1' then + like(f:read'*l', "^[^:]+: unrecognized option '%-%-u'", "unknown option") +end +like(f:read'*l', "^usage: ", "no file") +f:close() + +cmd = lua .. [[ -ltap -e "print(type(ok))"]] +f = io.popen(cmd) +is(f:read'*l', 'function', "-ltap") +f:close() + +cmd = lua .. [[ -l tap -e "print(type(ok))"]] +f = io.popen(cmd) +is(f:read'*l', 'function', "-l tap") +f:close() + +cmd = lua .. [[ -l lpeg -e "print(1)" 2>&1]] +f = io.popen(cmd) +isnt(f:read'*l', nil, "-l lpeg") +f:close() + +cmd = lua .. [[ -l no_lib hello-241.lua 2>&1]] +f = io.popen(cmd) +like(f:read'*l', "^[^:]+: module 'no_lib' not found:", "-l no lib") +f:close() + +if has_opt_W then + cmd = lua .. [[ -W -e "warn'foo'" 2>&1]] + f = io.popen(cmd) + is(f:read'*l', 'Lua warning: foo', "-W") + is(f:read'*l', nil) + f:close() +else + diag("no -W") +end + +os.remove('hello-241.lua') -- clean up +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/242-luac.t b/test/lua-Harness-tests/242-luac.t new file mode 100755 index 0000000..a95a334 --- /dev/null +++ b/test/lua-Harness-tests/242-luac.t @@ -0,0 +1,341 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2010-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Stand-alone + +=head2 Synopsis + + % prove t/242-luac.t + +=head2 Description + +See section "Lua Stand-alone" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#6>, +L<https://www.lua.org/manual/5.2/manual.html#7>, +L<https://www.lua.org/manual/5.3/manual.html#7>, +L<https://www.lua.org/manual/5.4/manual.html#7> + +=cut + +--]] + +require'tap' + +if jit then + skip_all("LuaJIT") +end + +if ravi then + skip_all("ravi") +end + +local lua = get_lua_binary_name() +local luac = lua .. 'c' + +if not pcall(io.popen, lua .. [[ -e "a=1"]]) then + skip_all "io.popen not supported" +end + +plan'no_plan' +diag(luac) + +local signature = "\x1bLua" +local bin_version +if _VERSION == 'Lua 5.1' then + bin_version = "\x51" +elseif _VERSION == 'Lua 5.2' then + bin_version = "\x52" +elseif _VERSION == 'Lua 5.3' then + bin_version = "\x53" +elseif _VERSION == 'Lua 5.4' then + bin_version = "\x54" +end +local format = "\x00" +local data = "\x19\x93\r\n\x1a\n" +local size_i = string.char(string.packsize and string.packsize'i' or 0) -- int +local size_T = string.char(string.packsize and string.packsize'T' or 0) -- size_t +local size_I = string.char(string.packsize and string.packsize'I' or 0) -- Instruction +local size_j = string.char(string.packsize and string.packsize'j' or 0) -- lua_Integer +local size_n = string.char(string.packsize and string.packsize'n' or 0) -- lua_Number +local sizes = size_i .. size_T .. size_I .. size_j .. size_n + +do -- hello.lua + local f = io.open('hello-242.lua', 'w') + f:write([[ +print 'Hello World' +]]) + f:close() +end + +do -- luac -v + local cmd = luac .. [[ -v 2>&1]] + local f = io.popen(cmd) + like(f:read'*l', '^Lua', "-v") + f:close() +end + +do -- luac -v -- + local cmd = luac .. [[ -v -- 2>&1]] + local f = io.popen(cmd) + like(f:read'*l', '^Lua', "-v --") + f:close() +end + +do -- luac -u + local cmd = luac .. [[ -u 2>&1]] + local f = io.popen(cmd) + like(f:read'*l', "^[^:]+: unrecognized option '%-u'", "unknown option") + like(f:read'*l', "^usage:") + f:close() +end + +do -- luac --u + local cmd = luac .. [[ --u 2>&1]] + local f = io.popen(cmd) + like(f:read'*l', "^[^:]+: unrecognized option '%-%-u'", "unknown option") + like(f:read'*l', "^usage:") + f:close() +end + +do -- luac -p hello-242.lua + local cmd = luac .. [[ -p hello-242.lua 2>&1]] + local f = io.popen(cmd) + is(f:read'*l', nil) + f:close() +end + +do -- luac -p - < hello-242.lua + local cmd = luac .. [[ -p - < hello-242.lua 2>&1]] + local f = io.popen(cmd) + is(f:read'*l', nil) + f:close() +end + +do -- luac -p no_file-242.lua + local cmd = luac .. [[ -p no_file-242.lua 2>&1]] + local f = io.popen(cmd) + like(f:read'*l', "^[^:]+: cannot open no_file%-242%.lua", "no file") + f:close() +end + +do -- luac -o + local cmd = luac .. [[ -o 2>&1]] + local f = io.popen(cmd) + like(f:read'*l', "^[^:]+: '%-o' needs argument", "-o needs argument") + f:close() +end + +do -- luac -v -l -l hello-242.lua + local cmd = luac .. [[ -v -l -l hello-242.lua]] + local f = io.popen(cmd) + like(f:read'*l', '^Lua', "-v -l -l") + is(f:read'*l', '') + like(f:read'*l', "^main") + f:close() +end + +os.remove('hello-242.lua') -- clean up + +do -- luac -l luac.out + local cmd = luac .. [[ -l luac.out]] + local f = io.popen(cmd) + is(f:read'*l', '', "-l luac.out") + like(f:read'*l', "^main") + f:close() +end + +do -- luac -l + local cmd = luac .. [[ -l]] + local f = io.popen(cmd) + is(f:read'*l', '', "-l") + like(f:read'*l', "^main") + f:close() +end + +do -- luac -l - < luac.out + local cmd = luac .. [[ -l - < luac.out]] + local f = io.popen(cmd) + is(f:read'*l', '', "-l -") + like(f:read'*l', "^main") + f:close() +end + +if _VERSION ~= 'Lua 5.1' then + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. format) + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + if _VERSION <= 'Lua 5.3' then + like(f:read'*l', "truncated precompiled chunk") + else + like(f:read'*l', "bad binary format %(truncated chunk%)") + end + f:close() +end + +if _VERSION ~= 'Lua 5.1' then -- bad signature + local f = io.open('luac.out', 'w') + f:write("\x1bFoo" .. bin_version .. format .. data .. sizes .. "Foo") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + if _VERSION <= 'Lua 5.3' then + like(f:read'*l', "not a precompiled chunk", "bad signature") + else + like(f:read'*l', "bad binary format %(not a binary chunk%)", "bad signature") + end + f:close() +end + +if _VERSION ~= 'Lua 5.1' then -- bad version + local f = io.open('luac.out', 'w') + f:write(signature .. "\x51" .. format .. data .. sizes .. "Foo") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + if _VERSION <= 'Lua 5.3' then + like(f:read'*l', "version mismatch in precompiled chunk", "bad version") + else + like(f:read'*l', "bad binary format %(version mismatch%)", "bad version") + end + f:close() +end + +if _VERSION ~= 'Lua 5.1' then -- bad format + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. "\x42" .. data .. sizes .. "Foo") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + if _VERSION == 'Lua 5.2' then + like(f:read'*l', "version mismatch in precompiled chunk", "bad format") + elseif _VERSION == 'Lua 5.3' then + like(f:read'*l', "format mismatch in precompiled chunk", "bad format") + else + like(f:read'*l', "bad binary format %(format mismatch%)", "bad format") + end + f:close() +end + +if _VERSION == 'Lua 5.2' then -- bad sizes + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. format .. "\xde\xad\xbe\xef\x00" .. data .. "Foo") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + like(f:read'*l', "incompatible precompiled chunk", "incompatible 5.2") + f:close() +end + +if _VERSION == 'Lua 5.2' then -- bad data / tail + sizes = string.dump(load "a = 1"):sub(7, 12) + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. format .. sizes .. "\x19\x99\r\n\x1a\n") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + like(f:read'*l', "corrupted precompiled chunk", "corrupted 5.2") + f:close() +end + +if _VERSION == 'Lua 5.3' then -- bad data + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. format .. "\x19\x99\r\n\x1a\n" .. sizes) + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + like(f:read'*l', "corrupted precompiled chunk", "corrupted") + f:close() +end + +if _VERSION == 'Lua 5.3' then -- bad sizes + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. format .. data .. "\xde\xad\xbe\xef\x00") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + like(f:read'*l', "int size mismatch in precompiled chunk", "bad sizes") + f:close() +end + +if _VERSION == 'Lua 5.3' then -- bad endianess + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. format .. data .. sizes .. "\0\0\0\0\0\0\0\0") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + like(f:read'*l', "endianness mismatch in precompiled chunk", "bad endian") + f:close() +end + +if _VERSION == 'Lua 5.3' then -- bad float format + local endian = string.dump(load "a = 1"):sub(18, 18 + string.packsize'n') + local f = io.open('luac.out', 'w') + f:write(signature .. bin_version .. format .. data .. sizes .. endian .. "\0\0\0\0\0\0\0\0") + f:close() + local cmd = luac .. [[ luac.out 2>&1]] + f = io.popen(cmd) + like(f:read'*l', "float format mismatch in precompiled chunk") + f:close() +end + +do -- cover.lua + local f = io.open('cover-242.lua', 'w') + f:write([[ +local a = false +b = a + 1 +pi = 3.14 +s = "all escaped \1\a\b\f\n\r\t\v\\\"" +local t = { "a", "b", "c", "d", [true] = 1 } +local f = table.concat +local function f () + while true do + print(a) + end +end +local function g (...) -- segfault with Lua 5.4.0-beta + return {...} +end +s = nil +]]) + f:close() + + local cmd = luac .. [[ -o cover-242.out cover-242.lua 2>&1]] + f = io.popen(cmd) + is(f:read'*l', nil, "-o cover-242.out cover-242.lua") + f:close() + + cmd = luac .. [[ -l cover-242.out]] + f = io.popen(cmd) + is(f:read'*l', '', "-l cover-242.out") + like(f:read'*l', "^main") + f:close() + + cmd = luac .. [[ -l -l cover-242.out]] + f = io.popen(cmd) + is(f:read'*l', '', "-l -l cover-242.out") + like(f:read'*l', "^main") + f:close() +end + +os.remove('luac.out') -- clean up +os.remove('cover-242.lua') -- clean up +os.remove('cover-242.out') -- clean up +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/301-basic.t b/test/lua-Harness-tests/301-basic.t new file mode 100755 index 0000000..f4f9235 --- /dev/null +++ b/test/lua-Harness-tests/301-basic.t @@ -0,0 +1,856 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Basic Library + +=head2 Synopsis + + % prove 301-basic.t + +=head2 Description + +Tests Lua Basic Library + +See section "Basic Functions" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.1>, +L<https://www.lua.org/manual/5.2/manual.html#6.1>, +L<https://www.lua.org/manual/5.3/manual.html#6.1>, +L<https://www.lua.org/manual/5.4/manual.html#6.1> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local has_error53 = _VERSION >= 'Lua 5.3' +local has_gcinfo = _VERSION == 'Lua 5.1' +local has_getfenv = _VERSION == 'Lua 5.1' +local has_ipairs53 = _VERSION >= 'Lua 5.3' +local has_load52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_loadfile52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_loadstring = _VERSION == 'Lua 5.1' +local has_alias_loadstring = profile.compat51 +local has_newproxy = _VERSION == 'Lua 5.1' +local has_rawlen = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_unpack = _VERSION == 'Lua 5.1' +local has_alias_unpack = profile.compat51 +local has_warn = _VERSION >= 'Lua 5.4' +local has_xpcall52 = _VERSION >= 'Lua 5.2' or jit +local has_xpcall53 = _VERSION >= 'Lua 5.3' or jit + +local lua = get_lua_binary_name() + +plan'no_plan' + +do -- assert + local v, msg = assert('text', "assert string") + is(v, 'text', "function assert") + is(msg, "assert string") + v, msg = assert({}, "assert table") + is(msg, "assert table") + + error_like(function () assert(false, "ASSERTION TEST") end, + "^[^:]+:%d+: ASSERTION TEST", + "function assert(false, msg)") + + error_like(function () assert(false) end, + "^[^:]+:%d+: assertion failed!", + "function assert(false)") + + if has_error53 then + v, msg = pcall(function() assert(false, 42) end) + is(msg, 42, "function assert(false, 42)") + else + error_like(function () assert(false, 42) end, + "^[^:]+:%d+: 42", + "function assert(false, 42)") + end + + if has_error53 then + local obj = {} + v, msg = pcall(function() assert(false, obj) end) + is(msg, obj, "function assert(false, {})") + else + diag("no assert with table") + end +end + +-- collectgarbage +if jit then + is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'") + is(collectgarbage('step'), false) + is(collectgarbage('restart'), 0) + is(collectgarbage('step'), false) + is(collectgarbage('collect'), 0) + is(collectgarbage('setpause', 10), 200) + is(collectgarbage('setstepmul', 200), 200) + is(collectgarbage(), 0) +elseif _VERSION == 'Lua 5.1' then + is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'") + is(collectgarbage('restart'), 0) + is(collectgarbage('step'), false) + is(collectgarbage('collect'), 0) + is(collectgarbage(), 0) +elseif _VERSION == 'Lua 5.2' then + is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'") + is(collectgarbage('isrunning'), false) + is(collectgarbage('step'), false) + is(collectgarbage('restart'), 0) + is(collectgarbage('isrunning'), true) + is(collectgarbage('step'), false) + is(collectgarbage('collect'), 0) + is(collectgarbage('setpause', 10), 200) + is(collectgarbage('setstepmul', 200), 200) + is(collectgarbage(), 0) + is(collectgarbage('generational'), 0) + is(collectgarbage('step'), false) + is(collectgarbage('incremental'), 0) + is(collectgarbage('setmajorinc'), 200) +elseif _VERSION == 'Lua 5.3' then + is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'") + is(collectgarbage('isrunning'), false) + --is(collectgarbage('step'), false) + type_ok(collectgarbage('step'), 'boolean') + is(collectgarbage('restart'), 0) + is(collectgarbage('isrunning'), true) + is(collectgarbage('step'), false) + is(collectgarbage('collect'), 0) + is(collectgarbage('setpause', 10), 200) + is(collectgarbage('setstepmul', 200), 200) + is(collectgarbage(), 0) + is(collectgarbage('step'), false) +elseif _VERSION == 'Lua 5.4' then + is(collectgarbage('stop'), 0, "function collectgarbage 'stop/restart/collect'") + is(collectgarbage('isrunning'), false) + is(collectgarbage('generational'), 'generational') + is(collectgarbage('incremental'), 'generational') + is(collectgarbage('incremental'), 'incremental') + is(collectgarbage('generational'), 'incremental') + is(collectgarbage('step'), false) + is(collectgarbage('restart'), 0) + is(collectgarbage('isrunning'), true) + is(collectgarbage('step'), false) + is(collectgarbage('collect'), 0) + is(collectgarbage('setpause', 10), 200) + is(collectgarbage('setstepmul', 200), 100) + is(collectgarbage(), 0) + is(collectgarbage('step'), false) +end + +type_ok(collectgarbage('count'), 'number', "function collectgarbage 'count'") + +error_like(function () collectgarbage('unknown') end, + "^[^:]+:%d+: bad argument #1 to 'collectgarbage' %(invalid option 'unknown'%)", + "function collectgarbage (invalid)") + +do -- dofile + local f = io.open('lib-301.lua', 'w') + f:write[[ +function norm (x, y) + return (x^2 + y^2)^0.5 +end + +function twice (x) + return 2*x +end +]] + f:close() + dofile('lib-301.lua') + local n = norm(3.4, 1.0) + like(twice(n), '^7%.088', "function dofile") + + os.remove('lib-301.lua') -- clean up + + error_like(function () dofile('no_file-301.lua') end, + "cannot open no_file%-301%.lua: No such file or directory", + "function dofile (no file)") + + f = io.open('foo-301.lua', 'w') + f:write[[?syntax error?]] + f:close() + error_like(function () dofile('foo-301.lua') end, + "^foo%-301%.lua:%d+:", + "function dofile (syntax error)") + + os.remove('foo-301.lua') -- clean up +end + +do -- error + error_like(function () error("ERROR TEST") end, + "^[^:]+:%d+: ERROR TEST", + "function error(msg)") + + error_is(function () error("ERROR TEST", 0) end, + "ERROR TEST", + "function error(msg, 0)") + + if has_error53 then + local v, msg = pcall(function() error(42) end) + is(msg, 42, "function error(42)") + else + error_like(function () error(42) end, + "^[^:]+:%d+: 42", + "function error(42)") + end + + local obj = {} + local v, msg = pcall(function() error(obj) end) + is(msg, obj, "function error({})") + + v, msg = pcall(function() error() end) + is(msg, nil, "function error()") +end + +-- gcinfo +if has_gcinfo then + type_ok(gcinfo(), 'number', "function gcinfo") +else + is(gcinfo, nil, "no gcinfo (removed)") +end + +-- getfenv +if has_getfenv then + type_ok(getfenv(0), 'table', "function getfenv") + is(getfenv(0), _G) + is(getfenv(1), _G) + is(getfenv(), _G) + local function f () end + type_ok(getfenv(f), 'table') + is(getfenv(f), _G) + type_ok(getfenv(print), 'table') + is(getfenv(print), _G) + + error_like(function () getfenv(-3) end, + "^[^:]+:%d+: bad argument #1 to 'getfenv' %(.-level.-%)", + "function getfenv (negative)") + + error_like(function () getfenv(12) end, + "^[^:]+:%d+: bad argument #1 to 'getfenv' %(invalid level%)", + "function getfenv (too depth)") +else + is(getfenv, nil, "no getfenv") +end + +do -- getmetatable + is(getmetatable(true), nil, "boolean has no metatable by default") + is(getmetatable(getmetatable), nil, "function has no metatable by default") + is(getmetatable(nil), nil, "nil has no metatable by default") + is(getmetatable(3.14), nil, "number has no metatable by default") + is(getmetatable({}), nil, "table has no metatable by default") + local co = coroutine.create(function () return 1 end) + is(getmetatable(co), nil, "thread has no metatable by default") + + type_ok(getmetatable('ABC'), 'table', "string has a metatable") + is(getmetatable('ABC'), getmetatable('abc'), "string has a shared metatable") +end + +do -- ipairs + local a = {'a','b','c'} + if has_ipairs53 then + a = setmetatable({ + [1] = 'a', + [3] = 'c', + }, { + __index = { + [2] = 'b', + } + }) + end + local f, v, s = ipairs(a) + type_ok(f, 'function', "function ipairs") + type_ok(v, 'table') + is(s, 0) + s, v = f(a, s) + is(s, 1) + is(v, 'a') + s, v = f(a, s) + is(s, 2) + is(v, 'b') + s, v = f(a, s) + is(s, 3) + is(v, 'c') + s, v = f(a, s) + is(s, nil) + is(v, nil) +end + +do -- load + local t = { [[ +function bar (x) + return x +end +]] } + local i = 0 + local function reader () + i = i + 1 + return t[i] + end + local f, msg = load(reader) + if msg then + diag(msg) + end + type_ok(f, 'function', "function load(reader)") + is(bar, nil) + f() + is(bar('ok'), 'ok') + bar = nil + + t = { [[ +function baz (x) + return x +end +]] } + i = -1 + function reader () + i = i + 1 + return t[i] + end + f, msg = load(reader) + if msg then + diag(msg) + end + type_ok(f, 'function', "function load(pathological reader)") + f() + if _VERSION == 'Lua 5.1' and not jit then + todo("not with 5.1") + end + is(baz, nil) + + t = { [[?syntax error?]] } + i = 0 + f, msg = load(reader, "errorchunk") + is(f, nil, "function load(syntax error)") + like(msg, "^%[string \"errorchunk\"%]:%d+:") + + f = load(function () return nil end) + type_ok(f, 'function', "when reader returns nothing") + + f, msg = load(function () return {} end) + is(f, nil, "reader function must return a string") + like(msg, "reader function must return a string") + + if has_load52 then + f = load([[ +function bar (x) + return x +end +]]) + is(bar, nil, "function load(str)") + f() + is(bar('ok'), 'ok') + bar = nil + + local env = {} + f = load([[ +function bar (x) + return x +end +]], "from string", 't', env) + is(env.bar, nil, "function load(str)") + f() + is(env.bar('ok'), 'ok') + + f, msg = load([[?syntax error?]], "errorchunk") + is(f, nil, "function load(syntax error)") + like(msg, "^%[string \"errorchunk\"%]:%d+:") + + f, msg = load([[print 'ok']], "chunk txt", 'b') + like(msg, "attempt to load") + is(f, nil, "mode") + + f, msg = load("\x1bLua", "chunk bin", 't') + like(msg, "attempt to load") + is(f, nil, "mode") + else + diag("no load with string") + end +end + +do -- loadfile + local f = io.open('foo-301.lua', 'w') + if _VERSION ~= 'Lua 5.1' or jit then + f:write'\xEF\xBB\xBF' -- BOM + end + f:write[[ +function foo (x) + return x +end +]] + f:close() + f = loadfile('foo-301.lua') + is(foo, nil, "function loadfile") + f() + is(foo('ok'), 'ok') + + if has_loadfile52 then + local msg + f, msg = loadfile('foo-301.lua', 'b') + like(msg, "attempt to load") + is(f, nil, "mode") + + local env = {} + f = loadfile('foo-301.lua', 't', env) + is(env.foo, nil, "function loadfile") + f() + is(env.foo('ok'), 'ok') + else + diag("no loadfile with mode & env") + end + + os.remove('foo-301.lua') -- clean up + + local msg + f, msg = loadfile('no_file-301.lua') + is(f, nil, "function loadfile (no file)") + is(msg, "cannot open no_file-301.lua: No such file or directory") + + f = io.open('foo-301.lua', 'w') + f:write[[?syntax error?]] + f:close() + f, msg = loadfile('foo-301.lua') + is(f, nil, "function loadfile (syntax error)") + like(msg, '^foo%-301%.lua:%d+:') + os.remove('foo-301.lua') -- clean up +end + +-- loadstring +if has_loadstring then + local f = loadstring([[i = i + 1]]) + i = 0 + f() + is(i, 1, "function loadstring") + f() + is(i, 2) + + i = 32 + local i = 0 + f = loadstring([[i = i + 1; return i]]) + local g = function () i = i + 1; return i end + is(f(), 33, "function loadstring") + is(g(), 1) + + local msg + f, msg = loadstring([[?syntax error?]]) + is(f, nil, "function loadstring (syntax error)") + like(msg, '^%[string "%?syntax error%?"%]:%d+:') +elseif has_alias_loadstring then + is(loadstring, load, "alias loadstring") +else + is(loadstring, nil, "no loadstring") +end + +-- newproxy +if has_newproxy then + local proxy = newproxy(false) + type_ok(proxy, 'userdata', "function newproxy(false)") + is(getmetatable(proxy), nil, "without metatable") + proxy = newproxy(true) + type_ok(proxy, 'userdata', "function newproxy(true)") + type_ok(getmetatable(proxy), 'table', "with metatable") + + local proxy2 = newproxy(proxy) + type_ok(proxy, 'userdata', "function newproxy(proxy)") + is(getmetatable(proxy2), getmetatable(proxy)) + + error_like(function () newproxy({}) end, + "^[^:]+:%d+: bad argument #1 to 'newproxy' %(boolean or proxy expected%)", + "function newproxy({})") +else + is(newproxy, nil, "no newproxy") +end + +do -- next + local t = {'a','b','c'} + local a = next(t, nil) + is(a, 1, "function next (array)") + a = next(t, 1) + is(a, 2) + a = next(t, 2) + is(a, 3) + a = next(t, 3) + is(a, nil) + + error_like(function () a = next() end, + "^[^:]+:%d+: bad argument #1 to 'next' %(table expected, got no value%)", + "function next (no arg)") + + error_like(function () a = next(t, 6) end, + "invalid key to 'next'", + "function next (invalid key)") + + t = {'a','b','c'} + a = next(t, 2) + is(a, 3, "function next (unorderer)") + a = next(t, 1) + is(a, 2) + a = next(t, 3) + is(a, nil) + + t = {} + a = next(t, nil) + is(a, nil, "function next (empty table)") +end + +do -- pairs + local a = {'a','b','c'} + local f, v, s = pairs(a) + type_ok(f, 'function', "function pairs") + type_ok(v, 'table') + is(s, nil) + s = f(v, s) + is(s, 1) + s = f(v, s) + is(s, 2) + s = f(v, s) + is(s, 3) + s = f(v, s) + is(s, nil) +end + +do -- pcall + local status, result = pcall(assert, 1) + is(status, true, "function pcall") + is(result, 1) + status, result = pcall(assert, false, 'catched') + is(status, false) + is(result, 'catched') + status = pcall(assert) + is(status, false) +end + +do -- rawequal + local t = {} + local a = t + is(rawequal(nil, nil), true, "function rawequal -> true") + is(rawequal(false, false), true) + is(rawequal(3, 3), true) + is(rawequal('text', 'text'), true) + is(rawequal(t, a), true) + is(rawequal(print, print), true) + + is(rawequal(nil, 2), false, "function rawequal -> false") + is(rawequal(false, true), false) + is(rawequal(false, 2), false) + is(rawequal(3, 2), false) + is(rawequal(3, '2'), false) + is(rawequal('text', '2'), false) + is(rawequal('text', 2), false) + is(rawequal(t, {}), false) + is(rawequal(t, 2), false) + is(rawequal(print, type), false) + is(rawequal(print, 2), false) +end + +-- rawlen +if has_rawlen then + is(rawlen("text"), 4, "function rawlen (string)") + is(rawlen({ 'a', 'b', 'c'}), 3, "function rawlen (table)") + error_like(function () local a = rawlen(true) end, + "^[^:]+:%d+: bad argument #1 to 'rawlen' %(table ", + "function rawlen (bad arg)") +else + is(rawlen, nil, "no rawlen") +end + +do -- rawget + local t = {a = 'letter a', b = 'letter b'} + is(rawget(t, 'a'), 'letter a', "function rawget") +end + +do -- rawset + local t = {} + is(rawset(t, 'a', 'letter a'), t, "function rawset") + is(t.a, 'letter a') + + error_like(function () t = {}; rawset(t, nil, 42) end, + "^table index is nil", + "function rawset (table index is nil)") +end + +do -- select + is(select('#'), 0, "function select") + is(select('#','a','b','c'), 3) + eq_array({select(1,'a','b','c')}, {'a','b','c'}) + eq_array({select(3,'a','b','c')}, {'c'}) + eq_array({select(5,'a','b','c')}, {}) + eq_array({select(-1,'a','b','c')}, {'c'}) + eq_array({select(-2,'a','b','c')}, {'b', 'c'}) + eq_array({select(-3,'a','b','c')}, {'a', 'b', 'c'}) + + error_like(function () select(0,'a','b','c') end, + "^[^:]+:%d+: bad argument #1 to 'select' %(index out of range%)", + "function select (out of range)") + + error_like(function () select(-4,'a','b','c') end, + "^[^:]+:%d+: bad argument #1 to 'select' %(index out of range%)", + "function select (out of range)") +end + +-- setfenv +if has_getfenv then + local t = {} + local function f () end + is(setfenv(f, t), f, "function setfenv") + type_ok(getfenv(f), 'table') + is(getfenv(f), t) + + save = getfenv(1) + a = 1 + setfenv(1, {g = _G}) + g.is(a, nil, "function setfenv") + g.is(g.a, 1) + g.setfenv(1, g.save) -- restore + + save = getfenv(1) + a = 1 + local newgt = {} -- create new environment + setmetatable(newgt, {__index = _G}) + setfenv(1, newgt) -- set it + is(a, 1, "function setfenv") + a = 10 + is(a, 10) + is(_G.a, 1) + _G.a = 20 + is(_G.a, 20) + setfenv(1, save) -- restore + + save = getfenv(1) + local function factory () + return function () + return a -- "global" a + end + end + a = 3 + local f1 = factory() + local f2 = factory() + is(f1(), 3, "function setfenv") + is(f2(), 3) + setfenv(f1, {a = 10}) + is(f1(), 10) + is(f2(), 3) + setfenv(1, save) -- restore + + is(setfenv(0, _G), nil, "function setfenv(0)") + + error_like(function () setfenv(-3, {}) end, + "^[^:]+:%d+: bad argument #1 to 'setfenv' %(.-level.-%)", + "function setfenv (negative)") + + error_like(function () setfenv(12, {}) end, + "^[^:]+:%d+: bad argument #1 to 'setfenv' %(invalid level%)", + "function setfenv (too depth)") + + t = {} + error_like(function () setfenv(t, {}) end, + "^[^:]+:%d+: bad argument #1 to 'setfenv' %(number expected, got table%)", + "function setfenv (bad arg)") + + error_like(function () setfenv(print, {}) end, + "^[^:]+:%d+: 'setfenv' cannot change environment of given object", + "function setfenv (forbidden)") +else + is(setfenv, nil, "no setfenv") +end + +do -- setmetatable + local mt = {} + local t = {} + is(t, setmetatable(t, mt), "setmetatable") + is(getmetatable(t), mt) + is(t, setmetatable(t, nil)) + is(getmetatable(t), nil) + + error_like(function () setmetatable(t, true) end, + "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected", + "function setmetatable (bad arg)") + error_like(function () setmetatable(true, mt) end, + "^[^:]+:%d+: bad argument #1 to 'setmetatable' %(table expected, got boolean%)", + "function setmetatable (bad arg)") +end + +do -- type + is(type("Hello world"), 'string', "function type") + is(type(10.4*3), 'number') + is(type(print), 'function') + is(type(type), 'function') + is(type(true), 'boolean') + is(type(nil), 'nil') + is(type(io.stdin), 'userdata') + is(type(type(X)), 'string') + + local a = nil + is(type(a), 'nil', "function type") + a = 10 + is(type(a), 'number') + a = "a string!!" + is(type(a), 'string') + a = print + is(type(a), 'function') + is(type(function () end), 'function') + + error_like(function () type() end, + "^[^:]+:%d+: bad argument #1 to 'type' %(value expected%)", + "function type (no arg)") +end + +do -- tonumber + is(tonumber('text12'), nil, "function tonumber") + is(tonumber('12text'), nil) + is(tonumber(3.14), 3.14) + is(tonumber('3.14'), 3.14) + is(tonumber(' 3.14 '), 3.14) + is(tonumber(tostring(111), 2), 7) + is(tonumber('111', 2), 7) + is(tonumber(' 111 ', 2), 7) + local a = {} + is(tonumber(a), nil) + + error_like(function () tonumber() end, + "^[^:]+:%d+: bad argument #1 to 'tonumber' %(value expected%)", + "function tonumber (no arg)") + + error_like(function () tonumber('111', 200) end, + "^[^:]+:%d+: bad argument #2 to 'tonumber' %(base out of range%)", + "function tonumber (bad base)") +end + +do -- tostring + is(tostring('text'), 'text', "function tostring") + is(tostring(3.14), '3.14') + is(tostring(nil), 'nil') + is(tostring(true), 'true') + is(tostring(false), 'false') + like(tostring({}), '^table: 0?[Xx]?%x+$') + like(tostring(print), '^function: 0?[Xx]?[builtin]*#?%x+$') + + error_like(function () tostring() end, + "^[^:]+:%d+: bad argument #1 to 'tostring' %(value expected%)", + "function tostring (no arg)") +end + +-- unpack +if has_unpack then + eq_array({unpack({})}, {}, "function unpack") + eq_array({unpack({'a'})}, {'a'}) + eq_array({unpack({'a','b','c'})}, {'a','b','c'}) + eq_array({(unpack({'a','b','c'}))}, {'a'}) + eq_array({unpack({'a','b','c','d','e'},2,4)}, {'b','c','d'}) + eq_array({unpack({'a','b','c'},2,4)}, {'b','c'}) +elseif has_alias_unpack then + is(unpack, table.unpack, "alias unpack") +else + is(unpack, nil, "no unpack") +end + +-- warn +if has_warn then + is(warn('foo'), nil, "function warn") + + local r, f = pcall(io.popen, lua .. [[ -W -e "warn'foo'" 2>&1]]) + if r then + is(f:read'*l', 'Lua warning: foo', "warn called with popen") + is(f:read'*l', nil) + is(f:close(), true) + else + diag("io.popen not supported") + end + + r, f = pcall(io.popen, lua .. [[ -e "warn'@on'; warn'foo'" 2>&1]]) + if r then + is(f:read'*l', 'Lua warning: foo', "warn called with popen") + is(f:read'*l', nil) + is(f:close(), true) + else + diag("io.popen not supported") + end + + r, f = pcall(io.popen, lua .. [[ -e "warn'@on'; warn('foo', 'bar')" 2>&1]]) + if r then + is(f:read'*l', 'Lua warning: foobar', "warn called with popen") + is(f:read'*l', nil) + is(f:close(), true) + else + diag("io.popen not supported") + end + + error_like(function () warn('foo', warn) end, + "^[^:]+:%d+: bad argument #2 to 'warn' %(string expected, got function%)", + "function warn (no arg)") + + error_like(function () warn() end, + "^[^:]+:%d+: bad argument #1 to 'warn' %(string expected, got no value%)", + "function warn (no arg)") +else + is(warn, nil, "no warn") +end + +do -- xpcall + local function err (obj) + return obj + end + + local function backtrace () + return 'not a back trace' + end + + local status, result = xpcall(function () return assert(1) end, err) + is(status, true, "function xpcall") + is(result, 1) + status, result = xpcall(function () return assert(false, 'catched') end, err) + is(status, false) + if jit then + is(result, 'catched') + else + like(result, ':%d+: catched') + end + status, result = xpcall(function () return assert(false, 'catched') end, backtrace) + is(status, false) + is(result, 'not a back trace') + + if has_xpcall52 then + status, result = xpcall(assert, err, 1) + is(status, true, "function xpcall with args") + is(result, 1) + status, result = xpcall(assert, err, false, 'catched') + is(status, false) + is(result, 'catched') + status, result = xpcall(assert, backtrace, false, 'catched') + is(status, false) + is(result, 'not a back trace') + end + + error_like(function () xpcall(assert) end, + "bad argument #2 to 'xpcall' %(.-", + "function xpcall") + + if has_xpcall53 then + error_like(function () xpcall(assert, 1) end, + "bad argument #2 to 'xpcall' %(function expected, got number%)", + "function xpcall") + else + is(xpcall(assert, nil), false, "function xpcall") + end +end + +if jit and pcall(require, 'ffi') then + dofile'lexicojit/basic.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/303-package.t b/test/lua-Harness-tests/303-package.t new file mode 100755 index 0000000..7e5216d --- /dev/null +++ b/test/lua-Harness-tests/303-package.t @@ -0,0 +1,290 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Package Library + +=head2 Synopsis + + % prove 303-package.t + +=head2 Description + +Tests Lua Package Library + +See section "Modules" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.3>, +L<https://www.lua.org/manual/5.2/manual.html#6.3>, +L<https://www.lua.org/manual/5.3/manual.html#6.3>, +L<https://www.lua.org/manual/5.4/manual.html#6.3> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT') +local has_loaders = _VERSION == 'Lua 5.1' +local has_alias_loaders = profile.compat51 +local has_loadlib52 = _VERSION >= 'Lua 5.2' or jit +local has_module = _VERSION == 'Lua 5.1' or profile.compat51 +local has_searchers = _VERSION >= 'Lua 5.2' +local has_alias_searchers = luajit21 and profile.luajit_compat52 +local has_searcherpath = _VERSION >= 'Lua 5.2' or jit +local has_require54 = _VERSION >= 'Lua 5.4' + +plan'no_plan' + + +type_ok(package.config, 'string') + +type_ok(package.cpath, 'string') + +type_ok(package.path, 'string') + +if has_loaders then + type_ok(package.loaders, 'table', "table package.loaders") +elseif has_alias_loaders then + is(package.loaders, package.searchers, "alias package.loaders") +else + is(package.loaders, nil, "no package.loaders") +end + +if has_searchers then + type_ok(package.searchers, 'table', "table package.searchers") +elseif has_alias_searchers then + is(package.searchers, package.loaders, "alias package.searchers") +else + is(package.searchers, nil, "no package.searchers") +end + +do -- loaded + ok(package.loaded._G, "table package.loaded") + ok(package.loaded.coroutine) + ok(package.loaded.io) + ok(package.loaded.math) + ok(package.loaded.os) + ok(package.loaded.package) + ok(package.loaded.string) + ok(package.loaded.table) + + local m = require'os' + is(m, package.loaded['os']) +end + +do -- preload + type_ok(package.preload, 'table', "table package.preload") + is(# package.preload, 0) + + local foo = {} + foo.bar = 1234 + local function foo_loader () + return foo + end + package.preload.foo = foo_loader + local m = require 'foo' + assert(m == foo) + is(m.bar, 1234, "function require & package.preload") +end + +do -- loadlib + local path_lpeg = package.searchpath and package.searchpath('lpeg', package.cpath) + + local f, msg = package.loadlib('libbar', 'baz') + is(f, nil, "loadlib") + type_ok(msg, 'string') + + if path_lpeg then + f, msg = package.loadlib(path_lpeg, 'baz') + is(f, nil, "loadlib") + like(msg, 'undefined symbol') + + f = package.loadlib(path_lpeg, 'luaopen_lpeg') + type_ok(f, 'function', "loadlib ok") + else + skip("no lpeg path") + end + + if has_loadlib52 then + f, msg = package.loadlib('libbar', '*') + is(f, nil, "loadlib '*'") + type_ok(msg, 'string') + + if path_lpeg then + f = package.loadlib(path_lpeg, '*') + is(f, true, "loadlib '*'") + else + skip("no lpeg path") + end + end +end + +-- searchpath +if has_searcherpath then + local p = package.searchpath('tap', package.path) + type_ok(p, 'string', "searchpath") + p = package.searchpath('tap', 'bad path') + is(p, nil) +else + is(package.searchpath, nil, "no package.searchpath") +end + +do -- require + local f = io.open('complex.lua', 'w') + f:write [[ +complex = {} + +function complex.new (r, i) return {r=r, i=i} end + +--defines a constant 'i' +complex.i = complex.new(0, 1) + +function complex.add (c1, c2) + return complex.new(c1.r + c2.r, c1.i + c2.i) +end + +function complex.sub (c1, c2) + return complex.new(c1.r - c2.r, c1.i - c2.i) +end + +function complex.mul (c1, c2) + return complex.new(c1.r*c2.r - c1.i*c2.i, + c1.r*c2.i + c1.i*c2.r) +end + +local function inv (c) + local n = c.r^2 + c.i^2 + return complex.new(c.r/n, -c.i/n) +end + +function complex.div (c1, c2) + return complex.mul(c1, inv(c2)) +end + +return complex +]] + f:close() + if has_require54 then + local m1, path1 = require 'complex' + is(m1, complex, "function require") + is(path1, './complex.lua') + local m2, path2 = require 'complex' + is(m1, m2) + is(path2, nil) + else + local m1 = require 'complex' + is(m1, complex, "function require") + local m2 = require 'complex' + is(m1, m2) + end + is(complex.i.r, 0) + is(complex.i.i, 1) + os.remove('complex.lua') -- clean up + + error_like(function () require('no_module') end, + "^[^:]+:%d+: module 'no_module' not found:", + "function require (no module)") + + f = io.open('syntax.lua', 'w') + f:write [[?syntax error?]] + f:close() + error_like(function () require('syntax') end, + "^error loading module 'syntax' from file '%.[/\\]syntax%.lua':", + "function require (syntax error)") + os.remove('syntax.lua') -- clean up + + f = io.open('bar.lua', 'w') + f:write [[ + print(" in bar.lua", ...) + a = ... +]] + f:close() + a = nil + require 'bar' + is(a, 'bar', "function require (arg)") + os.remove('bar.lua') -- clean up + + f = io.open('cplx.lua', 'w') + f:write [[ +-- print('cplx.lua', ...) +local _G = _G +_ENV = nil +local cplx = {} + +local function new (r, i) return {r=r, i=i} end +cplx.new = new + +--defines a constant 'i' +cplx.i = new(0, 1) + +function cplx.add (c1, c2) + return new(c1.r + c2.r, c1.i + c2.i) +end + +function cplx.sub (c1, c2) + return new(c1.r - c2.r, c1.i - c2.i) +end + +function cplx.mul (c1, c2) + return new(c1.r*c2.r - c1.i*c2.i, + c1.r*c2.i + c1.i*c2.r) +end + +local function inv (c) + local n = c.r^2 + c.i^2 + return new(c.r/n, -c.i/n) +end + +function cplx.div (c1, c2) + return mul(c1, inv(c2)) +end + +_G.cplx = cplx +return cplx +]] + f:close() + require 'cplx' + is(cplx.i.r, 0, "function require & module") + is(cplx.i.i, 1) + os.remove('cplx.lua') -- clean up +end + +-- module & seeall +local done_testing = done_testing +if has_module then + m = {} + package.seeall(m) + m.pass("function package.seeall") + + is(mod, nil, "function module & seeall") + module('mod', package.seeall) + type_ok(mod, 'table') + is(mod, package.loaded.mod) + + is(modz, nil, "function module") + local _G = _G + module('modz') + _G.type_ok(_G.modz, 'table') + _G.is(_G.modz, _G.package.loaded.modz) +else + is(package.seeall, nil, "package.seeall (removed)") + is(module, nil, "module (removed)") +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/304-string.t b/test/lua-Harness-tests/304-string.t new file mode 100755 index 0000000..991600a --- /dev/null +++ b/test/lua-Harness-tests/304-string.t @@ -0,0 +1,633 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua String Library + +=head2 Synopsis + + % prove 304-string.t + +=head2 Description + +Tests Lua String Library + +See section "String Manipulation" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.4>, +L<https://www.lua.org/manual/5.2/manual.html#6.4>, +L<https://www.lua.org/manual/5.3/manual.html#6.4>, +L<https://www.lua.org/manual/5.4/manual.html#6.4> + +=cut + +]] + +require'tap' +local profile = require'profile' +local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT') +local has_dump53 = _VERSION >= 'Lua 5.3' or jit +local has_format_a = _VERSION >= 'Lua 5.3' or profile.has_string_format_a or jit +local has_format_p = _VERSION >= 'Lua 5.4' +local has_format_q52 = _VERSION >= 'Lua 5.2' or jit +local has_format_q53 = _VERSION >= 'Lua 5.3' +local has_format_q54 = _VERSION >= 'Lua 5.4' +local has_gmatch54 = _VERSION >= 'Lua 5.4' +local has_pack = _VERSION >= 'Lua 5.3' or (jit and jit.version:match'moonjit') or profile.pack +local has_rep52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_class_g = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local loadstring = loadstring or load + +plan'no_plan' + +do -- metatable + local mt = getmetatable('ABC') + type_ok(mt, 'table', "metatable") + type_ok(mt.__index, 'table') + + if not profile.nocvts2n and _VERSION >= 'Lua 5.4' then + type_ok(mt.__add, 'function') + type_ok(mt.__div, 'function') + type_ok(mt.__idiv, 'function') + type_ok(mt.__mul, 'function') + type_ok(mt.__mod, 'function') + type_ok(mt.__pow, 'function') + type_ok(mt.__sub, 'function') + type_ok(mt.__unm, 'function') + else + is(mt.__add, nil) + is(mt.__div, nil) + is(mt.__idiv, nil) + is(mt.__mul, nil) + is(mt.__mod, nil) + is(mt.__pow, nil) + is(mt.__sub, nil) + is(mt.__unm, nil) + end + + is(mt.__index.byte, string.byte) + is(mt.__index.char, string.char) + is(mt.__index.dump, string.dump) + is(mt.__index.find, string.find) + is(mt.__index.format, string.format) + is(mt.__index.gmatch, string.gmatch) + is(mt.__index.gsub, string.gsub) + is(mt.__index.len, string.len) + is(mt.__index.lower, string.lower) + is(mt.__index.match, string.match) + is(mt.__index.rep, string.rep) + is(mt.__index.reverse, string.reverse) + is(mt.__index.sub, string.sub) + is(mt.__index.upper, string.upper) + + if has_pack then + is(mt.__index.pack, string.pack) + is(mt.__index.packsize, string.packsize) + is(mt.__index.unpack, string.unpack) + else + is(mt.__index.pack, nil) + is(mt.__index.packsize, nil) + is(mt.__index.unpack, nil) + end +end + +do -- byte + is(string.byte('ABC'), 65, "function byte") + is(string.byte('ABC', 2), 66) + is(string.byte('ABC', -1), 67) + is(string.byte('ABC', 4), nil) + is(string.byte('ABC', 0), nil) + eq_array({string.byte('ABC', 1, 3)}, {65, 66, 67}) + eq_array({string.byte('ABC', 1, 4)}, {65, 66, 67}) + + local s = "ABC" + is(s:byte(2), 66, "method s:byte") +end + +do -- char + is(string.char(65, 66, 67), 'ABC', "function char") + is(string.char(), '') + + error_like(function () string.char(0, 'bad') end, + "^[^:]+:%d+: bad argument #2 to 'char' %(number expected, got string%)", + "function char (bad arg)") + + error_like(function () string.char(0, 9999) end, + "^[^:]+:%d+: bad argument #2 to 'char' %(.-value.-%)", + "function char (invalid)") +end + +do -- dump + local signature + if jit then + signature = "\x1bLJ" + elseif ravi then + signature = "\x1bRavi" + elseif _VERSION >= 'Lua 5.2' then + signature = "\x1bLua" + end + + local function add (a, b) + return a + b + end + + local d = string.dump(add) + type_ok(d, 'string', "function dump") + local f = loadstring(d) + type_ok(f, 'function') + is(f(1, 2), 3) + + if signature then + local sig = d:sub(1, #signature) + is(sig, signature) + end + + if has_dump53 then + local d2 = string.dump(add, true) + type_ok(d2, 'string', "function dump with strip") + f = loadstring(d2) + type_ok(f, 'function') + is(f(1, 2), 3) + isnt(d2:len(), d:len()) + + if signature then + local sig = d2:sub(1, #signature) + is(sig, signature) + end + end + + error_like(function () string.dump(print) end, + "^[^:]+:%d+: unable to dump given function", + "function dump (C function)") +end + +do -- find + local s = "hello world" + eq_array({string.find(s, "hello")}, {1, 5}, "function find (mode plain)") + eq_array({string.find(s, "hello", 1, true)}, {1, 5}) + eq_array({string.find(s, "hello", 1)}, {1, 5}) + is(string.sub(s, 1, 5), "hello") + eq_array({string.find(s, "world")}, {7, 11}) + eq_array({string.find(s, "l")}, {3, 3}) + is(string.find(s, "lll"), nil) + is(string.find(s, "hello", 2, true), nil) + eq_array({string.find(s, "world", 2, true)}, {7, 11}) + is(string.find(s, "hello", 20), nil) + + s = "hello world" + eq_array({string.find(s, "^h.ll.")}, {1, 5}, "function find (with regex & captures)") + eq_array({string.find(s, "w.rld", 2)}, {7, 11}) + is(string.find(s, "W.rld"), nil) + eq_array({string.find(s, "^(h.ll.)")}, {1, 5, 'hello'}) + eq_array({string.find(s, "^(h.)l(l.)")}, {1, 5, 'he', 'lo'}) + s = "Deadline is 30/05/1999, firm" + local date = "%d%d/%d%d/%d%d%d%d" + is(string.sub(s, string.find(s, date)), "30/05/1999") + date = "%f[%S]%d%d/%d%d/%d%d%d%d" + is(string.sub(s, string.find(s, date)), "30/05/1999") + + error_like(function () string.find(s, '%f') end, + "^[^:]+:%d+: missing '%[' after '%%f' in pattern", + "function find (invalid frontier)") +end + +do -- format + is(string.format("pi = %.4f", math.pi), 'pi = 3.1416', "function format") + local d = 5; local m = 11; local y = 1990 + is(string.format("%02d/%02d/%04d", d, m, y), "05/11/1990") + is(string.format("%X %x", 126, 126), "7E 7e") + local tag, title = "h1", "a title" + is(string.format("<%s>%s</%s>", tag, title, tag), "<h1>a title</h1>") + + is(string.format('%q', 'a string with "quotes" and \n new line'), [["a string with \"quotes\" and \ + new line"]], "function format %q") + + if has_format_q52 then + is(string.format('%q', 'a string with \0 and \r.'), [["a string with \0 and \13."]], "function format %q") + is(string.format('%q', 'a string with \b and \b2'), [["a string with \8 and \0082"]], "function format %q") + else + is(string.format('%q', 'a string with \0 and \r.'), [["a string with \000 and \r."]], "function format %q") + is(string.format('%q', 'a string with \b and \b2'), '"a string with \b and \b2"', "function format %q") + end + + if has_format_q53 then + is(string.format('%q', 1.5), '0x1.8p+0', "function format %q") + is(string.format('%q', 7), '7', "function format %q") + else + is(string.format('%q', 1.5), [["1.5"]], "function format %q") + is(string.format('%q', 7), [["7"]], "function format %q") + end + + if has_format_q53 then + is(string.format('%q', nil), 'nil', "function format ('%q', nil)") + elseif luajit21 then + is(string.format('%q', nil), [["nil"]], "function format ('%q', nil)") + else + error_like(function () string.format("%q", nil) end, + "^[^:]+:%d+: bad argument #2 to 'format' %(", + "function format ('%q', nil)") + end + + if has_format_q54 then + is(string.format('%q', 0/0), '(0/0)', "function format ('%q', NaN)") + is(string.format('%q', 1/0), '1e9999', "function format ('%q', +Inf)") + is(string.format('%q', -1/0), '-1e9999', "function format ('%q', -Inf)") + + error_like(function () string.format("%-q", 0) end, + "^[^:]+:%d+: specifier '%%q' cannot have modifiers", + "function format '%-q'") + end + + if luajit21 then + like(string.format('%q', {}), [[^"table: ]], "function format ('%q', {})") + else + error_like(function () string.format("%q", {}) end, + "^[^:]+:%d+: bad argument #2 to 'format' %(", + "function format ('%q', {})") + end + + if has_format_a then + is(string.format('%a', 1.5), '0x1.8p+0', "function format %a") + end + + if has_format_p then + is(string.format('table: %p', string), tostring(string), "function format %p") + end + + is(string.format("%5s", 'foo'), ' foo', "function format (%5s)") + + if _VERSION >= 'Lua 5.3' then + error_like(function () string.format("%5s", "foo\0bar") end, + "^[^:]+:%d+: bad argument #2 to 'format' %(string contains zeros%)", + "function format format (%5s with \\0)") + end + + is(string.format("%s %s", 1, 2, 3), '1 2', "function format (too many arg)") + + is(string.format("%% %c %%", 65), '% A %', "function format (%%)") + + local r = string.rep("ab", 100) + is(string.format("%s %d", r, r:len()), r .. " 200") + + error_like(function () string.format("%s %s", 1) end, + "^[^:]+:%d+: bad argument #3 to 'format' %(.-no value%)", + "function format (too few arg)") + + error_like(function () string.format('%d', 'toto') end, + "^[^:]+:%d+: bad argument #2 to 'format' %(number expected, got string%)", + "function format (bad arg)") + + error_like(function () string.format('%k', 'toto') end, + "^[^:]+:%d+: invalid .- '%%k' to 'format'", + "function format (invalid conversion)") + + if luajit21 then + error_like(function () string.format('%111s', 'toto') end, + "^[^:]+:%d+: invalid option '%%111' to 'format'", + "function format (invalid format)") + else + error_like(function () string.format('%111s', 'toto') end, + "^[^:]+:%d+: invalid format %(width or precision too long%)", + "function format (invalid format)") + + error_like(function () string.format('%------s', 'toto') end, + "^[^:]+:%d+: invalid format %(repeated flags%)", + "function format (invalid format)") + end + + error_like(function () string.format('pi = %.123f', math.pi) end, + "^[^:]+:%d+: invalid ", + "function format (invalid format)") + + error_like(function () string.format('% 123s', 'toto') end, + "^[^:]+:%d+: invalid ", + "function format (invalid format)") +end + +do -- gmatch + local s = "hello" + local output = {} + for c in string.gmatch(s, '..') do + table.insert(output, c) + end + eq_array(output, {'he', 'll'}, "function gmatch") + if has_gmatch54 then + output = {} + for c in string.gmatch(s, '..', 2) do + table.insert(output, c) + end + eq_array(output, {'el', 'lo'}) + end + output = {} + for c1, c2 in string.gmatch(s, '(.)(.)') do + table.insert(output, c1) + table.insert(output, c2) + end + eq_array(output, {'h', 'e', 'l', 'l'}) + s = "hello world from Lua" + output = {} + for w in string.gmatch(s, '%a+') do + table.insert(output, w) + end + eq_array(output, {'hello', 'world', 'from', 'Lua'}) + s = "from=world, to=Lua" + output = {} + for k, v in string.gmatch(s, '(%w+)=(%w+)') do + table.insert(output, k) + table.insert(output, v) + end + eq_array(output, {'from', 'world', 'to', 'Lua'}) +end + +do -- gsub + is(string.gsub("hello world", "(%w+)", "%1 %1"), "hello hello world world", "function gsub") + is(string.gsub("hello world", "%w+", "%0 %0", 1), "hello hello world") + is(string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1"), "world hello Lua from") + if _VERSION == 'Lua 5.1' then + todo("not with 5.1") + end + error_like(function () string.gsub("hello world", "%w+", "%e") end, + "^[^:]+:%d+: invalid use of '%%' in replacement string", + "function gsub (invalid replacement string)") + is(string.gsub("home = $HOME, user = $USER", "%$(%w+)", string.reverse), "home = EMOH, user = RESU") + is(string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return tostring(loadstring(s)()) end), "4+5 = 9") + local t = {name='lua', version='5.1'} + is(string.gsub("$name-$version.tar.gz", "%$(%w+)", t), "lua-5.1.tar.gz") + + is(string.gsub("Lua is cute", 'cute', 'great'), "Lua is great") + is(string.gsub("all lii", 'l', 'x'), "axx xii") + is(string.gsub("Lua is great", '^Sol', 'Sun'), "Lua is great") + is(string.gsub("all lii", 'l', 'x', 1), "axl lii") + is(string.gsub("all lii", 'l', 'x', 2), "axx lii") + is(select(2, string.gsub("string with 3 spaces", ' ', ' ')), 3) + + eq_array({string.gsub("hello, up-down!", '%A', '.')}, {"hello..up.down.", 4}) + eq_array({string.gsub("hello, up-down!", '%A', '%%')}, {"hello%%up%down%", 4}) + local text = "hello world" + local nvow = select(2, string.gsub(text, '[AEIOUaeiou]', '')) + is(nvow, 3) + eq_array({string.gsub("one, and two; and three", '%a+', 'word')}, {"word, word word; word word", 5}) + local test = "int x; /* x */ int y; /* y */" + eq_array({string.gsub(test, "/%*.*%*/", '<COMMENT>')}, {"int x; <COMMENT>", 1}) + eq_array({string.gsub(test, "/%*.-%*/", '<COMMENT>')}, {"int x; <COMMENT> int y; <COMMENT>", 2}) + local s = "a (enclosed (in) parentheses) line" + eq_array({string.gsub(s, '%b()', '')}, {"a line", 1}) + + error_like(function () string.gsub(s, '%b(', '') end, + "^[^:]+:%d+: .- pattern", + "function gsub (malformed pattern)") + + eq_array({string.gsub("hello Lua!", "%a", "%0-%0")}, {"h-he-el-ll-lo-o L-Lu-ua-a!", 8}) + eq_array({string.gsub("hello Lua", "(.)(.)", "%2%1")}, {"ehll ouLa", 4}) + + local function expand (str) + return (string.gsub(str, '$(%w+)', _G)) + end + name = 'Lua'; status= 'great' + is(expand("$name is $status, isn't it?"), "Lua is great, isn't it?") + is(expand("$othername is $status, isn't it?"), "$othername is great, isn't it?") + + function expand (str) + return (string.gsub(str, '$(%w+)', function (n) + return tostring(_G[n]), 1 + end)) + end + like(expand("print = $print; a = $a"), "^print = function: [0]?[Xx]?[builtin]*#?%x+; a = nil") + + error_like(function () string.gsub("hello world", '(%w+)', '%2 %2') end, + "^[^:]+:%d+: invalid capture index", + "function gsub (invalid index)") + + error_like(function () string.gsub("hello world", '(%w+)', true) end, + "^[^:]+:%d+: bad argument #3 to 'gsub' %(string/function/table expected", + "function gsub (bad type)") + + error_like(function () + function expand (str) + return (string.gsub(str, '$(%w+)', _G)) + end + + name = 'Lua'; status= true + expand("$name is $status, isn't it?") + end, + "^[^:]+:%d+: invalid replacement value %(a boolean%)", + "function gsub (invalid value)") + + local function trim (str) + return (str:gsub('^%s*(.-)%s*$', '%1')) + end + is(trim('foo'), 'foo', "gsub trim") + is(trim(' foo bar '), 'foo bar') +end + +do -- len + is(string.len(''), 0, "function len") + is(string.len('test'), 4) + is(string.len("a\000b\000c"), 5) + is(string.len('"'), 1) +end + +do -- lower + is(string.lower('Test'), 'test', "function lower") + is(string.lower('TeSt'), 'test') +end + +do -- match + local s = "hello world" + is(string.match(s, '^hello'), 'hello', "function match") + is(string.match(s, 'world', 2), 'world') + is(string.match(s, 'World'), nil) + eq_array({string.match(s, '^(h.ll.)')}, {'hello'}) + eq_array({string.match(s, '^(h.)l(l.)')}, {'he', 'lo'}) + local date = "Today is 17/7/1990" + is(string.match(date, '%d+/%d+/%d+'), '17/7/1990') + eq_array({string.match(date, '(%d+)/(%d+)/(%d+)')}, {'17', '7', '1990'}) + is(string.match("The number 1298 is even", '%d+'), '1298') + local pair = "name = Anna" + eq_array({string.match(pair, '(%a+)%s*=%s*(%a+)')}, {'name', 'Anna'}) + + s = [[then he said: "it's all right"!]] + eq_array({string.match(s, "([\"'])(.-)%1")}, {'"', "it's all right"}, "function match (back ref)") + local p = "%[(=*)%[(.-)%]%1%]" + s = "a = [=[[[ something ]] ]==]x]=]; print(a)" + eq_array({string.match(s, p)}, {'=', '[[ something ]] ]==]x'}) + + if has_class_g then + is(string.match(s, "%g"), "a", "match graphic char") + end + + error_like(function () string.match("hello world", "%1") end, + "^[^:]+:%d+: invalid capture index", + "function match invalid capture") + + error_like(function () string.match("hello world", "%w)") end, + "^[^:]+:%d+: invalid pattern capture", + "function match invalid capture") +end + +-- pack +if has_pack then + is(string.pack('b', 0x31), '\x31', "function pack") + is(string.pack('>b', 0x31), '\x31') + is(string.pack('=b', 0x31), '\x31') + is(string.pack('<b', 0x31), '\x31') + is(string.pack('>B', 0x91), '\x91') + is(string.pack('=B', 0x91), '\x91') + is(string.pack('<B', 0x91), '\x91') + is(string.byte(string.pack('<h', 1)), 1) + is(string.byte(string.pack('>h', 1):reverse()), 1) + is(string.byte(string.pack('<H', 1)), 1) + is(string.byte(string.pack('>H', 1):reverse()), 1) + is(string.byte(string.pack('<l', 1)), 1) + is(string.byte(string.pack('>l', 1):reverse()), 1) + is(string.byte(string.pack('<L', 1)), 1) + is(string.byte(string.pack('>L', 1):reverse()), 1) + is(string.byte(string.pack('<j', 1)), 1) + is(string.byte(string.pack('>j', 1):reverse()), 1) + is(string.byte(string.pack('<J', 1)), 1) + is(string.byte(string.pack('>J', 1):reverse()), 1) + is(string.byte(string.pack('<T', 1)), 1) + is(string.byte(string.pack('>T', 1):reverse()), 1) + is(string.byte(string.pack('<i', 1)), 1) + is(string.byte(string.pack('>i', 1):reverse()), 1) + is(string.byte(string.pack('<I', 1)), 1) + is(string.byte(string.pack('>I', 1):reverse()), 1) + is(string.pack('i1', 0):len(), 1) + is(string.pack('i2', 0):len(), 2) + is(string.pack('i4', 0):len(), 4) + is(string.pack('i8', 0):len(), 8) + is(string.pack('i16', 0):len(), 16) + error_like(function () string.pack('i20', 0) end, + "^[^:]+:%d+: integral size %(20%) out of limits %[1,16%]", + "function pack out limit") + + is(string.pack('!2 i1 i4', 0, 0):len(), 6) + is(string.pack('i1 Xb i1', 0, 0):len(), 2) + is(string.pack('i1 x x i1', 0, 0):len(), 4) + + is(string.pack('c3', 'foo'), 'foo') + is(string.pack('z', 'foo'), 'foo\0') + is(string.pack('c4', 'foo'), 'foo\0') -- padding + + error_like(function () string.pack('w', 0) end, + "^[^:]+:%d+: invalid format option 'w'", + "function pack invalid format") + + error_like(function () string.pack('i1 Xz i1', 0, 0) end, + "^[^:]+:%d+: bad argument #1 to 'pack' %(invalid next option for option 'X'%)", + "function pack invalid next") + + error_like(function () string.pack('i', 'foo') end, + "^[^:]+:%d+: bad argument #2 to 'pack' %(number expected, got string%)", + "function pack bad arg") +else + is(string.pack, nil, "no string.pack"); +end + +-- packsize +if has_pack then + is(string.packsize('b'), 1, "function packsize") + + is(string.packsize(''), 0, "function packsize empty") + + error_like(function () string.packsize('z') end, + "^[^:]+:%d+: bad argument #1 to 'packsize' %(variable%-length format%)", + "function packsize bad arg") +else + is(string.packsize, nil, "no string.packsize"); +end + +do -- rep + is(string.rep('ab', 3), 'ababab', "function rep") + is(string.rep('ab', 0), '') + is(string.rep('ab', -1), '') + is(string.rep('', 5), '') + if has_rep52 then + is(string.rep('ab', 3, ','), 'ab,ab,ab', "with sep") + local n = 1e6 + is(string.rep('a', n), string.rep('', n + 1, 'a')) + else + diag("no rep with separator") + end + + if _VERSION >= 'Lua 5.3' then + error_like(function () string.rep('foo', 1e9) end, + "^[^:]+:%d+: resulting string too large", + "too large") + elseif luajit21 then + error_is(function () string.rep('foo', 1e9) end, + "not enough memory", + "too large") + end + + if _VERSION >= 'Lua 5.4' or jit then + is(string.rep('', 1e8), '', "rep ''") + else + diag('too slow') + end +end + +do -- reverse + is(string.reverse('abcde'), 'edcba', "function reverse") + is(string.reverse('abcd'), 'dcba') + is(string.reverse(''), '') +end + +do -- sub + is(string.sub('abcde', 1, 2), 'ab', "function sub") + is(string.sub('abcde', 3, 4), 'cd') + is(string.sub('abcde', -2), 'de') + is(string.sub('abcde', 3, 2), '') +end + +do -- upper + is(string.upper('Test'), 'TEST', "function upper") + is(string.upper('TeSt'), 'TEST') + is(string.upper(string.rep('Test', 10000)), string.rep('TEST', 10000)) +end + +-- unpack +if has_pack then + is(string.unpack('<h', string.pack('>h', 1):reverse()), 1, "function unpack") + is(string.unpack('<H', string.pack('>H', 1):reverse()), 1) + is(string.unpack('<l', string.pack('>l', 1):reverse()), 1) + is(string.unpack('<L', string.pack('>L', 1):reverse()), 1) + is(string.unpack('<j', string.pack('>j', 1):reverse()), 1) + is(string.unpack('<J', string.pack('>J', 1):reverse()), 1) + is(string.unpack('<T', string.pack('>T', 1):reverse()), 1) + is(string.unpack('<i', string.pack('>i', 1):reverse()), 1) + is(string.unpack('<I', string.pack('>I', 1):reverse()), 1) + is(string.unpack('<f', string.pack('>f', 1.0):reverse()), 1.0) + is(string.unpack('<d', string.pack('>d', 1.0):reverse()), 1.0) + is(string.unpack('<n', string.pack('>n', 1.0):reverse()), 1.0) + + is(string.unpack('c3', string.pack('c3', 'foo')), 'foo') + is(string.unpack('z', string.pack('z', 'foo')), 'foo') + is(string.unpack('s', string.pack('s', 'foo')), 'foo') + + error_like(function () string.unpack('c4', 'foo') end, + "^[^:]+:%d+: bad argument #2 to 'unpack' %(data string too short%)", + "function unpack data too short") + + error_like(function () string.unpack('c', 'foo') end, + "^[^:]+:%d+: missing size for format option 'c'", + "function unpack missing size") +else + is(string.unpack, nil, "no string.unpack"); +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/305-utf8.t b/test/lua-Harness-tests/305-utf8.t new file mode 100755 index 0000000..4304b6c --- /dev/null +++ b/test/lua-Harness-tests/305-utf8.t @@ -0,0 +1,55 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2014-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua UTF-8 support Library + +=head2 Synopsis + + % prove 305-utf8.t + +=head2 Description + +Tests Lua UTF-8 Library + +This library was introduced in Lua 5.3. + +See section "UTF-8 support" in "Reference Manual" +L<https://www.lua.org/manual/5.3/manual.html#6.5>, +L<https://www.lua.org/manual/5.4/manual.html#6.5> + +=cut + +--]] + +require 'tap' + +local profile = require'profile' +local has_utf8 = _VERSION >= 'Lua 5.3' or (jit and jit.version:match'moonjit') or profile.utf8 + +if not utf8 then + plan(1) + nok(has_utf8, "no has_utf8") +else + plan'no_plan' + dofile'lexico53/utf8.t' + if _VERSION >= 'Lua 5.4' then + dofile'lexico54/utf8.t' + end + done_testing() +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/306-table.t b/test/lua-Harness-tests/306-table.t new file mode 100755 index 0000000..9836655 --- /dev/null +++ b/test/lua-Harness-tests/306-table.t @@ -0,0 +1,372 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Table Library + +=head2 Synopsis + + % prove 305-table.t + +=head2 Description + +Tests Lua Table Library + +See section "Table Manipulation" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.5>, +L<https://www.lua.org/manual/5.2/manual.html#6.5>, +L<https://www.lua.org/manual/5.3/manual.html#6.6>, +L<https://www.lua.org/manual/5.4/manual.html#6.6> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT') +local has_foreach = _VERSION == 'Lua 5.1' +local has_foreachi = _VERSION == 'Lua 5.1' +local has_getn = _VERSION == 'Lua 5.1' +local has_setn_obsolete = _VERSION == 'Lua 5.1' and not jit +local has_maxn = _VERSION == 'Lua 5.1' or profile.compat51 or profile.has_table_maxn +local has_pack = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_move = _VERSION >= 'Lua 5.3' or luajit21 +local has_unpack = _VERSION >= 'Lua 5.2' +local has_alias_unpack = profile.luajit_compat52 +local nocvtn2s = profile.nocvtn2s + +plan'no_plan' + +do -- concat + local t = {'a','b','c','d','e'} + is(table.concat(t), 'abcde', "function concat") + is(table.concat(t, ','), 'a,b,c,d,e') + is(table.concat(t, ',',2), 'b,c,d,e') + is(table.concat(t, ',', 2, 4), 'b,c,d') + is(table.concat(t, ',', 4, 2), '') + + t = {'a','b',3,'d','e'} + if nocvtn2s then + error_like(function () table.concat(t,',') end, + "^[^:]+:%d+: invalid value %(number%) at index 3 in table for 'concat'", + "function concat (number no conv)") + else + is(table.concat(t,','), 'a,b,3,d,e', "function concat (number)") + end + + t = {'a','b','c','d','e'} + error_like(function () table.concat(t, ',', 2, 7) end, + "^[^:]+:%d+: invalid value %(nil%) at index 6 in table for 'concat'", + "function concat (out of range)") + + t = {'a','b',true,'d','e'} + error_like(function () table.concat(t, ',') end, + "^[^:]+:%d+: invalid value %(boolean%) at index 3 in table for 'concat'", + "function concat (non-string)") +end + +do -- insert + local a = {'10', '20', '30'} + table.insert(a, 1, '15') + is(table.concat(a,','), '15,10,20,30', "function insert") + local t = {} + table.insert(t, 'a') + is(table.concat(t, ','), 'a') + table.insert(t, 'b') + is(table.concat(t, ','), 'a,b') + table.insert(t, 1, 'c') + is(table.concat(t, ','), 'c,a,b') + table.insert(t, 2, 'd') + is(table.concat(t, ','), 'c,d,a,b') + table.insert(t, 5, 'e') + is(table.concat(t, ','), 'c,d,a,b,e') + + if _VERSION == 'Lua 5.1' then + todo("not with 5.1", 2) + end + error_like(function () table.insert(t, 7, 'f') end, + "^[^:]+:%d+: bad argument #2 to 'insert' %(position out of bounds%)", + "function insert (out of bounds)") + + error_like(function () table.insert(t, -9, 'f') end, + "^[^:]+:%d+: bad argument #2 to 'insert' %(position out of bounds%)", + "function insert (out of bounds)") + + error_like(function () table.insert(t, 2, 'g', 'h') end, + "^[^:]+:%d+: wrong number of arguments to 'insert'", + "function insert (too many arg)") +end + +-- foreach 5.0 +if has_foreach then + local t = {a=10, b=100} + local output = {} + table.foreach(t, function (k, v) output[k] = v end) + eq_array(output, t, "function foreach (hash)") + + t = {'a','b','c'} + output = {} + table.foreach(t, function (k, v) + table.insert(output, k) + table.insert(output, v) + end) + eq_array(output, {1, 'a', 2, 'b', 3, 'c'}, "function foreach (array)") +else + is(table.foreach, nil, "no table.foreach"); +end + +-- foreachi 5.0 +if has_foreachi then + local t = {'a','b','c'} + local output = {} + table.foreachi(t, function (i, v) + table.insert(output, i) + table.insert(output, v) + end) + eq_array(output, {1, 'a', 2, 'b', 3, 'c'}, "function foreachi") +else + is(table.foreachi, nil, "no table.foreachi"); +end + +if has_getn then + is(table.getn{10,2,4}, 3, "function getn") + is(table.getn{10,2,nil}, 2) +else + is(table.getn, nil, "no table.getn"); +end + +-- maxn +if has_maxn then + local t = {} + is(table.maxn(t), 0, "function maxn") + t[1] = 'a' + t[2] = 'b' + is(table.maxn(t), 2) + t[6] = 'g' + is(table.maxn(t), 6) + + local a = {} + a[10000] = 1 + is(table.maxn(a), 10000) +else + is(table.maxn, nil, "no table.maxn"); +end + +-- move +if has_move then + local a = {'a', 'b', 'c'} + local t = { 1, 2, 3, 4} + table.move(a, 1, 3, 1, t) + eq_array(t, {'a', 'b', 'c', 4}, "function move") + table.move(a, 1, 3, 3, t) + eq_array(t, {'a', 'b', 'a', 'b', 'c'}) + + table.move(a, 1, 3, 1) + eq_array(a, {'a', 'b', 'c'}) + table.move(a, 1, 3, 3) + eq_array(a, {'a', 'b', 'a', 'b', 'c'}) + + error_like(function () table.move(a, 1, 2, 1, 2) end, + "^[^:]+:%d+: bad argument #5 to 'move' %(table expected", + "function move (bad arg)") + + error_like(function () table.move(a, 1, 2) end, + "^[^:]+:%d+: bad argument #4 to 'move' %(number expected, got .-%)", + "function move (bad arg)") + + error_like(function () table.move(a, 1) end, + "^[^:]+:%d+: bad argument #3 to 'move' %(number expected, got .-%)", + "function move (bad arg)") +else + is(table.move, nil, "no table.move"); +end + +-- pack +if has_pack then + local t = table.pack("abc", "def", "ghi") + eq_array(t, { + "abc", + "def", + "ghi" + }, "function pack") + is(t.n, 3) + + t = table.pack() + eq_array(t, {}, "function pack (no element)") + is(t.n, 0) +else + is(table.pack, nil, "no table.pack"); +end + +do -- remove + local t = {} + local a = table.remove(t) + is(a, nil, "function remove") + t = {'a','b','c','d','e'} + a = table.remove(t) + is(a, 'e') + is(table.concat(t, ','), 'a,b,c,d') + a = table.remove(t,3) + is(a, 'c') + is(table.concat(t, ','), 'a,b,d') + a = table.remove(t,1) + is(a, 'a') + is(table.concat(t, ','), 'b,d') + + if _VERSION == 'Lua 5.1' then + todo("not with 5.1", 1) + end + error_like(function () table.remove(t,7) end, + "^[^:]+:%d+: bad argument #1 to 'remove' %(position out of bounds%)", + "function remove (out of bounds)") +end + +-- setn obsolete +if has_setn_obsolete then + local a = {} + error_like(function () table.setn(a, 10000) end, + "^[^:]+:%d+: 'setn' is obsolete", + "function setn") +else + is(table.setn, nil, "no table.setn"); +end + +do -- sort + local lines = { + luaH_set = 10, + luaH_get = 24, + luaH_present = 48, + } + + do + local a = {} + for n in pairs(lines) do a[#a + 1] = n end + table.sort(a) + local output = {} + for _, n in ipairs(a) do + table.insert(output, n) + end + eq_array(output, {'luaH_get', 'luaH_present', 'luaH_set'}, "function sort") + end + + do + local function pairsByKeys (t, f) + local a = {} + for n in pairs(t) do a[#a + 1] = n end + table.sort(a, f) + local i = 0 -- iterator variable + return function () -- iterator function + i = i + 1 + return a[i], t[a[i]] + end + end + + local output = {} + for name, line in pairsByKeys(lines) do + table.insert(output, name) + table.insert(output, line) + end + eq_array(output, {'luaH_get', 24, 'luaH_present', 48, 'luaH_set', 10}, "function sort") + + output = {} + for name, line in pairsByKeys(lines, function (a, b) return a < b end) do + table.insert(output, name) + table.insert(output, line) + end + eq_array(output, {'luaH_get', 24, 'luaH_present', 48, 'luaH_set', 10}, "function sort") + end + + do + local function permgen (a, n) + n = n or #a + if n <= 1 then + coroutine.yield(a) + else + for i=1,n do + a[n], a[i] = a[i], a[n] + permgen(a, n - 1) + a[n], a[i] = a[i], a[n] + end + end + end + + local function permutations (a) + local co = coroutine.create(function () permgen(a) end) + return function () + local code, res = coroutine.resume(co) + return res + end + end + + local t = {} + local output = {} + for _, v in ipairs{'a', 'b', 'c', 'd', 'e', 'f', 'g'} do + table.insert(t, v) + local ref = table.concat(t, ' ') + table.insert(output, ref) + local n = 0 + for p in permutations(t) do + local c = {} + for i, vv in ipairs(p) do + c[i] = vv + end + table.sort(c) + assert(ref == table.concat(c, ' '), table.concat(p, ' ')) + n = n + 1 + end + table.insert(output, n) + end + + eq_array(output, { + 'a', 1, + 'a b', 2, + 'a b c', 6, + 'a b c d', 24, + 'a b c d e', 120, + 'a b c d e f', 720, + 'a b c d e f g', 5040, + }, "function sort (all permutations)") + end + + if _VERSION == 'Lua 5.1' and not jit then + todo("not with 5.1") + end + error_like(function () + local t = { 1 } + table.sort( { t, t, t, t, }, function (a, b) return a[1] == b[1] end ) + end, + "^[^:]+:%d+: invalid order function for sorting", + "function sort (bad func)") +end + +-- unpack +if has_unpack then + eq_array({table.unpack({})}, {}, "function unpack") + eq_array({table.unpack({'a'})}, {'a'}) + eq_array({table.unpack({'a','b','c'})}, {'a','b','c'}) + eq_array({(table.unpack({'a','b','c'}))}, {'a'}) + eq_array({table.unpack({'a','b','c','d','e'},2,4)}, {'b','c','d'}) + eq_array({table.unpack({'a','b','c'},2,4)}, {'b','c'}) +elseif has_alias_unpack then + is(table.unpack, unpack, "alias table.unpack"); +else + is(table.unpack, nil, "no table.unpack"); +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/307-math.t b/test/lua-Harness-tests/307-math.t new file mode 100755 index 0000000..8b51ed1 --- /dev/null +++ b/test/lua-Harness-tests/307-math.t @@ -0,0 +1,375 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Mathematic Library + +=head2 Synopsis + + % prove 307-math.t + +=head2 Description + +Tests Lua Mathematic Library + +See section "Mathematical Functions" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.6>, +L<https://www.lua.org/manual/5.2/manual.html#6.6>, +L<https://www.lua.org/manual/5.3/manual.html#6.7>, +L<https://www.lua.org/manual/5.4/manual.html#6.7> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local has_integer = _VERSION >= 'Lua 5.3' or (jit and jit.version:match'moonjit') or profile.integer +local has_mathx = _VERSION < 'Lua 5.3' or profile.compat52 or profile.compat53 or profile.has_mathx +local has_log10 = _VERSION < 'Lua 5.2' or profile.compat51 or profile.has_math_log10 or + profile.compat52 or profile.compat53 or profile.has_mathx +local has_log_with_base = _VERSION >= 'Lua 5.2' or profile.compat52 +local has_mod = profile.has_math_mod or ujit +local nocvts2n = profile.nocvts2n or jit + +plan'no_plan' + +do -- abs + is(math.abs(-12.34), 12.34, "function abs (float)") + is(math.abs(12.34), 12.34) + if math.type then + is(math.type(math.abs(-12.34)), 'float') + end + is(math.abs(-12), 12, "function abs (integer)") + is(math.abs(12), 12) + if math.type then + is(math.type(math.abs(-12)), 'integer') + end +end + +do -- acos + like(math.acos(0.5), '^1%.047', "function acos") +end + +do -- asin + like(math.asin(0.5), '^0%.523', "function asin") +end + +do -- atan + like(math.atan(0.5), '^0%.463', "function atan") +end + +-- atan2 +if has_mathx then + like(math.atan2(1.0, 2.0), '^0%.463', "function atan2") +else + is(math.atan2, nil, "function atan2 (removed)") +end + +do -- ceil + is(math.ceil(12.34), 13, "function ceil") + is(math.ceil(-12.34), -12) + is(math.ceil(-12), -12) + if math.type then + is(math.type(math.ceil(-12.34)), 'integer') + end +end + +do -- cos + like(math.cos(1.0), '^0%.540', "function cos") +end + +-- cosh +if has_mathx then + like(math.cosh(1.0), '^1%.543', "function cosh") +else + is(math.cosh, nil, "function cosh (removed)") +end + +do -- deg + is(math.deg(math.pi), 180, "function deg") +end + +do -- exp + like(math.exp(1.0), '^2%.718', "function exp") +end + +do -- floor + is(math.floor(12.34), 12, "function floor") + is(math.floor(-12.34), -13) + is(math.floor(-12), -12) + if math.type then + is(math.type(math.floor(-12.34)), 'integer') + end +end + +do -- fmod + like(math.fmod(7.0001, 0.3), '^0%.100', "function fmod (float)") + like(math.fmod(-7.0001, 0.3), '^-0%.100') + like(math.fmod(-7.0001, -0.3), '^-0%.100') + if math.type then + is(math.type(math.fmod(7.0, 0.3)), 'float') + end + is(math.fmod(7, 3), 1, "function fmod (integer)") + is(math.fmod(-7, 3), -1) + is(math.fmod(-7, -1), 0) + if math.type then + is(math.type(math.fmod(7, 3)), 'integer') + end + if _VERSION >= 'Lua 5.3' then + error_like(function () math.fmod(7, 0) end, + "^[^:]+:%d+: bad argument #2 to 'fmod' %(zero%)", + "function fmod 0") + else + diag"fmod by zero -> nan" + end +end + +-- frexp +if has_mathx then + eq_array({math.frexp(1.5)}, {0.75, 1}, "function frexp") +else + is(math.frexp, nil, "function frexp (removed)") +end + +do -- huge + type_ok(math.huge, 'number', "variable huge") + if math.type then + is(math.type(math.huge), 'float') + end +end + +-- ldexp +if has_mathx then + is(math.ldexp(1.2, 3), 9.6, "function ldexp") +else + is(math.ldexp, nil, "function ldexp (removed)") +end + +do -- log + like(math.log(47), '^3%.85', "function log") + if has_log_with_base then + like(math.log(47, math.exp(1)), '^3%.85', "function log (base e)") + like(math.log(47, 2), '^5%.554', "function log (base 2)") + like(math.log(47, 10), '^1%.672', "function log (base 10)") + end +end + +-- log10 +if has_log10 then + like(math.log10(47.0), '^1%.672', "function log10") +else + is(math.log10, nil, "function log10 (removed)") +end + +do --max + is(math.max(1), 1, "function max") + is(math.max(1, 2), 2) + is(math.max(1, 2, 3, -4), 3) + + error_like(function () math.max() end, + "^[^:]+:%d+: bad argument #1 to 'max' %(.- expected", + "function max 0") +end + +-- maxinteger +if has_integer then + type_ok(math.maxinteger, 'number', "variable maxinteger") + if math.type then + is(math.type(math.maxinteger), 'integer') + end +else + is(math.maxinteger, nil, "no maxinteger") +end + +do --min + is(math.min(1), 1, "function min") + is(math.min(1, 2), 1) + is(math.min(1, 2, 3, -4), -4) + + error_like(function () math.min() end, + "^[^:]+:%d+: bad argument #1 to 'min' %(.- expected", + "function min 0") +end + +-- mininteger +if has_integer then + type_ok(math.mininteger, 'number', "variable mininteger") + if math.type then + is(math.type(math.mininteger), 'integer') + end +else + is(math.mininteger, nil, "no mininteger") +end + +-- mod (compat50) +if has_mod then + is(math.mod, math.fmod, "function mod (alias fmod)") +else + is(math.mod, nil, "function mod (alias removed)") +end + +do -- modf + eq_array({math.modf(2.25)}, {2, 0.25}, "function modf") + eq_array({math.modf(2)}, {2, 0.0}) +end + +do -- pi + like(tostring(math.pi), '^3%.14', "variable pi") +end + +-- pow +if has_mathx then + is(math.pow(-2, 3), -8, "function pow") +else + is(math.pow, nil, "function pow (removed)") +end + +do -- rad + like(math.rad(180), '^3%.14', "function rad") +end + +do -- random + like(math.random(), '^0%.%d+', "function random no arg") + if math.type then + is(math.type(math.random()), 'float') + end + like(math.random(9), '^%d$', "function random 1 arg") + if math.type then + is(math.type(math.random(9)), 'integer') + end + like(math.random(10, 19), '^1%d$', "function random 2 arg") + if math.type then + is(math.type(math.random(10, 19)), 'integer') + end + like(math.random(-19, -10), '^-1%d$', "function random 2 arg") + + if _VERSION >= 'Lua 5.4' then + like(math.random(0), '^%-?%d+$', "function random 0") + else + if jit then + todo("LuaJIT intentional. Don't check empty interval.") + end + error_like(function () math.random(0) end, + "^[^:]+:%d+: bad argument #1 to 'random' %(interval is empty%)", + "function random empty interval") + end + + if jit then + todo("LuaJIT intentional. Don't check empty interval.", 2) + end + error_like(function () math.random(-9) end, + "^[^:]+:%d+: bad argument #%d to 'random' %(interval is empty%)", + "function random empty interval") + + error_like(function () math.random(19, 10) end, + "^[^:]+:%d+: bad argument #%d to 'random' %(interval is empty%)", + "function random empty interval") + + if jit then + todo("LuaJIT intentional. Don't care about extra arguments.") + end + error_like(function () math.random(1, 2, 3) end, + "^[^:]+:%d+: wrong number of arguments", + "function random too many arg") +end + +do -- randomseed + math.randomseed(42) + local a = math.random() + math.randomseed(42) + local b = math.random() + is(a, b, "function randomseed") +end + +do -- sin + like(math.sin(1.0), '^0%.841', "function sin") +end + +-- sinh +if has_mathx then + like(math.sinh(1), '^1%.175', "function sinh") +else + is(math.sinh, nil, "function sinh (removed)") +end + +do -- sqrt + like(math.sqrt(2), '^1%.414', "function sqrt") +end + +do -- tan + like(math.tan(1.0), '^1%.557', "function tan") +end + +-- tanh +if has_mathx then + like(math.tanh(1), '^0%.761', "function tanh") +else + is(math.tanh, nil, "function tanh (removed)") +end + +-- tointeger +if has_integer then + is(math.tointeger(-12), -12, "function tointeger (number)") + is(math.tointeger(-12.0), -12) + is(math.tointeger(-12.34), nil) + if nocvts2n then + is(math.tointeger('-12'), nil, "function tointeger (string)") + is(math.tointeger('-12.0'), nil) + else + is(math.tointeger('-12'), -12, "function tointeger (string)") + is(math.tointeger('-12.0'), -12) + end + is(math.tointeger('-12.34'), nil) + is(math.tointeger('bad'), nil) + is(math.tointeger(true), nil, "function tointeger (boolean)") + is(math.tointeger({}), nil, "function tointeger (table)") +else + is(math.tointeger, nil, "no math.tointeger") +end + +-- type +if has_integer then + is(math.type(3), 'integer', "function type") + is(math.type(3.14), 'float') + is(math.type('3.14'), nil) +else + is(math.type, nil, "no math.type") +end + +-- ult +if has_integer then + is(math.ult(2, 3), true, "function ult") + is(math.ult(2, 2), false) + is(math.ult(2, 1), false) + + error_like(function () math.ult(3.14) end, + "^%S+ bad argument #1 to 'ult' %(number has no integer representation%)", + "function ult (float)") + error_like(function () math.ult(2, 3.14) end, + "^%S+ bad argument #2 to 'ult' %(number has no integer representation%)") + error_like(function () math.ult(true) end, + "^[^:]+:%d+: bad argument #1 to 'ult' %(number expected, got boolean%)", + "function ult (boolean)") + error_like(function () math.ult(2, true) end, + "^[^:]+:%d+: bad argument #2 to 'ult' %(number expected, got boolean%)") +else + is(math.ult, nil, "no math.ult") +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/308-io.t b/test/lua-Harness-tests/308-io.t new file mode 100755 index 0000000..35d39c0 --- /dev/null +++ b/test/lua-Harness-tests/308-io.t @@ -0,0 +1,397 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Input/Output Library + +=head2 Synopsis + + % prove 308-io.t + +=head2 Description + +Tests Lua Input/Output Library + +See section "Input and Output Facilities" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.7>, +L<https://www.lua.org/manual/5.2/manual.html#6.8>, +L<https://www.lua.org/manual/5.3/manual.html#6.8>, +L<https://www.lua.org/manual/5.4/manual.html#6.8> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT') +local has_write51 = _VERSION == 'Lua 5.1' and (not profile.luajit_compat52 or ujit) +local has_lines52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_read52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_read53 = _VERSION >= 'Lua 5.3' or luajit21 +local has_meta53 = _VERSION >= 'Lua 5.3' +local has_meta54 = _VERSION >= 'Lua 5.4' + +local lua = get_lua_binary_name() + +plan'no_plan' + +do -- stdin + like(io.stdin, '^file %(0?[Xx]?%x+%)$', "variable stdin") +end + +do -- stdout + like(io.stdout, '^file %(0?[Xx]?%x+%)$', "variable stdout") +end + +do -- stderr + like(io.stderr, '^file %(0?[Xx]?%x+%)$', "variable stderr") +end + +do -- metatable + local f = io.tmpfile() + local mt = getmetatable(f) + type_ok(mt, 'table', "metatable") + + type_ok(mt.__gc, 'function') + type_ok(mt.__tostring, 'function') + type_ok(mt.__index, 'table') + + if has_meta53 then + is(mt.__name, 'FILE*') + else + is(mt.__name, nil) + end + + if has_meta54 then + type_ok(mt.__close, 'function') + type_ok(mt.__index, 'table') + is(mt.close, nil) + is(mt.flush, nil) + is(mt.lines, nil) + is(mt.read, nil) + is(mt.seek, nil) + is(mt.setvbuf, nil) + is(mt.write, nil) + else + is(mt.__close, nil) + is(mt.__index, mt) + type_ok(mt.close, 'function') + type_ok(mt.flush, 'function') + type_ok(mt.lines, 'function') + type_ok(mt.read, 'function') + type_ok(mt.seek, 'function') + type_ok(mt.setvbuf, 'function') + type_ok(mt.write, 'function') + end + + type_ok(mt.__index.close, 'function') + type_ok(mt.__index.flush, 'function') + type_ok(mt.__index.lines, 'function') + type_ok(mt.__index.read, 'function') + type_ok(mt.__index.seek, 'function') + type_ok(mt.__index.setvbuf, 'function') + type_ok(mt.__index.write, 'function') +end + +do -- close + local r, msg = io.close(io.stderr) + is(r, nil, "close (std)") + is(msg, "cannot close standard file") +end + +do -- flush + is(io.flush(), true, "function flush") +end + +do -- open + os.remove('file-308.no') + local f, msg = io.open("file-308.no") + is(f, nil, "function open") + is(msg, "file-308.no: No such file or directory") + + os.remove('file-308.txt') + f = io.open('file-308.txt', 'w') + f:write("file with text\n") + f:close() + f = io.open('file-308.txt') + like(f, '^file %(0?[Xx]?%x+%)$', "function open") + + is(io.close(f), true, "function close") + + error_like(function () io.close(f) end, + "^[^:]+:%d+: attempt to use a closed file", + "function close (closed)") + + if _VERSION == 'Lua 5.1' then + todo("not with 5.1") + end + error_like(function () io.open('file-308.txt', 'baz') end, + "^[^:]+:%d+: bad argument #2 to 'open' %(invalid mode%)", + "function open (bad mode)") +end + +do -- type + is(io.type("not a file"), nil, "function type") + local f = io.open('file-308.txt') + is(io.type(f), 'file') + like(tostring(f), '^file %(0?[Xx]?%x+%)$') + io.close(f) + is(io.type(f), 'closed file') + is(tostring(f), 'file (closed)') +end + +do -- input + is(io.stdin, io.input(), "function input") + is(io.stdin, io.input(nil)) + local f = io.stdin + like(io.input('file-308.txt'), '^file %(0?[Xx]?%x+%)$') + is(f, io.input(f)) +end + +do -- output + is(io.output(), io.stdout, "function output") + is(io.output(nil), io.stdout) + local f = io.stdout + like(io.output('output.new'), '^file %(0?[Xx]?%x+%)$') + is(f, io.output(f)) + os.remove('output.new') +end + +do -- popen + local r, f = pcall(io.popen, lua .. [[ -e "print 'standard output'"]]) + if r then + is(io.type(f), 'file', "popen (read)") + is(f:read(), "standard output") + is(io.close(f), true) + else + diag("io.popen not supported") + end + + r, f = pcall(io.popen, lua .. [[ -e "for line in io.lines() do print((line:gsub('e', 'a'))) end"]], 'w') + if r then + is(io.type(f), 'file', "popen (write)") + f:write("# hello\n") -- not tested : hallo + is(io.close(f), true) + else + diag("io.popen not supported") + end +end + +do -- lines + for line in io.lines('file-308.txt') do + is(line, "file with text", "function lines(filename)") + end + + error_like(function () io.lines('file-308.no') end, + "No such file or directory", + "function lines(no filename)") +end + +do -- tmpfile + local f = io.tmpfile() + is(io.type(f), 'file', "function tmpfile") + f:write("some text") + f:close() +end + +do -- write + io.write() -- not tested + io.write('# text', 12, "\n") -- not tested : # text12 +end + +do -- :close + local r, msg = io.stderr:close() + is(r, nil, "method close (std)") + is(msg, "cannot close standard file") + + local f = io.open('file-308.txt') + is(f:close(), true, "method close") +end + +do -- :flush + is(io.stderr:flush(), true, "method flush") + + local f = io.open('file-308.txt') + f:close() + error_like(function () f:flush() end, + "^[^:]+:%d+: attempt to use a closed file", + "method flush (closed)") +end + +do -- :read & :write + local f = io.open('file-308.txt') + f:close() + error_like(function () f:read() end, + "^[^:]+:%d+: attempt to use a closed file", + "method read (closed)") + + f = io.open('file-308.txt') + local s = f:read() + is(s:len(), 14, "method read") + is(s, "file with text") + s = f:read() + is(s, nil) + f:close() + + f = io.open('file-308.txt') + error_like(function () f:read('*z') end, + "^[^:]+:%d+: bad argument #1 to 'read' %(invalid %w+%)", + "method read (invalid)") + f:close() + + f = io.open('file-308.txt') + local s1, s2 = f:read('*l', '*l') + is(s1:len(), 14, "method read *l") + is(s1, "file with text") + is(s2, nil) + f:close() + + if has_read52 then + f = io.open('file-308.txt') + s1, s2 = f:read('*L', '*L') + is(s1:len(), 15, "method read *L") + is(s1, "file with text\n") + is(s2, nil) + f:close() + else + diag("no read *L") + end + + f = io.open('file-308.txt') + local n1, n2 = f:read('*n', '*n') + is(n1, nil, "method read *n") + is(n2, nil) + f:close() + + f = io.open('file-308.num', 'w') + f:write('1\n') + f:write('0xFF\n') + f:write(string.rep('012', 90) .. '\n') + f:close() + + f = io.open('file-308.num') + n1, n2 = f:read('*n', '*n') + is(n1, 1, "method read *n") + is(n2, 255, "method read *n") + local n = f:read('*n') + if _VERSION < 'Lua 5.3' then + type_ok(n, 'number') + else + is(n, nil, "method read *n too long") + end + f:close() + + os.remove('file-308.num') -- clean up + + f = io.open('file-308.txt') + s = f:read('*a') + is(s:len(), 15, "method read *a") + is(s, "file with text\n") + f:close() + + if has_read53 then + f = io.open('file-308.txt') + s = f:read('a') + is(s:len(), 15, "method read a") + is(s, "file with text\n") + f:close() + else + diag("* mandatory") + end + + f = io.open('file-308.txt') + is(f:read(0), '', "method read number") + eq_array({f:read(5, 5, 15)}, {'file ', 'with ', "text\n"}) + f:close() +end + +do -- :lines + local f = io.open('file-308.txt') + for line in f:lines() do + is(line, "file with text", "method lines") + end + is(io.type(f), 'file') + f:close() + is(io.type(f), 'closed file') + + if has_lines52 then + f = io.open('file-308.txt') + for two_char in f:lines(2) do + is(two_char, "fi", "method lines (with read option)") + break + end + f:close() + else + diag("no lines with option") + end +end + +do -- :seek + local f = io.open('file-308.txt') + f:close() + + error_like(function () f:seek('end', 0) end, + "^[^:]+:%d+: attempt to use a closed file", + "method seek (closed)") + + f = io.open('file-308.txt') + error_like(function () f:seek('bad', 0) end, + "^[^:]+:%d+: bad argument #1 to 'seek' %(invalid option 'bad'%)", + "method seek (invalid)") + + f = io.open('file-308.bin', 'w') + f:write('ABCDE') + f:close() + f = io.open('file-308.bin') + is(f:seek('end', 0), 5, "method seek") + f:close() + os.remove('file-308.bin') --clean up +end + +do -- :setvbuf + local f = io.open('file-308.txt') + is(f:setvbuf('no'), true, "method setvbuf 'no'") + + is(f:setvbuf('full', 4096), true, "method setvbuf 'full'") + + is(f:setvbuf('line', 132), true, "method setvbuf 'line'") + f:close() +end + +os.remove('file-308.txt') -- clean up + +do -- :write + local f = io.open('file-308.out', 'w') + f:close() + error_like(function () f:write('end') end, + "^[^:]+:%d+: attempt to use a closed file", + "method write (closed)") + + f = io.open('file-308.out', 'w') + if has_write51 then + is(f:write('end'), true, "method write") + else + is(f:write('end'), f, "method write") + end + f:close() + + os.remove('file-308.out') --clean up +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/309-os.t b/test/lua-Harness-tests/309-os.t new file mode 100755 index 0000000..a787b14 --- /dev/null +++ b/test/lua-Harness-tests/309-os.t @@ -0,0 +1,271 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Operating System Library + +=head2 Synopsis + + % prove 309-os.t + +=head2 Description + +Tests Lua Operating System Library + +See section "Operating System Facilities" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.8>, +L<https://www.lua.org/manual/5.2/manual.html#6.9>, +L<https://www.lua.org/manual/5.3/manual.html#6.9>, +L<https://www.lua.org/manual/5.4/manual.html#6.9> + +=cut + +--]] + +require'tap' +local profile = require'profile' +local luajit20 = jit and (jit.version_num < 20100 and not jit.version:match'^RaptorJIT') +local has_execute51 = _VERSION == 'Lua 5.1' and (not profile.luajit_compat52 or ujit) +local lua = get_lua_binary_name() + +plan'no_plan' + +do -- clock + local clk = os.clock() + type_ok(clk, 'number', "function clock") + ok(clk <= os.clock()) +end + +do -- date + local d = os.date('!*t', 0) + is(d.year, 1970, "function date") + is(d.month, 1) + is(d.day, 1) + is(d.hour, 0) + is(d.min, 0) + is(d.sec, 0) + is(d.wday, 5) + is(d.yday, 1) + is(d.isdst, false) + + is(os.date('!%d/%m/%y %H:%M:%S', 0), '01/01/70 00:00:00', "function date") + + like(os.date('%H:%M:%S'), '^%d%d:%d%d:%d%d', "function date") + + if (_VERSION == 'Lua 5.1' and not jit) or luajit20 then + todo("not with 5.1") + end + is(os.date('%Oy', 0), '70') + + if _VERSION == 'Lua 5.1' then + todo("not with 5.1") + end + error_like(function () os.date('%Ja', 0) end, + "^[^:]+:%d+: bad argument #1 to 'date' %(invalid conversion specifier '%%Ja'%)", + "function date (invalid)") +end + +do -- difftime + is(os.difftime(1234, 1200), 34, "function difftime") +end + +do -- execute + if has_execute51 then + local res = os.execute() + is(res, 1, "function execute -> shell is available") + + ok(os.execute('__IMPROBABLE__') > 0, "function execute __IMPROBABLE__") + + local cmd = lua .. [[ -e "print '# hello from external Lua'"]] + is(os.execute(cmd), 0, "function execute") + else + local res = os.execute() + is(res, true, "function execute -> shell is available") + + local r, s, n = os.execute('__IMPROBABLE__') + is(r, nil, "function execute __IMPROBABLE__") + is(s, 'exit') + type_ok(n, 'number') + + local cmd = lua .. [[ -e "print '# hello from external Lua'"]] + r, s, n = os.execute(cmd) + is(r, true, "function execute") + is(s, 'exit') + is(n, 0) + end +end + +do -- exit called with execute + if has_execute51 then + local cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(2)"]] + ok(os.execute(cmd) > 0, "function exit called with execute") + else + local cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(2)"]] + local r, s, n = os.execute(cmd) + is(r, nil, "function exit called with execute") + is(s, 'exit') + is(n, 2, "exit value") + + cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(false)"]] + r, s, n = os.execute(cmd) + is(r, nil, "function exit called with execute") + is(s, 'exit') + is(n, 1, "exit value") + + cmd = lua .. [[ -e "print '# hello from external Lua'; os.exit(true, true)"]] + r, s, n = os.execute(cmd) + is(r, true, "exit called with execute") + is(s, 'exit') + is(n, 0, "exit value") + end +end + +do -- exit called with popen + local cmd = lua .. [[ -e "print 'reached'; os.exit(); print 'not reached';"]] + local res, f = pcall(io.popen, cmd) + if res then + is(f:read'*l', 'reached', "exit called with popen") + is(f:read'*l', nil) + if has_execute51 then + local code = f:close() + is(code, true, "exit code") + else + local r, s, n = f:close() + is(r, true) + is(s, 'exit', "exit code") + is(n, 0, "exit value") + end + else + diag("io.popen not supported") + end + + cmd = lua .. [[ -e "print 'reached'; os.exit(3); print 'not reached';"]] + res, f = pcall(io.popen, cmd) + if res then + is(f:read'*l', 'reached', "exit called with popen") + is(f:read'*l', nil) + if has_execute51 then + local code = f:close() + is(code, true, "exit code") + else + local r, s, n = f:close() + is(r, nil) + is(s, 'exit', "exit code") + is(n, 3, "exit value") + end + else + diag("io.popen not supported") + end +end + +do -- getenv + is(os.getenv('__IMPROBABLE__'), nil, "function getenv") + + local user = os.getenv('LOGNAME') or os.getenv('USERNAME') + type_ok(user, 'string', "function getenv") +end + +do -- remove + local f = io.open('file-309.rm', 'w') + f:write("file to remove") + f:close() + local r = os.remove("file-309.rm") + is(r, true, "function remove") + + local msg + r, msg = os.remove('file-309.rm') + is(r, nil, "function remove") + like(msg, '^file%-309%.rm: No such file or directory') +end + +do -- rename + local f = io.open('file-309.old', 'w') + f:write("file to rename") + f:close() + os.remove('file-309.new') + local r = os.rename('file-309.old', 'file-309.new') + is(r, true, "function rename") + os.remove('file-309.new') -- clean up + + local msg + r, msg = os.rename('file-309.old', 'file-309.new') + is(r, nil, "function rename") + like(msg, 'No such file or directory') +end + +do -- setlocale + is(os.setlocale('C', 'all'), 'C', "function setlocale") + is(os.setlocale(), 'C') + is(os.setlocale('unk_loc', 'all'), nil, "function setlocale (unknown locale)") +end + +do -- time + like(os.time(), '^%d+%.?%d*$', "function time") + like(os.time(nil), '^%d+%.?%d*$', "function time") + like(os.time({ + sec = 0, + min = 0, + hour = 0, + day = 1, + month = 1, + year = 2000, + isdst = false, + }), '^946%d+$', "function time") + + error_like(function () os.time{} end, + "^[^:]+:%d+: field '%w+' missing in date table", + "function time (missing field)") + + error_like(function () os.time({ day = 'bad', year = 'bad' }) end, + "^[^:]+:%d+: field '%w+'", + "function time (bad field)") + + if _VERSION < 'Lua 5.3' then + todo("only with integer") + end + error_like(function () os.time({ day = 1.5, year = 1.5 }) end, + "^[^:]+:%d+: field '%w+' is not an integer", + "function time (not integer)") + + if string.packsize and string.packsize('l') == 8 then + skip('64bit platforms') + else + if _VERSION < 'Lua 5.3' then + todo"only with 5.3" + end + error_like(function () os.time({ + sec = 0, + min = 0, + hour = 0, + day = 1, + month = 1, + year = 1000, + isdst = false, + }) end, + "^[^:]+:%d+: time result cannot be represented in this installation", + "function time (invalid)") + end +end + +do -- tmpname + local fname = os.tmpname() + type_ok(fname, 'string', "function tmpname") + ok(fname ~= os.tmpname()) +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/310-debug.t b/test/lua-Harness-tests/310-debug.t new file mode 100755 index 0000000..f78af03 --- /dev/null +++ b/test/lua-Harness-tests/310-debug.t @@ -0,0 +1,322 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Debug Library + +=head2 Synopsis + + % prove 310-debug.t + +=head2 Description + +Tests Lua Debug Library + +See section "The Debug Library" in "Reference Manual" +L<https://www.lua.org/manual/5.1/manual.html#5.9>, +L<https://www.lua.org/manual/5.2/manual.html#6.10>, +L<https://www.lua.org/manual/5.3/manual.html#6.10>, +L<https://www.lua.org/manual/5.4/manual.html#6.10> + +=cut + +]] + +require 'tap' +local profile = require'profile' +local has_getfenv = _VERSION == 'Lua 5.1' +local has_gethook54 = _VERSION >= 'Lua 5.4' +local has_getlocal52 = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_getuservalue = _VERSION >= 'Lua 5.2' or profile.luajit_compat52 +local has_getuservalue54 = _VERSION >= 'Lua 5.4' +local has_setcstacklimit = _VERSION >= 'Lua 5.4' +local has_setmetatable52 = _VERSION >= 'Lua 5.2' or (profile.luajit_compat52 and not ujit) +local has_upvalueid = _VERSION >= 'Lua 5.2' or jit +local has_upvaluejoin = _VERSION >= 'Lua 5.2' or jit + +local debug = require 'debug' + +if not debug then + skip_all("no debug") +end + +plan'no_plan' + +-- getfenv +if has_getfenv then + is(debug.getfenv(3.14), nil, "function getfenv") + local function f () end + type_ok(debug.getfenv(f), 'table') + is(debug.getfenv(f), _G) + type_ok(debug.getfenv(print), 'table') + is(debug.getfenv(print), _G) + + local a = coroutine.create(function () return 1 end) + type_ok(debug.getfenv(a), 'table', "function getfenv (thread)") + is(debug.getfenv(a), _G) +else + is(debug.getfenv, nil, "no debug.getfenv (removed)") +end + +do -- getinfo + local info = debug.getinfo(is) + type_ok(info, 'table', "function getinfo (function)") + is(info.func, is, " .func") + + info = debug.getinfo(is, 'L') + type_ok(info, 'table', "function getinfo (function, opt)") + type_ok(info.activelines, 'table') + + info = debug.getinfo(1) + type_ok(info, 'table', "function getinfo (level)") + like(info.func, "^function: [0]?[Xx]?%x+", " .func") + + is(debug.getinfo(12), nil, "function getinfo (too depth)") + + error_like(function () debug.getinfo('bad') end, + "bad argument #1 to 'getinfo' %(.- expected", + "function getinfo (bad arg)") + + error_like(function () debug.getinfo(is, 'X') end, + "bad argument #2 to 'getinfo' %(invalid option%)", + "function getinfo (bad opt)") +end + +do -- getlocal + local name, value = debug.getlocal(0, 1) + type_ok(name, 'string', "function getlocal (level)") + is(value, 0) + + error_like(function () debug.getlocal(42, 1) end, + "bad argument #1 to 'getlocal' %(level out of range%)", + "function getlocal (out of range)") + + if has_getlocal52 then + name, value = debug.getlocal(like, 1) + type_ok(name, 'string', "function getlocal (func)") + is(value, nil) + else + diag("no getlocal with function") + end +end + +do -- getmetatable + local t = {} + is(debug.getmetatable(t), nil, "function getmetatable") + local t1 = {} + debug.setmetatable(t, t1) + is(debug.getmetatable(t), t1) + + local a = true + is(debug.getmetatable(a), nil) + debug.setmetatable(a, t1) + is(debug.getmetatable(t), t1) + + a = 3.14 + is(debug.getmetatable(a), nil) + debug.setmetatable(a, t1) + is(debug.getmetatable(t), t1) +end + +do -- getregistry + local reg = debug.getregistry() + type_ok(reg, 'table', "function getregistry") + type_ok(reg._LOADED, 'table') +end + +do -- getupvalue + local name = debug.getupvalue(plan, 1) + type_ok(name, 'string', "function getupvalue") +end + +do -- gethook + debug.sethook() + local hook, mask, count + if has_gethook54 then + hook = debug.gethook() + is(hook, nil, "function gethook") + else + hook, mask, count = debug.gethook() + is(hook, nil, "function gethook") + is(mask, '') + is(count, 0) + end + local function f () end + debug.sethook(f, 'c', 42) + hook , mask, count = debug.gethook() + is(hook, f, "function gethook") + is(mask, 'c') + is(count, 42) + + local co = coroutine.create(function () print "thread" end) + hook = debug.gethook(co) + if jit then + type_ok(hook, 'function', "function gethook(thread)") + else + is(hook, nil, "function gethook(thread)") + end +end + +do -- setlocal + local name = debug.setlocal(0, 1, 0) + type_ok(name, 'string', "function setlocal (level)") + + name = debug.setlocal(0, 42, 0) + is(name, nil, "function setlocal (level)") + + error_like(function () debug.setlocal(42, 1, true) end, + "bad argument #1 to 'setlocal' %(level out of range%)", + "function setlocal (out of range)") +end + +-- setcstacklimit +if has_setcstacklimit then + type_ok(debug.setcstacklimit(200), 'number', "function setcstacklimit") + is(debug.setcstacklimit(1000), 200) + + error_like(function () debug.setcstacklimit('bad') end, + "^[^:]+:%d+: bad argument #1 to 'setcstacklimit' %(number expected, got string%)", + "function setcstacklimit (bad arg)") +else + is(debug.setcstacklimit, nil, "no debug.setcstacklimit") +end + +-- setfenv +if has_getfenv then + local t = {} + local function f () end + is(debug.setfenv(f, t), f, "function setfenv") + type_ok(debug.getfenv(f), 'table') + is(debug.getfenv(f), t) + is(debug.setfenv(print, t), print) + type_ok(debug.getfenv(print), 'table') + is(debug.getfenv(print), t) + + t = {} + local a = coroutine.create(function () return 1 end) + is(debug.setfenv(a, t), a, "function setfenv (thread)") + type_ok(debug.getfenv(a), 'table') + is(debug.getfenv(a), t) + + error_like(function () t = {}; debug.setfenv(t, t) end, + "^[^:]+:%d+: 'setfenv' cannot change environment of given object", + "function setfenv (forbidden)") +else + is(debug.setfenv, nil, "no debug.setfenv (removed)") +end + +do -- setmetatable + local t = {} + local t1 = {} + if has_setmetatable52 then + is(debug.setmetatable(t, t1), t, "function setmetatable") + else + is(debug.setmetatable(t, t1), true, "function setmetatable") + end + is(getmetatable(t), t1) + + error_like(function () debug.setmetatable(t, true) end, + "^[^:]+:%d+: bad argument #2 to 'setmetatable' %(nil or table expected") +end + +do -- setupvalue + local r, tb = pcall(require, 'Test.Builder') + local value = r and tb:new() or {} + local name = debug.setupvalue(plan, 1, value) + type_ok(name, 'string', "function setupvalue") + + name = debug.setupvalue(plan, 42, true) + is(name, nil) +end + +-- getuservalue / setuservalue +if has_getuservalue54 then + local u = io.tmpfile() -- lua_newuserdatauv(L, sizeof(LStream), 0); + is(debug.getuservalue(u, 0), nil, "function getuservalue") + is(debug.getuservalue(true), nil) + + error_like(function () debug.getuservalue(u, 'foo') end, + "^[^:]+:%d+: bad argument #2 to 'getuservalue' %(number expected, got string%)") + + local data = {} + is(debug.setuservalue(u, data, 42), nil, "function setuservalue") + + error_like(function () debug.setuservalue({}, data) end, + "^[^:]+:%d+: bad argument #1 to 'setuservalue' %(userdata expected, got table%)") + + error_like(function () debug.setuservalue(u, data, 'foo') end, + "^[^:]+:%d+: bad argument #3 to 'setuservalue' %(number expected, got string%)") +elseif has_getuservalue then + local u = io.tmpfile() + local old = debug.getuservalue(u) + if jit then + type_ok(old, 'table', "function getuservalue") + else + is(old, nil, "function getuservalue") + end + is(debug.getuservalue(true), nil) + + local data = {} + local r = debug.setuservalue(u, data) + is(r, u, "function setuservalue") + is(debug.getuservalue(u), data) + r = debug.setuservalue(u, old) + is(debug.getuservalue(u), old) + + error_like(function () debug.setuservalue({}, data) end, + "^[^:]+:%d+: bad argument #1 to 'setuservalue' %(userdata expected, got table%)") +else + is(debug.getuservalue, nil, "no getuservalue") + is(debug.setuservalue, nil, "no setuservalue") +end + +do -- traceback + like(debug.traceback(), "^stack traceback:\n", "function traceback") + + like(debug.traceback("message\n"), "^message\n\nstack traceback:\n", "function traceback with message") + + like(debug.traceback(false), "false", "function traceback") +end + +-- upvalueid +if has_upvalueid then + local id = debug.upvalueid(plan, 1) + type_ok(id, 'userdata', "function upvalueid") +else + is(debug.upvalueid, nil, "no upvalueid") +end + +-- upvaluejoin +if has_upvaluejoin and jit then + diag("jit upvaluejoin") + -- TODO +elseif has_upvaluejoin then + debug.upvaluejoin(pass, 1, fail, 1) + + error_like(function () debug.upvaluejoin(true, 1, nil, 1) end, + "bad argument #1 to 'upvaluejoin' %(function expected, got boolean%)", + "function upvaluejoin (bad arg)") + + error_like(function () debug.upvaluejoin(pass, 1, true, 1) end, + "bad argument #3 to 'upvaluejoin' %(function expected, got boolean%)", + "function upvaluejoin (bad arg)") +else + is(debug.upvaluejoin, nil, "no upvaluejoin") +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/311-bit32.t b/test/lua-Harness-tests/311-bit32.t new file mode 100755 index 0000000..7023906 --- /dev/null +++ b/test/lua-Harness-tests/311-bit32.t @@ -0,0 +1,127 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2010-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Bitwise Library + +=head2 Synopsis + + % prove 311-bit32.t + +=head2 Description + +Tests Lua Bitwise Library + +This library was introduced in Lua 5.2 and deprecated in Lua 5.3. + +See section "Bitwise Operations" in "Reference Manual" +L<https://www.lua.org/manual/5.2/manual.html#6.7> + +=cut + +--]] + +require 'tap' +local profile = require'profile' +local has_bit32 = _VERSION == 'Lua 5.2' or profile.compat52 or profile.has_bit32 + +if not bit32 then + plan(1) + nok(has_bit32, "no has_bit32") + os.exit(0) +end + +plan(20) + +do -- arshift + is(bit32.arshift(0x06, 1), 0x03, "function arshift") + is(bit32.arshift(-3, 1), bit32.arshift(-6, 2), "function arshift") +end + +do -- band + is(bit32.band(0x01, 0x03, 0x07), 0x01, "function band") +end + +do -- bnot + if string.pack and #string.pack('n', 0) == 4 then + is(bit32.bnot(0x03), (-1 - 0x03), "function bnot") + else + is(bit32.bnot(0x03), (-1 - 0x03) % 2^32, "function bnot") + end +end + +do -- bor + is(bit32.bor(0x01, 0x03, 0x07), 0x07, "function bor") +end + +do -- btest + is(bit32.btest(0x01), true, "function btest") + is(bit32.btest(0x00), false, "function btest") +end + +do -- bxor + is(bit32.bxor(0x01, 0x03, 0x07), 0x05, "function bxor") +end + +do -- extract + is(bit32.extract(0xFFFF, 3, 3), 0x07, "function extract") + + error_like(function () bit32.extract(0xFFFF, 99) end, + "^[^:]+:%d+: trying to access non%-existent bits", + "function extract (non-existent bits)") + + error_like(function () bit32.extract(0xFFFF, -3) end, + "^[^:]+:%d+: bad argument #2 to 'extract' %(field cannot be negative%)", + "function extract (negatif field)") + + error_like(function () bit32.extract(0xFFFF, 3, -3) end, + "^[^:]+:%d+: bad argument #3 to 'extract' %(width must be positive%)", + "function extract (negative width)") +end + +do -- replace + is(bit32.replace(0x0000, 0xFFFF, 3, 3), 0x38, "function replace") + + error_like(function () bit32.replace(0x0000, 0xFFFF, 99) end, + "^[^:]+:%d+: trying to access non%-existent bits", + "function replace (non-existent bits)") + + error_like(function () bit32.replace(0x0000, 0xFFFF, -3) end, + "^[^:]+:%d+: bad argument #3 to 'replace' %(field cannot be negative%)", + "function replace (negatif field)") + + error_like(function () bit32.replace(0x0000, 0xFFFF, 3, -3) end, + "^[^:]+:%d+: bad argument #4 to 'replace' %(width must be positive%)", + "function replace (negative width)") +end + +do -- lrotate + is(bit32.lrotate(0x03, 2), 0x0C, "function lrotate") +end + +do -- lshift + is(bit32.lshift(0x03, 2), 0x0C, "function lshift") +end + +do -- rrotate + is(bit32.rrotate(0x06, 1), 0x03, "function rrotate") +end + +do -- rshift + is(bit32.rshift(0x06, 1), 0x03, "function rshift") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/314-regex.t b/test/lua-Harness-tests/314-regex.t new file mode 100755 index 0000000..ad4554c --- /dev/null +++ b/test/lua-Harness-tests/314-regex.t @@ -0,0 +1,222 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Regex Compiler + +=head2 Synopsis + + % prove 314-regex.t + +=head2 Description + +Tests Lua Regex + +Individual tests are stored in the C<rx_*> files in the same directory; +There is one test per line: each test consists of the following +columns (separated by one *or more* tabs): + +=over 4 + +=item pattern + +The Lua regex to test. + +=item target + +The string that will be matched against the pattern. Use '' to indicate +an empty string. + +=item result + +The expected result of the match. + +=item description + +Description of the test. + +=back + +=cut + +--]] + +require'tap' +local loadstring = loadstring or load + +plan(162) + +local test_files = { + 'rx_captures', + 'rx_charclass', + 'rx_metachars', +} + +local todo_info = {} + +if _VERSION == 'Lua 5.1' then + if not jit then + todo_info[130] = "printable. %g" + --todo_info[131] = "printable. %g" + todo_info[132] = "not printable. %G" + --todo_info[133] = "not printable. %G" + end + todo_info[147] = "embedded nul. \\0" + todo_info[149] = "embedded nul. \\0" + todo_info[151] = "embedded nul. [^\\0]" + todo_info[153] = "embedded nul. [^\\0]" +end + +local function split (line) + local pattern, target, result, desc = '', '', '', '' + local idx = 1 + local c = line:sub(idx, idx) + while (c ~= '' and c ~= "\t") do + if (c == '"') then + pattern = pattern .. "\\\"" + else + pattern = pattern .. c + end + idx = idx + 1 + c = line:sub(idx, idx) + end + if pattern == "''" then + pattern = '' + end + while (c ~= '' and c == "\t") do + idx = idx + 1 + c = line:sub(idx, idx) + end + while (c ~= '' and c ~= "\t") do + if (c == '"') then + target = target .. "\\\"" + else + target = target .. c + end + idx = idx + 1 + c = line:sub(idx, idx) + end + if target == "''" then + target = '' + end + while (c ~= '' and c == "\t") do + idx = idx + 1 + c = line:sub(idx, idx) + end + while (c ~= '' and c ~= "\t") do + if c == "\\" then + idx = idx + 1 + c = line:sub(idx, idx) + if c == 'f' then + result = result .. "\f" + elseif c == 'n' then + result = result .. "\n" + elseif c == 'r' then + result = result .. "\r" + elseif c == 't' then + result = result .. "\t" + elseif c == '0' then + idx = idx + 1 + c = line:sub(idx, idx) + if c == '1' then + result = result .. "\01" + elseif c == '2' then + result = result .. "\02" + elseif c == '3' then + result = result .. "\03" + elseif c == '4' then + result = result .. "\04" + else + result = result .. "\0" .. c + end + elseif c == "\t" then + result = result .. "\\" + else + result = result .. "\\" .. c + end + else + result = result .. c + end + idx = idx + 1 + c = line:sub(idx, idx) + end + if result == "''" then + result = '' + end + while (c ~= '' and c == "\t") do + idx = idx + 1 + c = line:sub(idx, idx) + end + while (c ~= '' and c ~= "\t") do + desc = desc .. c + idx = idx + 1 + c = line:sub(idx, idx) + end + return pattern, target, result, desc +end + +local test_number = 0 +local dirname = arg[0]:sub(1, arg[0]:find'314' -1) +for _, filename in ipairs(test_files) do + local f, msg = io.open(dirname .. filename, 'r') + if f == nil then + diag(msg) + break + else + for line in f:lines() do + if line:len() == 0 then + break + end + local pattern, target, result, desc = split(line) + test_number = test_number + 1 + if todo_info[test_number] then + todo(todo_info[test_number]) + end + local code = [[ + local t = {string.match("]] .. target .. [[", "]] .. pattern .. [[")} + if #t== 0 then + return 'nil' + else + for i = 1, #t do + t[i] = tostring(t[i]) + end + return table.concat(t, "\t") + end + ]] + local compiled + compiled, msg = loadstring(code) + if not compiled then + error("can't compile : " .. code .. "\n" .. msg) + end + if result:sub(1, 1) == '/' then + pattern = result:sub(2, result:len() - 1) + error_like(compiled, pattern, desc) + else + local r, out + r, msg = pcall(function () out = compiled() end) + if r then + is(out, result, desc) + else + fail(desc) + diag(msg) + end + end + end + f:close() + end +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/320-stdin.t b/test/lua-Harness-tests/320-stdin.t new file mode 100755 index 0000000..4828285 --- /dev/null +++ b/test/lua-Harness-tests/320-stdin.t @@ -0,0 +1,133 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 Lua Library + +=head2 Synopsis + + % prove 320-stdin.t + +=head2 Description + +Tests Lua Basic & IO Libraries with stdin + +=cut + +--]] + +require'tap' + +local lua = get_lua_binary_name() + +if not pcall(io.popen, lua .. [[ -e "a=1"]]) then + skip_all "io.popen not supported" +end + +plan(12) + +do + local f = io.open('lib-320.lua', 'w') + f:write[[ +function norm (x, y) + return (x^2 + y^2)^0.5 +end + +function twice (x) + return 2*x +end +]] + f:close() + + local cmd = lua .. [[ -e "dofile(); n = norm(3.4, 1.0); print(twice(n))" < lib-320.lua]] + f = io.popen(cmd) + like(f:read'*l', '^7%.088', "function dofile (stdin)") + f:close() + + os.remove('lib-320.lua') -- clean up +end + +do + local f = io.open('foo-320.lua', 'w') + f:write[[ +function foo (x) + return x +end +]] + f:close() + + local cmd = lua .. [[ -e "f = loadfile(); print(foo); f(); print(foo('ok'))" < foo-320.lua]] + f = io.popen(cmd) + is(f:read'*l', 'nil', "function loadfile (stdin)") + is(f:read'*l', 'ok') + f:close() + + os.remove('foo-320.lua') -- clean up +end + +do + local f = io.open('file-320.txt', 'w') + f:write("file with text\n") + f:close() + + local cmd = lua .. [[ -e "print(io.read'*l'); print(io.read'*l'); print(io.type(io.stdin))" < file-320.txt]] + f = io.popen(cmd) + is(f:read'*l', 'file with text', "function io.read *l") + is(f:read'*l', 'nil') + is(f:read'*l', 'file') + f:close() + + cmd = lua .. [[ -e "for line in io.lines() do print(line) end" < file-320.txt]] + f = io.popen(cmd) + is(f:read'*l', 'file with text', "function io.lines") + is(f:read'*l', nil) + f:close() + + os.remove('file-320.txt') -- clean up +end + +do + local f = io.open('number-320.txt', 'w') + f:write("6.0 -3.23 15e3\n") + f:write("4.3 234 1000001\n") + f:close() + + local cmd = lua .. [[ -e "while true do local n1, n2, n3 = io.read('*number', '*number', '*number'); if not n1 then break end; print(math.max(n1, n2, n3)) end" < number-320.txt]] + f = io.popen(cmd) + like(f:read'*l', '15000%.?', "function io:read *number") + is(f:read'*l', '1000001') + f:close() + + os.remove('number-320.txt') -- clean up +end + +do + local f = io.open('dbg-320.txt', 'w') + f:write("print 'ok'\n") + f:write("error 'dbg'\n") + f:write("cont\n") + f:close() + + local cmd = lua .. [[ -e "debug.debug()" < dbg-320.txt]] + f = io.popen(cmd) + is(f:read'*l', 'ok', "function debug.debug") + is(f:read'*l', nil) + f:close() + + os.remove('dbg-320.txt') -- clean up +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/401-bitop.t b/test/lua-Harness-tests/401-bitop.t new file mode 100755 index 0000000..f95aebf --- /dev/null +++ b/test/lua-Harness-tests/401-bitop.t @@ -0,0 +1,106 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 BitOp Library + +=head2 Synopsis + + % prove 401-bitop.t + +=head2 Description + +See L<http://bitop.luajit.org/>. + +=cut + +--]] + +require 'tap' + +if not jit then + skip_all("only with LuaJIT") +end + +plan(29) + +is(package.loaded.bit, _G.bit, "package.loaded") +is(require'bit', bit, "require") + +do -- arshift + is(bit.arshift(256, 8), 1, "function arshift") + is(bit.arshift(-256, 8), -1) +end + +do -- band + is(bit.band(0x12345678, 0xff), 0x00000078, "function band") +end + +do -- bnot + is(bit.bnot(0), -1, "function bnot") + is(bit.bnot(-1), 0) + is(bit.bnot(0xffffffff), 0) +end + +do -- bor + is(bit.bor(1, 2, 4, 8), 15, "function bor") +end + +do -- bswap + is(bit.bswap(0x12345678), 0x78563412, "function bswap") + is(bit.bswap(0x78563412), 0x12345678) +end + +do -- bxor + is(bit.bxor(0xa5a5f0f0, 0xaa55ff00), 0x0ff00ff0, "function bxor") +end + +do -- lshift + is(bit.lshift(1, 0), 1, "function lshift") + is(bit.lshift(1, 8), 256) + is(bit.lshift(1, 40), 256) + is(bit.lshift(0x87654321, 12), 0x54321000) +end + +do -- rol + is(bit.rol(0x12345678, 12), 0x45678123, "function rol") +end + +do -- ror + is(bit.ror(0x12345678, 12), 0x67812345, "function ror") +end + +do -- rshift + is(bit.rshift(256, 8), 1, "function rshift") + is(bit.rshift(-256, 8), 16777215) + is(bit.rshift(0x87654321, 12), 0x00087654) +end + +do -- tobit + is(bit.tobit(0xffffffff + 1), 0, "function tobit") + is(bit.tobit(2^40 + 1234), 1234) +end + +do -- tohex + is(bit.tohex(1), '00000001', "function tohex") + is(bit.tohex(-1), 'ffffffff') + is(bit.tohex(0xffffffff), 'ffffffff') + is(bit.tohex(-1, -8), 'FFFFFFFF') + is(bit.tohex(0x21, 4), '0021') + is(bit.tohex(0x87654321, 4), '4321') +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/402-ffi.t b/test/lua-Harness-tests/402-ffi.t new file mode 100755 index 0000000..a2e32a5 --- /dev/null +++ b/test/lua-Harness-tests/402-ffi.t @@ -0,0 +1,142 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 FFI Library + +=head2 Synopsis + + % prove 402-ffi.t + +=head2 Description + +See L<http://luajit.org/ext_ffi.html>. + +=cut + +--]] + +require 'tap' + +if not jit then + skip_all("only with LuaJIT") +end + +if not pcall(require, 'ffi') then + plan(2) + is(_G.ffi, nil, "no FFI") + is(package.loaded.ffi, nil) + os.exit(0) +end + +plan(33) + +is(_G.ffi, nil, "ffi not loaded by default") +ffi = require'ffi' +is(package.loaded.ffi, ffi, "package.loaded") +is(require'ffi', ffi, "require") + +do -- C + type_ok(ffi.C, 'userdata', 'C') +end + +do -- abi + type_ok(ffi.abi('32bit'), 'boolean', "abi") + type_ok(ffi.abi('64bit'), 'boolean') + type_ok(ffi.abi('le'), 'boolean') + type_ok(ffi.abi('be'), 'boolean') + type_ok(ffi.abi('fpu'), 'boolean') + type_ok(ffi.abi('softfp'), 'boolean') + type_ok(ffi.abi('hardfp'), 'boolean') + type_ok(ffi.abi('eabi'), 'boolean') + type_ok(ffi.abi('win'), 'boolean') + is(ffi.abi('bad'), false) + is(ffi.abi(0), false) + + error_like(function () ffi.abi(true) end, + "^[^:]+:%d+: bad argument #1 to 'abi' %(string expected, got boolean%)", + "function unpack missing size") +end + +do -- alignof + type_ok(ffi.alignof, 'function', "alignof") +end + +do -- arch + is(ffi.arch, jit.arch, "alias arch") +end + +do -- cast + type_ok(ffi.cast, 'function', "cast") +end + +do -- cdef + type_ok(ffi.cdef, 'function', "cdef") +end + +do -- copy + type_ok(ffi.copy, 'function', "copy") +end + +do -- errno + type_ok(ffi.errno, 'function', "errno") +end + +do -- fill + type_ok(ffi.fill, 'function', "fill") +end + +do -- gc + type_ok(ffi.gc, 'function', "gc") +end + +do -- istype + type_ok(ffi.istype, 'function', "istype") +end + +do -- load + type_ok(ffi.load, 'function', "load") +end + +do -- metatype + type_ok(ffi.metatype, 'function', "metatype") +end + +do -- new + type_ok(ffi.new, 'function', "new") +end + +do -- offsetof + type_ok(ffi.offsetof, 'function', "offsetof") +end + +do -- os + is(ffi.os, jit.os, "alias os") +end + +do -- sizeof + type_ok(ffi.sizeof, 'function', "sizeof") +end + +do -- string + type_ok(ffi.string, 'function', "string") +end + +do -- typeof + type_ok(ffi.typeof, 'function', "typeof") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/403-jit.t b/test/lua-Harness-tests/403-jit.t new file mode 100755 index 0000000..0073c90 --- /dev/null +++ b/test/lua-Harness-tests/403-jit.t @@ -0,0 +1,163 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 JIT Library + +=head2 Synopsis + + % prove 403-jit.t + +=head2 Description + +See L<http://luajit.org/ext_jit.html>. + +=cut + +--]] + +require 'tap' +local profile = require'profile' + +if not jit then + skip_all("only with LuaJIT") +end + +local compiled_with_jit = jit.status() +local luajit20 = jit.version_num < 20100 and not jit.version:match'RaptorJIT' +local has_jit_opt = compiled_with_jit +local has_jit_security = jit.security +local has_jit_util = not ujit and not jit.version:match'RaptorJIT' + +plan'no_plan' + +is(package.loaded.jit, _G.jit, "package.loaded") +is(require'jit', jit, "require") + +do -- arch + type_ok(jit.arch, 'string', "arch") +end + +do -- flush + type_ok(jit.flush, 'function', "flush") +end + +do -- off + jit.off() + is(jit.status(), false, "off") +end + +-- on +if compiled_with_jit then + jit.on() + is(jit.status(), true, "on") +else + error_like(function () jit.on() end, + "^[^:]+:%d+: JIT compiler permanently disabled by build option", + "no jit.on") +end + +-- opt +if has_jit_opt then + type_ok(jit.opt, 'table', "opt.*") + type_ok(jit.opt.start, 'function', "opt.start") +else + is(jit.opt, nil, "no jit.opt") +end + +do -- os + type_ok(jit.os, 'string', "os") +end + +-- prngstate +if profile.openresty then + type_ok(jit.prngstate(), 'table', "prngstate") + local s1 = { 1, 2, 3, 4, 5, 6, 7, 8} + type_ok(jit.prngstate(s1), 'table') + local s2 = { 8, 7, 6, 5, 4, 3, 2, 1} + eq_array(jit.prngstate(s2), s1) + eq_array(jit.prngstate(), s2) + + type_ok(jit.prngstate(32), 'table', "backward compat") + eq_array(jit.prngstate(5617), { 32, 0, 0, 0, 0, 0, 0, 0 }) + eq_array(jit.prngstate(), { 5617, 0, 0, 0, 0, 0, 0, 0 }) + + error_like(function () jit.prngstate(-1) end, + "^[^:]+:%d+: bad argument #1 to 'prngstate' %(PRNG state must be an array with up to 8 integers or an integer%)") + + error_like(function () jit.prngstate(false) end, + "^[^:]+:%d+: bad argument #1 to 'prngstate' %(table expected, got boolean%)") +elseif jit.version:match'moonjit' then + is(jit.prngstate(), 0, "prngstate") +else + is(jit.prngstate, nil, "no jit.prngstate"); +end + +-- security +if has_jit_security then + type_ok(jit.security, 'function', "security") + type_ok(jit.security('prng'), 'number', "prng") + type_ok(jit.security('strhash'), 'number', "strhash") + type_ok(jit.security('strid'), 'number', "stdid") + type_ok(jit.security('mcode'), 'number', "mcode") + + error_like(function () jit.security('foo') end, + "^[^:]+:%d+: bad argument #1 to 'security' %(invalid option 'foo'%)") +else + is(jit.security, nil, "no jit.security") +end + +do -- status + local status = { jit.status() } + type_ok(status[1], 'boolean', "status") + if compiled_with_jit then + for i = 2, #status do + type_ok(status[i], 'string', status[i]) + end + else + is(#status, 1) + end +end + +-- util +if has_jit_util then + local jutil = require'jit.util' + type_ok(jutil, 'table', "util") + is(package.loaded['jit.util'], jutil) + + if luajit20 then + is(jit.util, jutil, "util inside jit") + else + is(jit.util, nil, "no util inside jit") + end +else + local r = pcall(require, 'jit.util') + is(r, false, "no jit.util") +end + +do -- version + type_ok(jit.version, 'string', "version") + like(jit.version, '^%w+ %d%.%d%.%d') +end + +do -- version_num + type_ok(jit.version_num, 'number', "version_num") + like(string.format("%06d", jit.version_num), '^0[12]0[012]%d%d$') +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/404-ext.t b/test/lua-Harness-tests/404-ext.t new file mode 100755 index 0000000..22a52c7 --- /dev/null +++ b/test/lua-Harness-tests/404-ext.t @@ -0,0 +1,171 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2019-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 JIT Library extensions + +=head2 Synopsis + + % prove 404-ext.t + +=head2 Description + +See L<http://luajit.org/ext_jit.html>. + +=cut + +--]] + +require 'tap' +local profile = require'profile' + +local luajit21 = jit and (jit.version_num >= 20100 or jit.version:match'^RaptorJIT') +if not luajit21 then + skip_all("only with LuaJIT 2.1") +end + +plan'no_plan' + +do -- table.new + local r, new = pcall(require, 'table.new') + is(r, true, 'table.new') + type_ok(new, 'function') + is(package.loaded['table.new'], new) + + type_ok(new(100, 0), 'table') + type_ok(new(0, 100), 'table') + type_ok(new(200, 200), 'table') + + error_like(function () new(42) end, + "^[^:]+:%d+: bad argument #2 to 'new' %(number expected, got no value%)") +end + +do -- table.clear + local r, clear = pcall(require, 'table.clear') + is(r, true, 'table.clear') + type_ok(clear, 'function') + is(package.loaded['table.clear'], clear) + + local t = { 'foo', bar = 42 } + is(t[1], 'foo') + is(t.bar, 42) + clear(t) + is(t[1], nil) + is(t.bar, nil) + + error_like(function () clear(42) end, + "^[^:]+:%d+: bad argument #1 to 'clear' %(table expected, got number%)") +end + +-- table.clone +if profile.openresty then + local r, clone = pcall(require, 'table.clone') + is(r, true, 'table.clone') + type_ok(clone, 'function') + is(package.loaded['table.clone'], clone) + + local mt = {} + local t = setmetatable({ 'foo', bar = 42 }, mt) + is(t[1], 'foo') + is(t.bar, 42) + local t2 = clone(t) + type_ok(t2, 'table') + isnt(t2, t) + is(getmetatable(t2), nil) + is(t2[1], 'foo') + is(t2.bar, 42) + + error_like(function () clone(42) end, + "^[^:]+:%d+: bad argument #1 to 'clone' %(table expected, got number%)") +else + is(pcall(require, 'table.clone'), false, 'no table.clone') +end + +-- table.isarray +if profile.openresty then + local r, isarray = pcall(require, 'table.isarray') + is(r, true, 'table.isarray') + type_ok(isarray, 'function') + is(package.loaded['table.isarray'], isarray) + + is(isarray({ [3] = 3, [5.3] = 4 }), false) + is(isarray({ [3] = 'a', [5] = true }), true) + is(isarray({ 'a', nil, true, 3.14 }), true) + is(isarray({}), true) + is(isarray({ ['1'] = 3, ['2'] = 4 }), false) + is(isarray({ ['dog'] = 3, ['cat'] = 4 }), false) + is(isarray({ 'dog', 'cat', true, ['bird'] = 3 }), false) + + error_like(function () isarray(42) end, + "^[^:]+:%d+: bad argument #1 to 'isarray' %(table expected, got number%)") +else + is(pcall(require, 'table.isarray'), false, 'no table.isarray') +end + +-- table.isempty +if profile.openresty then + local r, isempty = pcall(require, 'table.isempty') + is(r, true, 'table.isempty') + type_ok(isempty, 'function') + is(package.loaded['table.isempty'], isempty) + + is(isempty({}), true) + is(isempty({ nil }), true) + is(isempty({ dogs = nil }), true) + is(isempty({ 3.1 }), false) + is(isempty({ 'a', 'b' }), false) + is(isempty({ nil, false }), false) + is(isempty({ dogs = 3 }), false) + is(isempty({ dogs = 3, cats = 4 }), false) + is(isempty({ dogs = 3, 5 }), false) + + error_like(function () isempty(42) end, + "^[^:]+:%d+: bad argument #1 to 'isempty' %(table expected, got number%)") +else + is(pcall(require, 'table.isempty'), false, 'no table.isempty') +end + +-- table.nkeys +if profile.openresty then + local r, nkeys = pcall(require, 'table.nkeys') + is(r, true, 'table.nkeys') + type_ok(nkeys, 'function') + is(package.loaded['table.nkeys'], nkeys) + + is(nkeys({}), 0) + is(nkeys({ cats = 4 }), 1) + is(nkeys({ dogs = 3, cats = 4 }), 2) + is(nkeys({ dogs = nil, cats = 4 }), 1) + is(nkeys({ 'cats' }), 1) + is(nkeys({ 'dogs', 3, 'cats', 4 }), 4) + is(nkeys({ 'dogs', nil, 'cats', 4 }), 3) + is(nkeys({ cats = 4, 5, 6 }), 3) + is(nkeys({ nil, 'foo', dogs = 3, cats = 4 }), 3) + + error_like(function () nkeys(42) end, + "^[^:]+:%d+: bad argument #1 to 'nkeys' %(table expected, got number%)") +else + is(pcall(require, 'table.nkeys'), false, 'no table.nkeys') +end + +-- thread.exdata +if pcall(require, 'ffi') and (profile.openresty or jit.version:match'moonjit') then + dofile'lexicojit/ext.t' +end + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/411-luajit.t b/test/lua-Harness-tests/411-luajit.t new file mode 100755 index 0000000..feb752e --- /dev/null +++ b/test/lua-Harness-tests/411-luajit.t @@ -0,0 +1,211 @@ +#! /usr/bin/lua +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +--[[ + +=head1 LuaJIT Stand-alone + +=head2 Synopsis + + % prove 411-luajit.t + +=head2 Description + +See L<http://luajit.org/running.html> + +=cut + +--]] + +require'tap' +local profile = require'profile' + +if not jit or ujit then + skip_all("only with LuaJIT") +end + +local lua = get_lua_binary_name() + +if not pcall(io.popen, lua .. [[ -e "a=1"]]) then + skip_all("io.popen not supported") +end + +local compiled_with_jit = jit.status() +local has_jutil = pcall(require, 'jit.util') +local has_openresty_listing = profile.openresty or jit.version:match'moonjit' + +plan'no_plan' +diag(lua) + +local f = io.open('hello-404.lua', 'w') +f:write([[ +print 'Hello World' +]]) +f:close() + +os.execute(lua .. " -b hello-404.lua hello-404.out") +local cmd = lua .. " hello-404.out" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "-b") +f:close() + +os.execute(lua .. " -bg hello-404.lua hello-404.out") +cmd = lua .. " hello-404.out" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "-bg") +f:close() + +os.execute(lua .. " -be 'print[[Hello World]]' hello-404.out") +cmd = lua .. " hello-404.out" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "-be") +f:close() + +os.remove('hello-404.out') -- clean up + +if has_jutil then + cmd = lua .. " -bl hello-404.lua" + f = io.popen(cmd) + like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bl hello.lua") + if has_openresty_listing then + like(f:read'*l', '^KGC 0') + like(f:read'*l', '^KGC 1') + end + like(f:read'*l', '^0001 %u[%u%d]+%s+') + like(f:read'*l', '^0002 %u[%u%d]+%s+') + like(f:read'*l', '^0003 %u[%u%d]+%s+') + f:close() + + os.execute(lua .. " -bl hello-404.lua hello-404.txt") + f = io.open('hello-404.txt', 'r') + like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bl hello.lua hello.txt") + if has_openresty_listing then + like(f:read'*l', '^KGC 0') + like(f:read'*l', '^KGC 1') + end + like(f:read'*l', '^0001 %u[%u%d]+%s+') + like(f:read'*l', '^0002 %u[%u%d]+%s+') + like(f:read'*l', '^0003 %u[%u%d]+%s+') + f:close() +end + +if has_openresty_listing then + cmd = lua .. " -bL hello-404.lua" + f = io.popen(cmd) + like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bL hello.lua") + like(f:read'*l', '^KGC 0') + like(f:read'*l', '^KGC 1') + like(f:read'*l', '^0001 %[1%] %u[%u%d]+%s+') + like(f:read'*l', '^0002 %[1%] %u[%u%d]+%s+') + like(f:read'*l', '^0003 %[1%] %u[%u%d]+%s+') + f:close() + + os.execute(lua .. " -bL hello-404.lua hello-404.txt") + f = io.open('hello-404.txt', 'r') + like(f:read'*l', '^%-%- BYTECODE %-%- hello%-404%.lua', "-bL hello.lua hello.txt") + like(f:read'*l', '^KGC 0') + like(f:read'*l', '^KGC 1') + like(f:read'*l', '^0001 %[1%] %u[%u%d]+%s+') + like(f:read'*l', '^0002 %[1%] %u[%u%d]+%s+') + like(f:read'*l', '^0003 %[1%] %u[%u%d]+%s+') + f:close() +end + +os.remove('hello-404.txt') -- clean up + +os.execute(lua .. " -b hello-404.lua hello-404.c") +f = io.open('hello-404.c', 'r') +like(f:read'*l', '^#ifdef __?cplusplus$', "-b hello.lua hello.c") +like(f:read'*l', '^extern "C"$') +like(f:read'*l', '^#endif$') +like(f:read'*l', '^#ifdef _WIN32$') +like(f:read'*l', '^__declspec%(dllexport%)$') +like(f:read'*l', '^#endif$') +like(f:read'*l', '^const.- char luaJIT_BC_hello_404%[%] = {$') +like(f:read'*l', '^%d+,%d+,%d+,') +f:close() + +os.remove('hello-404.c') -- clean up + +os.execute(lua .. " -b hello-404.lua hello-404.h") +f = io.open('hello-404.h', 'r') +like(f:read'*l', '^#define luaJIT_BC_hello_404_SIZE %d+$', "-b hello.lua hello.h") +like(f:read'*l', '^static const.- char luaJIT_BC_hello_404%[%] = {$') +like(f:read'*l', '^%d+,%d+,%d+,') +f:close() + +os.remove('hello-404.h') -- clean up + +cmd = lua .. " -j flush hello-404.lua" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "-j flush") +f:close() + +cmd = lua .. " -joff hello-404.lua" +f = io.popen(cmd) +is(f:read'*l', 'Hello World', "-joff") +f:close() + +cmd = lua .. " -jon hello-404.lua 2>&1" +f = io.popen(cmd) +if compiled_with_jit then + is(f:read'*l', 'Hello World', "-jon") +else + like(f:read'*l', "^[^:]+: JIT compiler permanently disabled by build option", "no jit") +end +f:close() + +cmd = lua .. " -j bad hello-404.lua 2>&1" +f = io.popen(cmd) +like(f:read'*l', "^[^:]+: unknown luaJIT command or jit%.%* modules not installed", "-j bad") +f:close() + +if compiled_with_jit then + cmd = lua .. " -O hello-404.lua" + f = io.popen(cmd) + is(f:read'*l', 'Hello World', "-O") + f:close() + + cmd = lua .. " -O3 hello-404.lua" + f = io.popen(cmd) + is(f:read'*l', 'Hello World', "-O3") + f:close() + + cmd = lua .. " -Ocse -O-dce -Ohotloop=10 hello-404.lua" + f = io.popen(cmd) + is(f:read'*l', 'Hello World', "-Ocse -O-dce -Ohotloop=10") + f:close() + + cmd = lua .. " -O+cse,-dce,hotloop=10 hello-404.lua" + f = io.popen(cmd) + is(f:read'*l', 'Hello World', "-O+cse,-dce,hotloop=10") + f:close() + + cmd = lua .. " -O+bad hello-404.lua 2>&1" + f = io.popen(cmd) + like(f:read'*l', "^[^:]+: unknown or malformed optimization flag '%+bad'", "-O+bad") + f:close() +else + cmd = lua .. " -O0 hello-404.lua 2>&1" + f = io.popen(cmd) + like(f:read'*l', "^[^:]+: attempt to index a nil value") + f:close() +end + +os.remove('hello-404.lua') -- clean up + +done_testing() + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/CMakeLists.txt b/test/lua-Harness-tests/CMakeLists.txt new file mode 100644 index 0000000..9b35e5a --- /dev/null +++ b/test/lua-Harness-tests/CMakeLists.txt @@ -0,0 +1,49 @@ +# Test suite that has been added from lua-Harness test suite +# in scope of https://github.com/tarantool/tarantool/issues/4473. + +# See the rationale in the root CMakeLists.txt +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) + +find_program(PROVE prove) +if(NOT PROVE) + message(WARNING "`prove' is not found, so lua-Harness-tests target is not generated") + return() +endif() + +set(LUA_TEST_FLAGS --failures --shuffle) +if(CMAKE_VERBOSE_MAKEFILE) + list(APPEND LUA_TEST_FLAGS --verbose) +endif() + +string(CONCAT LUA_PATH + "./?.lua\;" + "${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;" + "${LUAJIT_SOURCE_DIR}/?.lua\;" +) + +string(CONCAT LUA_CPATH + "./?${CMAKE_SHARED_LIBRARY_SUFFIX}\;" + "${LUAJIT_SOURCE_DIR}/?${CMAKE_SHARED_LIBRARY_SUFFIX}\;" +) + +add_custom_target(lua-Harness-tests DEPENDS ${LUAJIT_TEST_BINARY}) + +add_custom_command(TARGET lua-Harness-tests + COMMENT "Running lua-Harness tests" + COMMAND + env + LUA_PATH="${LUA_PATH}\;" + LUA_CPATH="${LUA_CPATH}\;" + # Tarantool doesn't support LUA_INIT and most likely it + # never will. + # See https://github.com/tarantool/tarantool/issues/5744 + # for more info. + # So use less preferable way for tests. + # See the root CMakeLists.txt for more info. + ${PROVE} ${CMAKE_CURRENT_SOURCE_DIR} + --exec '${LUAJIT_TEST_COMMAND} -l profile_luajit21' + ${LUA_TEST_FLAGS} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +# vim: expandtab tabstop=2 shiftwidth=2 diff --git a/test/lua-Harness-tests/lexico52/lexico.t b/test/lua-Harness-tests/lexico52/lexico.t new file mode 100644 index 0000000..ff6bb99 --- /dev/null +++ b/test/lua-Harness-tests/lexico52/lexico.t @@ -0,0 +1,45 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2012-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +is("\x41", "A") +is("\x3d", "=") +is("\x3D", "=") + +do + local f, msg = load [[a = "A\xyz"]] + like(msg, "^[^:]+:%d+: .- near") + + f, msg = load [[a = "A\Z"]] + like(msg, "^[^:]+:%d+: .- escape .- near") +end + +do + local a = 'alo\n123"' + is("alo\n\z + 123\"", a) + + local f, msg = load [[a = " escape \z unauthorized +new line" ]] + like(msg, "^[^:]+:%d+: unfinished string near") +end + +is(0x0.1E, 0x1E / 0x100) -- 0.1171875 +is(0xA23p-4, 0xA23 / (2^4)) -- 162.1875 +if string.pack and #string.pack('n', 0) == 4 then + diag('Small Lua') +else + is(0X1.921FB54442D18P+1, (1 + 0x921FB54442D18/0x10000000000000) * 2) +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/boolean.t b/test/lua-Harness-tests/lexico53/boolean.t new file mode 100644 index 0000000..693ac76 --- /dev/null +++ b/test/lua-Harness-tests/lexico53/boolean.t @@ -0,0 +1,43 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +error_like(function () return ~true end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "~true") + +error_like(function () return true // 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on a boolean value", + "true // 3") + +error_like(function () return true & 7 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "true & 7") + +error_like(function () return true | 1 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "true | 1") + +error_like(function () return true ~ 4 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "true ~ 4") + +error_like(function () return true >> 5 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "true >> 5") + +error_like(function () return true << 2 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "true << 2") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/function.t b/test/lua-Harness-tests/lexico53/function.t new file mode 100644 index 0000000..2471be6 --- /dev/null +++ b/test/lua-Harness-tests/lexico53/function.t @@ -0,0 +1,66 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +local f = function () return 1 end + +error_like(function () return ~f end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "~f") + +error_like(function () f = print; return ~f end, + "^[^:]+:%d+: attempt to perform bitwise operation on") + +error_like(function () return f // 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "f // 3") + +error_like(function () f = print; return f // 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on") + +error_like(function () return f & 7 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "f & 7") + +error_like(function () f = print; return f & 7 end, + "^[^:]+:%d+: attempt to perform bitwise operation on") + +error_like(function () return f | 1 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "f | 1") + +error_like(function () f = print; return f | 1 end, + "^[^:]+:%d+: attempt to perform bitwise operation on") + +error_like(function () return f ~ 4 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "f ~ 4") + +error_like(function () f = print; return f ~ 4 end, + "^[^:]+:%d+: attempt to perform bitwise operation on") + +error_like(function () return f >> 5 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "f >> 5") + +error_like(function () f = print; return f >> 5 end, + "^[^:]+:%d+: attempt to perform bitwise operation on") + +error_like(function () return f << 2 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "f << 2") + +error_like(function () f = print; return f << 2 end, + "^[^:]+:%d+: attempt to perform bitwise operation on") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/lexico.t b/test/lua-Harness-tests/lexico53/lexico.t new file mode 100644 index 0000000..41b0d89 --- /dev/null +++ b/test/lua-Harness-tests/lexico53/lexico.t @@ -0,0 +1,30 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2015-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +is("\u{41}", "A") +is("\u{20AC}", "\xE2\x82\xAC") +is("\u{20ac}", "\xe2\x82\xac") + +do + local f, msg = load [[a = "A\u{yz}"]] + like(msg, "^[^:]+:%d+: .- near") + + f, msg = load [[a = "A\u{41"]] + like(msg, "^[^:]+:%d+: .- near") + + f, msg = load [[a = "A\u{FFFFFFFFFF}"]] + like(msg, "^[^:]+:%d+: .- near") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/nil.t b/test/lua-Harness-tests/lexico53/nil.t new file mode 100644 index 0000000..a6438e2 --- /dev/null +++ b/test/lua-Harness-tests/lexico53/nil.t @@ -0,0 +1,43 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +error_like(function () return ~nil end, + "^[^:]+:%d+: attempt to perform bitwise operation on a nil value", + "~nil") + +error_like(function () return nil // 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on a nil value", + "nil // 3") + +error_like(function () return nil & 7 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a nil value", + "nil & 7") + +error_like(function () return nil | 1 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a nil value", + "nil | 1") + +error_like(function () return nil ~ 4 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a nil value", + "nil ~ 4") + +error_like(function () return nil >> 5 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a nil value", + "nil >> 5") + +error_like(function () return nil << 2 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a nil value", + "nil << 2") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/number.t b/test/lua-Harness-tests/lexico53/number.t new file mode 100644 index 0000000..d205da3 --- /dev/null +++ b/test/lua-Harness-tests/lexico53/number.t @@ -0,0 +1,181 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +local profile = require'profile' + +is(~4, -5, "~4") + +error_like(function () return ~3.14 end, + "^[^:]+:%d+: number has no integer representation", + "~3.14") + +is(25.5 // 3.5, 7.0, "25.5 // 3.5") + +is(25 // 3, 8, "25 // 3") + +is(25 // -3, -9, "25 // -3") + +is(1 // -1, -1, "1 // -1") + +type_ok(1.0 // 0, 'number', "1.0 // 0") + +error_like(function () return 1 // 0 end, + "^[^:]+:%d+: attempt to divide by zero", + "1 // 0") + +is(3 & 7, 3, "3 & 7") + +is(4 | 1, 5, "4 | 1") + +is(7 ~ 1, 6, "7 ~ 1") + +is(100 >> 5, 3, "100 >> 5") + +is(3 << 2, 12, "3 << 2") + +error_like(function () return 25 // {} end, + "^[^:]+:%d+: attempt to perform arithmetic on a table value", + "25 // {}") + +error_like(function () return 3 & true end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "3 & true") + +error_like(function () return 4 | true end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "4 | true") + +error_like(function () return 7 ~ true end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "7 ~ true") + +error_like(function () return 100 >> true end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "100 >> true") + +error_like(function () return 3 << true end, + "^[^:]+:%d+: attempt to perform bitwise operation on a boolean value", + "3 << true") + +error_like(function () return 25 // 'text' end, + "^[^:]+:%d+: attempt to", + "25 // 'text'") + +error_like(function () return 3 & 'text' end, + "^[^:]+:%d+: attempt to", + "3 & 'text'") + +error_like(function () return 4 | 'text' end, + "^[^:]+:%d+: attempt to", + "4 | 'text'") + +error_like(function () return 7 ~ 'text' end, + "^[^:]+:%d+: attempt to", + "7 ~ 'text'") + +error_like(function () return 100 >> 'text' end, + "^[^:]+:%d+: attempt to", + "100 >> 'text'") + +error_like(function () return 3 << 'text' end, + "^[^:]+:%d+: attempt to", + "3 << 'text'") + +if profile.nocvts2n then + error_like(function () return 25.5 // '3.5' end, + "^[^:]+:%d+: attempt to", + "25.5 // '3.5'") + + error_like(function () return 25 // '3' end, + "^[^:]+:%d+: attempt to", + "25 // '3'") +else + is(25.5 // '3.5', 7.0, "25.5 // '3.5'") + + is(25 // '3', 8, "25 // '3'") +end + +if profile.nocvts2n or _VERSION >= 'Lua 5.4' then + error_like(function () return 3 & '7' end, + "^[^:]+:%d+: attempt to", + "3 & '7'") + + error_like(function () return 4 | '1' end, + "^[^:]+:%d+: attempt to", + "4 | '1'") + + error_like(function () return 7 ~ '1' end, + "^[^:]+:%d+: attempt to", + "7 ~ '1'") + + error_like(function () return 100 >> '5' end, + "^[^:]+:%d+: attempt to", + "100 >> '5'") + + error_like(function () return 3 << '2' end, + "^[^:]+:%d+: attempt to", + "3 << '2'") +else + is(3 & '7', 3, "3 & '7'") + + is(4 | '1', 5, "4 | '1'") + + is(7 ~ '1', 6, "7 ~ '1'") + + is(100 >> '5', 3, "100 >> '5'") + + is(3 << '2', 12, "3 << '2'") +end + +error_like(function () return 3.5 & 7 end, + "^[^:]+:%d+: number has no integer representation", + "3.5 & 7") + +error_like(function () return 3 & 7.5 end, + "^[^:]+:%d+: number has no integer representation", + "3 & 7.5") + +error_like(function () return 4.5 | 1 end, + "^[^:]+:%d+: number has no integer representation", + "4.5 | 1") + +error_like(function () return 4 | 1.5 end, + "^[^:]+:%d+: number has no integer representation", + "4 | 1.5") + +error_like(function () return 7.5 ~ 1 end, + "^[^:]+:%d+: number has no integer representation", + "7.5 ~ 1") + +error_like(function () return 7 ~ 1.5 end, + "^[^:]+:%d+: number has no integer representation", + "7 ~ 1.5") + +error_like(function () return 100.5 >> 5 end, + "^[^:]+:%d+: number has no integer representation", + "100.5 >> 5") + +error_like(function () return 100 >> 5.5 end, + "^[^:]+:%d+: number has no integer representation", + "100 >> 5.5") + +error_like(function () return 3.5 << 2 end, + "^[^:]+:%d+: number has no integer representation", + "3.5 << 2") + +error_like(function () return 3 << 2.5 end, + "^[^:]+:%d+: number has no integer representation", + "3 << 2.5") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/string.t b/test/lua-Harness-tests/lexico53/string.t new file mode 100644 index 0000000..eb74064 --- /dev/null +++ b/test/lua-Harness-tests/lexico53/string.t @@ -0,0 +1,169 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +local profile = require'profile' + +if profile.nocvts2n or _VERSION >= 'Lua 5.4' then + error_like(function () return ~'4' end, + "^[^:]+:%d+: attempt to", + "~'4'") +else + is(~'4', -5, "~'4'") +end + +error_like(function () return ~'text' end, + "^[^:]+:%d+: attempt to", + "~'text'") + +if profile.nocvts2n then + error_like(function () return '25.5' // 3.5 end, + "^[^:]+:%d+: attempt to", + "'25.5' // 3.5") + + error_like(function () return '25' // 3 end, + "^[^:]+:%d+: attempt to", + "'25' // 3") +else + is('25.5' // 3.5, 7.0, "'25.5' // 3.5") + + is('25' // 3, 8, "'25' // 3") +end + +if profile.nocvts2n or _VERSION >= 'Lua 5.4' then + error_like(function () return '3' & 7 end, + "^[^:]+:%d+: attempt to", + "'3' & 7") + + error_like(function () return '4' | 1 end, + "^[^:]+:%d+: attempt to", + "'4' | 1") + + error_like(function () return '7' ~ 1 end, + "^[^:]+:%d+: attempt to", + "'7' ~ 1") + + error_like(function () return '100' >> 5 end, + "^[^:]+:%d+: attempt to", + "'100' >> 5") + + error_like(function () return '3' << 2 end, + "^[^:]+:%d+: attempt to", + "'3' << 2") +else + is('3' & 7, 3, "'3' & 7") + + is('4' | 1, 5, "'4' | 1") + + is('7' ~ 1, 6, "'7' ~ 1") + + is('100' >> 5, 3, "'100' >> 5") + + is('3' << 2, 12, "'3' << 2") +end + +error_like(function () return '25' // {} end, + "^[^:]+:%d+: attempt to", + "'25' // {}") + +error_like(function () return '3' & true end, + "^[^:]+:%d+: attempt to", + "'3' & true") + +error_like(function () return '4' | true end, + "^[^:]+:%d+: attempt to", + "'4' | true") + +error_like(function () return '7' ~ true end, + "^[^:]+:%d+: attempt to", + "'7' ~ true") + +error_like(function () return '100' >> true end, + "^[^:]+:%d+: attempt to", + "'100' >> true") + +error_like(function () return '3' << true end, + "^[^:]+:%d+: attempt to", + "'3' << true") + +error_like(function () return '25' // 'text' end, + "^[^:]+:%d+: attempt to", + "'25' // 'text'") + +error_like(function () return '3' & 'text' end, + "^[^:]+:%d+: attempt to", + "'3' & 'text'") + +error_like(function () return '4' | 'text' end, + "^[^:]+:%d+: attempt to", + "'4' | 'text'") + +error_like(function () return '7' ~ 'text' end, + "^[^:]+:%d+: attempt to", + "'7' ~ 'text'") + +error_like(function () return '100' >> 'text' end, + "^[^:]+:%d+: attempt to", + "'100' >> 'text'") + +error_like(function () return '3' << 'text' end, + "^[^:]+:%d+: attempt to", + "'3' << 'text'") + +if profile.nocvts2n then + error_like(function () return '25.5' // '3.5' end, + "^[^:]+:%d+: attempt to", + "'25.5' // '3.5'") + + error_like(function () return '25' // '3' end, + "^[^:]+:%d+: attempt to", + "'25' // '3'") +else + is('25.5' // '3.5', 7.0, "'25.5' // '3.5'") + + is('25' // '3', 8, "'25' // '3'") +end + +if profile.nocvts2n or _VERSION >= 'Lua 5.4' then + error_like(function () return '3' & '7' end, + "^[^:]+:%d+: attempt to", + "'3' & '7'") + + error_like(function () return '4' | '1' end, + "^[^:]+:%d+: attempt to", + "'4' | '1'") + + error_like(function () return '7' ~ '1' end, + "^[^:]+:%d+: attempt to", + "'7' ~ '1'") + + error_like(function () return '100' >> '5' end, + "^[^:]+:%d+: attempt to", + "'100' >> '5'") + + error_like(function () return '3' << '2' end, + "^[^:]+:%d+: attempt to", + "'3' << '2'") +else + is('3' & '7', 3, "'3' & '7'") + + is('4' | '1', 5, "'4' | '1'") + + is('7' ~ '1', 6, "'7' ~ '1'") + + is('100' >> '5', 3, "'100' >> '5'") + + is('3' << '2', 12, "'3' << 2") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/table.t b/test/lua-Harness-tests/lexico53/table.t new file mode 100644 index 0000000..007232d --- /dev/null +++ b/test/lua-Harness-tests/lexico53/table.t @@ -0,0 +1,43 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +error_like(function () return ~{} end, + "^[^:]+:%d+: attempt to perform bitwise operation on a table value", + "~{}") + +error_like(function () return {} // 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "{} // 3") + +error_like(function () return {} & 7 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a table value", + "{} & 7") + +error_like(function () return {} | 1 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a table value", + "{} | 1") + +error_like(function () return {} ~ 4 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a table value", + "{} ~ 4") + +error_like(function () return {} >> 5 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a table value", + "{} >> 5") + +error_like(function () return {} << 2 end, + "^[^:]+:%d+: attempt to perform bitwise operation on a table value", + "{} << 2") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/thread.t b/test/lua-Harness-tests/lexico53/thread.t new file mode 100644 index 0000000..ef9e57b --- /dev/null +++ b/test/lua-Harness-tests/lexico53/thread.t @@ -0,0 +1,45 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +local co = coroutine.create(function () return 1 end) + +error_like(function () return ~co end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "~co") + +error_like(function () return co // 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "co // 3") + +error_like(function () return co & 7 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "co & 7") + +error_like(function () return co | 1 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "co | 1") + +error_like(function () return co ~ 4 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "co ~ 4") + +error_like(function () return co >> 5 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "co >> 5") + +error_like(function () return co << 2 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "co << 2") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/userdata.t b/test/lua-Harness-tests/lexico53/userdata.t new file mode 100644 index 0000000..06b96f9 --- /dev/null +++ b/test/lua-Harness-tests/lexico53/userdata.t @@ -0,0 +1,45 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2009-2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +local u = io.stdin + +error_like(function () return ~u end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "~u") + +error_like(function () return u // 3 end, + "^[^:]+:%d+: attempt to perform arithmetic on", + "u // 3") + +error_like(function () return u & 7 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "u & 7") + +error_like(function () return u | 1 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "u | 1") + +error_like(function () return u ~ 4 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "u ~ 4") + +error_like(function () return u >> 5 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "u >> 5") + +error_like(function () return u << 2 end, + "^[^:]+:%d+: attempt to perform bitwise operation on", + "u << 2") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico53/utf8.t b/test/lua-Harness-tests/lexico53/utf8.t new file mode 100644 index 0000000..87d3f6d --- /dev/null +++ b/test/lua-Harness-tests/lexico53/utf8.t @@ -0,0 +1,179 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2014-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +local has_char54 = _VERSION >= 'Lua 5.4' +local has_charpattern54 = _VERSION >= 'Lua 5.4' + +do -- char + is(utf8.char(65, 66, 67), 'ABC', "function char") + is(utf8.char(0x20AC), '\u{20AC}') + is(utf8.char(), '') + + is(utf8.char(0):len(), 1) + is(utf8.char(0x7F):len(), 1) + is(utf8.char(0x80):len(), 2) + is(utf8.char(0x7FF):len(), 2) + is(utf8.char(0x800):len(), 3) + is(utf8.char(0xFFFF):len(), 3) + is(utf8.char(0x10000):len(), 4) + is(utf8.char(0x10FFFF):len(), 4) + if has_char54 then + is(utf8.char(0x1FFFFF):len(), 4) + is(utf8.char(0x200000):len(), 5) + is(utf8.char(0x3FFFFFF):len(), 5) + is(utf8.char(0x4000000):len(), 6) + is(utf8.char(0x7FFFFFFF):len(), 6) + else + error_like(function () utf8.char(0x110000) end, + "^[^:]+:%d+: bad argument #1 to 'char' %(value out of ", + "function char (out of range)") + end + + error_like(function () utf8.char(0, -1) end, + "^[^:]+:%d+: bad argument #2 to 'char' %(value out of ", + "function char (out of range)") + + error_like(function () utf8.char(0, 'bad') end, + "^[^:]+:%d+: bad argument #2 to 'char' %(number expected, got string%)", + "function char (bad)") +end + +do -- charpattern + if has_charpattern54 then + is(utf8.charpattern, "[\0-\x7F\xC2-\xFD][\x80-\xBF]*", "charpattern") + else + is(utf8.charpattern, "[\0-\x7F\xC2-\xF4][\x80-\xBF]*", "charpattern") + end +end + +do -- codes + local ap = {} + local ac = {} + for p, c in utf8.codes("A\u{20AC}3") do + ap[#ap+1] = p + ac[#ac+1] = c + end + eq_array(ap, {1, 2, 5}, "function codes") + eq_array(ac, {0x41, 0x20AC, 0x33}) + + local empty = true + for p, c in utf8.codes('') do + empty = false + end + ok(empty, "codes (empty)") + + error_like(function () utf8.codes() end, + "^[^:]+:%d+: bad argument #1 to 'codes' %(string expected, got no value%)", + "function codes ()") + + error_like(function () utf8.codes(true) end, + "^[^:]+:%d+: bad argument #1 to 'codes' %(string expected, got boolean%)", + "function codes (true)") + + error_like(function () for p, c in utf8.codes('invalid\xFF') do end end, + "^[^:]+:%d+: invalid UTF%-8 code", + "function codes (invalid)") +end + +do -- codepoints + is(utf8.codepoint("A\u{20AC}3"), 0x41, "function codepoint") + is(utf8.codepoint("A\u{20AC}3", 2), 0x20AC) + is(utf8.codepoint("A\u{20AC}3", -1), 0x33) + is(utf8.codepoint("A\u{20AC}3", 5), 0x33) + eq_array({utf8.codepoint("A\u{20AC}3", 1, 5)}, {0x41, 0x20AC, 0x33}) + eq_array({utf8.codepoint("A\u{20AC}3", 1, 4)}, {0x41, 0x20AC}) + + error_like(function () utf8.codepoint("A\u{20AC}3", 6) end, + "^[^:]+:%d+: bad argument #3 to 'codepoint' %(out of ", + "function codepoint (out of range)") + + error_like(function () utf8.codepoint("A\u{20AC}3", 8) end, + "^[^:]+:%d+: bad argument #3 to 'codepoint' %(out of ", + "function codepoint (out of range)") + + error_like(function () utf8.codepoint("invalid\xFF", 8) end, + "^[^:]+:%d+: invalid UTF%-8 code", + "function codepoint (invalid)") +end + +do -- len + is(utf8.len('A'), 1, "function len") + is(utf8.len(''), 0) + is(utf8.len("\u{41}\u{42}\u{43}"), 3) + is(utf8.len("A\u{20AC}3"), 3) + + is(utf8.len('A', 1), 1) + is(utf8.len('A', 2), 0) + is(utf8.len('ABC', 1, 1), 1) + is(utf8.len('ABC', 2, 2), 1) + is(utf8.len('ABC', -1), 1) + is(utf8.len('ABC', -2), 2) + + error_like(function () utf8.len('A', 3) end, + "^[^:]+:%d+: bad argument #2 to 'len' %(initial position out of ", + "function len (out of range)") + + local len, pos = utf8.len('invalid\xFF') + is(len, nil, "function len (invalid)") + is(pos, 8) +end + +do -- offset + is(utf8.offset("A\u{20AC}3", 1), 1, "function offset") + is(utf8.offset("A\u{20AC}3", 2), 2) + is(utf8.offset("A\u{20AC}3", 3), 5) + is(utf8.offset("A\u{20AC}3", 4), 6) + is(utf8.offset("A\u{20AC}3", 5), nil) + is(utf8.offset("A\u{20AC}3", 6), nil) + is(utf8.offset("A\u{20AC}3", -1), 5) + is(utf8.offset("A\u{20AC}3", 1, 2), 2) + is(utf8.offset("A\u{20AC}3", 2, 2), 5) + is(utf8.offset("A\u{20AC}3", 3, 2), 6) + is(utf8.offset("A\u{20AC}3", 4, 2), nil) + is(utf8.offset("A\u{20AC}3", -1, 2), 1) + is(utf8.offset("A\u{20AC}3", -2, 2), nil) + is(utf8.offset("A\u{20AC}3", 1, 5), 5) + is(utf8.offset("A\u{20AC}3", 2, 5), 6) + is(utf8.offset("A\u{20AC}3", 3, 5), nil) + is(utf8.offset("A\u{20AC}3", -1, 5), 2) + is(utf8.offset("A\u{20AC}3", -2, 5), 1) + is(utf8.offset("A\u{20AC}3", -3, 5), nil) + is(utf8.offset("A\u{20AC}3", 1, 6), 6) + is(utf8.offset("A\u{20AC}3", 2, 6), nil) + is(utf8.offset("A\u{20AC}3", 1, -1), 5) + is(utf8.offset("A\u{20AC}3", -1, -1), 2) + is(utf8.offset("A\u{20AC}3", -2, -1), 1) + is(utf8.offset("A\u{20AC}3", -3, -1), nil) + is(utf8.offset("A\u{20AC}3", 1, -4), 2) + is(utf8.offset("A\u{20AC}3", 2, -4), 5) + is(utf8.offset("A\u{20AC}3", -1, -4), 1) + is(utf8.offset("A\u{20AC}3", -2, -4), nil) + + is(utf8.offset("A\u{20AC}3", 0, 1), 1) + is(utf8.offset("A\u{20AC}3", 0, 2), 2) + is(utf8.offset("A\u{20AC}3", 0, 3), 2) + is(utf8.offset("A\u{20AC}3", 0, 4), 2) + is(utf8.offset("A\u{20AC}3", 0, 5), 5) + is(utf8.offset("A\u{20AC}3", 0, 6), 6) + + error_like(function () utf8.offset("A\u{20AC}3", 1, 7) end, + "^[^:]+:%d+: bad argument #3 to 'offset' %(position out of ", + "function offset (out of range)") + + error_like(function () utf8.offset("\x80", 1) end, + "^[^:]+:%d+: initial position is a continuation byte", + "function offset (continuation byte)") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico54/lexico.t b/test/lua-Harness-tests/lexico54/lexico.t new file mode 100644 index 0000000..4523a51 --- /dev/null +++ b/test/lua-Harness-tests/lexico54/lexico.t @@ -0,0 +1,19 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +is("\u{10000}", "\xF0\x90\x80\x80") +is("\u{200000}", "\xF8\x88\x80\x80\x80") +is("\u{4000000}", "\xFC\x84\x80\x80\x80\x80") + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico54/metatable.t b/test/lua-Harness-tests/lexico54/metatable.t new file mode 100644 index 0000000..4685b34 --- /dev/null +++ b/test/lua-Harness-tests/lexico54/metatable.t @@ -0,0 +1,38 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2019-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +do -- toclose + local called = false + do + local foo <close> = setmetatable({}, { __close = function () called = true end }) + type_ok(foo, 'table', "toclose") + is(called, false) + end + is(called, true) + + error_like(function () do local foo <close> = {} end end, + "^[^:]+:%d+: variable 'foo' got a non%-closable value") + + lives_ok(function () + local var1 <const> = nil + local var2 <const> = nil + do + local var3 <close> = setmetatable({}, { __close = function () end }) + end + local var4 = true + -- attempt to close non-closable variable 'var4' + end, "blocker bug 5.4.0-rc3") +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexico54/utf8.t b/test/lua-Harness-tests/lexico54/utf8.t new file mode 100644 index 0000000..1aa70cc --- /dev/null +++ b/test/lua-Harness-tests/lexico54/utf8.t @@ -0,0 +1,54 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2019, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +do -- codes + local ap = {} + local ac = {} + for p, c in utf8.codes("A\u{200000}3", true) do + ap[#ap+1] = p + ac[#ac+1] = c + end + eq_array(ap, {1, 2, 7}, "function codes lax") + eq_array(ac, {0x41, 0x200000, 0x33}) + + error_like(function () for _ in utf8.codes("A\u{200000}3", false) do end end, + "^[^:]+:%d+: invalid UTF%-8 code") + + error_like(function () for _ in utf8.codes("A\u{200000}3") do end end, + "^[^:]+:%d+: invalid UTF%-8 code") +end + +do -- codepoints + eq_array({utf8.codepoint("A\u{200000}3", 1, 7, true)}, {0x41, 0x200000, 0x33}, "function codepoint lax") + + error_like(function () utf8.codepoint("A\u{200000}3", 1, 7, false) end, + "^[^:]+:%d+: invalid UTF%-8 code") + + error_like(function () utf8.codepoint("A\u{200000}3", 1, 7) end, + "^[^:]+:%d+: invalid UTF%-8 code") +end + +do -- len + is(utf8.len('A\u{200000}C', 1, -1, true), 3, "function len lax") + + local len, pos = utf8.len('A\u{200000}C') + is(len, nil) + is(pos, 2) + + len, pos = utf8.len('A\u{200000}C', 1, -1, false) + is(len, nil) + is(pos, 2) +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexicojit/basic.t b/test/lua-Harness-tests/lexicojit/basic.t new file mode 100644 index 0000000..8ad3a59 --- /dev/null +++ b/test/lua-Harness-tests/lexicojit/basic.t @@ -0,0 +1,27 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +do -- tonumber + is(tonumber(42uLL), 42, "function tonumber (cdata)") + is(tonumber(42LL), 42) +end + +do -- tostring + is(tostring(42uLL), '42ULL', "function tostring (cdata)") + is(tostring(42LL), '42LL') + is(tostring(1i), '0+1i') + is(tostring(12.5i), '0+12.5i') +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexicojit/ext.t b/test/lua-Harness-tests/lexicojit/ext.t new file mode 100644 index 0000000..8c44b99 --- /dev/null +++ b/test/lua-Harness-tests/lexicojit/ext.t @@ -0,0 +1,52 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2019-2020, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +local profile = require'profile' + +do -- thread.exdata + local r, exdata = pcall(require, 'thread.exdata') + is(r, true, 'thread.exdata') + type_ok(exdata, 'function') + is(package.loaded['thread.exdata'], exdata) + + local ffi = require'ffi' + local u64 = ffi.new('uintptr_t', 0xefdeaddeadbeefLL) + local ptr = ffi.cast('void *', u64) + exdata(u64) -- set + is(exdata(), ptr) -- get + + error_like(function () exdata(42) end, + "^[^:]+:%d+: bad argument #1 to 'exdata' %(cdata expected, got number%)") +end + +-- thread.exdata2 +if profile.openresty then + local r, exdata2 = pcall(require, 'thread.exdata2') + is(r, true, 'thread.exdata2') + type_ok(exdata2, 'function') + is(package.loaded['thread.exdata2'], exdata2) + + local ffi = require'ffi' + local u64 = ffi.new('uintptr_t', 0xefdeaddeadbeefLL) + local ptr = ffi.cast('void *', u64) + exdata2(u64) -- set + is(exdata2(), ptr) -- get + + error_like(function () exdata2(42) end, + "^[^:]+:%d+: bad argument #1 to 'exdata2' %(cdata expected, got number%)") +else + is(pcall(require, 'thread.exdata2'), false, 'no thread.exdata2') +end + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/lexicojit/lexico.t b/test/lua-Harness-tests/lexicojit/lexico.t new file mode 100644 index 0000000..1a973b5 --- /dev/null +++ b/test/lua-Harness-tests/lexicojit/lexico.t @@ -0,0 +1,32 @@ +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- +-- Copyright (C) 2018, Perrad Francois +-- +-- This code is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- + +type_ok(42LL, 'cdata', "42LL") +type_ok(42ULL, 'cdata', "42ULL") +type_ok(42uLL, 'cdata', "42uLL") +type_ok(42ull, 'cdata', "42ull") + +type_ok(0x2aLL, 'cdata', "0x2aLL") +type_ok(0x2aULL, 'cdata', "0x2aULL") +type_ok(0x2auLL, 'cdata', "0x2auLL") +type_ok(0x2aull, 'cdata', "0x2aull") + +type_ok(12.5i, 'cdata', '12.5i') +type_ok(12.5I, 'cdata', '12.5I') +type_ok(1i, 'cdata', '1i') +type_ok(1I, 'cdata', '1I') +type_ok(0i, 'cdata', '0i') +type_ok(0I, 'cdata', '0I') + +-- Local Variables: +-- mode: lua +-- lua-indent-level: 4 +-- fill-column: 100 +-- End: +-- vim: ft=lua expandtab shiftwidth=4: diff --git a/test/lua-Harness-tests/profile.lua b/test/lua-Harness-tests/profile.lua new file mode 100644 index 0000000..50c0c11 --- /dev/null +++ b/test/lua-Harness-tests/profile.lua @@ -0,0 +1,53 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = true, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = true, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua51.lua b/test/lua-Harness-tests/profile_lua51.lua new file mode 100644 index 0000000..8625b23 --- /dev/null +++ b/test/lua-Harness-tests/profile_lua51.lua @@ -0,0 +1,46 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +-- [[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua51_strict.lua b/test/lua-Harness-tests/profile_lua51_strict.lua new file mode 100644 index 0000000..d8d1efd --- /dev/null +++ b/test/lua-Harness-tests/profile_lua51_strict.lua @@ -0,0 +1,46 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua52.lua b/test/lua-Harness-tests/profile_lua52.lua new file mode 100644 index 0000000..fbc2fc4 --- /dev/null +++ b/test/lua-Harness-tests/profile_lua52.lua @@ -0,0 +1,46 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = true, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua52_strict.lua b/test/lua-Harness-tests/profile_lua52_strict.lua new file mode 100644 index 0000000..d8d1efd --- /dev/null +++ b/test/lua-Harness-tests/profile_lua52_strict.lua @@ -0,0 +1,46 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua53.lua b/test/lua-Harness-tests/profile_lua53.lua new file mode 100644 index 0000000..ed1b91f --- /dev/null +++ b/test/lua-Harness-tests/profile_lua53.lua @@ -0,0 +1,52 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = true, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua53_noconv.lua b/test/lua-Harness-tests/profile_lua53_noconv.lua new file mode 100644 index 0000000..c4500b3 --- /dev/null +++ b/test/lua-Harness-tests/profile_lua53_noconv.lua @@ -0,0 +1,55 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = true, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + nocvtn2s = true, + nocvts2n = true, + + compat53 = false, +--[[ + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua53_strict.lua b/test/lua-Harness-tests/profile_lua53_strict.lua new file mode 100644 index 0000000..399282b --- /dev/null +++ b/test/lua-Harness-tests/profile_lua53_strict.lua @@ -0,0 +1,52 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua54.lua b/test/lua-Harness-tests/profile_lua54.lua new file mode 100644 index 0000000..ef4daa3 --- /dev/null +++ b/test/lua-Harness-tests/profile_lua54.lua @@ -0,0 +1,52 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = true, +--[[ + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua54_noconv.lua b/test/lua-Harness-tests/profile_lua54_noconv.lua new file mode 100644 index 0000000..b9e17c3 --- /dev/null +++ b/test/lua-Harness-tests/profile_lua54_noconv.lua @@ -0,0 +1,55 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + nocvtn2s = true, + nocvts2n = true, + + compat53 = true, +--[[ + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_lua54_strict.lua b/test/lua-Harness-tests/profile_lua54_strict.lua new file mode 100644 index 0000000..9fcfb79 --- /dev/null +++ b/test/lua-Harness-tests/profile_lua54_strict.lua @@ -0,0 +1,53 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_luajit20.lua b/test/lua-Harness-tests/profile_luajit20.lua new file mode 100644 index 0000000..75461c2 --- /dev/null +++ b/test/lua-Harness-tests/profile_luajit20.lua @@ -0,0 +1,53 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +-- [[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +-- [[ luajit + luajit_compat52 = false, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_luajit20_compat52.lua b/test/lua-Harness-tests/profile_luajit20_compat52.lua new file mode 100644 index 0000000..7064470 --- /dev/null +++ b/test/lua-Harness-tests/profile_luajit20_compat52.lua @@ -0,0 +1,53 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = false, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +-- [[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_luajit21.lua b/test/lua-Harness-tests/profile_luajit21.lua new file mode 100644 index 0000000..f24e85e --- /dev/null +++ b/test/lua-Harness-tests/profile_luajit21.lua @@ -0,0 +1,53 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +-- [[ luajit + luajit_compat52 = false, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_luajit21_compat52.lua b/test/lua-Harness-tests/profile_luajit21_compat52.lua new file mode 100644 index 0000000..7064470 --- /dev/null +++ b/test/lua-Harness-tests/profile_luajit21_compat52.lua @@ -0,0 +1,53 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = false, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +-- [[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_openresty.lua b/test/lua-Harness-tests/profile_openresty.lua new file mode 100644 index 0000000..c151a39 --- /dev/null +++ b/test/lua-Harness-tests/profile_openresty.lua @@ -0,0 +1,53 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = false, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +-- [[ luajit + luajit_compat52 = true, + openresty = true, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_ravi.lua b/test/lua-Harness-tests/profile_ravi.lua new file mode 100644 index 0000000..8cd2464 --- /dev/null +++ b/test/lua-Harness-tests/profile_ravi.lua @@ -0,0 +1,58 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +-- luacheck: globals _VERSION +_VERSION = 'Lua 5.3' -- instead of 'Ravi 5.3' + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = true, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = true, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + nocvtn2s = false, + nocvts2n = false, + + compat53 = false, +--[[ + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +--[[ luajit + luajit_compat52 = true, + openresty = false, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/profile_tiny_fork.lua b/test/lua-Harness-tests/profile_tiny_fork.lua new file mode 100644 index 0000000..f0df77b --- /dev/null +++ b/test/lua-Harness-tests/profile_tiny_fork.lua @@ -0,0 +1,60 @@ +--- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +--- + +require'compat53.math' +-- luacheck: globals utf8 +utf8 = require'compat53.utf8' + +local profile = { + +--[[ compat 5.0 + has_string_gfind = true, + has_math_mod = true, +--]] + + compat51 = false, +--[[ + has_unpack = true, + has_package_loaders = true, + has_math_log10 = true, + has_loadstring = true, + has_table_maxn = true, + has_module = true, + has_package_seeall = true, +--]] + + compat52 = false, +--[[ + has_mathx = true, + has_bit32 = true, + has_metamethod_ipairs = true, +--]] + + compat53 = false, +--[[ + has_math_log10 = true, + has_mathx = true, + has_metamethod_ipairs = true, +--]] + +-- [[ luajit + luajit_compat52 = false, + openresty = false, + pack = true, + integer = true, + utf8 = true, +--]] + +} + +package.loaded.profile = profile -- prevents loading of default profile + +return profile + +-- +-- Copyright (c) 2018-2019 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- diff --git a/test/lua-Harness-tests/rx_captures b/test/lua-Harness-tests/rx_captures new file mode 100644 index 0000000..e209d26 --- /dev/null +++ b/test/lua-Harness-tests/rx_captures @@ -0,0 +1,13 @@ +(a.)..(..) zzzabcdefzzz ab\tef basic match +(a(b(c))(d)) abcd abcd\tbc\tc\td nested match +((%w+)) abcd abcd\tabcd nested match +(a*(.)%w(%s*)) aa!b c aa!b \t!\t nested match +(a?).. abcd a opt +(A?).. abcd '' opt +()aa() flaaap 3\t5 empty capture +(.)%1 bookkeeper o backreference +(%w+)%s+%1 hello hello hello backreference +(.*)x 123x 123 repeated dot capture +$(%w+) $abc= abc not escaped + +## vim: noexpandtab tabstop=4 shiftwidth=4 diff --git a/test/lua-Harness-tests/rx_charclass b/test/lua-Harness-tests/rx_charclass new file mode 100644 index 0000000..af5cb45 --- /dev/null +++ b/test/lua-Harness-tests/rx_charclass @@ -0,0 +1,38 @@ +[c] abcdef c character class +^[a] abcdef a anchored character class +[^e] abcdef a negated character class +^[a]? abcdef a anchored optional character class +[^e]? abcdef a negated optional character class +^[^e] abcdef a anchored negated character class +^[^a] abcdef nil anchored negated character class +[b-d] abcdef b character range +[b-d] abxxef b character range +[b-d] axcxef c character range +[b-d] axxdef d character range +[b-d] axxxef nil character range +[^b-d] abcdef a negated character range +[^b-d] bbccdd nil negated character range +[-] ab-def - unescaped hyphen +[%-] ab-def - escaped hyphen +[%-] abcdef nil escaped hyphen +[^%-] ---x-- x negated escaped hyphen +[^%-] ------ nil negated escaped hyphen +[%-+] ab-def - escaped hyphen in range +[%-+] ab+def + escaped hyphen in range +[%-+] abcdef nil escaped hyphen in range +[+%-] ab-def - escaped hyphen in range +[+%-] ab+def + escaped hyphen in range +[+%-] abcdef nil escaped hyphen in range +[^%-+] ---x-- x negated escaped hyphen in range +[^%-+] ------ nil negated escaped hyphen in range +[^+%-] ---x-- x negated escaped hyphen in range +[^+%-] ------ nil negated escaped hyphen in range +["\\] \\ \ escaped backslash +[%]] ] ] escaped close bracket +[%] \\]] /malformed pattern %(missing ']'%)/ unescaped backslash (or no closing brace) +ab\\cd ab\092cd ab\cd literal match with backslash +%? ab<? ? literal match with question mark +[A-Z0-9] abcdef nil two enumerated ranges +[A-Z0-9] abcDef D two enumerated ranges + +## vim: noexpandtab tabstop=4 shiftwidth=4 diff --git a/test/lua-Harness-tests/rx_metachars b/test/lua-Harness-tests/rx_metachars new file mode 100644 index 0000000..8716ca1 --- /dev/null +++ b/test/lua-Harness-tests/rx_metachars @@ -0,0 +1,117 @@ +. a a dot (.) +. \n \n dot (.) +. '' nil dot (.) +a%s+f abcdef nil whitespace (%s) +ab%s+cdef ab cdef ab cdef whitespace (%s) +a%S+f abcdef abcdef not whitespace (%S) +a%S+f ab cdef nil not whitespace (%S) +^abc abcdef abc start and end of string (^) +^abc abc\ndef abc start and end of string (^) +^abc def\nabc nil start and end of string (^) +def\n^abc def\nabc nil start and end of string (^) +def$ abcdef def start and end of string ($) +def$ abc\ndef def start and end of string ($) +def$ def\nabc nil start and end of string ($) +def$\nabc def\nabc nil start and end of string (^) +abc\n$ abc\n abc\n end of string ($) +abc$ abc\n nil end of string ($) +c\nd abc\ndef c\nd newline (\n) +c\nd abc\010def c\nd newline (\n) +c\n+d abc\n\ndef c\n\nd newline (\n) +a\n+f abcdef nil newline (\n) +b\nc abc\ndef nil newline (\n) +c\td abc\tdef c\td horizontal tab (\t) +c\td abc\09def c\td horizontal tab (\t) +c\t+d abc\t\tdef c\t\td horizontal tab (\t) +a\t+f abcdef nil horizontal tab (\t) +b\tc abc\tdef nil horizontal tab (\t) +c\rd abc\rdef c\rd return (\r) +c\rd abc\013def c\rd return (\r) +c\r+d abc\r\rdef c\r\rd return (\r) +a\r+f abcdef nil return (\r) +b\rc abc\rdef nil return (\r) +c\fd abc\fdef c\fd formfeed (\f) +c\fd abc\012def c\fd formfeed (\f) +c\f+d abc\f\fdef c\f\fd formfeed (\f) +a\f+f abcdef nil formfeed (\f) +b\fc abc\fdef nil formfeed (\f) +c\033d abc!def c!d dec (\0) +c\033d abc\033def c!d dec (\0) +c\033+d abc!!def c!!d dec (\0) +a\033+f abcdef nil dec (\0) +b\033c abc!def nil dec (\0) +a%^d a^d a^d escaped (useless) +a^d a^d a^d not escaped +%^d ^d ^d escaped +a%$d a$d a$d escaped (useless) +a$d a$d a$d not escaped +a%$ a$ a$ escaped +a%(d a(d a(d escaped +a%)d a)d a)d escaped +a%%d a%d a%d escaped +a% a% /malformed pattern %(ends with '%%'%)/ not escaped +a%.d a.d a.d escaped +a%.d abd nil escaped +a%[d a[d a[d escaped +a%]d a]d a]d escaped +a%*d a*d a*d escaped +*ad *ad *ad not escaped +a%+d a+d a+d escaped +a%-d a-d a-d escaped +a%?d a?d a?d escaped +a%yd ayd ayd escaped +a%w+f a=[ *f nil word character +a%w+f abcdef abcdef word character +a%W+f a&%- f a&%- f not word character +a%W+f abcdef nil not word character +a%d+f abcdef nil digit +ab%d+cdef ab42cdef ab42cdef digit +a%D+f abcdef abcdef not digit +a%D+f ab0cdef nil not digit +a%l+f aBCDEf nil lowercase letter +a%l+f abcdef abcdef lowercase letter +a%L+f a&2D f a&2D f not lowercase letter +a%L+f aBCdEf nil not lowercase letter +a%u+f abcdef nil uppercase letter +a%u+f aBCDEf aBCDEf uppercase letter +a%U+f a&2d f a&2d f not uppercase letter +a%U+f a&2D f nil not uppercase letter +a%a+f aBcDef aBcDef all letter +a%a+f a=[ *f nil all letter +a%A+f a&%- f a&%- f not all letter +a%A+f abcdef nil not all letter +a%g+f aBcDef aBcDef printable +a%g+f a=[ *f nil printable +a%G+f a \nf a \nf not printable +a%G+f abcdef nil not printable +a%p+f abcdef nil ponctuation +a%p+f a,;:!f a,;:!f ponctuation +a%P+f abcdef abcdef not ponctuation +a%P+f adc:ef nil not ponctuation +a%c+f abcdef nil control character +a%c+f a\04\03\02f a\04\03\02f control character +a%C+f abcdef abcdef not control character +a%C+f abc\01ef nil not control character +a%x+f axyzef nil hexadecimal +a%x+f ab3Def ab3Def hexadecimal +a%X+f abcdef nil not hexadecimal +a%X+f axy;Zf axy;Zf not hexadecimal +a%z+f abcdef nil zero (deprecated) +a\0+f abcdef nil zero +a%z+f a\0f a\0f zero (deprecated) +a\0+f a\0f a\0f zero +a%Z+f abcdef abcdef not zero (deprecated) +a[^\0]+f abcdef abcdef not zero +a%Z+f abc\0ef nil not zero (deprecated) +a[^\0]+f abc\0ef nil not zero +a%b()f a(bcde)f a(bcde)f balanced +a%b()f a(b(de)f nil balanced +a%b()f a(b(d)e)f a(b(d)e)f balanced +a%b''f a'bcde'f a'bcde'f balanced +a%b""f a"bcde"f a"bcde"f balanced +%f[b]bc abcdef bc frontier +%f[b]c abcdef nil frontier +%f[^ab]c abacdef c frontier +%f[^ab]d abacdef nil frontier + +## vim: noexpandtab tabstop=4 shiftwidth=4 diff --git a/test/lua-Harness-tests/tap.lua b/test/lua-Harness-tests/tap.lua new file mode 100644 index 0000000..5ce95e6 --- /dev/null +++ b/test/lua-Harness-tests/tap.lua @@ -0,0 +1,212 @@ + +-- +-- lua-Harness : <https://fperrad.frama.io/lua-Harness/> +-- + +--[[ + + Test Anything Protocol : minimalist version + +]] + +if pcall(require, 'Test.More') then + diag 'Test.More loaded' + return +end + +local os = os +local pcall = pcall +local print = print +local require = require +local tostring = tostring +local type = type + +local curr_test = 0 +local expected_tests = 0 +local todo_upto = 0 +local todo_reason + +function plan (arg) + if arg ~= 'no_plan' then + expected_tests = arg + print("1.." .. tostring(arg)) + end +end + +function done_testing () + print("1.." .. tostring(curr_test)) +end + +function skip_all (reason) + out = "1..0" + if reason then + out = out .. " # SKIP " .. reason + end + print(out) + os.exit(0) +end + +function ok (test, name) + curr_test = curr_test + 1 + local out = '' + if not test then + out = "not " + end + out = out .. "ok " .. tostring(curr_test) + if name then + out = out .. " - " .. name + end + if todo_reason and todo_upto >= curr_test then + out = out .. " # TODO # " .. todo_reason + end + print(out) +end + +function nok (test, name) + ok(not test, name) +end + +function is (got, expected, name) + local pass = got == expected + ok(pass, name) + if not pass then + diag(" got: " .. tostring(got)) + diag(" expected: " .. tostring(expected)) + end +end + +function isnt (got, not_expected, name) + local pass = got ~= not_expected + ok(pass, name) + if not pass then + diag(" got: " .. tostring(got)) + diag(" expected: anything else") + end +end + +function like (got, pattern, name) + local pass = tostring(got):match(pattern) + ok(pass, name) + if not pass then + diag(" " .. tostring(got)) + diag(" doesn't match '" .. tostring(pattern) .. "'") + end +end + +function type_ok (val, t, name) + if type(val) == t then + ok(true, name) + else + ok(false, name) + diag(" " .. tostring(val) .. " isn't a '" .. t .."' it's '" .. type(val) .. "'") + end +end + +function pass (name) + ok(true, name) +end + +function fail (name) + ok(false, name) +end + +function require_ok (mod) + local r, msg = pcall(require, mod) + ok(r, "require '" .. mod .. "'") + if not r then + diag(" " .. msg) + end + return r +end + +function eq_array (got, expected, name) + for i = 1, #expected do + local v = expected[i] + local val = got[i] + if val ~= v then + ok(false, name) + diag(" at index: " .. tostring(i)) + diag(" got: " .. tostring(val)) + diag(" expected: " .. tostring(v)) + return + end + end + local extra = #got - #expected + if extra ~= 0 then + ok(false, name) + diag(" " .. tostring(extra) .. " unexpected item(s)") + else + ok(true, name) + end +end + +function error_is (code, expected, name) + local r, msg = pcall(code) + if r then + ok(false, name) + diag(" unexpected success") + diag(" expected: " .. tostring(pattern)) + else + is(msg, expected, name) + end +end + +function error_like (code, pattern, name) + local r, msg = pcall(code) + if r then + ok(false, name) + diag(" unexpected success") + diag(" expected: " .. tostring(pattern)) + else + like(msg, pattern, name) + end +end + +function lives_ok (code, name) + local r, msg = pcall(code) + ok(r, name) + if not r then + diag(" " .. msg) + end +end + +function diag (msg) + print("# " .. msg) +end + +function skip (reason, count) + count = count or 1 + local name = "# skip" + if reason then + name = name .. " " ..reason + end + for i = 1, count do + ok(true, name) + end +end + +function skip_rest (reason) + skip(reason, expected_tests - curr_test) +end + +function todo (reason, count) + count = count or 1 + todo_upto = curr_test + count + todo_reason = reason +end + +-- The last arg element is guaranteed name of tested binary. +function get_lua_binary_name () + local i = 0 + while arg[i] do + i = i - 1 + end + return arg[i + 1] +end + +-- +-- Copyright (c) 2009-2018 Francois Perrad +-- +-- This library is licensed under the terms of the MIT/X11 license, +-- like Lua itself. +-- -- 2.28.0
next prev parent reply other threads:[~2021-03-12 5:31 UTC|newest] Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-03-12 5:27 [Tarantool-patches] [PATCH luajit 0/6] Adapt " Sergey Kaplun via Tarantool-patches 2021-03-12 5:27 ` Sergey Kaplun via Tarantool-patches [this message] 2021-03-15 13:05 ` [Tarantool-patches] [PATCH luajit 1/6] test: add " Igor Munkin via Tarantool-patches 2021-03-12 5:27 ` [Tarantool-patches] [PATCH luajit 2/6] test: adjust lua-Harness test suite for Tarantool Sergey Kaplun via Tarantool-patches 2021-03-13 18:41 ` Sergey Ostanevich via Tarantool-patches 2021-03-15 13:22 ` Igor Munkin via Tarantool-patches 2021-03-12 5:27 ` [Tarantool-patches] [PATCH luajit 3/6] test: disable 305-utf8 of lua-Harness suite Sergey Kaplun via Tarantool-patches 2021-03-13 18:45 ` Sergey Ostanevich via Tarantool-patches 2021-03-15 12:45 ` Igor Munkin via Tarantool-patches 2021-03-12 5:27 ` [Tarantool-patches] [PATCH luajit 4/6] test: disable 241-standalone " Sergey Kaplun via Tarantool-patches 2021-03-13 18:45 ` Sergey Ostanevich via Tarantool-patches 2021-03-15 12:47 ` Igor Munkin via Tarantool-patches 2021-03-12 5:27 ` [Tarantool-patches] [PATCH luajit 5/6] test: disable 411-luajit " Sergey Kaplun via Tarantool-patches 2021-03-13 18:46 ` Sergey Ostanevich via Tarantool-patches 2021-03-15 12:48 ` Igor Munkin via Tarantool-patches 2021-03-12 5:27 ` [Tarantool-patches] [PATCH luajit 6/6] test: skip test for getenv in 309-os.t Sergey Kaplun via Tarantool-patches 2021-03-13 18:50 ` Sergey Ostanevich via Tarantool-patches 2021-03-15 10:22 ` Igor Munkin via Tarantool-patches 2021-03-13 18:22 ` [Tarantool-patches] [PATCH luajit 0/6] Adapt lua-Harness test suite Sergey Ostanevich via Tarantool-patches
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=639a4804ee9c20ac3b8cd58540c612d0bcf693ad.1615470667.git.skaplun@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=imun@tarantool.org \ --cc=sergos@tarantool.org \ --cc=skaplun@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH luajit 1/6] test: add lua-Harness test suite' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox