Merge pull request #3 from loud-hound/cooper_features

Add luaunit framework, extend lua tests, fix shared-table bug (values…
This commit is contained in:
Ilia 2017-01-21 01:32:25 +03:00 committed by GitHub
commit ca7978e852
12 changed files with 159 additions and 79 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "tests/gtest"]
path = tests/gtest
url = https://github.com/google/googletest.git
[submodule "lua-tests/luaunit"]
path = lua-tests/luaunit
url = https://github.com/bluebird75/luaunit

View File

@ -43,6 +43,4 @@ set_target_properties(tests PROPERTIES COMPILE_FLAGS "${ENABLE_WARNINGS} ${GENER
# INSTALL -
#----------
FILE(GLOB TESTS tests/*.lua)
FILE(GLOB LUA_SOURCES lua-api/*.lua)
install(FILES ${TESTS} ${LUA_SOURCES} DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
install(FILES ${LUA_SOURCES} DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})

View File

@ -1,6 +0,0 @@
--local thr = require('libbevy')
package.cpath = package.cpath .. ";./?.dylib" -- MAC OS support
local api = require('libwoofer')
api.thread.thread_id = nil
api.thread.join = nil
return api

1
lua-tests/luaunit Submodule

@ -0,0 +1 @@
Subproject commit d2f1ffa86582d51b77dc29b1f7216e75fe2bc6d0

59
lua-tests/run_tests.lua Executable file
View File

@ -0,0 +1,59 @@
#!/usr/bin/lua
package.cpath = package.cpath .. ";../build/?.so;;../build/?.dylib"
test = require "luaunit.luaunit"
do
-- Hack input arguments to make tests verbose by default
local found = false
for _, v in ipairs(arg) do
if v == '-o' or v == '--output' then
found = true
break
end
end
if not found then
table.insert(arg, '-o')
table.insert(arg, 'TAP')
end
end
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)
local startTime = os.time()
while ( (os.time() - startTime) <= timeInSec) do
if condition ~= nil then
if type(condition) == 'function' then
if condition() then
return true
end
else
if condition then
return true
end
end
end
end
return false
end
function sleep(timeInSec)
wait(timeInMsec, nil)
end
-----------
-- TESTS --
-----------
require("smoke_test")
-----------
os.exit( test.LuaUnit.run() )

52
lua-tests/smoke_test.lua Normal file
View File

@ -0,0 +1,52 @@
TestSmoke = {}
function TestSmoke:testGeneralWorkability()
local woofer = require('libwoofer')
local share = woofer.share()
share["number"] = 100500
share["string"] = "string value"
share["bool"] = true
log "Start thread"
local thread = woofer.thread(
function(share)
share["child.number"] = share["number"]
share["child.string"] = share["string"]
share["child.bool"] = share["bool"]
end,
share
)
log "Join thread"
thread:join()
log "Check values"
test.assertEquals(share["child.number"], share["number"],
"'number' fields are not equal")
test.assertEquals(share["child.string"], share["string"],
"'string' fields are not equal")
test.assertEquals(share["child.bool"], share["bool"],
"'bool' fields are not equal")
end
function TestSmoke:testDetach()
local woofer = require('libwoofer')
local share = woofer.share()
share["finished"] = false
log "Start thread"
local thread = woofer.thread(
function(share)
local startTime = os.time()
while ( (os.time() - startTime) <= 3) do --[[ Like we are working 3sec ... ]] end
share["finished"] = true
end,
share
)
log "Detach thread"
thread:detach()
log "Waiting for thread completion..."
test.assertEquals(wait(4, function() return share["finished"] end) , true)
log "Stop waiting"
end

View File

@ -1,16 +1,26 @@
#include "lua.hpp"
#include "threading.h"
#include "shared-table.h"
#include <lua.hpp>
static sol::object create_thread(sol::this_state lua, sol::function func, const sol::variadic_args& args)
{
return sol::make_object(lua, std::make_unique<threading::LuaThread>(func, args));
}
static sol::object create_share(sol::this_state lua)
{
return sol::make_object(lua, std::make_unique<share_data::SharedTable>());
}
extern "C" int luaopen_libwoofer(lua_State *L)
{
sol::state_view lua(L);
auto thread_obj = threading::LuaThread::get_user_type(lua);
auto share_obj = share_data::SharedTable::get_user_type(lua);
threading::LuaThread::get_user_type(lua);
share_data::SharedTable::get_user_type(lua);
sol::table public_api = lua.create_table_with(
"thread", thread_obj,
"share", share_obj
"thread", create_thread,
"share", create_share
);
sol::stack::push(lua, public_api);
return 1;

View File

@ -27,7 +27,7 @@ void SharedTable::luaSet(sol::stack_object luaKey, sol::stack_object luaValue) n
} else {
StoredObject value(luaValue);
std::lock_guard<SpinMutex> g(lock_);
data_.emplace(std::make_pair(std::move(key), std::move(value)));
data_[std::move(key)] = std::move(value);
}
}

View File

@ -27,11 +27,11 @@ LuaThread::LuaThread(const sol::function& function, const sol::variadic_args& ar
void LuaThread::store_args(const sol::variadic_args& args) noexcept
{
const auto end = --args.end();
for(auto iter = args.begin(); iter != end; iter++)
p_arguments_ = std::make_shared<std::vector<sol::object>>();
for(auto iter = args.begin(); iter != args.end(); iter++)
{
share_data::StoredObject store(iter->get<sol::object>());
arguments_.push_back(store.unpack(sol::this_state{p_state_->lua_state()}));
p_arguments_->push_back(store.unpack(sol::this_state{p_state_->lua_state()}));
}
}
@ -42,16 +42,31 @@ void LuaThread::join() noexcept
p_thread_->join();
p_thread_.reset();
}
arguments_.clear();
if (p_arguments_.get())
p_arguments_.reset();
if (p_state_.get())
p_state_.reset();
}
void LuaThread::detach() noexcept
{
p_thread_->detach();
}
void LuaThread::work() noexcept
{
sol::state& lua = *p_state_;
sol::function_result func = lua["loadstring"](str_function_);
func.get<sol::function>()(sol::as_args(arguments_));
if (p_state_.get() && p_arguments_.get())
{
std::string func_owner = std::move(str_function_);
std::shared_ptr<sol::state> state_owner = p_state_;
std::shared_ptr<std::vector<sol::object>> arguments_owner = p_arguments_;
sol::function_result func = (*state_owner)["loadstring"](func_owner);
func.get<sol::function>()(sol::as_args(*arguments_owner));
}
else
{
throw sol::error("Internal error: invalid thread Lua state");
}
}
std::string LuaThread::thread_id() noexcept
@ -66,6 +81,7 @@ sol::object LuaThread::get_user_type(sol::state_view& lua) noexcept
static sol::usertype<LuaThread> type(
sol::call_construction(), sol::constructors<sol::types<sol::function, sol::variadic_args>>(),
"join", &LuaThread::join,
"detach", &LuaThread::detach,
"thread_id", &LuaThread::thread_id
);
sol::stack::push(lua, type);

View File

@ -16,6 +16,7 @@ public:
LuaThread(const sol::function& function, const sol::variadic_args& args) noexcept;
virtual ~LuaThread() noexcept = default;
void join() noexcept;
void detach() noexcept;
static std::string thread_id() noexcept;
static sol::object get_user_type(sol::state_view& lua) noexcept;
@ -27,7 +28,7 @@ private:
std::string str_function_;
std::shared_ptr<sol::state> p_state_;
std::shared_ptr<std::thread> p_thread_;
std::vector<sol::object> arguments_;
std::shared_ptr<std::vector<sol::object>> p_arguments_;
};
}

1
tests/lua/lunatest Submodule

@ -0,0 +1 @@
Subproject commit 32e3ecfdb64d37c7f5e72b33bd32fdc3992b967d

View File

@ -1,55 +0,0 @@
function compare(o1, o2)
if o1 == o2 then return true end
local o1Type = type(o1)
local o2Type = type(o2)
if o1Type ~= o2Type then return false end
if o1Type ~= 'table' then return false end
local keySet = {}
for key1, value1 in pairs(o1) do
local value2 = o2[key1]
if value2 == nil or equals(value1, value2) == false then
return false
end
keySet[key1] = true
end
for key2, _ in pairs(o2) do
if not keySet[key2] then return false end
end
return true
end
function check(left, right)
if not compare(left, right) then
print("ERROR")
end
end
-----------
-- TESTS --
-----------
do -- Simple smoke
package.cpath = package.cpath .. ";./?.dylib" -- MAC OS support
local woofer = require('libwoofer')
local share = woofer.share()
share["number"] = 100500
share["string"] = "string value"
share["bool"] = true
local thread = woofer.thread(
function(share)
share["child.number"] = share["number"]
share["child.string"] = share["string"]
share["child.bool"] = share["bool"]
end,
share
)
thread:join()
check(share["child.number"], share["number"])
check(share["child.string"], share["string"])
check(share["child.bool"], share["bool"])
end