parent
4e5e3e9c18
commit
7947d7af17
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -7,3 +7,6 @@
|
|||||||
[submodule "libs/luaunit"]
|
[submodule "libs/luaunit"]
|
||||||
path = libs/luaunit
|
path = libs/luaunit
|
||||||
url = https://github.com/bluebird75/luaunit
|
url = https://github.com/bluebird75/luaunit
|
||||||
|
[submodule "libs/u-test"]
|
||||||
|
path = libs/u-test
|
||||||
|
url = https://github.com/IUdalov/u-test.git
|
||||||
|
|||||||
@ -16,6 +16,9 @@ FILE(GLOB LUA_SOURCES src/lua/*.lua)
|
|||||||
if(APPLE)
|
if(APPLE)
|
||||||
# Supress warning CMP0042
|
# Supress warning CMP0042
|
||||||
set(CMAKE_MACOSX_RPATH 1)
|
set(CMAKE_MACOSX_RPATH 1)
|
||||||
|
set(LIBRARY_EXT dylib)
|
||||||
|
else()
|
||||||
|
set(LIBRARY_EXT so)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(effil SHARED ${SOURCES})
|
add_library(effil SHARED ${SOURCES})
|
||||||
@ -30,25 +33,24 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -g0 -DNDEBUG")
|
|||||||
#----------
|
#----------
|
||||||
# TESTS ---
|
# TESTS ---
|
||||||
#----------
|
#----------
|
||||||
|
|
||||||
FILE(GLOB TEST_SOURCES tests/cpp/*.cpp tests/cpp/*.h)
|
FILE(GLOB TEST_SOURCES tests/cpp/*.cpp tests/cpp/*.h)
|
||||||
FILE(GLOB LUA_TEST_SOURCES tests/lua/run_tests.lua)
|
|
||||||
set(GTEST_DIR libs/gtest/googletest)
|
set(GTEST_DIR libs/gtest/googletest)
|
||||||
|
set(LUA_TESTS tests/lua/tests.lua)
|
||||||
|
|
||||||
include_directories(${GTEST_DIR}/include ${GTEST_DIR})
|
include_directories(${GTEST_DIR}/include ${GTEST_DIR})
|
||||||
add_executable(tests ${TEST_SOURCES} ${GTEST_DIR}/src/gtest-all.cc)
|
add_executable(tests ${TEST_SOURCES} ${GTEST_DIR}/src/gtest-all.cc)
|
||||||
target_link_libraries(tests effil)
|
target_link_libraries(tests effil)
|
||||||
|
|
||||||
#----------
|
|
||||||
# INSTALL -
|
|
||||||
#----------
|
|
||||||
install(FILES ${LUA_SOURCES} ${LUA_TEST_SOURCES}
|
|
||||||
DESTINATION ${CMAKE_BINARY_DIR}
|
|
||||||
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
|
|
||||||
|
|
||||||
#----------
|
#----------
|
||||||
# FORMAT -
|
# FORMAT -
|
||||||
#----------
|
#----------
|
||||||
add_custom_target( format
|
add_custom_target( format
|
||||||
COMMAND clang-format -i ${TEST_SOURCES} ${SOURCES}
|
COMMAND clang-format -i ${TEST_SOURCES} ${SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#----------
|
||||||
|
# INSTALL -
|
||||||
|
#----------
|
||||||
|
install(FILES ${LUA_TESTS}
|
||||||
|
DESTINATION ${CMAKE_BINARY_DIR}
|
||||||
|
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
|
||||||
|
|||||||
@ -4,5 +4,5 @@ set -e
|
|||||||
for build_type in debug release; do
|
for build_type in debug release; do
|
||||||
mkdir -p $build_type
|
mkdir -p $build_type
|
||||||
(cd $build_type && cmake -DCMAKE_BUILD_TYPE=$build_type $@ .. && make -j4 install)
|
(cd $build_type && cmake -DCMAKE_BUILD_TYPE=$build_type $@ .. && make -j4 install)
|
||||||
(cd $build_type && ./tests && lua run_tests.lua --extra-checks)
|
(cd $build_type && ./tests && STRESS=1 lua tests.lua)
|
||||||
done
|
done
|
||||||
|
|||||||
1
libs/u-test
Submodule
1
libs/u-test
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 34ee5de696c2c12d8ded5793f2c5504f2e6ee168
|
||||||
36
tests/lua/bootstrap-tests.lua
Normal file
36
tests/lua/bootstrap-tests.lua
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
effil = require "effil"
|
||||||
|
test = require "u-test"
|
||||||
|
|
||||||
|
function default_tear_down()
|
||||||
|
collectgarbage()
|
||||||
|
effil.gc.collect()
|
||||||
|
-- effil.G is always present
|
||||||
|
-- thus, gc has one object
|
||||||
|
test.equal(effil.gc.count(), 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function wait(timeInSec, condition, silent)
|
||||||
|
local result = false
|
||||||
|
local startTime = os.time()
|
||||||
|
while ( (os.time() - startTime) <= timeInSec) do
|
||||||
|
if condition ~= nil then
|
||||||
|
if type(condition) == 'function' then
|
||||||
|
if condition() then
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if condition then
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function sleep(timeInSec, silent)
|
||||||
|
wait(timeInSec, nil, true)
|
||||||
|
end
|
||||||
63
tests/lua/channel-stress.lua
Normal file
63
tests/lua/channel-stress.lua
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
require "bootstrap-tests"
|
||||||
|
|
||||||
|
test.channel_stress.tear_down = default_tear_down
|
||||||
|
|
||||||
|
test.channel_stress.with_multiple_threads = function ()
|
||||||
|
local exchange_channel, result_channel = effil.channel(), effil.channel()
|
||||||
|
|
||||||
|
local threads_number = 1000
|
||||||
|
for i = 1, threads_number do
|
||||||
|
effil.thread(function(exchange_channel, result_channel, indx)
|
||||||
|
if indx % 2 == 0 then
|
||||||
|
for i = 1, 10000 do
|
||||||
|
exchange_channel:push(indx .. "_".. i)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
repeat
|
||||||
|
local ret = exchange_channel:pop(10)
|
||||||
|
if ret then
|
||||||
|
result_channel:push(ret)
|
||||||
|
end
|
||||||
|
until ret == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)(exchange_channel, result_channel, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = {}
|
||||||
|
for i = 1, (threads_number / 2) * 10000 do
|
||||||
|
local ret = result_channel:pop(10)
|
||||||
|
test.is_not_nil(ret)
|
||||||
|
test.is_string(ret)
|
||||||
|
test.is_nil(data[ret])
|
||||||
|
data[ret] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for thr_id = 2, threads_number, 2 do
|
||||||
|
for iter = 1, 10000 do
|
||||||
|
test.is_true(data[thr_id .. "_".. iter])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test.channel_stress.timed_read = function ()
|
||||||
|
local chan = effil.channel()
|
||||||
|
local delayed_writer = function(channel, delay)
|
||||||
|
require("effil").sleep(delay)
|
||||||
|
channel:push("hello!")
|
||||||
|
end
|
||||||
|
effil.thread(delayed_writer)(chan, 70)
|
||||||
|
|
||||||
|
local function check_time(real_time, use_time, metric, result)
|
||||||
|
local start_time = os.time()
|
||||||
|
test.equal(chan:pop(use_time, metric), result)
|
||||||
|
test.almost_equal(os.time(), start_time + real_time, 1)
|
||||||
|
end
|
||||||
|
check_time(2, 2, nil, nil) -- second by default
|
||||||
|
check_time(2, 2, 's', nil)
|
||||||
|
check_time(60, 1, 'm', nil)
|
||||||
|
|
||||||
|
local start_time = os.time()
|
||||||
|
test.equal(chan:pop(10), "hello!")
|
||||||
|
test.is_true(os.time() < start_time + 10)
|
||||||
|
end
|
||||||
@ -1,38 +1,40 @@
|
|||||||
TestChannels = {tearDown = tearDown}
|
require "bootstrap-tests"
|
||||||
|
|
||||||
function TestChannels:testCapacityUsage()
|
test.channel.tear_down = default_tear_down
|
||||||
|
|
||||||
|
test.channel.capacity_usage = function()
|
||||||
local chan = effil.channel(2)
|
local chan = effil.channel(2)
|
||||||
|
|
||||||
test.assertTrue(chan:push(14))
|
test.is_true(chan:push(14))
|
||||||
test.assertTrue(chan:push(88))
|
test.is_true(chan:push(88))
|
||||||
test.assertFalse(chan:push(1488))
|
test.is_false(chan:push(1488))
|
||||||
|
|
||||||
test.assertEquals(chan:pop(), 14)
|
test.equal(chan:pop(), 14)
|
||||||
test.assertEquals(chan:pop(), 88)
|
test.equal(chan:pop(), 88)
|
||||||
test.assertIsNil(chan:pop(0))
|
test.is_nil(chan:pop(0))
|
||||||
|
|
||||||
test.assertTrue(chan:push(14, 88), true)
|
test.is_true(chan:push(14, 88), true)
|
||||||
local ret1, ret2 = chan:pop()
|
local ret1, ret2 = chan:pop()
|
||||||
test.assertEquals(ret1, 14)
|
test.equal(ret1, 14)
|
||||||
test.assertEquals(ret2, 88)
|
test.equal(ret2, 88)
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestChannels:testRecursiveChannels()
|
test.channel.recursive = function ()
|
||||||
local chan1 = effil.channel()
|
local chan1 = effil.channel()
|
||||||
local chan2 = effil.channel()
|
local chan2 = effil.channel()
|
||||||
local msg1, msg2 = "first channel", "second channel"
|
local msg1, msg2 = "first channel", "second channel"
|
||||||
test.assertTrue(chan1:push(msg1, chan2))
|
test.is_true(chan1:push(msg1, chan2))
|
||||||
test.assertTrue(chan2:push(msg2, chan1))
|
test.is_true(chan2:push(msg2, chan1))
|
||||||
|
|
||||||
local ret1 = { chan1:pop() }
|
local ret1 = { chan1:pop() }
|
||||||
test.assertEquals(ret1[1], msg1)
|
test.equal(ret1[1], msg1)
|
||||||
test.assertEquals(type(ret1[2]), "userdata")
|
test.equal(type(ret1[2]), "userdata")
|
||||||
local ret2 = { ret1[2]:pop() }
|
local ret2 = { ret1[2]:pop() }
|
||||||
test.assertEquals(ret2[1], msg2)
|
test.equal(ret2[1], msg2)
|
||||||
test.assertEquals(type(ret2[2]), "userdata")
|
test.equal(type(ret2[2]), "userdata")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestChannels:testWithThread()
|
test.channel.with_threads = function ()
|
||||||
local chan = effil.channel()
|
local chan = effil.channel()
|
||||||
local thread = effil.thread(function(chan)
|
local thread = effil.thread(function(chan)
|
||||||
chan:push("message1")
|
chan:push("message1")
|
||||||
@ -43,15 +45,15 @@ function TestChannels:testWithThread()
|
|||||||
)(chan)
|
)(chan)
|
||||||
|
|
||||||
local start_time = os.time()
|
local start_time = os.time()
|
||||||
test.assertEquals(chan:pop(), "message1")
|
test.equal(chan:pop(), "message1")
|
||||||
thread:wait()
|
thread:wait()
|
||||||
test.assertEquals(chan:pop(0), "message2")
|
test.equal(chan:pop(0), "message2")
|
||||||
test.assertEquals(chan:pop(1), "message3")
|
test.equal(chan:pop(1), "message3")
|
||||||
test.assertEquals(chan:pop(1, 'm'), "message4")
|
test.equal(chan:pop(1, 'm'), "message4")
|
||||||
test.assertTrue(os.time() < start_time + 1)
|
test.is_true(os.time() < start_time + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestChannels:testWithSharedTable()
|
test.channel.with_shared_table = function ()
|
||||||
local chan = effil.channel()
|
local chan = effil.channel()
|
||||||
local table = effil.table()
|
local table = effil.table()
|
||||||
|
|
||||||
@ -59,73 +61,9 @@ function TestChannels:testWithSharedTable()
|
|||||||
table.test_key = test_value
|
table.test_key = test_value
|
||||||
|
|
||||||
chan:push(table)
|
chan:push(table)
|
||||||
test.assertEquals(chan:pop().test_key, test_value)
|
test.equal(chan:pop().test_key, test_value)
|
||||||
|
|
||||||
table.channel = chan
|
table.channel = chan
|
||||||
table.channel:push(test_value)
|
table.channel:push(test_value)
|
||||||
test.assertEquals(table.channel:pop(), test_value)
|
test.equal(table.channel:pop(), test_value)
|
||||||
end
|
end
|
||||||
|
|
||||||
if WITH_EXTRA_CHECKS then
|
|
||||||
|
|
||||||
function TestChannels:testStressLoadWithMultipleThreads()
|
|
||||||
local exchange_channel, result_channel = effil.channel(), effil.channel()
|
|
||||||
|
|
||||||
local threads_number = 1000
|
|
||||||
for i = 1, threads_number do
|
|
||||||
effil.thread(function(exchange_channel, result_channel, indx)
|
|
||||||
if indx % 2 == 0 then
|
|
||||||
for i = 1, 10000 do
|
|
||||||
exchange_channel:push(indx .. "_".. i)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
repeat
|
|
||||||
local ret = exchange_channel:pop(10)
|
|
||||||
if ret then
|
|
||||||
result_channel:push(ret)
|
|
||||||
end
|
|
||||||
until ret == nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
)(exchange_channel, result_channel, i)
|
|
||||||
end
|
|
||||||
|
|
||||||
local data = {}
|
|
||||||
for i = 1, (threads_number / 2) * 10000 do
|
|
||||||
local ret = result_channel:pop(10)
|
|
||||||
test.assertNotIsNil(ret)
|
|
||||||
test.assertIsString(ret)
|
|
||||||
test.assertIsNil(data[ret])
|
|
||||||
data[ret] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
for thr_id = 2, threads_number, 2 do
|
|
||||||
for iter = 1, 10000 do
|
|
||||||
test.assertTrue(data[thr_id .. "_".. iter])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestChannels:testTimedRead()
|
|
||||||
local chan = effil.channel()
|
|
||||||
local delayedWriter = function(channel, delay)
|
|
||||||
require("effil").sleep(delay)
|
|
||||||
channel:push("hello!")
|
|
||||||
end
|
|
||||||
effil.thread(delayedWriter)(chan, 70)
|
|
||||||
|
|
||||||
local function check_time(real_time, use_time, metric, result)
|
|
||||||
local start_time = os.time()
|
|
||||||
test.assertEquals(chan:pop(use_time, metric), result)
|
|
||||||
test.assertAlmostEquals(os.time(), start_time + real_time, 1)
|
|
||||||
end
|
|
||||||
check_time(2, 2, nil, nil) -- second by default
|
|
||||||
check_time(2, 2, 's', nil)
|
|
||||||
check_time(60, 1, 'm', nil)
|
|
||||||
|
|
||||||
local start_time = os.time()
|
|
||||||
test.assertEquals(chan:pop(10), "hello!")
|
|
||||||
test.assertTrue(os.time() < start_time + 10)
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- WITH_EXTRA_CHECKS
|
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
local effil = require "effil"
|
require "bootstrap-tests"
|
||||||
|
|
||||||
local gc = effil.gc
|
local gc = effil.gc
|
||||||
|
|
||||||
TestGC = { tearDown = tearDown }
|
test.gc.tear_down = default_tear_down
|
||||||
|
|
||||||
function TestGC:testCleanup()
|
test.gc.cleanup = function ()
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
test.assertEquals(gc.count(), 1)
|
test.equal(gc.count(), 1)
|
||||||
|
|
||||||
for i = 0, 10000 do
|
for i = 0, 10000 do
|
||||||
local tmp = effil.table()
|
local tmp = effil.table()
|
||||||
@ -14,27 +15,27 @@ function TestGC:testCleanup()
|
|||||||
|
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
test.assertEquals(gc.count(), 1)
|
test.equal(gc.count(), 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestGC:testDisableGC()
|
test.gc.disable = function ()
|
||||||
local nobjects = 10000
|
local nobjects = 10000
|
||||||
|
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
test.assertEquals(gc.count(), 1)
|
test.equal(gc.count(), 1)
|
||||||
|
|
||||||
gc.pause()
|
gc.pause()
|
||||||
test.assertFalse(gc.enabled())
|
test.is_false(gc.enabled())
|
||||||
|
|
||||||
for i = 1, nobjects do
|
for i = 1, nobjects do
|
||||||
local tmp = effil.table()
|
local tmp = effil.table()
|
||||||
end
|
end
|
||||||
|
|
||||||
test.assertEquals(gc.count(), nobjects + 1)
|
test.equal(gc.count(), nobjects + 1)
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
test.assertEquals(gc.count(), 1)
|
test.equal(gc.count(), 1)
|
||||||
|
|
||||||
gc.resume()
|
gc.resume()
|
||||||
end
|
end
|
||||||
177
tests/lua/metatable.lua
Normal file
177
tests/lua/metatable.lua
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
require "bootstrap-tests"
|
||||||
|
|
||||||
|
test.metatable.tear_down = function (metatable)
|
||||||
|
collectgarbage()
|
||||||
|
effil.gc.collect()
|
||||||
|
|
||||||
|
-- if metatable is shared_table - it counts as gr object
|
||||||
|
-- and it will be destroyed after tear_down
|
||||||
|
if type(metatable) == "table" then
|
||||||
|
test.equal(effil.gc.count(), 1)
|
||||||
|
else
|
||||||
|
test.equal(effil.gc.count(), 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run_test_with_different_metatables(name, ...)
|
||||||
|
test.metatable[name]({}, ...)
|
||||||
|
test.metatable[name](effil.table(), ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
test.metatable.index = function (metatable)
|
||||||
|
local share = effil.table()
|
||||||
|
metatable.__index = function(t, key)
|
||||||
|
return "mt_" .. effil.rawget(t, key)
|
||||||
|
end
|
||||||
|
effil.setmetatable(share, metatable)
|
||||||
|
|
||||||
|
share.table_key = "table_value"
|
||||||
|
test.equal(share.table_key, "mt_table_value")
|
||||||
|
end
|
||||||
|
|
||||||
|
test.metatable.new_index = function (metatable)
|
||||||
|
local share = effil.table()
|
||||||
|
metatable.__newindex = function(t, key, value)
|
||||||
|
effil.rawset(t, "mt_" .. key, "mt_" .. value)
|
||||||
|
end
|
||||||
|
effil.setmetatable(share, metatable)
|
||||||
|
|
||||||
|
share.table_key = "table_value"
|
||||||
|
test.equal(share.mt_table_key, "mt_table_value")
|
||||||
|
end
|
||||||
|
|
||||||
|
test.metatable.call = function (metatable)
|
||||||
|
local share = effil.table()
|
||||||
|
metatable.__call = function(t, val1, val2, val3)
|
||||||
|
return tostring(val1) .. "_" .. tostring(val2), tostring(val2) .. "_" .. tostring(val3)
|
||||||
|
end
|
||||||
|
effil.setmetatable(share, metatable)
|
||||||
|
|
||||||
|
local first_ret, second_ret = share("val1", "val2", "val3")
|
||||||
|
test.equal(first_ret, "val1_val2")
|
||||||
|
test.equal(second_ret, "val2_val3")
|
||||||
|
end
|
||||||
|
|
||||||
|
run_test_with_different_metatables("index")
|
||||||
|
run_test_with_different_metatables("new_index")
|
||||||
|
run_test_with_different_metatables("call")
|
||||||
|
|
||||||
|
test.metatable.binary_op = function (metatable, metamethod, op, exp_value)
|
||||||
|
local testTable, operand = effil.table(), effil.table()
|
||||||
|
metatable['__' .. metamethod] = function(left, right)
|
||||||
|
left.was_called = true
|
||||||
|
return left.value .. '_'.. right.value
|
||||||
|
end
|
||||||
|
effil.setmetatable(testTable, metatable)
|
||||||
|
testTable.was_called = false
|
||||||
|
testTable.value = "left"
|
||||||
|
operand.value = "right"
|
||||||
|
local left_operand, right_operand = unpack({testTable, operand})
|
||||||
|
test.equal(op(left_operand, right_operand),
|
||||||
|
exp_value == nil and "left_right" or exp_value)
|
||||||
|
test.is_true(testTable.was_called)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function test_binary_op(...)
|
||||||
|
run_test_with_different_metatables("binary_op", ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_binary_op("concat", function(a, b) return a .. b end)
|
||||||
|
test_binary_op("add", function(a, b) return a + b end)
|
||||||
|
test_binary_op("sub", function(a, b) return a - b end)
|
||||||
|
test_binary_op("mul", function(a, b) return a * b end)
|
||||||
|
test_binary_op("div", function(a, b) return a / b end)
|
||||||
|
test_binary_op("mod", function(a, b) return a % b end)
|
||||||
|
test_binary_op("pow", function(a, b) return a ^ b end)
|
||||||
|
test_binary_op("le", function(a, b) return a <= b end, true)
|
||||||
|
test_binary_op("lt", function(a, b) return a < b end, true)
|
||||||
|
test_binary_op("eq", function(a, b) return a == b end, true)
|
||||||
|
|
||||||
|
|
||||||
|
test.metatable.unary_op = function(metatable, metamethod, op)
|
||||||
|
local share = effil.table()
|
||||||
|
metatable['__' .. metamethod] = function(t)
|
||||||
|
t.was_called = true
|
||||||
|
return t.value .. "_suffix"
|
||||||
|
end
|
||||||
|
effil.setmetatable(share, metatable)
|
||||||
|
|
||||||
|
share.was_called = false
|
||||||
|
share.value = "value"
|
||||||
|
test.equal(op(share), "value_suffix")
|
||||||
|
test.is_true(share.was_called)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function test_unary_op(...)
|
||||||
|
run_test_with_different_metatables("unary_op", ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_unary_op("unm", function(a) return -a end)
|
||||||
|
test_unary_op("tostring", function(a) return tostring(a) end)
|
||||||
|
test_unary_op("len", function(a) return #a end)
|
||||||
|
|
||||||
|
test.shared_table_with_metatable.tear_down = default_tear_down
|
||||||
|
|
||||||
|
test.shared_table_with_metatable.iterators = function (iterator_type)
|
||||||
|
local share = effil.table()
|
||||||
|
local iterator = iterator_type
|
||||||
|
effil.setmetatable(share, {
|
||||||
|
["__" .. iterator] = function(table)
|
||||||
|
return function(t, key)
|
||||||
|
local effil = require 'effil'
|
||||||
|
local ret = (key and key * 2) or 1
|
||||||
|
if ret > 2 ^ 10 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return ret, effil.rawget(t, ret)
|
||||||
|
end, table
|
||||||
|
end
|
||||||
|
})
|
||||||
|
-- Add some values
|
||||||
|
for i = 0, 10 do
|
||||||
|
local pow = 2 ^ i
|
||||||
|
share[pow] = math.random(pow)
|
||||||
|
end
|
||||||
|
-- Add some noise
|
||||||
|
for i = 1, 100 do
|
||||||
|
share[math.random(1000) * 10 - 1] = math.random(1000)
|
||||||
|
end
|
||||||
|
-- Check that *pairs iterator works
|
||||||
|
local pow_iter = 1
|
||||||
|
for k,v in _G[iterator](share) do
|
||||||
|
test.equal(k, pow_iter)
|
||||||
|
test.equal(v, share[pow_iter])
|
||||||
|
pow_iter = pow_iter * 2
|
||||||
|
end
|
||||||
|
test.equal(pow_iter, 2 ^ 11)
|
||||||
|
end
|
||||||
|
|
||||||
|
test.shared_table_with_metatable.iterators("pairs")
|
||||||
|
test.shared_table_with_metatable.iterators("ipairs")
|
||||||
|
|
||||||
|
test.shared_table_with_metatable.as_shared_table = function()
|
||||||
|
local share = effil.table()
|
||||||
|
local mt = effil.table()
|
||||||
|
effil.setmetatable(share, mt)
|
||||||
|
-- Empty metatable
|
||||||
|
test.equal(share.table_key, nil)
|
||||||
|
|
||||||
|
-- Only __index metamethod
|
||||||
|
mt.__index = function(t, key)
|
||||||
|
return "mt_" .. effil.rawget(t, key)
|
||||||
|
end
|
||||||
|
share.table_key = "table_value"
|
||||||
|
test.equal(share.table_key, "mt_table_value")
|
||||||
|
|
||||||
|
-- Both __index and __newindex metamethods
|
||||||
|
mt.__newindex = function(t, key, value)
|
||||||
|
effil.rawset(t, key, "mt_" .. value)
|
||||||
|
end
|
||||||
|
share.table_key = "table_value"
|
||||||
|
test.equal(share.table_key, "mt_mt_table_value")
|
||||||
|
|
||||||
|
-- Remove __index, use only __newindex metamethods
|
||||||
|
mt.__index = nil
|
||||||
|
share.table_key = "table_value"
|
||||||
|
test.equal(share.table_key, "mt_table_value")
|
||||||
|
end
|
||||||
@ -1,55 +0,0 @@
|
|||||||
#!/usr/bin/env lua
|
|
||||||
|
|
||||||
-- TODO: remove hardcode
|
|
||||||
package.path = package.path .. ";../libs/luaunit/?.lua;../tests/lua/?.lua"
|
|
||||||
|
|
||||||
print("---------------")
|
|
||||||
print("-- " .. _VERSION .. " --")
|
|
||||||
print("---------------")
|
|
||||||
|
|
||||||
do
|
|
||||||
-- Hack input arguments to make tests verbose by default
|
|
||||||
local make_verbose = true
|
|
||||||
for i, v in ipairs(arg) do
|
|
||||||
if v == '-o' or v == '--output' then
|
|
||||||
make_verbose = false
|
|
||||||
elseif v == "--extra-checks" then
|
|
||||||
table.remove(arg, i)
|
|
||||||
WITH_EXTRA_CHECKS = true
|
|
||||||
print "# RUN TESTS WITH EXTRA CHECKS"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if make_verbose then
|
|
||||||
table.insert(arg, '-o')
|
|
||||||
table.insert(arg, 'TAP')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------
|
|
||||||
-- TESTS --
|
|
||||||
-----------
|
|
||||||
|
|
||||||
test = require "luaunit"
|
|
||||||
effil = require 'effil'
|
|
||||||
require 'test_utils'
|
|
||||||
require 'thread'
|
|
||||||
require 'shared_table'
|
|
||||||
require 'gc'
|
|
||||||
require 'channel'
|
|
||||||
require 'type'
|
|
||||||
|
|
||||||
-- Hack tests functions to print when test starts
|
|
||||||
for suite_name, suite in pairs(_G) do
|
|
||||||
if string.sub(suite_name, 1, 4):lower() == 'test' and type(_G[suite_name]) == 'table' then -- is a test suite
|
|
||||||
for test_name, test_func in pairs(suite) do
|
|
||||||
if string.sub(test_name, 1, 4):lower() == 'test' then -- is a test function
|
|
||||||
suite[test_name] = function(...)
|
|
||||||
print("# Starting test: " .. suite_name .. '.' .. test_name)
|
|
||||||
return test_func(...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
os.exit( test.LuaUnit.run() )
|
|
||||||
87
tests/lua/shared-table.lua
Normal file
87
tests/lua/shared-table.lua
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
require "bootstrap-tests"
|
||||||
|
|
||||||
|
test.shared_table.tear_down = default_tear_down
|
||||||
|
|
||||||
|
test.shared_table.pairs = function ()
|
||||||
|
local share = effil.table()
|
||||||
|
local data = { 0, 0, 0, ["key1"] = 0, ["key2"] = 0, ["key3"] = 0 }
|
||||||
|
|
||||||
|
for k, _ in pairs(data) do
|
||||||
|
share[k] = k .. "-value"
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in pairs(share) do
|
||||||
|
test.equal(data[k], 0)
|
||||||
|
data[k] = 1
|
||||||
|
test.equal(v, k .. "-value")
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in pairs(data) do
|
||||||
|
test.equal(v, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in ipairs(share) do
|
||||||
|
test.equal(data[k], 1)
|
||||||
|
data[k] = 2
|
||||||
|
test.equal(v, k .. "-value")
|
||||||
|
end
|
||||||
|
|
||||||
|
for k,v in ipairs(data) do
|
||||||
|
test.equal(v, 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test.shared_table.length = function ()
|
||||||
|
local share = effil.table()
|
||||||
|
share[1] = 10
|
||||||
|
share[2] = 20
|
||||||
|
share[3] = 30
|
||||||
|
share[4] = 40
|
||||||
|
share["str"] = 50
|
||||||
|
test.equal(#share, 4)
|
||||||
|
share[3] = nil
|
||||||
|
test.equal(#share, 2)
|
||||||
|
share[1] = nil
|
||||||
|
test.equal(#share, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
test.shared_table.size = function ()
|
||||||
|
local share = effil.table()
|
||||||
|
test.equal(effil.size(share), 0)
|
||||||
|
share[1] = 10
|
||||||
|
test.equal(effil.size(share), 1)
|
||||||
|
share[2] = "value1"
|
||||||
|
share["key1"] = function() end
|
||||||
|
test.equal(effil.size(share), 3)
|
||||||
|
share[2] = nil
|
||||||
|
test.equal(effil.size(share), 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
test.shared_table.user_data_classification = function ()
|
||||||
|
local share = effil.table()
|
||||||
|
share.thread = effil.thread(function(a, b) return a + b end)(19, 33)
|
||||||
|
share.sub_table = effil.table()
|
||||||
|
share.sub_table.some_key = "some_value"
|
||||||
|
|
||||||
|
local result = share.thread:get()
|
||||||
|
test.equal(result, 52)
|
||||||
|
test.equal(share.sub_table.some_key, "some_value")
|
||||||
|
end
|
||||||
|
|
||||||
|
test.shared_table.global = function ()
|
||||||
|
test.not_equal(effil.G, nil)
|
||||||
|
effil.G.test_key = "test_value"
|
||||||
|
local thr = effil.thread(function()
|
||||||
|
local effil = require "effil"
|
||||||
|
if effil.G == nil or effil.G.test_key ~= "test_value" then
|
||||||
|
error("Invalid value of global table: " .. tostring(effil.G and effil.G.test_key or nil))
|
||||||
|
end
|
||||||
|
effil.G.test_key = "checked"
|
||||||
|
end)()
|
||||||
|
local status, err = thr:wait()
|
||||||
|
if status == "failed" then
|
||||||
|
print("Thread failed with message: " .. err)
|
||||||
|
end
|
||||||
|
test.equal(status, "completed")
|
||||||
|
test.equal(effil.G.test_key, "checked")
|
||||||
|
end
|
||||||
@ -1,269 +0,0 @@
|
|||||||
TestSharedTable = {tearDown = tearDown}
|
|
||||||
|
|
||||||
function TestSharedTable:testPairs()
|
|
||||||
local share = effil.table()
|
|
||||||
local data = { 0, 0, 0, ["key1"] = 0, ["key2"] = 0, ["key3"] = 0 }
|
|
||||||
|
|
||||||
for k, _ in pairs(data) do
|
|
||||||
share[k] = k .. "-value"
|
|
||||||
end
|
|
||||||
|
|
||||||
for k,v in pairs(share) do
|
|
||||||
test.assertEquals(data[k], 0)
|
|
||||||
data[k] = 1
|
|
||||||
test.assertEquals(v, k .. "-value")
|
|
||||||
end
|
|
||||||
|
|
||||||
for k,v in pairs(data) do
|
|
||||||
log("Check: " .. k)
|
|
||||||
test.assertEquals(v, 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
for k,v in ipairs(share) do
|
|
||||||
test.assertEquals(data[k], 1)
|
|
||||||
data[k] = 2
|
|
||||||
test.assertEquals(v, k .. "-value")
|
|
||||||
end
|
|
||||||
|
|
||||||
for k,v in ipairs(data) do
|
|
||||||
log("Check: " .. k)
|
|
||||||
test.assertEquals(v, 2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestSharedTable:testLength()
|
|
||||||
local share = effil.table()
|
|
||||||
share[1] = 10
|
|
||||||
share[2] = 20
|
|
||||||
share[3] = 30
|
|
||||||
share[4] = 40
|
|
||||||
share["str"] = 50
|
|
||||||
log "Check values"
|
|
||||||
test.assertEquals(#share, 4)
|
|
||||||
share[3] = nil
|
|
||||||
test.assertEquals(#share, 2)
|
|
||||||
share[1] = nil
|
|
||||||
test.assertEquals(#share, 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestSharedTable:testSize()
|
|
||||||
local share = effil.table()
|
|
||||||
test.assertEquals(effil.size(share), 0)
|
|
||||||
share[1] = 10
|
|
||||||
test.assertEquals(effil.size(share), 1)
|
|
||||||
share[2] = "value1"
|
|
||||||
share["key1"] = function() end
|
|
||||||
test.assertEquals(effil.size(share), 3)
|
|
||||||
share[2] = nil
|
|
||||||
test.assertEquals(effil.size(share), 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestSharedTable:testUserDataClassification()
|
|
||||||
local share = effil.table()
|
|
||||||
share.thread = effil.thread(function(a, b) return a + b end)(19, 33)
|
|
||||||
share.sub_table = effil.table()
|
|
||||||
share.sub_table.some_key = "some_value"
|
|
||||||
|
|
||||||
local result = share.thread:get()
|
|
||||||
test.assertEquals(result, 52)
|
|
||||||
test.assertEquals(share.sub_table.some_key, "some_value")
|
|
||||||
end
|
|
||||||
|
|
||||||
TestGeneralSharedTableMetaTable = { tearDown = tearDown }
|
|
||||||
|
|
||||||
function TestGeneralSharedTableMetaTable:useMetatable(shared_table, metatable)
|
|
||||||
local mt = self.test_param()
|
|
||||||
for k, v in pairs(metatable) do
|
|
||||||
mt[k] = v
|
|
||||||
end
|
|
||||||
effil.setmetatable(shared_table, mt)
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestGeneralSharedTableMetaTable:testMetamethodIndex()
|
|
||||||
local share = effil.table()
|
|
||||||
self:useMetatable(share, {
|
|
||||||
__index = function(t, key)
|
|
||||||
return "mt_" .. effil.rawget(t, key)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)
|
|
||||||
share.table_key = "table_value"
|
|
||||||
test.assertEquals(share.table_key, "mt_table_value")
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestGeneralSharedTableMetaTable:testMetamethodNewIndex()
|
|
||||||
local share = effil.table()
|
|
||||||
self:useMetatable(share, {
|
|
||||||
__newindex = function(t, key, value)
|
|
||||||
effil.rawset(t, "mt_" .. key, "mt_" .. value)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)
|
|
||||||
share.table_key = "table_value"
|
|
||||||
test.assertEquals(share.mt_table_key, "mt_table_value")
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestGeneralSharedTableMetaTable:testMetamethodCall()
|
|
||||||
local share = effil.table()
|
|
||||||
self:useMetatable(share, {
|
|
||||||
__call = function(t, val1, val2, val3)
|
|
||||||
return tostring(val1) .. "_" .. tostring(val2), tostring(val2) .. "_" .. tostring(val3)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)
|
|
||||||
local first_ret, second_ret = share("val1", "val2", "val3")
|
|
||||||
test.assertEquals(first_ret, "val1_val2")
|
|
||||||
test.assertEquals(second_ret, "val2_val3")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function CreateMetatableTestForBinaryOperator(method_info, op)
|
|
||||||
for _, reversed in pairs({true, false}) do
|
|
||||||
TestGeneralSharedTableMetaTable["testMetamethod" .. method_info.metamethod
|
|
||||||
.. (reversed and "Reversed" or "")] =
|
|
||||||
function(self)
|
|
||||||
local testTable, operand = effil.table(), effil.table()
|
|
||||||
self:useMetatable(testTable, {
|
|
||||||
['__' .. string.lower(method_info.metamethod)] =
|
|
||||||
reversed and function(left, right)
|
|
||||||
right.was_called = true
|
|
||||||
return right.value .. '_'.. left.value
|
|
||||||
end
|
|
||||||
or function(left, right)
|
|
||||||
left.was_called = true
|
|
||||||
return left.value .. '_'.. right.value
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)
|
|
||||||
testTable.was_called = false
|
|
||||||
testTable.value = "left"
|
|
||||||
operand.value = "right"
|
|
||||||
local left_operand, right_operand = unpack(reversed and {operand, testTable} or {testTable, operand})
|
|
||||||
test.assertEquals(op(left_operand, right_operand),
|
|
||||||
method_info.exp_value == nil and "left_right" or method_info.exp_value)
|
|
||||||
test.assertTrue(testTable.was_called)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Concat"}, function(a, b) return a.. b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Add"}, function(a, b) return a + b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Sub"}, function(a, b) return a - b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Mul"}, function(a, b) return a * b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Div"}, function(a, b) return a / b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Mod"}, function(a, b) return a % b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Pow"}, function(a, b) return a ^ b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Le", exp_value = true }, function(a, b) return a <= b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Lt", exp_value = true }, function(a, b) return a < b end)
|
|
||||||
CreateMetatableTestForBinaryOperator({ metamethod = "Eq", exp_value = true },
|
|
||||||
function(a, b) return a == b end)
|
|
||||||
|
|
||||||
local function CreateMetatableTestForUnaryOperator(methodName, op)
|
|
||||||
TestGeneralSharedTableMetaTable["testMetamethod" .. methodName] =
|
|
||||||
function(self)
|
|
||||||
local share = effil.table()
|
|
||||||
self:useMetatable(share, {
|
|
||||||
['__' .. string.lower(methodName)] = function(t)
|
|
||||||
t.was_called = true
|
|
||||||
return t.value .. "_suffix"
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)
|
|
||||||
share.was_called = false
|
|
||||||
share.value = "value"
|
|
||||||
test.assertEquals(op(share), "value_suffix")
|
|
||||||
test.assertTrue(share.was_called)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
CreateMetatableTestForUnaryOperator("Unm", function(a) return -a end)
|
|
||||||
CreateMetatableTestForUnaryOperator("ToString", function(a) return tostring(a) end)
|
|
||||||
CreateMetatableTestForUnaryOperator("Len", function(a) return #a end)
|
|
||||||
|
|
||||||
make_test_with_param(TestGeneralSharedTableMetaTable, ".+" --[[ Any test in this test suite]],
|
|
||||||
function() return {} end,
|
|
||||||
function() return effil.table() end
|
|
||||||
)
|
|
||||||
|
|
||||||
TestSharedTableWithMetaTable = { tearDown = tearDown }
|
|
||||||
|
|
||||||
function TestSharedTableWithMetaTable:testMetamethodIterators()
|
|
||||||
local share = effil.table()
|
|
||||||
local iterator = self.test_param
|
|
||||||
effil.setmetatable(share, {
|
|
||||||
["__" .. iterator] = function(table)
|
|
||||||
return function(t, key)
|
|
||||||
local effil = require 'effil'
|
|
||||||
local ret = (key and key * 2) or 1
|
|
||||||
if ret > 2 ^ 10 then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
return ret, effil.rawget(t, ret)
|
|
||||||
end, table
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)
|
|
||||||
-- Add some values
|
|
||||||
for i = 0, 10 do
|
|
||||||
local pow = 2 ^ i
|
|
||||||
share[pow] = math.random(pow)
|
|
||||||
end
|
|
||||||
-- Add some noise
|
|
||||||
for i = 1, 100 do
|
|
||||||
share[math.random(1000) * 10 - 1] = math.random(1000)
|
|
||||||
end
|
|
||||||
-- Check that *pairs iterator works
|
|
||||||
local pow_iter = 1
|
|
||||||
for k,v in _G[iterator](share) do
|
|
||||||
test.assertEquals(k, pow_iter)
|
|
||||||
test.assertEquals(v, share[pow_iter])
|
|
||||||
pow_iter = pow_iter * 2
|
|
||||||
end
|
|
||||||
test.assertEquals(pow_iter, 2 ^ 11)
|
|
||||||
end
|
|
||||||
|
|
||||||
make_test_with_param(TestSharedTableWithMetaTable, "testMetamethodIterators", "pairs", "ipairs")
|
|
||||||
|
|
||||||
function TestSharedTableWithMetaTable:testMetatableAsSharedTable()
|
|
||||||
local share = effil.table()
|
|
||||||
local mt = effil.table()
|
|
||||||
effil.setmetatable(share, mt)
|
|
||||||
-- Empty metatable
|
|
||||||
test.assertEquals(share.table_key, nil)
|
|
||||||
|
|
||||||
-- Only __index metamethod
|
|
||||||
mt.__index = function(t, key)
|
|
||||||
return "mt_" .. effil.rawget(t, key)
|
|
||||||
end
|
|
||||||
share.table_key = "table_value"
|
|
||||||
test.assertEquals(share.table_key, "mt_table_value")
|
|
||||||
|
|
||||||
-- Both __index and __newindex metamethods
|
|
||||||
mt.__newindex = function(t, key, value)
|
|
||||||
effil.rawset(t, key, "mt_" .. value)
|
|
||||||
end
|
|
||||||
share.table_key = "table_value"
|
|
||||||
test.assertEquals(share.table_key, "mt_mt_table_value")
|
|
||||||
|
|
||||||
-- Remove __index, use only __newindex metamethods
|
|
||||||
mt.__index = nil
|
|
||||||
share.table_key = "table_value"
|
|
||||||
test.assertEquals(share.table_key, "mt_table_value")
|
|
||||||
end
|
|
||||||
|
|
||||||
function TestSharedTable:testGlobalTable()
|
|
||||||
test.assertNotEquals(effil.G, nil)
|
|
||||||
effil.G.test_key = "test_value"
|
|
||||||
local thr = effil.thread(function()
|
|
||||||
local effil = require "effil"
|
|
||||||
if effil.G == nil or effil.G.test_key ~= "test_value" then
|
|
||||||
error("Invalid value of global table: " .. tostring(effil.G and effil.G.test_key or nil))
|
|
||||||
end
|
|
||||||
effil.G.test_key = "checked"
|
|
||||||
end)()
|
|
||||||
local status, err = thr:wait()
|
|
||||||
if status == "failed" then
|
|
||||||
print("Thread failed with message: " .. err)
|
|
||||||
end
|
|
||||||
test.assertEquals(status, "completed")
|
|
||||||
test.assertEquals(effil.G.test_key, "checked")
|
|
||||||
end
|
|
||||||
@ -1,75 +0,0 @@
|
|||||||
function log(...)
|
|
||||||
local msg = '@\t\t' .. os.date('%Y-%m-%d %H:%M:%S ',os.time())
|
|
||||||
for _, val in ipairs({...}) do
|
|
||||||
msg = msg .. tostring(val) .. ' '
|
|
||||||
end
|
|
||||||
io.write(msg .. '\n')
|
|
||||||
io.flush()
|
|
||||||
end
|
|
||||||
|
|
||||||
function wait(timeInSec, condition, silent)
|
|
||||||
if not silent then
|
|
||||||
log("Start waiting for " .. tostring(timeInSec) .. "sec...")
|
|
||||||
end
|
|
||||||
local result = false
|
|
||||||
local startTime = os.time()
|
|
||||||
while ( (os.time() - startTime) <= timeInSec) do
|
|
||||||
if condition ~= nil then
|
|
||||||
if type(condition) == 'function' then
|
|
||||||
if condition() then
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if condition then
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not silent then
|
|
||||||
log "Give up"
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
function sleep(timeInSec, silent)
|
|
||||||
if not silent then
|
|
||||||
log("Start sleep for " .. tostring(timeInSec) .. "sec...")
|
|
||||||
end
|
|
||||||
wait(timeInSec, nil, true)
|
|
||||||
if not silent then
|
|
||||||
log "Wake up"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function tearDown()
|
|
||||||
collectgarbage()
|
|
||||||
effil.gc.collect()
|
|
||||||
-- effil.G is always present
|
|
||||||
-- thus, gc has one object
|
|
||||||
test.assertEquals(effil.gc.count(), 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function make_test_with_param(test_suite, test_case_pattern, ...)
|
|
||||||
local tests_to_delete, tests_to_add = {}, {}
|
|
||||||
for test_name, test_func in pairs(test_suite) do
|
|
||||||
if string.sub(test_name, 1, 4):lower() == 'test' and string.match(test_name, test_case_pattern) then
|
|
||||||
table.insert(tests_to_delete, test_name)
|
|
||||||
for i, param in ipairs({...}) do
|
|
||||||
tests_to_add[test_name .. "/" .. i] = function(t)
|
|
||||||
print("# with params: " .. tostring(param))
|
|
||||||
t.test_param = param
|
|
||||||
return test_func(t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for _, test_name in ipairs(tests_to_delete) do
|
|
||||||
test_suite[test_name] = nil
|
|
||||||
end
|
|
||||||
for test_name, test_func in pairs(tests_to_add) do
|
|
||||||
test_suite[test_name] = test_func
|
|
||||||
end
|
|
||||||
end
|
|
||||||
17
tests/lua/tests.lua
Executable file
17
tests/lua/tests.lua
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env lua
|
||||||
|
|
||||||
|
package.path = ";../tests/lua/?.lua;../libs/u-test/?.lua;../src/lua/?.lua"
|
||||||
|
|
||||||
|
require "type"
|
||||||
|
require "gc"
|
||||||
|
require "channel"
|
||||||
|
require "thread"
|
||||||
|
require "shared-table"
|
||||||
|
require "metatable"
|
||||||
|
|
||||||
|
if os.getenv("STRESS") then
|
||||||
|
require "channel-stress"
|
||||||
|
require "thread-stress"
|
||||||
|
end
|
||||||
|
|
||||||
|
test.summary()
|
||||||
15
tests/lua/thread-stress.lua
Normal file
15
tests/lua/thread-stress.lua
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
require "bootstrap-tests"
|
||||||
|
|
||||||
|
test.thread_stress.tear_down = default_tear_down
|
||||||
|
|
||||||
|
test.thread_stress.time = function ()
|
||||||
|
local function check_time(real_time, use_time, metric)
|
||||||
|
local start_time = os.time()
|
||||||
|
effil.sleep(use_time, metric)
|
||||||
|
test.almost_equal(os.time(), start_time + real_time, 1)
|
||||||
|
end
|
||||||
|
check_time(4, 4, nil) -- seconds by default
|
||||||
|
check_time(4, 4, 's')
|
||||||
|
check_time(4, 4000, 'ms')
|
||||||
|
check_time(60, 1, 'm')
|
||||||
|
end
|
||||||
@ -1,51 +1,51 @@
|
|||||||
local effil = require 'effil'
|
require "bootstrap-tests"
|
||||||
|
|
||||||
TestThread = {tearDown = tearDown }
|
test.thread.tear_down = default_tear_down
|
||||||
|
|
||||||
function TestThread:testWait()
|
test.thread.wait = function ()
|
||||||
local thread = effil.thread(function() print 'Effil is not that tower' end)()
|
local thread = effil.thread(function() print 'Effil is not that tower' end)()
|
||||||
local status = thread:wait()
|
local status = thread:wait()
|
||||||
test.assertNil(thread:get())
|
test.is_nil(thread:get())
|
||||||
test.assertEquals(status, "completed")
|
test.equal(status, "completed")
|
||||||
test.assertEquals(thread:status(), "completed")
|
test.equal(thread:status(), "completed")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testMultipleWaitGet()
|
test.thread.multiple_wait_get = function ()
|
||||||
local thread = effil.thread(function() return "test value" end)()
|
local thread = effil.thread(function() return "test value" end)()
|
||||||
local status1 = thread:wait()
|
local status1 = thread:wait()
|
||||||
local status2 = thread:wait()
|
local status2 = thread:wait()
|
||||||
test.assertEquals(status1, "completed")
|
test.equal(status1, "completed")
|
||||||
test.assertEquals(status2, status1)
|
test.equal(status2, status1)
|
||||||
|
|
||||||
local value = thread:get()
|
local value = thread:get()
|
||||||
test.assertEquals(value, "test value")
|
test.equal(value, "test value")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testTimedGet()
|
test.thread.timed_get = function ()
|
||||||
local thread = effil.thread(function()
|
local thread = effil.thread(function()
|
||||||
require('effil').sleep(2)
|
require('effil').sleep(2)
|
||||||
return "-_-"
|
return "-_-"
|
||||||
end)()
|
end)()
|
||||||
test.assertNil(thread:get(1))
|
test.is_nil(thread:get(1))
|
||||||
test.assertEquals(thread:get(2), "-_-")
|
test.equal(thread:get(2), "-_-")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testTimedWait()
|
test.thread.timed_get = function ()
|
||||||
local thread = effil.thread(function()
|
local thread = effil.thread(function()
|
||||||
require('effil').sleep(2)
|
require('effil').sleep(2)
|
||||||
return 8
|
return 8
|
||||||
end)()
|
end)()
|
||||||
|
|
||||||
local status = thread:wait(1)
|
local status = thread:wait(1)
|
||||||
test.assertEquals(status, "running")
|
test.equal(status, "running")
|
||||||
|
|
||||||
local value = thread:get(2, "s")
|
local value = thread:get(2, "s")
|
||||||
test.assertEquals(value, 8);
|
test.equal(value, 8);
|
||||||
|
|
||||||
test.assertEquals(thread:status(), "completed")
|
test.equal(thread:status(), "completed")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testAsyncWait()
|
test.thread.async_wait = function()
|
||||||
local thread = effil.thread( function()
|
local thread = effil.thread( function()
|
||||||
require('effil').sleep(1)
|
require('effil').sleep(1)
|
||||||
end)()
|
end)()
|
||||||
@ -55,11 +55,11 @@ function TestThread:testAsyncWait()
|
|||||||
iter = iter + 1
|
iter = iter + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
test.assertTrue(iter > 10)
|
test.is_true(iter > 10)
|
||||||
test.assertEquals(thread:status(), "completed")
|
test.equal(thread:status(), "completed")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testDetached()
|
test.thread.detached = function ()
|
||||||
local st = effil.table()
|
local st = effil.table()
|
||||||
|
|
||||||
for i = 1, 32 do
|
for i = 1, 32 do
|
||||||
@ -73,20 +73,20 @@ function TestThread:testDetached()
|
|||||||
effil.sleep(1)
|
effil.sleep(1)
|
||||||
|
|
||||||
for i = 1, 32 do
|
for i = 1, 32 do
|
||||||
test.assertEquals(st[i], i)
|
test.equal(st[i], i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testCancel()
|
test.thread.cancel = function ()
|
||||||
local thread = effil.thread(function()
|
local thread = effil.thread(function()
|
||||||
while true do end
|
while true do end
|
||||||
end)()
|
end)()
|
||||||
|
|
||||||
test.assertTrue(thread:cancel())
|
test.is_true(thread:cancel())
|
||||||
test.assertEquals(thread:status(), "canceled")
|
test.equal(thread:status(), "canceled")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testAsyncCancel()
|
test.thread.async_cancel = function ()
|
||||||
local thread_runner = effil.thread(
|
local thread_runner = effil.thread(
|
||||||
function()
|
function()
|
||||||
local startTime = os.time()
|
local startTime = os.time()
|
||||||
@ -98,11 +98,11 @@ function TestThread:testAsyncCancel()
|
|||||||
sleep(2) -- let thread starts working
|
sleep(2) -- let thread starts working
|
||||||
thread:cancel(0)
|
thread:cancel(0)
|
||||||
|
|
||||||
test.assertTrue(wait(2, function() return thread:status() ~= 'running' end))
|
test.is_true(wait(2, function() return thread:status() ~= 'running' end))
|
||||||
test.assertEquals(thread:status(), 'canceled')
|
test.equal(thread:status(), 'canceled')
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testPauseResumeCancel()
|
test.thread.pause_resume_cancel = function ()
|
||||||
local data = effil.table()
|
local data = effil.table()
|
||||||
data.value = 0
|
data.value = 0
|
||||||
local thread = effil.thread(
|
local thread = effil.thread(
|
||||||
@ -112,20 +112,20 @@ function TestThread:testPauseResumeCancel()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
)(data)
|
)(data)
|
||||||
test.assertTrue(wait(2, function() return data.value > 100 end))
|
test.is_true(wait(2, function() return data.value > 100 end))
|
||||||
test.assertTrue(thread:pause())
|
test.is_true(thread:pause())
|
||||||
test.assertEquals(thread:status(), "paused")
|
test.equal(thread:status(), "paused")
|
||||||
|
|
||||||
local savedValue = data.value
|
local savedValue = data.value
|
||||||
sleep(1)
|
sleep(1)
|
||||||
test.assertEquals(data.value, savedValue)
|
test.equal(data.value, savedValue)
|
||||||
|
|
||||||
thread:resume()
|
thread:resume()
|
||||||
test.assertTrue(wait(5, function() return (data.value - savedValue) > 100 end))
|
test.is_true(wait(5, function() return (data.value - savedValue) > 100 end))
|
||||||
test.assertTrue(thread:cancel())
|
test.is_true(thread:cancel())
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testPauseCancel()
|
test.thread.pause_cancel = function ()
|
||||||
local data = effil.table()
|
local data = effil.table()
|
||||||
data.value = 0
|
data.value = 0
|
||||||
local thread = effil.thread(
|
local thread = effil.thread(
|
||||||
@ -136,17 +136,17 @@ function TestThread:testPauseCancel()
|
|||||||
end
|
end
|
||||||
)(data)
|
)(data)
|
||||||
|
|
||||||
test.assertTrue(wait(2, function() return data.value > 100 end))
|
test.is_true(wait(2, function() return data.value > 100 end))
|
||||||
thread:pause(0)
|
thread:pause(0)
|
||||||
test.assertTrue(wait(2, function() return thread:status() == "paused" end))
|
test.is_true(wait(2, function() return thread:status() == "paused" end))
|
||||||
local savedValue = data.value
|
local savedValue = data.value
|
||||||
sleep(1)
|
sleep(1)
|
||||||
test.assertEquals(data.value, savedValue)
|
test.equal(data.value, savedValue)
|
||||||
|
|
||||||
test.assertTrue(thread:cancel(0))
|
test.is_true(thread:cancel(0))
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testAsyncPauseResumeCancel()
|
test.thread.async_pause_resume_cancel = function ()
|
||||||
local data = effil.table()
|
local data = effil.table()
|
||||||
data.value = 0
|
data.value = 0
|
||||||
local thread = effil.thread(
|
local thread = effil.thread(
|
||||||
@ -157,21 +157,22 @@ function TestThread:testAsyncPauseResumeCancel()
|
|||||||
end
|
end
|
||||||
)(data)
|
)(data)
|
||||||
|
|
||||||
test.assertTrue(wait(2, function() return data.value > 100 end))
|
test.is_true(wait(2, function() return data.value > 100 end))
|
||||||
thread:pause()
|
thread:pause()
|
||||||
|
|
||||||
local savedValue = data.value
|
local savedValue = data.value
|
||||||
sleep(1)
|
sleep(1)
|
||||||
test.assertEquals(data.value, savedValue)
|
test.equal(data.value, savedValue)
|
||||||
|
|
||||||
thread:resume()
|
thread:resume()
|
||||||
test.assertTrue(wait(5, function() return (data.value - savedValue) > 100 end))
|
test.is_true(wait(5, function() return (data.value - savedValue) > 100 end))
|
||||||
|
|
||||||
thread:cancel(0)
|
thread:cancel(0)
|
||||||
test.assertTrue(wait(5, function() return thread:status() == "canceled" end))
|
test.is_true(wait(5, function() return thread:status() == "canceled" end))
|
||||||
|
thread:wait()
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testCheckThreadReturns()
|
test.thread.returns = function ()
|
||||||
local share = effil.table()
|
local share = effil.table()
|
||||||
share.value = "some value"
|
share.value = "some value"
|
||||||
|
|
||||||
@ -184,36 +185,35 @@ function TestThread:testCheckThreadReturns()
|
|||||||
local status = thread:wait()
|
local status = thread:wait()
|
||||||
local returns = { thread:get() }
|
local returns = { thread:get() }
|
||||||
|
|
||||||
log "Check values"
|
test.equal(status, "completed")
|
||||||
test.assertEquals(status, "completed")
|
|
||||||
|
|
||||||
test.assertNumber(returns[1])
|
test.is_number(returns[1])
|
||||||
test.assertEquals(returns[1], 100500)
|
test.equal(returns[1], 100500)
|
||||||
|
|
||||||
test.assertString(returns[2])
|
test.is_string(returns[2])
|
||||||
test.assertEquals(returns[2], "string value")
|
test.equal(returns[2], "string value")
|
||||||
|
|
||||||
test.assertBoolean(returns[3])
|
test.is_boolean(returns[3])
|
||||||
test.assertTrue(returns[3])
|
test.is_true(returns[3])
|
||||||
|
|
||||||
test.assertUserdata(returns[4])
|
test.is_userdata(returns[4])
|
||||||
test.assertEquals(returns[4].value, share.value)
|
test.equal(returns[4].value, share.value)
|
||||||
|
|
||||||
test.assertFunction(returns[5])
|
test.is_function(returns[5])
|
||||||
test.assertEquals(returns[5](11, 89), 100)
|
test.equal(returns[5](11, 89), 100)
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThread:testTimedCancel()
|
test.thread.timed_cancel = function ()
|
||||||
local thread = effil.thread(function()
|
local thread = effil.thread(function()
|
||||||
require("effil").sleep(2)
|
require("effil").sleep(2)
|
||||||
end)()
|
end)()
|
||||||
test.assertFalse(thread:cancel(1))
|
test.is_false(thread:cancel(1))
|
||||||
thread:wait()
|
thread:wait()
|
||||||
end
|
end
|
||||||
|
|
||||||
TestThreadWithTable = {tearDown = tearDown }
|
test.thread_with_table.tear_down = default_tear_down
|
||||||
|
|
||||||
function TestThreadWithTable:testSharedTableTypes()
|
test.thread_with_table.types = function ()
|
||||||
local share = effil.table()
|
local share = effil.table()
|
||||||
|
|
||||||
share["number"] = 100500
|
share["number"] = 100500
|
||||||
@ -232,14 +232,13 @@ function TestThreadWithTable:testSharedTableTypes()
|
|||||||
local thread = thread_factory(share)
|
local thread = thread_factory(share)
|
||||||
thread:wait()
|
thread:wait()
|
||||||
|
|
||||||
log "Check values"
|
test.equal(share["child.number"], share["number"])
|
||||||
test.assertEquals(share["child.number"], share["number"])
|
test.equal(share["child.string"], share["string"])
|
||||||
test.assertEquals(share["child.string"], share["string"])
|
test.equal(share["child.bool"], share["bool"])
|
||||||
test.assertEquals(share["child.bool"], share["bool"])
|
test.equal(share["child.function"], share["function"](11,45))
|
||||||
test.assertEquals(share["child.function"], share["function"](11,45))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestThreadWithTable:testRecursiveTables()
|
test.thread_with_table.recursive = function ()
|
||||||
local share = effil.table()
|
local share = effil.table()
|
||||||
|
|
||||||
local magic_number = 42
|
local magic_number = 42
|
||||||
@ -258,16 +257,15 @@ function TestThreadWithTable:testRecursiveTables()
|
|||||||
local thread = thread_factory(share)
|
local thread = thread_factory(share)
|
||||||
thread:wait()
|
thread:wait()
|
||||||
|
|
||||||
log "Check values"
|
test.equal(share["subtable1"]["subtable1"]["magic_number"], magic_number)
|
||||||
test.assertEquals(share["subtable1"]["subtable1"]["magic_number"], magic_number)
|
test.equal(share["subtable1"]["subtable2"]["magic_number"], magic_number)
|
||||||
test.assertEquals(share["subtable1"]["subtable2"]["magic_number"], magic_number)
|
test.equal(share["subtable2"]["magic_number"], magic_number)
|
||||||
test.assertEquals(share["subtable2"]["magic_number"], magic_number)
|
test.equal(share["magic_number"], nil)
|
||||||
test.assertEquals(share["magic_number"], nil)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
TestThisThread = {tearDown = tearDown }
|
test.this_thread.tear_down = default_tear_down
|
||||||
|
|
||||||
function TestThisThread:testThisThreadFunctions()
|
test.this_thread.functions = function ()
|
||||||
local share = effil.table()
|
local share = effil.table()
|
||||||
|
|
||||||
local thread_factory = effil.thread(
|
local thread_factory = effil.thread(
|
||||||
@ -278,24 +276,8 @@ function TestThisThread:testThisThreadFunctions()
|
|||||||
local thread = thread_factory(share)
|
local thread = thread_factory(share)
|
||||||
thread:get()
|
thread:get()
|
||||||
|
|
||||||
test.assertString(share["child.id"])
|
test.is_string(share["child.id"])
|
||||||
test.assertNumber(tonumber(share["child.id"]))
|
test.is_number(tonumber(share["child.id"]))
|
||||||
test.assertNotEquals(share["child.id"], effil.thread_id())
|
test.not_equal(share["child.id"], effil.thread_id())
|
||||||
effil.yield() -- just call it
|
effil.yield() -- just call it
|
||||||
end
|
end
|
||||||
|
|
||||||
if WITH_EXTRA_CHECKS then
|
|
||||||
|
|
||||||
function TestThisThread:testTime()
|
|
||||||
local function check_time(real_time, use_time, metric)
|
|
||||||
local start_time = os.time()
|
|
||||||
effil.sleep(use_time, metric)
|
|
||||||
test.assertAlmostEquals(os.time(), start_time + real_time, 1)
|
|
||||||
end
|
|
||||||
check_time(4, 4, nil) -- seconds by default
|
|
||||||
check_time(4, 4, 's')
|
|
||||||
check_time(4, 4000, 'ms')
|
|
||||||
check_time(60, 1, 'm')
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- WITH_EXTRA_CHECKS
|
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
local effil = require 'effil'
|
require "bootstrap-tests"
|
||||||
|
|
||||||
TestType = { tearDown = tearDown }
|
test.type = function()
|
||||||
|
test.equal(effil.type(1), "number")
|
||||||
function TestType:testType()
|
test.equal(effil.type("string"), "string")
|
||||||
test.assertEquals(effil.type(1), "number")
|
test.equal(effil.type(effil.table()), "effil.table")
|
||||||
test.assertEquals(effil.type("string"), "string")
|
test.equal(effil.type(effil.channel()), "effil.channel")
|
||||||
test.assertEquals(effil.type(effil.table()), "effil.table")
|
test.equal(effil.type(effil.thread(function() end)()), "effil.thread")
|
||||||
test.assertEquals(effil.type(effil.channel()), "effil.channel")
|
|
||||||
test.assertEquals(effil.type(effil.thread(function() end)()), "effil.thread")
|
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user