view C++/Tests/Luae/main.cpp @ 250:b686a09fb9c6

Merge
author David Demelier <markand@malikania.fr>
date Wed, 01 Oct 2014 14:39:24 +0200
parents C++/Tests/Luae/TestLuae.cpp@927c4f3b8a88 C++/Tests/Luae/TestLuae.cpp@3b4ae8feca1c
children
line wrap: on
line source

/*
 * main.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 <gtest/gtest.h>

#include <Luae.h>
#include <LuaeState.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
 * -------------------------------------------------------- */

TEST(Push, point)
{
	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) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Push, object)
{
	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) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Push, shared)
{
	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) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Push, sharedTwice)
{
	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) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

/* --------------------------------------------------------
 * Other functions
 * -------------------------------------------------------- */

TEST(Basic, 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) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Basic, 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) {
		FAIL() << "unexpected exception: "  << error.what();
	}
}

/* --------------------------------------------------------
 * Standard types push / get / check
 * -------------------------------------------------------- */

TEST(Standard, 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);
		ASSERT_FALSE(Luae::check<bool>(L, 1));
	} catch (const std::runtime_error &error) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Standard, 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);
		ASSERT_EQ(-10.0, Luae::check<double>(L, 1));
	} catch (const std::runtime_error &error) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Standard, 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);
		ASSERT_EQ(-123, Luae::check<int>(L, 1));
	} catch (const std::runtime_error &error) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Standard, 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);
		ASSERT_EQ(-9999L, Luae::check<long>(L, 1));
	} catch (const std::runtime_error &error) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Standard, 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);
		ASSERT_EQ(LUA_TNIL, Luae::type(L, -1));
	} catch (const std::runtime_error &error) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Standard, 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);
		ASSERT_EQ("olleH", Luae::check<std::string>(L, 1));
	} catch (const std::runtime_error &error) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Standard, 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);
		ASSERT_EQ(expected, Luae::check<std::u32string>(L, 1));
	} catch (const std::runtime_error &error) {
		FAIL() << "unexpected exception: " << error.what();
	}
}

TEST(Standard, optionalbool)
{
	LuaeState L;
	Luae::openlibs(L);

	Luae::push(L, nullptr);
	ASSERT_FALSE(Luae::optional<bool>(L, -1, false));

	Luae::push(L, true);
	ASSERT_TRUE(Luae::optional<bool>(L, -1, false));
}

TEST(Standard, optionalint)
{
	LuaeState L;
	Luae::openlibs(L);

	Luae::push(L, nullptr);
	ASSERT_EQ(123, Luae::optional<int>(L, -1, 123));

	Luae::push(L, 456);
	ASSERT_EQ(456, Luae::optional<int>(L, -1, 999));
}

TEST(Standard, optionallong)
{
	LuaeState L;
	Luae::openlibs(L);

	Luae::push(L, nullptr);
	ASSERT_EQ(123456789, Luae::optional<long>(L, -1, 123456789));

	Luae::push(L, 789);
	ASSERT_EQ(789, Luae::optional<long>(L, -1, 888));
}

TEST(Standard, optionaldouble)
{
	LuaeState L;
	Luae::openlibs(L);

	Luae::push(L, nullptr);
	ASSERT_EQ(123.321, Luae::optional<double>(L, -1, 123.321));

	Luae::push(L, 99.44);
	ASSERT_EQ(99.44, Luae::optional<double>(L, -1, 321.321));
}

TEST(Standard, optionalstring)
{
	LuaeState L;
	Luae::openlibs(L);

	Luae::push(L, nullptr);
	ASSERT_EQ("abc", Luae::optional<std::string>(L, -1, "abc"));

	Luae::push(L, "xyz");
	ASSERT_EQ("xyz", Luae::optional<std::string>(L, -1, "qwerty"));
}

TEST(Standard, optionalustring)
{
	LuaeState L;
	Luae::openlibs(L);

	std::u32string expected { 'a', 'b', 'c' };
	Luae::push(L, nullptr);
	ASSERT_EQ(expected, Luae::optional<std::u32string>(L, -1, expected));

	std::u32string notthatone { 'x', 'y' };
	Luae::push(L, expected);
	ASSERT_EQ(expected, Luae::optional<std::u32string>(L, -1, notthatone));
}

int main(int argc, char **argv)
{
	testing::InitGoogleTest(&argc, argv);

	return RUN_ALL_TESTS();
}