Blender V4.5
main_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "testing/testing.h"
5
6#include "CLG_log.h"
7
8#include "BLI_listbase.h"
9#include "BLI_path_utils.hh"
10#include "BLI_string.h"
11
12#include "BKE_collection.hh"
13#include "BKE_idtype.hh"
14#include "BKE_lib_id.hh"
15#include "BKE_library.hh"
16#include "BKE_main.hh"
17
18#include "DNA_ID.h"
20#include "DNA_object_types.h"
21
22namespace blender::bke::tests {
23
24class BMainTest : public testing::Test {
25 public:
26 static void SetUpTestSuite()
27 {
28 CLG_init();
30 }
31 static void TearDownTestSuite()
32 {
33 CLG_exit();
34 }
35};
36
37class BMainMergeTest : public BMainTest {
38 public:
39 void SetUp() override
40 {
43 }
44
45 void TearDown() override
46 {
47 if (bmain_src) {
49 }
50 if (bmain_dst) {
52 }
53 }
54
57};
58
60{
61 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_dst->libraries));
62 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_dst->collections));
63 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_dst->objects));
64
65 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_src->libraries));
66 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_src->collections));
67 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_src->objects));
68
69 BKE_id_new(bmain_dst, ID_GR, "Coll_dst");
70 Collection *coll = BKE_id_new<Collection>(bmain_src, "Coll_src");
71 Object *ob = BKE_id_new<Object>(bmain_src, "Ob_src");
72 BKE_collection_object_add(bmain_src, coll, ob);
73
74 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->collections));
75 EXPECT_EQ(0, BLI_listbase_count(&bmain_dst->objects));
76 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->collections));
77 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->objects));
78
80 BKE_main_merge(bmain_dst, &bmain_src, reports);
81
82 EXPECT_EQ(2, BLI_listbase_count(&bmain_dst->collections));
83 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->objects));
84 EXPECT_EQ(2, reports.num_merged_ids);
85 EXPECT_EQ(0, reports.num_unknown_ids);
86 EXPECT_EQ(0, reports.num_remapped_ids);
87 EXPECT_EQ(0, reports.num_remapped_libraries);
88 EXPECT_EQ(nullptr, bmain_src);
89
90 bmain_src = BKE_main_new();
91 Collection *coll_2 = BKE_id_new<Collection>(bmain_src, "Coll_src_2");
92 Object *ob_2 = BKE_id_new<Object>(bmain_src, "Ob_src");
93 BKE_collection_object_add(bmain_src, coll_2, ob_2);
94
95 EXPECT_EQ(2, BLI_listbase_count(&bmain_dst->collections));
96 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->objects));
97 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->collections));
98 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->objects));
99
100 reports = {};
101 BKE_main_merge(bmain_dst, &bmain_src, reports);
102
103 /* The second `Ob_src` object in `bmain_src` cannot be merged in `bmain_dst`, since its name
104 * would collide with the first object. */
105 EXPECT_EQ(3, BLI_listbase_count(&bmain_dst->collections));
106 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->objects));
107 EXPECT_EQ(1, reports.num_merged_ids);
108 EXPECT_EQ(0, reports.num_unknown_ids);
109 EXPECT_EQ(1, reports.num_remapped_ids);
110 EXPECT_EQ(0, reports.num_remapped_libraries);
111 EXPECT_EQ(nullptr, bmain_src);
112
113 /* `Coll_src_2` should have been remapped to using `Ob_src` in `bmain_dst`, instead of `Ob_src`
114 * in `bmain_src`. */
116 EXPECT_EQ(ob, static_cast<CollectionObject *>(coll_2->gobject.first)->ob);
117}
118
120{
121#ifdef WIN32
122# define ABS_ROOT "C:" SEP_STR
123#else
124# define ABS_ROOT SEP_STR
125#endif
126 constexpr char DST_PATH[] = ABS_ROOT "tmp" SEP_STR "dst" SEP_STR "dst.blend";
127 constexpr char SRC_PATH[] = ABS_ROOT "tmp" SEP_STR "src" SEP_STR "src.blend";
128 constexpr char LIB_PATH[] = ABS_ROOT "tmp" SEP_STR "lib" SEP_STR "lib.blend";
129
130 constexpr char LIB_PATH_RELATIVE[] = "//lib" SEP_STR "lib.blend";
131 constexpr char LIB_PATH_RELATIVE_ABS_SRC[] = ABS_ROOT "tmp" SEP_STR "src" SEP_STR "lib" SEP_STR
132 "lib.blend";
133
134 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_dst->libraries));
135 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_dst->collections));
136 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_dst->objects));
137
138 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_src->libraries));
139 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_src->collections));
140 EXPECT_TRUE(BLI_listbase_is_empty(&bmain_src->objects));
141
142 STRNCPY(bmain_dst->filepath, DST_PATH);
143 STRNCPY(bmain_src->filepath, SRC_PATH);
144
145 BKE_id_new<Collection>(bmain_dst, "Coll_dst");
146
147 Collection *coll_1 = BKE_id_new<Collection>(bmain_src, "Coll_src");
148 Library *lib_src_1 = BKE_id_new<Library>(bmain_src, LIB_PATH);
149 BKE_library_filepath_set(bmain_src, lib_src_1, LIB_PATH);
150 Object *ob_1 = static_cast<Object *>(BKE_id_new_in_lib(bmain_src, lib_src_1, ID_OB, "Ob_src"));
151 BKE_collection_object_add(bmain_src, coll_1, ob_1);
152
153 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->collections));
154 EXPECT_EQ(0, BLI_listbase_count(&bmain_dst->objects));
155 EXPECT_EQ(0, BLI_listbase_count(&bmain_dst->libraries));
156 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->collections));
157 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->objects));
158 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->libraries));
159
161 BKE_main_merge(bmain_dst, &bmain_src, reports);
162
163 EXPECT_EQ(2, BLI_listbase_count(&bmain_dst->collections));
164 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->objects));
165 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->libraries));
166 EXPECT_EQ(ob_1, bmain_dst->objects.first);
167 EXPECT_EQ(lib_src_1, bmain_dst->libraries.first);
168 EXPECT_EQ(ob_1->id.lib, lib_src_1);
169 EXPECT_EQ(3, reports.num_merged_ids);
170 EXPECT_EQ(0, reports.num_unknown_ids);
171 EXPECT_EQ(0, reports.num_remapped_ids);
172 EXPECT_EQ(0, reports.num_remapped_libraries);
173 EXPECT_EQ(nullptr, bmain_src);
174
175 /* Try another merge, with the same library path - second library should be skipped, destination
176 * merge should still have only one library ID. */
177 bmain_src = BKE_main_new();
178 STRNCPY(bmain_src->filepath, SRC_PATH);
179
180 Collection *coll_2 = BKE_id_new<Collection>(bmain_src, "Coll_src_2");
181 Library *lib_src_2 = BKE_id_new<Library>(bmain_src, LIB_PATH);
182 BKE_library_filepath_set(bmain_src, lib_src_2, LIB_PATH);
183 std::cout << lib_src_1->runtime->filepath_abs << "\n";
184 std::cout << lib_src_2->runtime->filepath_abs << "\n";
185 Object *ob_2 = static_cast<Object *>(BKE_id_new_in_lib(bmain_src, lib_src_2, ID_OB, "Ob_src_2"));
186 BKE_collection_object_add(bmain_src, coll_2, ob_2);
187 Object *ob_2_2 = static_cast<Object *>(
188 BKE_id_new_in_lib(bmain_src, lib_src_2, ID_OB, "Ob_src_2_2"));
189 BKE_collection_object_add(bmain_src, coll_2, ob_2_2);
190
191 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->collections));
192 EXPECT_EQ(2, BLI_listbase_count(&bmain_src->objects));
193 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->libraries));
194
195 reports = {};
196 BKE_main_merge(bmain_dst, &bmain_src, reports);
197
198 EXPECT_EQ(3, BLI_listbase_count(&bmain_dst->collections));
199 EXPECT_EQ(3, BLI_listbase_count(&bmain_dst->objects));
200 EXPECT_EQ(1, BLI_listbase_count(&bmain_dst->libraries));
201 EXPECT_EQ(ob_1, bmain_dst->objects.first);
202 EXPECT_EQ(ob_2_2, bmain_dst->objects.last);
203 EXPECT_EQ(lib_src_1, bmain_dst->libraries.first);
204 EXPECT_EQ(ob_1->id.lib, lib_src_1);
205 EXPECT_EQ(ob_2->id.lib, lib_src_1);
206 EXPECT_EQ(ob_2_2->id.lib, lib_src_1);
207 EXPECT_EQ(3, reports.num_merged_ids);
208 EXPECT_EQ(0, reports.num_unknown_ids);
209 EXPECT_EQ(0, reports.num_remapped_ids);
210 EXPECT_EQ(1, reports.num_remapped_libraries);
211 EXPECT_EQ(nullptr, bmain_src);
212
213 /* Use a relative library path. Since this is a different library, even though the object re-use
214 * the same name, it should still be moved into `bmain_dst`. The library filepath should also be
215 * updated and become relative the path of bmain_dst too. */
216 bmain_src = BKE_main_new();
217 STRNCPY(bmain_src->filepath, SRC_PATH);
218
219 Collection *coll_3 = BKE_id_new<Collection>(bmain_src, "Coll_src_3");
220 Library *lib_src_3 = BKE_id_new<Library>(bmain_src, LIB_PATH_RELATIVE);
221 BKE_library_filepath_set(bmain_src, lib_src_3, LIB_PATH_RELATIVE);
222 Object *ob_3 = static_cast<Object *>(BKE_id_new_in_lib(bmain_src, lib_src_3, ID_OB, "Ob_src"));
223 BKE_collection_object_add(bmain_src, coll_3, ob_3);
224
225 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->collections));
226 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->objects));
227 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->libraries));
228 EXPECT_TRUE(STREQ(lib_src_3->filepath, LIB_PATH_RELATIVE));
229 EXPECT_TRUE(STREQ(lib_src_3->runtime->filepath_abs, LIB_PATH_RELATIVE_ABS_SRC));
230
231 reports = {};
232 BKE_main_merge(bmain_dst, &bmain_src, reports);
233
234 EXPECT_EQ(4, BLI_listbase_count(&bmain_dst->collections));
235 EXPECT_EQ(4, BLI_listbase_count(&bmain_dst->objects));
236 EXPECT_EQ(2, BLI_listbase_count(&bmain_dst->libraries));
237 EXPECT_EQ(ob_1, bmain_dst->objects.first);
238 EXPECT_EQ(ob_3, bmain_dst->objects.last);
239 EXPECT_EQ(lib_src_3, bmain_dst->libraries.first);
240 EXPECT_EQ(lib_src_1, bmain_dst->libraries.last);
241 EXPECT_EQ(ob_1->id.lib, lib_src_1);
242 EXPECT_EQ(ob_2->id.lib, lib_src_1);
243 EXPECT_EQ(ob_2_2->id.lib, lib_src_1);
244 EXPECT_EQ(ob_3->id.lib, lib_src_3);
245 EXPECT_FALSE(STREQ(lib_src_3->filepath, LIB_PATH_RELATIVE));
246 EXPECT_TRUE(STREQ(lib_src_3->runtime->filepath_abs, LIB_PATH_RELATIVE_ABS_SRC));
247 EXPECT_EQ(3, reports.num_merged_ids);
248 EXPECT_EQ(0, reports.num_unknown_ids);
249 EXPECT_EQ(0, reports.num_remapped_ids);
250 EXPECT_EQ(0, reports.num_remapped_libraries);
251 EXPECT_EQ(nullptr, bmain_src);
252
253 /* Try another merge, with the library path set to the path of the destination bmain. That source
254 * library should also be skipped, and the 'linked' object in source bmain should become a local
255 * object in destination bmain. */
256 bmain_src = BKE_main_new();
257 STRNCPY(bmain_src->filepath, SRC_PATH);
258
259 Library *lib_src_4 = BKE_id_new<Library>(bmain_src, DST_PATH);
260 BKE_library_filepath_set(bmain_src, lib_src_4, DST_PATH);
261 Collection *coll_4 = static_cast<Collection *>(
262 BKE_id_new_in_lib(bmain_src, lib_src_4, ID_GR, "Coll_src"));
263 Object *ob_4 = static_cast<Object *>(BKE_id_new_in_lib(bmain_src, lib_src_4, ID_OB, "Ob_src_4"));
264 BKE_collection_object_add(bmain_src, coll_4, ob_4);
265
266 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->collections));
267 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->objects));
268 EXPECT_EQ(1, BLI_listbase_count(&bmain_src->libraries));
269
270 reports = {};
271 BKE_main_merge(bmain_dst, &bmain_src, reports);
272
273 /* `bmain_dst` is unchanged, since both `coll_4` and `ob_4` were defined as linked from
274 * `bmain_dst`. */
275 EXPECT_EQ(4, BLI_listbase_count(&bmain_dst->collections));
276 EXPECT_EQ(4, BLI_listbase_count(&bmain_dst->objects));
277 EXPECT_EQ(2, BLI_listbase_count(&bmain_dst->libraries));
278 EXPECT_EQ(lib_src_3, bmain_dst->libraries.first);
279 EXPECT_EQ(lib_src_1, bmain_dst->libraries.last);
280 EXPECT_EQ(ob_1->id.lib, lib_src_1);
281 EXPECT_EQ(ob_2->id.lib, lib_src_1);
282 EXPECT_EQ(ob_2_2->id.lib, lib_src_1);
283 EXPECT_EQ(ob_3->id.lib, lib_src_3);
284 EXPECT_EQ(0, reports.num_merged_ids);
285 EXPECT_EQ(1, reports.num_unknown_ids);
286 EXPECT_EQ(1, reports.num_remapped_ids);
287 EXPECT_EQ(1, reports.num_remapped_libraries);
288 EXPECT_EQ(nullptr, bmain_src);
289}
290
291} // namespace blender::bke::tests
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
void BKE_idtype_init()
Definition idtype.cc:122
void * BKE_id_new_in_lib(Main *bmain, std::optional< Library * > owner_library, short type, const char *name)
Definition lib_id.cc:1477
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1495
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
Definition library.cc:171
void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &reports)
Definition main.cc:321
Main * BKE_main_new()
Definition main.cc:48
void BKE_main_free(Main *bmain)
Definition main.cc:175
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define STREQ(a, b)
void CLG_exit(void)
Definition clog.c:704
void CLG_init(void)
Definition clog.c:697
ID and Library types, which are fundamental for SDNA.
@ ID_GR
@ ID_OB
Object groups, one object can be in many groups at once.
Object is a sort of wrapper for general info.
ReportList * reports
Definition WM_types.hh:1025
#define ABS_ROOT
TEST_F(BKE_armature_find_selected_bones_test, some_bones_selected)
struct Library * lib
Definition DNA_ID.h:410
char filepath[1024]
Definition DNA_ID.h:507
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:516
void * first
#define SEP_STR
Definition unit.cc:39