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