/* * 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(ManagedObjectTest); namespace { static void* instance = nullptr; class Trace : public ScriptClass { public: explicit Trace(const Local& thiz) : ScriptClass(thiz) { EXPECT_EQ(instance, nullptr); instance = this; } ~Trace() override { EXPECT_EQ(instance, this); instance = nullptr; } }; ClassDefine trace = defineClass("Trace").constructor().build(); } // namespace TEST_F(ManagedObjectTest, EngineDispose) { { EngineScope engineScope(engine); { Global leak; StackFrameScope stack; engine->registerNativeClass(trace); auto local = engine->newNativeClass(); leak = Global(local); EXPECT_TRUE(instance != nullptr); } } destroyEngine(); EXPECT_EQ(instance, nullptr); } namespace { class DestructWithGc : public ScriptClass { public: explicit DestructWithGc(const Local& thiz) : ScriptClass(thiz) {} protected: ~DestructWithGc() override { getScriptEngine()->gc(); } }; ClassDefine def = defineClass("X").constructor().build(); } // namespace TEST_F(ManagedObjectTest, EngineDisposeWithGc) { { EngineScope engineScope(engine); { Global leak; StackFrameScope stack; engine->registerNativeClass(def); auto local = engine->newNativeClass(); leak = Global(local); } } } TEST_F(ManagedObjectTest, CallGcWhilGc) { { EngineScope engineScope(engine); { Global leak; StackFrameScope stack; engine->registerNativeClass(def); auto local = engine->newNativeClass(); leak = Global(local); } } engine->gc(); } #ifdef SCRIPTX_BACKEND_V8 // V8Engine specific test TEST_F(ManagedObjectTest, EngineDisposeWithSlave) { { auto slave = static_cast(engine)->newSlaveEngine(); EngineScope engineScope(slave.get()); { slave->registerNativeClass(trace); Global leak; StackFrameScope stack; auto local = slave->newNativeClass(); leak = Global(local); EXPECT_TRUE(instance != nullptr); } } EXPECT_EQ(instance, nullptr); // gc should not destruct ScriptClass twice } #endif namespace { void* functionCallback = nullptr; class FunctionCallbackTest { bool live_; public: FunctionCallbackTest() : live_(true) { EXPECT_EQ(functionCallback, nullptr); functionCallback = this; } FunctionCallbackTest(const FunctionCallbackTest& copy) : live_(true) { functionCallback = this; } FunctionCallbackTest(FunctionCallbackTest&& move) noexcept : live_(move.live_) { move.live_ = false; if (live_) functionCallback = this; } Local operator()(const Arguments& args) { return Boolean::newBoolean(true); } ~FunctionCallbackTest() { if (live_) { EXPECT_EQ(functionCallback, this); functionCallback = nullptr; } } }; } // namespace TEST_F(ManagedObjectTest, FunctionCallback) { { EngineScope engineScope(engine); { // when use std::function with functor // be careful with move-constructor! auto function = Function::newFunction(FunctionCallbackTest()); EXPECT_TRUE(functionCallback != nullptr); } } destroyEngine(); EXPECT_EQ(functionCallback, nullptr); } } // namespace script::test