Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/scriptinterface/tests/test_ScriptInterface.h
Show All 22 Lines | |||||
#include <boost/random/linear_congruential.hpp> | #include <boost/random/linear_congruential.hpp> | ||||
class TestScriptInterface : public CxxTest::TestSuite | class TestScriptInterface : public CxxTest::TestSuite | ||||
{ | { | ||||
public: | public: | ||||
void test_loadscript_basic() | void test_loadscript_basic() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
TestLogger logger; | TestLogger logger; | ||||
TS_ASSERT(script.LoadScript(L"test.js", "var x = 1+1;")); | TS_ASSERT(script.LoadScript(L"test.js", "var x = 1+1;")); | ||||
TS_ASSERT_STR_NOT_CONTAINS(logger.GetOutput(), "JavaScript error"); | TS_ASSERT_STR_NOT_CONTAINS(logger.GetOutput(), "JavaScript error"); | ||||
TS_ASSERT_STR_NOT_CONTAINS(logger.GetOutput(), "JavaScript warning"); | TS_ASSERT_STR_NOT_CONTAINS(logger.GetOutput(), "JavaScript warning"); | ||||
} | } | ||||
void test_loadscript_error() | void test_loadscript_error() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
TestLogger logger; | TestLogger logger; | ||||
TS_ASSERT(!script.LoadScript(L"test.js", "1+")); | TS_ASSERT(!script.LoadScript(L"test.js", "1+")); | ||||
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: expected expression, got end of script"); | TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: expected expression, got end of script"); | ||||
} | } | ||||
void test_loadscript_strict_warning() | void test_loadscript_strict_warning() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
TestLogger logger; | TestLogger logger; | ||||
// in strict mode, this inside a function doesn't point to the global object | // in strict mode, this inside a function doesn't point to the global object | ||||
TS_ASSERT(script.LoadScript(L"test.js", "var isStrict = (function() { return !this; })();warn('isStrict is '+isStrict);")); | TS_ASSERT(script.LoadScript(L"test.js", "var isStrict = (function() { return !this; })();warn('isStrict is '+isStrict);")); | ||||
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "WARNING: isStrict is true"); | TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "WARNING: isStrict is true"); | ||||
} | } | ||||
void test_loadscript_strict_error() | void test_loadscript_strict_error() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
TestLogger logger; | TestLogger logger; | ||||
TS_ASSERT(!script.LoadScript(L"test.js", "with(1){}")); | TS_ASSERT(!script.LoadScript(L"test.js", "with(1){}")); | ||||
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements"); | TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements"); | ||||
} | } | ||||
void test_clone_basic() | void test_clone_basic() | ||||
{ | { | ||||
ScriptInterface script1("Test", "Test", g_ScriptRuntime); | ScriptInterface script1("Test", "Test", g_ScriptContext); | ||||
ScriptInterface script2("Test", "Test", g_ScriptRuntime); | ScriptInterface script2("Test", "Test", g_ScriptContext); | ||||
ScriptInterface::Request rq1(script1); | ScriptInterface::Request rq1(script1); | ||||
JS::RootedValue obj1(rq1.cx); | JS::RootedValue obj1(rq1.cx); | ||||
TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", &obj1)); | TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", &obj1)); | ||||
{ | { | ||||
ScriptInterface::Request rq2(script2); | ScriptInterface::Request rq2(script2); | ||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); | JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); | ||||
std::string source; | std::string source; | ||||
TS_ASSERT(script2.CallFunction(obj2, "toSource", source)); | TS_ASSERT(script2.CallFunction(obj2, "toSource", source)); | ||||
TS_ASSERT_STR_EQUALS(source, "({x:123, y:[1, 1.5, \"2\", \"test\", (void 0), null, true, false]})"); | TS_ASSERT_STR_EQUALS(source, "({x:123, y:[1, 1.5, \"2\", \"test\", (void 0), null, true, false]})"); | ||||
} | } | ||||
} | } | ||||
void test_clone_getters() | void test_clone_getters() | ||||
{ | { | ||||
// The tests should be run with JS_SetGCZeal so this can try to find GC bugs | // The tests should be run with JS_SetGCZeal so this can try to find GC bugs | ||||
ScriptInterface script1("Test", "Test", g_ScriptRuntime); | ScriptInterface script1("Test", "Test", g_ScriptContext); | ||||
ScriptInterface script2("Test", "Test", g_ScriptRuntime); | ScriptInterface script2("Test", "Test", g_ScriptContext); | ||||
ScriptInterface::Request rq1(script1); | ScriptInterface::Request rq1(script1); | ||||
JS::RootedValue obj1(rq1.cx); | JS::RootedValue obj1(rq1.cx); | ||||
TS_ASSERT(script1.Eval("var s = '?'; var v = ({get x() { return 123 }, 'y': {'w':{get z() { delete v.y; delete v.n; v = null; s += s; return 4 }}}, 'n': 100}); v", &obj1)); | TS_ASSERT(script1.Eval("var s = '?'; var v = ({get x() { return 123 }, 'y': {'w':{get z() { delete v.y; delete v.n; v = null; s += s; return 4 }}}, 'n': 100}); v", &obj1)); | ||||
{ | { | ||||
ScriptInterface::Request rq2(script2); | ScriptInterface::Request rq2(script2); | ||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); | JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); | ||||
std::string source; | std::string source; | ||||
TS_ASSERT(script2.CallFunction(obj2, "toSource", source)); | TS_ASSERT(script2.CallFunction(obj2, "toSource", source)); | ||||
TS_ASSERT_STR_EQUALS(source, "({x:123, y:{w:{z:4}}})"); | TS_ASSERT_STR_EQUALS(source, "({x:123, y:{w:{z:4}}})"); | ||||
} | } | ||||
} | } | ||||
void test_clone_cyclic() | void test_clone_cyclic() | ||||
{ | { | ||||
ScriptInterface script1("Test", "Test", g_ScriptRuntime); | ScriptInterface script1("Test", "Test", g_ScriptContext); | ||||
ScriptInterface script2("Test", "Test", g_ScriptRuntime); | ScriptInterface script2("Test", "Test", g_ScriptContext); | ||||
ScriptInterface::Request rq1(script1); | ScriptInterface::Request rq1(script1); | ||||
JS::RootedValue obj1(rq1.cx); | JS::RootedValue obj1(rq1.cx); | ||||
TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", &obj1)); | TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", &obj1)); | ||||
{ | { | ||||
ScriptInterface::Request rq2(script2); | ScriptInterface::Request rq2(script2); | ||||
Show All 14 Lines | public: | ||||
} | } | ||||
/** | /** | ||||
* This test is mainly to make sure that all required template overloads get instantiated at least once so that compiler errors | * This test is mainly to make sure that all required template overloads get instantiated at least once so that compiler errors | ||||
* in these functions are revealed instantly (but it also tests the basic functionality of these functions). | * in these functions are revealed instantly (but it also tests the basic functionality of these functions). | ||||
*/ | */ | ||||
void test_rooted_templates() | void test_rooted_templates() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
ScriptInterface::Request rq(script); | ScriptInterface::Request rq(script); | ||||
JS::RootedValue val(rq.cx); | JS::RootedValue val(rq.cx); | ||||
JS::RootedValue out(rq.cx); | JS::RootedValue out(rq.cx); | ||||
TS_ASSERT(script.Eval("({ " | TS_ASSERT(script.Eval("({ " | ||||
"'0':0," | "'0':0," | ||||
"inc:function() { this[0]++; return this[0]; }, " | "inc:function() { this[0]++; return this[0]; }, " | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | void handle_templates_test(const ScriptInterface& script, JS::HandleValue val, JS::MutableHandleValue out, JS::HandleValue nbrVal) | ||||
nbr = 0; | nbr = 0; | ||||
script.GetPropertyInt(val, 0, out); | script.GetPropertyInt(val, 0, out); | ||||
ScriptInterface::FromJSVal(rq, out, nbr); | ScriptInterface::FromJSVal(rq, out, nbr); | ||||
TS_ASSERT_EQUALS(nbr, 7); | TS_ASSERT_EQUALS(nbr, 7); | ||||
} | } | ||||
void test_random() | void test_random() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
double d1, d2; | double d1, d2; | ||||
TS_ASSERT(script.Eval("Math.random()", d1)); | TS_ASSERT(script.Eval("Math.random()", d1)); | ||||
TS_ASSERT(script.Eval("Math.random()", d2)); | TS_ASSERT(script.Eval("Math.random()", d2)); | ||||
TS_ASSERT_DIFFERS(d1, d2); | TS_ASSERT_DIFFERS(d1, d2); | ||||
boost::rand48 rng; | boost::rand48 rng; | ||||
script.ReplaceNondeterministicRNG(rng); | script.ReplaceNondeterministicRNG(rng); | ||||
rng.seed((u64)0); | rng.seed((u64)0); | ||||
TS_ASSERT(script.Eval("Math.random()", d1)); | TS_ASSERT(script.Eval("Math.random()", d1)); | ||||
TS_ASSERT(script.Eval("Math.random()", d2)); | TS_ASSERT(script.Eval("Math.random()", d2)); | ||||
TS_ASSERT_DIFFERS(d1, d2); | TS_ASSERT_DIFFERS(d1, d2); | ||||
rng.seed((u64)0); | rng.seed((u64)0); | ||||
TS_ASSERT(script.Eval("Math.random()", d2)); | TS_ASSERT(script.Eval("Math.random()", d2)); | ||||
TS_ASSERT_EQUALS(d1, d2); | TS_ASSERT_EQUALS(d1, d2); | ||||
} | } | ||||
void test_json() | void test_json() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
ScriptInterface::Request rq(script); | ScriptInterface::Request rq(script); | ||||
std::string input = "({'x':1,'z':[2,'3\\u263A\\ud800'],\"y\":true})"; | std::string input = "({'x':1,'z':[2,'3\\u263A\\ud800'],\"y\":true})"; | ||||
JS::RootedValue val(rq.cx); | JS::RootedValue val(rq.cx); | ||||
TS_ASSERT(script.Eval(input.c_str(), &val)); | TS_ASSERT(script.Eval(input.c_str(), &val)); | ||||
std::string stringified = script.StringifyJSON(&val); | std::string stringified = script.StringifyJSON(&val); | ||||
TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\": 1,\n \"z\": [\n 2,\n \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n ],\n \"y\": true\n}"); | TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\": 1,\n \"z\": [\n 2,\n \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n ],\n \"y\": true\n}"); | ||||
TS_ASSERT(script.ParseJSON(stringified, &val)); | TS_ASSERT(script.ParseJSON(stringified, &val)); | ||||
TS_ASSERT_STR_EQUALS(script.ToString(&val), "({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})"); | TS_ASSERT_STR_EQUALS(script.ToString(&val), "({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})"); | ||||
} | } | ||||
// This function tests a common way to mod functions, by crating a wrapper that | // This function tests a common way to mod functions, by crating a wrapper that | ||||
// extends the functionality and is then assigned to the name of the function. | // extends the functionality and is then assigned to the name of the function. | ||||
void test_function_override() | void test_function_override() | ||||
{ | { | ||||
ScriptInterface script("Test", "Test", g_ScriptRuntime); | ScriptInterface script("Test", "Test", g_ScriptContext); | ||||
ScriptInterface::Request rq(script); | ScriptInterface::Request rq(script); | ||||
TS_ASSERT(script.Eval( | TS_ASSERT(script.Eval( | ||||
"function f() { return 1; }" | "function f() { return 1; }" | ||||
"f = (function (originalFunction) {" | "f = (function (originalFunction) {" | ||||
"return function () { return originalFunction() + 1; }" | "return function () { return originalFunction() + 1; }" | ||||
"})(f);" | "})(f);" | ||||
)); | )); | ||||
Show All 9 Lines |
Wildfire Games · Phabricator