/**************************************************************************/1/* test_packed_scene.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "tests/test_macros.h"3132TEST_FORCE_LINK(test_packed_scene)3334#include "core/object/callable_mp.h"35#include "scene/resources/packed_scene.h"3637namespace TestPackedScene {3839TEST_CASE("[PackedScene] Pack Scene and Retrieve State") {40// Create a scene to pack.41Node *scene = memnew(Node);42scene->set_name("TestScene");4344// Pack the scene.45PackedScene packed_scene;46const Error err = packed_scene.pack(scene);47CHECK(err == OK);4849// Retrieve the packed state.50Ref<SceneState> state = packed_scene.get_state();51CHECK(state.is_valid());52CHECK(state->get_node_count() == 1);53CHECK(state->get_node_name(0) == "TestScene");5455memdelete(scene);56}5758TEST_CASE("[PackedScene] Signals Preserved when Packing Scene") {59// Create main scene60// root61// `- sub_node (local)62// `- sub_scene (instance of another scene)63// `- sub_scene_node (owned by sub_scene)64Node *main_scene_root = memnew(Node);65Node *sub_node = memnew(Node);66Node *sub_scene_root = memnew(Node);67Node *sub_scene_node = memnew(Node);6869main_scene_root->add_child(sub_node);70sub_node->set_owner(main_scene_root);7172sub_scene_root->add_child(sub_scene_node);73sub_scene_node->set_owner(sub_scene_root);7475main_scene_root->add_child(sub_scene_root);76sub_scene_root->set_owner(main_scene_root);7778SUBCASE("Signals that should be saved") {79int main_flags = Object::CONNECT_PERSIST;80// sub node to a node in main scene81sub_node->connect("ready", callable_mp(main_scene_root, &Node::is_ready), main_flags);82// subscene root to a node in main scene83sub_scene_root->connect("ready", callable_mp(main_scene_root, &Node::is_ready), main_flags);84//subscene root to subscene root (connected within main scene)85sub_scene_root->connect("ready", callable_mp(sub_scene_root, &Node::is_ready), main_flags);8687// Pack the scene.88Ref<PackedScene> packed_scene;89packed_scene.instantiate();90const Error err = packed_scene->pack(main_scene_root);91CHECK(err == OK);9293// Make sure the right connections are in packed scene.94Ref<SceneState> state = packed_scene->get_state();95CHECK_EQ(state->get_connection_count(), 3);96}9798/*99// FIXME: This subcase requires GH-48064 to be fixed.100SUBCASE("Signals that should not be saved") {101int subscene_flags = Object::CONNECT_PERSIST | Object::CONNECT_INHERITED;102// subscene node to itself103sub_scene_node->connect("ready", callable_mp(sub_scene_node, &Node::is_ready), subscene_flags);104// subscene node to subscene root105sub_scene_node->connect("ready", callable_mp(sub_scene_root, &Node::is_ready), subscene_flags);106//subscene root to subscene root (connected within sub scene)107sub_scene_root->connect("ready", callable_mp(sub_scene_root, &Node::is_ready), subscene_flags);108109// Pack the scene.110Ref<PackedScene> packed_scene;111packed_scene.instantiate();112const Error err = packed_scene->pack(main_scene_root);113CHECK(err == OK);114115// Make sure the right connections are in packed scene.116Ref<SceneState> state = packed_scene->get_state();117CHECK_EQ(state->get_connection_count(), 0);118}119*/120121memdelete(main_scene_root);122}123124TEST_CASE("[PackedScene] Clear Packed Scene") {125// Create a scene to pack.126Node *scene = memnew(Node);127scene->set_name("TestScene");128129// Pack the scene.130PackedScene packed_scene;131packed_scene.pack(scene);132133// Clear the packed scene.134packed_scene.clear();135136// Check if it has been cleared.137Ref<SceneState> state = packed_scene.get_state();138CHECK_FALSE(state->get_node_count() == 1);139140memdelete(scene);141}142143TEST_CASE("[PackedScene] Can Instantiate Packed Scene") {144// Create a scene to pack.145Node *scene = memnew(Node);146scene->set_name("TestScene");147148// Pack the scene.149PackedScene packed_scene;150packed_scene.pack(scene);151152// Check if the packed scene can be instantiated.153const bool can_instantiate = packed_scene.can_instantiate();154CHECK(can_instantiate == true);155156memdelete(scene);157}158159TEST_CASE("[PackedScene] Instantiate Packed Scene") {160// Create a scene to pack.161Node *scene = memnew(Node);162scene->set_name("TestScene");163164// Pack the scene.165PackedScene packed_scene;166packed_scene.pack(scene);167168// Instantiate the packed scene.169Node *instance = packed_scene.instantiate();170CHECK(instance != nullptr);171CHECK(instance->get_name() == "TestScene");172173memdelete(scene);174memdelete(instance);175}176177TEST_CASE("[PackedScene] Instantiate Packed Scene With Children") {178// Create a scene to pack.179Node *scene = memnew(Node);180scene->set_name("TestScene");181182// Add persisting child nodes to the scene.183Node *child1 = memnew(Node);184child1->set_name("Child1");185scene->add_child(child1);186child1->set_owner(scene);187188Node *child2 = memnew(Node);189child2->set_name("Child2");190scene->add_child(child2);191child2->set_owner(scene);192193// Add non persisting child node to the scene.194Node *child3 = memnew(Node);195child3->set_name("Child3");196scene->add_child(child3);197198// Pack the scene.199PackedScene packed_scene;200packed_scene.pack(scene);201202// Instantiate the packed scene.203Node *instance = packed_scene.instantiate();204CHECK(instance != nullptr);205CHECK(instance->get_name() == "TestScene");206207// Validate the child nodes of the instantiated scene.208CHECK(instance->get_child_count() == 2);209CHECK(instance->get_child(0)->get_name() == "Child1");210CHECK(instance->get_child(1)->get_name() == "Child2");211CHECK(instance->get_child(0)->get_owner() == instance);212CHECK(instance->get_child(1)->get_owner() == instance);213214memdelete(scene);215memdelete(instance);216}217218TEST_CASE("[PackedScene] Set Path") {219// Create a scene to pack.220Node *scene = memnew(Node);221scene->set_name("TestScene");222223// Pack the scene.224PackedScene packed_scene;225packed_scene.pack(scene);226227// Set a new path for the packed scene.228const String new_path = "NewTestPath";229packed_scene.set_path(new_path);230231// Check if the path has been set correctly.232Ref<SceneState> state = packed_scene.get_state();233CHECK(state.is_valid());234CHECK(state->get_path() == new_path);235236memdelete(scene);237}238239TEST_CASE("[PackedScene] Replace State") {240// Create a scene to pack.241Node *scene = memnew(Node);242scene->set_name("TestScene");243244// Pack the scene.245PackedScene packed_scene;246packed_scene.pack(scene);247248// Create another scene state to replace with.249Ref<SceneState> new_state = memnew(SceneState);250new_state->set_path("NewPath");251252// Replace the state.253packed_scene.replace_state(new_state);254255// Check if the state has been replaced.256Ref<SceneState> state = packed_scene.get_state();257CHECK(state.is_valid());258CHECK(state == new_state);259260memdelete(scene);261}262263TEST_CASE("[PackedScene] Recreate State") {264// Create a scene to pack.265Node *scene = memnew(Node);266scene->set_name("TestScene");267268// Pack the scene.269Ref<PackedScene> packed_scene;270packed_scene.instantiate();271packed_scene->pack(scene);272273// Recreate the state.274packed_scene->recreate_state();275276// Check if the state has been recreated.277Ref<SceneState> state = packed_scene->get_state();278CHECK(state.is_valid());279CHECK(state->get_node_count() == 0); // Since the state was recreated, it should be empty.280281memdelete(scene);282}283284} // namespace TestPackedScene285286287