mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-06 12:03:39 +00:00
212 lines
5.7 KiB
C++
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
|