Improved tests, added a build.ninja for TeamCity, and fixed formatting again to work with Rapptz's style.

This commit is contained in:
ThePhD 2013-12-11 11:18:13 -05:00
parent dd63621453
commit 350f430d74
8 changed files with 250 additions and 125 deletions

3
.gitignore vendored
View File

@ -1,6 +1,5 @@
obj/* obj/*
bin/* bin/*
*.ninja*
demacro.txt demacro.txt
Shinobi2 Shinobi2
dev.* dev.*
@ -16,3 +15,5 @@ x64/
*.sln *.sln
*.gitattributes *.gitattributes
liblua.a liblua.a
sol/include/
.ninja*

27
build.ninja Normal file
View File

@ -0,0 +1,27 @@
# This file has been generated by shinobi version 0.9.5
ninja_required_version = 1.3
builddir = bin
objdir = obj
cxx = g++
cxxflags = -std=c++11 -pedantic -pedantic-errors -Wextra -Wall -O2 -DNDEBUG
incflags = -I"." -I"./include" -I"." -I"./lua-5.2.2/src/" -I"./Catch/include/"
linkflags = -static liblua.a -L"./lib"
rule compile
command = $cxx -MMD -MF $out.d $cxxflags -c $in -o $out $incflags
deps = gcc
depfile = $out.d
description = Compiling $in
rule link
command = $cxx $in -o $out $linkflags
description = Creating $out
build $objdir/sol.scratch.o: compile sol.scratch.cpp
build $builddir/sol.scratch: link $objdir/sol.scratch.o
build install: phony $builddir/sol.scratch
default install

View File

@ -16,95 +16,184 @@ struct object {
}; };
int plop_xyz(int x, int y, std::string z) {
std::cout << x << " " << y << " " << z << std::endl;
return 11;
}
void run_script(sol::state& lua) { void run_script(sol::state& lua) {
lua.script("assert(os.fun() == \"test\")\n" lua.script("assert(os.fun() == \"test\")\n"
"assert(os.name == \"windows\")"); "assert(os.name == \"windows\")");
} }
TEST_CASE( "simple/set_global", "Check if the set_global works properly." ) { TEST_CASE("simple/set_global", "Check if the set_global works properly.") {
sol::state lua; sol::state lua;
lua.set( "a", 9 ); lua.set("a", 9);
REQUIRE_NOTHROW( lua.script( "if a ~= 9 then error('wrong value') end" ) ); REQUIRE_NOTHROW(lua.script("if a ~= 9 then error('wrong value') end"));
lua.set( "d", "hello" ); lua.set("d", "hello");
REQUIRE_NOTHROW( lua.script( "if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end" ) ); REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
lua.set( "e", std::string( "hello" ) ); lua.set("e", std::string("hello"));
REQUIRE_NOTHROW( lua.script( "if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end" ) ); REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
lua.set( "f", true ); lua.set("f", true);
REQUIRE_NOTHROW( lua.script( "if f ~= true then error('wrong value') end" ) ); REQUIRE_NOTHROW(lua.script("if f ~= true then error('wrong value') end"));
} }
TEST_CASE( "simple/get", "Tests if the get function works properly." ) { TEST_CASE("simple/get", "Tests if the get function works properly.") {
sol::state lua; sol::state lua;
lua.script( "a = 9" ); lua.script("a = 9");
auto a = lua.get<int>( "a" ); auto a = lua.get<int>("a");
REQUIRE( a == 9.0 ); REQUIRE(a == 9.0);
lua.script( "b = nil" ); lua.script("b = nil");
REQUIRE_NOTHROW( auto b = lua.get<sol::nil_t>( "b" ) ); REQUIRE_NOTHROW(auto b = lua.get<sol::nil_t>("b"));
lua.script( "d = 'hello'" ); lua.script("d = 'hello'");
auto d = lua.get<std::string>( "d" ); auto d = lua.get<std::string>("d");
REQUIRE( d == "hello" ); REQUIRE(d == "hello");
lua.script( "e = true" ); lua.script("e = true");
auto e = lua.get<bool>( "e" ); auto e = lua.get<bool>("e");
REQUIRE( e == true ); REQUIRE(e == true);
} }
TEST_CASE( "simple/addition", "" ) { TEST_CASE("simple/addition", "") {
sol::state lua; sol::state lua;
lua.set( "b", 0.2 ); lua.set("b", 0.2);
lua.script( "c = 9 + b" ); lua.script("c = 9 + b");
auto c = lua.get<double>( "c" ); auto c = lua.get<double>("c");
REQUIRE( c == 9.2 ); REQUIRE(c == 9.2);
}
TEST_CASE("simple/if", "") {
sol::state lua;
std::string program = "if true then f = 0.1 else f = 'test' end";
lua.script(program);
auto f = lua.get<double>("f");
REQUIRE(f == 0.1);
}
TEST_CASE("simple/evalStream", "The VM evaluates a stream's contents using a reader") {
sol::state lua;
std::stringstream sscript;
int g = 9;
sscript << "g = " << g << ";";
REQUIRE_NOTHROW(lua.script(sscript.str()));
REQUIRE(lua.get<double>("g") == 9.0);
}
TEST_CASE("simple/callWithParameters", "Lua function is called with a few parameters from C++") {
sol::state lua;
REQUIRE_NOTHROW(lua.script("function my_add(i, j, k) return i + j + k end"));
auto f = lua.get<sol::function>("my_add");
REQUIRE_NOTHROW(f.call<int>(1, 2, 3));
REQUIRE_THROWS(f.call<int>(1, 2, "arf"));
}
TEST_CASE("simple/callCppFunction", "C++ function is called from lua") {
sol::state lua;
lua.set_function("plop_xyz", plop_xyz);
lua.script("x = plop_xyz(2, 6, 'hello')");
REQUIRE(lua.get<int>("x") == 11);
}
TEST_CASE("simple/callLambda", "A C++ lambda is exposed to lua and called") {
sol::state lua;
int x = 0;
lua.set_function("foo", [ &x ] { x = 1; });
lua.script("foo()");
REQUIRE(x == 1);
}
TEST_CASE("advanced/callLambdaReturns", "Checks for lambdas returning values") {
sol::state lua;
lua.set_function("a", [ ] { return 42; });
lua.set_function("b", [ ] { return 42u; });
lua.set_function("c", [ ] { return 3.14; });
lua.set_function("d", [ ] { return 6.28f; });
lua.set_function("e", [ ] { return "lol"; });
lua.set_function("f", [ ] { return true; });
lua.set_function("g", [ ] { return std::string("str"); });
lua.set_function("h", [ ] { });
lua.set_function("i", [ ] { return sol::nil; });
}
TEST_CASE("advanced/callLambda2", "A C++ lambda is exposed to lua and called") {
sol::state lua;
int x = 0;
lua.set_function("set_x", [ &] (int new_x) {
x = new_x;
return 0;
});
lua.script("set_x(9)");
REQUIRE(x == 9);
}
TEST_CASE("negative/basicError", "Check if error handling works correctly") {
sol::state lua;
REQUIRE_THROWS(lua.script("nil[5]"));
} }
/* /*
lua.get<sol::table>( "os" ).set( "name", "windows" ); lua.get<sol::table>("os").set("name", "windows");
SECTION( "" ) SECTION("")
lua.get<sol::table>( "os" ).set_function( "fun", lua.get<sol::table>("os").set_function("fun",
[ ] ( ) { [ ] () {
std::cout << "stateless lambda()" << std::endl; std::cout << "stateless lambda()" << std::endl;
return "test"; return "test";
} }
); );
run_script( lua ); run_script(lua);
lua.get<sol::table>( "os" ).set_function( "fun", &free_function ); lua.get<sol::table>("os").set_function("fun", &free_function);
run_script( lua ); run_script(lua);
// l-value, can optomize // l-value, can optomize
auto lval = object( ); auto lval = object();
lua.get<sol::table>( "os" ).set_function( "fun", &object::operator(), lval ); lua.get<sol::table>("os").set_function("fun", &object::operator(), lval);
run_script( lua ); run_script(lua);
// Tests will begin failing here // Tests will begin failing here
// stateful lambda: non-convertible, unoptomizable // stateful lambda: non-convertible, unoptomizable
int breakit = 50; int breakit = 50;
lua.get<sol::table>( "os" ).set_function( "fun", lua.get<sol::table>("os").set_function("fun",
[ &breakit ] ( ) { [ &breakit ] () {
std::cout << "stateless lambda()" << std::endl; std::cout << "stateless lambda()" << std::endl;
return "test"; return "test";
} }
); );
run_script( lua ); run_script(lua);
// r-value, cannot optomize // r-value, cannot optomize
lua.get<sol::table>( "os" ).set_function( "fun", &object::operator(), object( ) ); lua.get<sol::table>("os").set_function("fun", &object::operator(), object());
run_script( lua ); run_script(lua);
// r-value, cannot optomize // r-value, cannot optomize
auto rval = object( ); auto rval = object();
lua.get<sol::table>( "os" ).set_function( "fun", &object::operator(), std::move( rval ) ); lua.get<sol::table>("os").set_function("fun", &object::operator(), std::move(rval));
run_script( lua ); run_script(lua);
} }
*/ */

View File

@ -30,22 +30,22 @@ namespace sol {
class function : virtual public reference { class function : virtual public reference {
private: private:
template<typename... Ret> template<typename... Ret>
std::tuple<Ret...> call(types<Ret...>, std::size_t n) { std::tuple<Ret...> invoke(types<Ret...>, std::size_t n) {
lua_pcall(state(), n, sizeof...(Ret), 0); lua_pcall(state(), static_cast<int>(n), sizeof...(Ret), 0);
return stack::pop_call(state(), std::make_tuple<Ret...>, types<Ret...>()); return stack::pop_call(state(), std::make_tuple<Ret...>, types<Ret...>());
} }
template<typename Ret> template<typename Ret>
Ret call(types<Ret>, std::size_t n) { Ret invoke(types<Ret>, std::size_t n) {
lua_pcall(state(), n, 1, 0); lua_pcall(state(), static_cast<int>(n), 1, 0);
return stack::pop<Ret>(state()); return stack::pop<Ret>(state());
} }
void call(types<void>, std::size_t n) { void invoke(types<void>, std::size_t n) {
lua_pcall(state(), static_cast<uint32_t>(n), 0, 0); lua_pcall(state(), static_cast<uint32_t>(n), 0, 0);
} }
void call(types<>, std::size_t n) { void invoke(types<>, std::size_t n) {
lua_pcall(state(), static_cast<uint32_t>(n), 0, 0); lua_pcall(state(), static_cast<uint32_t>(n), 0, 0);
} }
@ -56,10 +56,10 @@ public:
} }
template<typename... Ret, typename... Args> template<typename... Ret, typename... Args>
auto invoke(Args&&... args) -> decltype(call(types<Ret...>(), sizeof...(Args))) { auto call(Args&&... args) -> decltype(invoke(types<Ret...>(), sizeof...(Args))) {
push(); push();
stack::push_args(state(), std::forward<Args>(args)...); stack::push_args(state(), std::forward<Args>(args)...);
return call(types<Ret...>(), sizeof...(Args)); return invoke(types<Ret...>(), sizeof...(Args));
} }
}; };
} // sol } // sol

View File

@ -29,32 +29,32 @@
namespace sol { namespace sol {
namespace detail { namespace detail {
template<typename T, std::size_t n> template<typename T, std::size_t n>
void get_upvalue_ptr( lua_State* L, T*& data, std::size_t datasize, std::array<void*, n> voiddata, int& upvalue ) { void get_upvalue_ptr(lua_State* L, T*& data, std::size_t datasize, std::array<void*, n> voiddata, int& upvalue) {
for ( std::size_t i = 0, d = 0; d < datasize; ++i, d += sizeof( void* ) ) { for (std::size_t i = 0, d = 0; d < datasize; ++i, d += sizeof(void*)) {
voiddata[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); voiddata[ i ] = lua_touserdata(L, lua_upvalueindex(upvalue++));
} }
data = reinterpret_cast<T*>( static_cast<void*>( voiddata.data( ) ) ); data = reinterpret_cast<T*>(static_cast<void*>(voiddata.data()));
} }
template<typename T, std::size_t n> template<typename T, std::size_t n>
void get_upvalue_ptr( lua_State* L, T*& data, std::array<void*, n> voiddata, int& upvalue ) { void get_upvalue_ptr(lua_State* L, T*& data, std::array<void*, n> voiddata, int& upvalue) {
get_upvalue_ptr( L, data, sizeof( T ), voiddata, upvalue ); get_upvalue_ptr(L, data, sizeof(T), voiddata, upvalue);
} }
template<typename T> template<typename T>
void get_upvalue_ptr( lua_State* L, T*& data, int& upvalue ) { void get_upvalue_ptr(lua_State* L, T*& data, int& upvalue) {
const static std::size_t data_t_count = ( sizeof(T)+( sizeof(void*)-1 ) ) / sizeof( void* ); const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*);
typedef std::array<void*, data_t_count> data_t; typedef std::array<void*, data_t_count> data_t;
data_t voiddata{{}}; data_t voiddata{{}};
return get_upvalue_ptr(L, data, voiddata, upvalue); return get_upvalue_ptr(L, data, voiddata, upvalue);
} }
template<typename T> template<typename T>
void get_upvalue( lua_State* L, T& data, int& upvalue ) { void get_upvalue(lua_State* L, T& data, int& upvalue) {
const static std::size_t data_t_count = ( sizeof(T)+( sizeof(void*)-1 ) ) / sizeof( void* ); const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*);
typedef std::array<void*, data_t_count> data_t; typedef std::array<void*, data_t_count> data_t;
data_t voiddata{ { } }; data_t voiddata{ { } };
for ( std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof( void* ) ) { for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
voiddata[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); voiddata[ i ] = lua_touserdata(L, lua_upvalueindex(upvalue++));
} }
data = *reinterpret_cast<T*>( static_cast<void*>( voiddata.data( ) ) ); data = *reinterpret_cast<T*>(static_cast<void*>(voiddata.data()));
} }
} // detail } // detail
@ -80,7 +80,7 @@ struct static_lua_func {
static int call(lua_State* L) { static int call(lua_State* L) {
int upvalue = 1; int upvalue = 1;
fx_t* fx; fx_t* fx;
detail::get_upvalue( L, fx, upvalue ); detail::get_upvalue(L, fx, upvalue);
int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), fx, L); int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), fx, L);
return r; return r;
} }
@ -105,8 +105,8 @@ struct static_object_lua_func {
template<typename TR, typename... Args> template<typename TR, typename... Args>
static int typed_call(types<TR>, types<Args...>, T& item, fx_t& ifx, lua_State* L) { static int typed_call(types<TR>, types<Args...>, T& item, fx_t& ifx, lua_State* L) {
auto fx = [ &item, &ifx ] (Args&&... args) -> TR { auto fx = [ &item, &ifx ] (Args&&... args) -> TR {
return (item.*ifx)(std::forward<Args>(args)...); return (item.*ifx)(std::forward<Args>(args)...);
}; };
auto r = stack::pop_call(L, fx, types<Args...>()); auto r = stack::pop_call(L, fx, types<Args...>());
stack::push(L, std::move(r)); stack::push(L, std::move(r));
return 1; return 1;
@ -121,19 +121,19 @@ struct static_object_lua_func {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
const static std::size_t data_t_count = ( sizeof(fx_t)+( sizeof(void*)-1 ) ) / sizeof( void* ); const static std::size_t data_t_count = (sizeof(fx_t)+(sizeof(void*)-1)) / sizeof(void*);
typedef std::array<void*, data_t_count> data_t; typedef std::array<void*, data_t_count> data_t;
int upvalue = 1; int upvalue = 1;
data_t data = { { } }; data_t data = { { } };
fx_t* fxptr; fx_t* fxptr;
for ( std::size_t i = 0, d = 0; d < sizeof(fx_t*); ++i, d += sizeof( void* ) ) { for (std::size_t i = 0, d = 0; d < sizeof(fx_t*); ++i, d += sizeof(void*)) {
data[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); data[ i ] = lua_touserdata(L, lua_upvalueindex(upvalue++));
} }
fxptr = reinterpret_cast<fx_t*>( static_cast<void*>( data.data( ) ) ); fxptr = reinterpret_cast<fx_t*>(static_cast<void*>(data.data()));
fx_t& mem_ptr = *fxptr; fx_t& mem_ptr = *fxptr;
void* objectdata = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); void* objectdata = lua_touserdata(L, lua_upvalueindex(upvalue++));
T& obj = *static_cast<T*>( objectdata ); T& obj = *static_cast<T*>(objectdata);
int r = typed_call( tuple_types<typename fx_traits::return_type>( ), typename fx_traits::args_type( ), obj, mem_ptr, L ); int r = typed_call(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), obj, mem_ptr, L);
return r; return r;
} }

View File

@ -45,7 +45,7 @@ inline T get_unsigned(lua_State* L, std::true_type, int index = -1) {
template<typename T> template<typename T>
inline T get_unsigned(lua_State* L, std::false_type, int index = -1) { inline T get_unsigned(lua_State* L, std::false_type, int index = -1) {
return static_cast<T>( lua_tointeger(L, index) ); return static_cast<T>(lua_tointeger(L, index));
} }
template<typename T> template<typename T>
@ -68,7 +68,7 @@ inline T get_helper(lua_State* L, std::true_type, int index = -1) {
template<typename T> template<typename T>
inline T get_nil(lua_State* L, std::true_type, int index = -1) { inline T get_nil(lua_State* L, std::true_type, int index = -1) {
if (lua_isnil(L, index) == 0) if (lua_isnil(L, index) == 0)
throw sol::sol_error("not nil"); throw sol::sol_error("not nil");
return nil_t{}; return nil_t{};
} }
@ -196,19 +196,19 @@ inline void push(lua_State* L, const std::array<T, N>& data) {
} }
} }
template <typename T> template<typename T>
inline int push_user( lua_State* L, T& item ) { inline int push_user(lua_State* L, T& item) {
typedef typename std::decay<T>::type TValue; typedef typename std::decay<T>::type TValue;
const static std::size_t itemsize = sizeof( TValue ); const static std::size_t itemsize = sizeof(TValue);
const static std::size_t voidsize = sizeof( void* ); const static std::size_t voidsize = sizeof(void*);
const static std::size_t voidsizem1 = voidsize - 1; const static std::size_t voidsizem1 = voidsize - 1;
const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize;
typedef std::array<void*, data_t_count> data_t; typedef std::array<void*, data_t_count> data_t;
data_t data{{}}; data_t data{{}};
std::memcpy( std::addressof( data[ 0 ] ), std::addressof( item ), itemsize ); std::memcpy(std::addressof(data[ 0 ]), std::addressof(item), itemsize);
push( L, data ); push(L, data);
return data_t_count; return data_t_count;
} }
namespace detail { namespace detail {

View File

@ -115,14 +115,22 @@ public:
} }
} }
void eval(const std::string& code) {
script(code);
}
void script(const std::string& code) { void script(const std::string& code) {
if(luaL_dostring(L.get(), code.c_str())) { if(luaL_dostring(L.get(), code.c_str())) {
lua_error(L.get()); lua_error(L.get());
} }
} }
void open_file(const std::string& filename) { void eval_file(const std::string& filename) {
if(luaL_dofile(L.get(), filename.c_str())) { script_file(filename);
}
void script_file(const std::string& filename) {
if (luaL_dofile(L.get(), filename.c_str())) {
lua_error(L.get()); lua_error(L.get());
} }
} }

View File

@ -170,7 +170,7 @@ private:
push(); push();
int upvalues = stack::push_user( state( ), target ); int upvalues = stack::push_user(state(), target);
luaL_setfuncs(state(), funcreg, upvalues); luaL_setfuncs(state(), funcreg, upvalues);
lua_pop(state(), 1); lua_pop(state(), 1);
@ -199,7 +199,7 @@ private:
lua_settable(state(), -3); lua_settable(state(), -3);
} }
push(); push();
stack::push_user(state(), userdata, metatablename); stack::push_user(state(), userdata, metatablename);
luaL_setfuncs(state(), funcreg, 1); luaL_setfuncs(state(), funcreg, 1);