view C++/tests/Js/main.cpp @ 391:e2cefd0ee511

Add Js, Duktape wrapper
author David Demelier <markand@malikania.fr>
date Mon, 28 Sep 2015 13:18:14 +0200
parents
children 69adcefe73ae
line wrap: on
line source

/*
 * TestJsUnicode.cpp -- test irccd JS functions
 *
 * Copyright (c) 2013, 2014, 2015 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 <Js.h>

using namespace js;

/* --------------------------------------------------------
 * Push & get
 * -------------------------------------------------------- */

TEST(PushAndGet, boolean)
{
	Context context;

	push(context, true);
	ASSERT_TRUE(get<bool>(context, -1));
	push(context, false);
	ASSERT_FALSE(get<bool>(context, -1));
}

TEST(PushAndGet, integer)
{
	Context context;

	push(context, 123);
	ASSERT_EQ(123, get<int>(context, -1));
	push(context, 456);
	ASSERT_EQ(456, get<int>(context, -1));
}

TEST(PushAndGet, number)
{
	Context context;

	push(context, 10.5);
	ASSERT_EQ(10.5, get<double>(context, -1));
	push(context, 50.1);
	ASSERT_EQ(50.1, get<double>(context, -1));
}

TEST(PushAndGet, string)
{
	Context context;

	push(context, "hello world!");
	ASSERT_EQ("hello world!", get<std::string>(context, -1));
}

/* --------------------------------------------------------
 * Basics
 * -------------------------------------------------------- */

TEST(Basics, global)
{
	Context context;

	// boolean
	setGlobal(context, "valueBoolean", true);
	ASSERT_TRUE(getGlobal<bool>(context, "valueBoolean"));

	// integer
	setGlobal(context, "valueInteger", 123);
	ASSERT_EQ(123, getGlobal<int>(context, "valueInteger"));
}

TEST(Basics, top)
{
	Context context;

	int current = top(context);
	push(context, true);
	ASSERT_EQ(current + 1, top(context));
}

TEST(Basics, pop1)
{
	Context context;

	int current = top(context);
	push(context, true);
	pop(context);
	ASSERT_EQ(current, top(context));
}

TEST(Basics, pop2)
{
	Context context;

	int current = top(context);
	push(context, true);
	push(context, true);
	pop(context, 2);
	ASSERT_EQ(current, top(context));
}

TEST(Basics, setObject)
{
	Context context;

	push(context, Object{});
	setObject(context, -1, "x", 123);
	ASSERT_EQ(123, getObject<int>(context, -1, "x"));
}

TEST(Basics, enumerate)
{
	Context context;

	push(context, Object{});
	setObject(context, -1, "x", 123);
	setObject(context, -1, "y", 456);

	enumerate(context, -1, 0, true, [] (ContextPtr ctx) {
		ASSERT_EQ(DUK_TYPE_STRING, duk_get_type(ctx, -2));
		ASSERT_EQ(DUK_TYPE_NUMBER, duk_get_type(ctx, -1));

		if (get<std::string>(ctx, -2) == "x")
			ASSERT_EQ(123, get<int>(ctx, -1));
		if (get<std::string>(ctx, -2) == "y")
			ASSERT_EQ(456, get<int>(ctx, -1));
	});
}

TEST(Basics, call)
{
	Context context;

	push(context, Function{[] (ContextPtr ctx) -> duk_ret_t {
		setGlobal(ctx, "x", 123);

		return 0;
	}});
	call(context);

	ASSERT_EQ(123, getGlobal<int>(context, "x"));
}

/* ------------------------------------------------------------------
 * Eval
 * ------------------------------------------------------------------ */

TEST(Eval, simple)
{
	Context context;

	evalString(context, "x = 123;");
	ASSERT_EQ(123, getGlobal<int>(context, "x"));
}

TEST(Eval, function)
{
	Context context;

	evalString(context, "function f() { x = 123; }; f();");
	ASSERT_EQ(123, getGlobal<int>(context, "x"));
}

TEST(Eval, cfunction)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		setGlobal(ctx, "x", 123);

		return 0;
	}});
	evalString(context, "f()");
	ASSERT_EQ(123, getGlobal<int>(context, "x"));
}

/* ------------------------------------------------------------------
 * Protected eval
 * ------------------------------------------------------------------ */

TEST(Peval, success)
{
	Context context;

	try {
		pevalString(context, "x = 1");
	} catch (const ErrorInfo &info) {
		FAIL() << "error unexpected: " << info.what();
	}
}

TEST(Peval, failure)
{
	Context context;

	try {
		pevalString(context, "doesnotexists()");

		FAIL() << "expected exception";
	} catch (const ErrorInfo &) {
	}
}

/* ------------------------------------------------------------------
 * Exception handling
 * ------------------------------------------------------------------ */

TEST(Exception, error)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		raise(ctx, Error{"error thrown"});

		return 0;
	}});
	evalString(context,
		"try {"
		"  f();"
		"} catch (ex) {"
		"  name = ex.name;"
		"  message = ex.message;"
		"  received = true;"
		"}"
	);

	ASSERT_TRUE(getGlobal<bool>(context, "received"));
	ASSERT_EQ("Error", getGlobal<std::string>(context, "name"));
	ASSERT_EQ("error thrown", getGlobal<std::string>(context, "message"));
}

TEST(Exception, evalError)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		raise(ctx, EvalError{"failed"});

		return 0;
	}});
	evalString(context,
		"try {"
		"  f();"
		"} catch (ex) {"
		"  name = ex.name;"
		"  message = ex.message;"
		"  received = true;"
		"}"
	);

	ASSERT_TRUE(getGlobal<bool>(context, "received"));
	ASSERT_EQ("EvalError", getGlobal<std::string>(context, "name"));
	ASSERT_EQ("failed", getGlobal<std::string>(context, "message"));
}

TEST(Exception, rangeError)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		raise(ctx, RangeError{"e2big"});

		return 0;
	}});
	evalString(context,
		"try {"
		"  f();"
		"} catch (ex) {"
		"  name = ex.name;"
		"  message = ex.message;"
		"  received = true;"
		"}"
	);

	ASSERT_TRUE(getGlobal<bool>(context, "received"));
	ASSERT_EQ("RangeError", getGlobal<std::string>(context, "name"));
	ASSERT_EQ("e2big", getGlobal<std::string>(context, "message"));
}

TEST(Exception, referenceError)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		raise(ctx, ReferenceError{"does not exists"});

		return 0;
	}});
	evalString(context,
		"try {"
		"  f();"
		"} catch (ex) {"
		"  name = ex.name;"
		"  message = ex.message;"
		"  received = true;"
		"}"
	);

	ASSERT_TRUE(getGlobal<bool>(context, "received"));
	ASSERT_EQ("ReferenceError", getGlobal<std::string>(context, "name"));
	ASSERT_EQ("does not exists", getGlobal<std::string>(context, "message"));
}

TEST(Exception, syntaxError)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		raise(ctx, SyntaxError{"missing token"});

		return 0;
	}});
	evalString(context,
		"try {"
		"  f();"
		"} catch (ex) {"
		"  name = ex.name;"
		"  message = ex.message;"
		"  received = true;"
		"}"
	);

	ASSERT_TRUE(getGlobal<bool>(context, "received"));
	ASSERT_EQ("SyntaxError", getGlobal<std::string>(context, "name"));
	ASSERT_EQ("missing token", getGlobal<std::string>(context, "message"));
}

TEST(Exception, typeError)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		raise(ctx, TypeError{"int requested"});

		return 0;
	}});
	evalString(context,
		"try {"
		"  f();"
		"} catch (ex) {"
		"  name = ex.name;"
		"  message = ex.message;"
		"  received = true;"
		"}"
	);

	ASSERT_TRUE(getGlobal<bool>(context, "received"));
	ASSERT_EQ("TypeError", getGlobal<std::string>(context, "name"));
	ASSERT_EQ("int requested", getGlobal<std::string>(context, "message"));
}

TEST(Exception, uriError)
{
	Context context;

	setGlobal(context, "f", Function{[] (ContextPtr ctx) -> duk_idx_t {
		raise(ctx, URIError{"invalid scheme"});

		return 0;
	}});
	evalString(context,
		"try {"
		"  f();"
		"} catch (ex) {"
		"  name = ex.name;"
		"  message = ex.message;"
		"  received = true;"
		"}"
	);

	ASSERT_TRUE(getGlobal<bool>(context, "received"));
	ASSERT_EQ("URIError", getGlobal<std::string>(context, "name"));
	ASSERT_EQ("invalid scheme", getGlobal<std::string>(context, "message"));
}

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

	return RUN_ALL_TESTS();
}