Files
test/source/blender/blenkernel/intern/scene_test.cc
Bastien Montagne 861a174a82 Fix #148220: Scene 'Linked Copy' does not remap to newly copied data-block.
While more of a theoritical issue currently, this change is a
pre-requisite to support properly compo nodes duplication in 'linked
copy' case (see !148210).

Also add a basic unittest for this case.

Pull Request: https://projects.blender.org/blender/blender/pulls/148222
2025-10-17 14:17:42 +02:00

157 lines
5.6 KiB
C++

/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_anim_data.hh"
#include "BKE_appdir.hh"
#include "BKE_idprop.hh"
#include "BKE_idtype.hh"
#include "BKE_lib_id.hh"
#include "BKE_main.hh"
#include "BKE_scene.hh"
#include "BLO_userdef_default.h"
#include "IMB_imbuf.hh"
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "CLG_log.h"
#include "testing/testing.h"
namespace blender::bke::tests {
TEST(scene, frame_snap_by_seconds)
{
Scene fake_scene = {};
/* Regular 24 FPS snapping. */
fake_scene.r.frs_sec = 24;
fake_scene.r.frs_sec_base = 1.0;
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 47));
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 49));
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 59));
EXPECT_FLOAT_EQ(72.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 60));
EXPECT_FLOAT_EQ(9984.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 2.0, 10000.0));
/* 12 FPS snapping by incrementing the base. */
fake_scene.r.frs_sec = 24;
fake_scene.r.frs_sec_base = 2.0;
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 47));
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 49));
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 53));
EXPECT_FLOAT_EQ(60.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 54));
EXPECT_FLOAT_EQ(9996.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 1.0, 10000.0));
/* 0.1 FPS snapping to 2-second intervals. */
fake_scene.r.frs_sec = 1;
fake_scene.r.frs_sec_base = 10.0;
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 2.0, 48.0));
EXPECT_FLOAT_EQ(48.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 2.0, 48.1));
EXPECT_FLOAT_EQ(48.2, BKE_scene_frame_snap_by_seconds(&fake_scene, 2.0, 48.2));
EXPECT_FLOAT_EQ(10000.0, BKE_scene_frame_snap_by_seconds(&fake_scene, 2.0, 10000.0));
}
class SceneTest : public ::testing::Test {
public:
Main *bmain;
static void SetUpTestSuite()
{
CLG_init();
BKE_appdir_init();
IMB_init();
BKE_idtype_init();
/* #BKE_scene_duplicate() uses #U::dupflag. */
U = blender::dna::shallow_copy(U_default);
}
static void TearDownTestSuite()
{
IMB_exit();
BKE_appdir_exit();
CLG_exit();
}
void SetUp() override
{
bmain = BKE_main_new();
}
void TearDown() override
{
BKE_main_free(bmain);
}
};
TEST_F(SceneTest, linked_copy_id_remapping)
{
Scene *scene_src = BKE_id_new<Scene>(bmain, "Scene_source");
bAction *action_src = BKE_id_new<bAction>(bmain, "Scene_source_action");
BKE_animdata_set_action(nullptr, &scene_src->id, action_src);
AnimData *animdata_src = BKE_animdata_from_id(&scene_src->id);
ASSERT_NE(animdata_src, nullptr);
EXPECT_EQ(animdata_src->action, action_src);
constexpr blender::StringRef idp_scene2scene_name = "scene2scene";
constexpr blender::StringRef idp_scene2action_name = "scene2action";
constexpr blender::StringRef idp_action2scene_name = "action2scene";
constexpr blender::StringRef idp_action2action_name = "action2action";
IDProperty *scene_idgroup_src = IDP_EnsureProperties(&scene_src->id);
IDP_AddToGroup(scene_idgroup_src,
bke::idprop::create(idp_scene2scene_name, &scene_src->id).release());
IDP_AddToGroup(scene_idgroup_src,
bke::idprop::create(idp_scene2action_name, &action_src->id).release());
IDProperty *action_idgroup_src = IDP_EnsureProperties(&action_src->id);
IDP_AddToGroup(action_idgroup_src,
bke::idprop::create(idp_action2scene_name, &scene_src->id).release());
IDP_AddToGroup(action_idgroup_src,
bke::idprop::create(idp_action2action_name, &action_src->id).release());
Scene *scene_copy = BKE_scene_duplicate(bmain, scene_src, SCE_COPY_LINK_COLLECTION);
/* Source data should remain unchanged. */
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(scene_idgroup_src, idp_scene2scene_name)),
&scene_src->id);
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(scene_idgroup_src, idp_scene2action_name)),
&action_src->id);
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(action_idgroup_src, idp_action2scene_name)),
&scene_src->id);
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(action_idgroup_src, idp_action2action_name)),
&action_src->id);
/* Copied data should have its ID usages remapped to new copies if possible. */
EXPECT_NE(scene_copy, scene_src);
AnimData *animdata_copy = BKE_animdata_from_id(&scene_copy->id);
ASSERT_NE(animdata_copy, nullptr);
EXPECT_NE(animdata_copy, animdata_src);
bAction *action_copy = animdata_copy->action;
ASSERT_NE(action_copy, nullptr);
EXPECT_NE(action_copy, action_src);
IDProperty *scene_idgroup_copy = IDP_GetProperties(&scene_copy->id);
ASSERT_NE(scene_idgroup_copy, nullptr);
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(scene_idgroup_copy, idp_scene2scene_name)),
&scene_copy->id);
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(scene_idgroup_copy, idp_scene2action_name)),
&action_copy->id);
IDProperty *action_idgroup_copy = IDP_GetProperties(&action_copy->id);
ASSERT_NE(action_idgroup_copy, nullptr);
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(action_idgroup_copy, idp_action2scene_name)),
&scene_copy->id);
EXPECT_EQ(IDP_ID_get(IDP_GetPropertyFromGroup(action_idgroup_copy, idp_action2action_name)),
&action_copy->id);
}
} // namespace blender::bke::tests