Mercurial > code
diff C++/Tests/Luae/TestLuae.cpp @ 225:e01ee0c72c43
Luae: begin refactoring of Luae
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 09 May 2014 17:12:25 +0200 |
parents | |
children | 927c4f3b8a88 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C++/Tests/Luae/TestLuae.cpp Fri May 09 17:12:25 2014 +0200 @@ -0,0 +1,418 @@ +/* + * TestLuae.cpp -- test the Luae class + * + * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cppunit/TextTestRunner.h> + +#include <Luae.h> +#include <LuaeState.h> + +#include "TestLuae.h" + +/* -------------------------------------------------------- + * Custom type Point + * -------------------------------------------------------- */ + +struct Point { + int x; + int y; +}; + +template <> +struct Luae::TypeInfo<Point> : Luae::TypeCustom { + static void push(lua_State *L, const Point &point) + { + lua_createtable(L, 0, 0); + lua_pushinteger(L, point.x); + lua_setfield(L, -2, "x"); + lua_pushinteger(L, point.y); + lua_setfield(L, -2, "y"); + } + + static Point get(lua_State *L, int index) + { + Point p{0, 0}; + + if (lua_type(L, index) == LUA_TTABLE) { + lua_getfield(L, index, "x"); + p.x = luaL_optint(L, -1, 0); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.y = luaL_optint(L, -1, 0); + lua_pop(L, 1); + } + + return p; + } + + static Point check(lua_State *L, int index) + { + luaL_checktype(L, index, LUA_TTABLE); + + return get(L, index); + } +}; + +/* -------------------------------------------------------- + * Userdata type Object + * -------------------------------------------------------- */ + +struct Object { + std::string hello() + { + return "hello"; + } +}; + +template <> +struct Luae::TypeInfo<Object> : Luae::TypeUserdata { + static constexpr const char *name = "Object"; +}; + +int l_hello(lua_State *L) +{ + return Luae::push(L, Luae::check<Object>(L, 1)->hello()); +} + +const Luae::Reg methods { + { "hello", l_hello } +}; + +/* -------------------------------------------------------- + * Userdata as shared_ptr Widget + * -------------------------------------------------------- */ + +class Widget { +private: + int m_width; + int m_height; + std::string m_name; + +public: + Widget(int width, int height, const std::string &name) + : m_width(width) + , m_height(height) + , m_name(name) + { + } + + int width() const + { + return m_width; + } + + int height() const + { + return m_height; + } + + const std::string &name() const + { + return m_name; + } +}; + +using WidgetPtr = std::shared_ptr<Widget>; + +template <> +struct Luae::TypeInfo<Widget> : Luae::TypeUserdata { + static constexpr const char *name = "Widget"; +}; + +int l_width(lua_State *L) +{ + return Luae::push(L, Luae::check<WidgetPtr>(L, 1)->width()); +} + +int l_height(lua_State *L) +{ + return Luae::push(L, Luae::check<WidgetPtr>(L, 1)->height()); +} + +int l_name(lua_State *L) +{ + return Luae::push(L, Luae::check<WidgetPtr>(L, 1)->name()); +} + +const Luae::Reg widgetMethods { + { "width", l_width }, + { "height", l_height }, + { "name", l_name } +}; + +/* -------------------------------------------------------- + * Push function tests + * -------------------------------------------------------- */ + +void TestLuae::pushPoint() +{ + LuaeState L; + Luae::openlibs(L); + + try { + Luae::dofile(L, "push.lua"); + Luae::getglobal(L, "pushPoint"); + Luae::push(L, Point{10, 20}); + Luae::pcall(L, 1, 0); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::pushObject() +{ + LuaeState L; + Luae::openlibs(L); + + // Object metatable + Luae::newmetatable(L, "Object"); + Luae::newlib(L, methods); + Luae::setfield(L, -2, "__index"); + Luae::pop(L); + + try { + Luae::dofile(L, "push.lua"); + Luae::getglobal(L, "pushObject"); + Luae::push(L, Object()); + Luae::pcall(L, 1, 0); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::pushShared() +{ + LuaeState L; + Luae::openlibs(L); + + // Widget metatable + Luae::newmetatable(L, "Widget"); + Luae::newlib(L, widgetMethods); + Luae::setfield(L, -2, "__index"); + Luae::pop(L); + + try { + Luae::dofile(L, "push.lua"); + Luae::getglobal(L, "pushShared"); + Luae::push(L, std::make_shared<Widget>(100, 200, "Button")); + Luae::pcall(L, 1, 0); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::pushSharedTwice() +{ + LuaeState L; + Luae::openlibs(L); + + // Widget metatable + Luae::newmetatable(L, "Widget"); + Luae::newlib(L, widgetMethods); + Luae::setfield(L, -2, "__index"); + Luae::pop(L); + + try { + auto widget = std::make_shared<Widget>(640, 480, "Screen"); + + Luae::dofile(L, "push.lua"); + Luae::getglobal(L, "pushSharedTwice"); + Luae::push(L, widget); + Luae::push(L, widget); + Luae::pcall(L, 2, 0); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +/* -------------------------------------------------------- + * Other functions + * -------------------------------------------------------- */ + +void TestLuae::preload() +{ + LuaeState L; + Luae::openlibs(L); + + Luae::preload(L, "luae", [] (lua_State *L) -> int { + lua_createtable(L, 0, 0); + lua_pushstring(L, "1.0"); + lua_setfield(L, -2, "version"); + lua_pushstring(L, "Luae"); + lua_setfield(L, -2, "name"); + + return 1; + }); + + try { + Luae::dofile(L, "loading.lua"); + Luae::getglobal(L, "test"); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::require() +{ + LuaeState L; + Luae::openlibs(L); + + Luae::require(L, "luae", [] (lua_State *L) -> int { + lua_createtable(L, 0, 0); + lua_pushstring(L, "1.0"); + lua_setfield(L, -2, "version"); + lua_pushstring(L, "Luae"); + lua_setfield(L, -2, "name"); + + return 1; + }); + + try { + Luae::dofile(L, "loading.lua"); + Luae::getglobal(L, "test"); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +/* -------------------------------------------------------- + * Standard types push / get / check + * -------------------------------------------------------- */ + +void TestLuae::testbool() +{ + LuaeState L; + Luae::openlibs(L); + + try { + Luae::dofile(L, "standard.lua"); + Luae::getglobal(L, "testbool"); + Luae::push(L, true); + Luae::pcall(L, 1, 1); + CPPUNIT_ASSERT_EQUAL(Luae::check<bool>(L, 1), false); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::testdouble() +{ + LuaeState L; + Luae::openlibs(L); + + try { + Luae::dofile(L, "standard.lua"); + Luae::getglobal(L, "testdouble"); + Luae::push(L, 10.0); + Luae::pcall(L, 1, 1); + CPPUNIT_ASSERT_EQUAL(Luae::check<double>(L, 1), -10.0); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::testint() +{ + LuaeState L; + Luae::openlibs(L); + + try { + Luae::dofile(L, "standard.lua"); + Luae::getglobal(L, "testint"); + Luae::push(L, 123); + Luae::pcall(L, 1, 1); + CPPUNIT_ASSERT_EQUAL(Luae::check<int>(L, 1), -123); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::testlong() +{ + LuaeState L; + Luae::openlibs(L); + + try { + Luae::dofile(L, "standard.lua"); + Luae::getglobal(L, "testlong"); + Luae::push(L, 9999L); + Luae::pcall(L, 1, 1); + CPPUNIT_ASSERT_EQUAL(Luae::check<long>(L, 1), -9999L); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::testnil() +{ + LuaeState L; + Luae::openlibs(L); + + try { + Luae::dofile(L, "standard.lua"); + Luae::getglobal(L, "testnil"); + Luae::push(L, nullptr); + Luae::pcall(L, 1, 1); + CPPUNIT_ASSERT_EQUAL(Luae::type(L, -1), LUA_TNIL); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::teststring() +{ + LuaeState L; + Luae::openlibs(L); + + try { + Luae::dofile(L, "standard.lua"); + Luae::getglobal(L, "teststring"); + Luae::push(L, "Hello"); + Luae::pcall(L, 1, 1); + CPPUNIT_ASSERT_EQUAL(Luae::check<std::string>(L, 1), std::string("olleH")); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +void TestLuae::testustring() +{ + LuaeState L; + Luae::openlibs(L); + + try { + std::u32string arg{'H', 'e', 'l', 'l', 'o'}; + std::u32string expected{'o', 'l', 'l', 'e', 'H'}; + + Luae::dofile(L, "standard.lua"); + Luae::getglobal(L, "testustring"); + Luae::push(L, arg); + Luae::pcall(L, 1, 1); + CPPUNIT_ASSERT_MESSAGE("u32string failure", Luae::check<std::u32string>(L, 1) == expected); + } catch (const std::runtime_error &error) { + CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false); + } +} + +int main() +{ + CppUnit::TextTestRunner runnerText; + + runnerText.addTest(TestLuae::suite()); + + return runnerText.run("", false) == 1 ? 0 : 1; +} \ No newline at end of file