LiteLoaderBDS-1.16.40/Tools/ScriptX/test/src/ExceptionTest.cc
2023-03-03 10:18:21 -08:00

212 lines
5.7 KiB
C++

/*
* Tencent is pleased to support the open source community by making ScriptX available.
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "test.h"
namespace script::test {
DEFINE_ENGINE_TEST(ExceptionTest);
TEST_F(ExceptionTest, Normal) {
{
// ok
EngineScope engineScope(engine);
try {
throw Exception("inside");
} catch (const Exception&) {
}
}
}
TEST_F(ExceptionTest, ExceptionOutOfEngineScope) {
try {
EngineScope engineScope(engine);
throw Exception("inside");
// exception go out of engine scope, still ok
} catch (const Exception&) {
}
}
TEST_F(ExceptionTest, Function) {
EngineScope engineScope(engine);
try {
EXPECT_THROW(
{
engine->eval(TS().js("throw Error('hello error')").lua("error('hello error')").select());
},
Exception);
auto func = Function::newFunction([](const script::Arguments& args) {
if (args.size() == 0) {
throw Exception("invalid argument");
}
return Number::newNumber(0);
});
func.call({}, {Object::newObject()});
EXPECT_THROW({ func.call({}); }, Exception);
engine->set("func", func);
Local<Value> ret;
ret = engine->eval(TS().js(R"(
try {
func();
false;
} catch (e) {
true;
}
)")
.lua(R"(
return not pcall(func)
)")
.select());
EXPECT_TRUE(ret.isBoolean());
EXPECT_TRUE(ret.asBoolean().value());
engine->set("func", {});
try {
func.call({});
FAIL();
} catch (Exception& e) {
EXPECT_NE(e.message().find("invalid argument"), std::string::npos);
}
} catch (Exception& exception) {
FAIL() << exception.message() << exception.stacktrace();
}
}
TEST_F(ExceptionTest, StackTrace) {
EngineScope engineScope(engine);
Local<Value> func;
func = engine->eval(TS().js(R"(
function exceptionStackTraceTestThrow() {
throw new Error("recursive too deep");
}
function exceptionStackTraceTest(depth) {
if (depth >= 10) exceptionStackTraceTestThrow();
exceptionStackTraceTest(depth + 1);
}
exceptionStackTraceTest;
)")
.lua(R"(
function exceptionStackTraceTestThrow()
error("recursive too deep")
end
function exceptionStackTraceTest(depth)
if depth >= 10 then exceptionStackTraceTestThrow() end
exceptionStackTraceTest(depth + 1)
end
return exceptionStackTraceTest
)")
.select());
try {
#ifdef SCRIPTX_BACKEND_QUICKJS
// update max stack size for QuickJs
// otherwise a "stack overflow" maybe thrown
// even we have limited to 10 layers of recursion.
JS_SetMaxStackSize(qjs_interop::currentRuntime(), 1024 * 1024);
#endif
func.asFunction().call({}, Number::newNumber(0));
FAIL() << "should thrown";
} catch (const Exception& e) {
EXPECT_NE(e.message().find("recursive too deep"), std::string::npos) << e;
EXPECT_NE(e.stacktrace().find("exceptionStackTraceTestThrow"), std::string::npos) << e;
EXPECT_NE(e.stacktrace().find("exceptionStackTraceTest"), std::string::npos) << e;
}
Exception().stacktrace();
std::ostringstream() << Exception();
}
TEST_F(ExceptionTest, Cross) {
EngineScope engineScope(engine);
Exception e("test");
EXPECT_NE(e.message().find("test"), std::string::npos);
EXPECT_NE(std::string(e.what()).find("test"), std::string::npos);
auto exception = e.exception();
try {
EXPECT_FALSE(exception.isNull());
auto throwIt = engine->eval(TS().js("function throwIt(e) { throw e; }; throwIt")
.lua("return function (e) error(e) end;")
.select());
throwIt.asFunction().call({}, exception);
} catch (Exception& ex) {
EXPECT_NE(ex.message().find("test"), std::string::npos);
#ifdef SCRIPTX_LANG_JAVASCRIPT
EXPECT_TRUE(exception == ex.exception());
#endif
#ifdef SCRIPTX_LANG_LUA
auto exException = ex.exception();
EXPECT_TRUE(exException.isObject());
EXPECT_NE(exException.asObject().get("message").asString().toString().find(
exception.asString().toString()),
std::string::npos);
#endif
}
{
Exception ex(String::newString("test"));
EXPECT_NE(ex.message().find("test"), std::string::npos);
}
}
#ifndef SCRIPTX_BACKEND_WEBASSEMBLY
TEST_F(ExceptionTest, EngineScopeOnDestroy) {
bool executed = false;
{
EngineScope engineScope(engine);
utils::Message m([](auto msg) {},
[](auto msg) {
*static_cast<bool*>(msg.ptr0) = true;
EXPECT_THROW({ EngineScope scope(static_cast<ScriptEngine*>(msg.ptr1)); },
std::logic_error);
});
m.tag = engine;
m.ptr0 = &executed;
m.ptr1 = engine;
engine->messageQueue()->postMessage(m);
}
destroyEngine();
EXPECT_TRUE(executed);
}
#endif
TEST_F(ExceptionTest, ThrowPerformance) {
std::string chunk;
chunk.resize(1024, '.');
EngineScope engineScope(engine);
for (int i = 0; i < 1000; ++i) {
try {
throw Exception(chunk);
} catch (Exception&) {
}
}
}
} // namespace script::test