Blender V4.3
lib_id_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "testing/testing.h"
5
6#include "MEM_guardedalloc.h"
7
8#include "BLI_listbase.h"
9#include "BLI_string.h"
10
11#include "BKE_idtype.hh"
12#include "BKE_lib_id.hh"
13#include "BKE_main.hh"
14#include "BKE_main_namemap.hh"
15
16#include "DNA_ID.h"
17#include "DNA_mesh_types.h"
18#include "DNA_object_types.h"
19
20namespace blender::bke::tests {
21
35
36static void test_lib_id_main_sort_check_order(std::initializer_list<ID *> list)
37{
38 ID *prev_id = nullptr;
39 for (ID *id : list) {
40 EXPECT_EQ(id->prev, prev_id);
41 if (prev_id != nullptr) {
42 EXPECT_EQ(prev_id->next, id);
43 }
44 prev_id = id;
45 }
46 EXPECT_EQ(prev_id->next, nullptr);
47}
48
49TEST(lib_id_main_sort, local_ids_1)
50{
52 EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
53
54 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
55 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
56 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
57 EXPECT_TRUE(ctx.bmain->objects.first == id_a);
58 EXPECT_TRUE(ctx.bmain->objects.last == id_c);
59 test_lib_id_main_sort_check_order({id_a, id_b, id_c});
60
61 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
62}
63
64static void change_lib(Main *bmain, ID *id, Library *lib)
65{
66 if (id->lib == lib) {
67 return;
68 }
69 BKE_main_namemap_remove_name(bmain, id, id->name + 2);
70 id->lib = lib;
71 BKE_main_namemap_get_name(bmain, id, id->name + 2, false);
72}
73
74static IDNewNameResult change_name(Main *bmain, ID *id, const char *name, const IDNewNameMode mode)
75{
76 return BKE_libblock_rename(*bmain, *id, name, mode);
77}
78
79TEST(lib_id_main_sort, linked_ids_1)
80{
82 EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
83
84 Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A"));
85 Library *lib_b = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_B"));
86 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
87 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
88 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
89
90 change_lib(ctx.bmain, id_a, lib_a);
91 id_sort_by_name(&ctx.bmain->objects, id_a, nullptr);
92 change_lib(ctx.bmain, id_b, lib_a);
93 id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
94 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
95 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
96 test_lib_id_main_sort_check_order({id_c, id_a, id_b});
97
98 change_lib(ctx.bmain, id_a, lib_b);
99 id_sort_by_name(&ctx.bmain->objects, id_a, nullptr);
100 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
101 EXPECT_TRUE(ctx.bmain->objects.last == id_a);
102 test_lib_id_main_sort_check_order({id_c, id_b, id_a});
103
104 change_lib(ctx.bmain, id_b, lib_b);
105 id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
106 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
107 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
108 test_lib_id_main_sort_check_order({id_c, id_a, id_b});
109
110 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
111
112 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
113}
114
115TEST(lib_id_main_unique_name, local_ids_rename_existing_never)
116{
118 EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
119
120 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
121 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
122 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
123 test_lib_id_main_sort_check_order({id_a, id_b, id_c});
124
125 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
126
128
129 /* Rename to different root name. */
130 result = change_name(ctx.bmain, id_c, "OB_A", IDNewNameMode::RenameExistingNever);
131
133 // EXPECT_EQ(result.other_id, id_a); /* other_id purposely not looked-up currently. */
134 EXPECT_EQ(result.other_id, nullptr);
135 EXPECT_STREQ(id_c->name + 2, "OB_A.001");
136 EXPECT_STREQ(id_a->name + 2, "OB_A");
137 EXPECT_TRUE(ctx.bmain->objects.first == id_a);
138 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
139 test_lib_id_main_sort_check_order({id_a, id_c, id_b});
140
141 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
142
143 /* Rename to same root name. */
144 result = change_name(ctx.bmain, id_c, "OB_A", IDNewNameMode::RenameExistingNever);
145
147 // EXPECT_EQ(result.other_id, id_a); /* other_id purposely not looked-up currently. */
148 EXPECT_EQ(result.other_id, nullptr);
149 EXPECT_STREQ(id_c->name + 2, "OB_A.001");
150 EXPECT_STREQ(id_a->name + 2, "OB_A");
151 EXPECT_TRUE(ctx.bmain->objects.first == id_a);
152 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
153 test_lib_id_main_sort_check_order({id_a, id_c, id_b});
154
155 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
156
157 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
158
159 /* Test lower-level #BKE_main_namemap_get_name itself. */
160 /* Name already in use, needs additional numeric suffix. */
161 char future_name[MAX_ID_NAME - 2];
162 STRNCPY(future_name, "OB_B");
163 EXPECT_TRUE(BKE_main_namemap_get_name(ctx.bmain, id_c, future_name, false));
164 EXPECT_STREQ(future_name, "OB_B.001");
165 /* Name not already in use, no need to alter it. */
166 STRNCPY(future_name, "OB_BBBB");
167 EXPECT_FALSE(BKE_main_namemap_get_name(ctx.bmain, id_c, future_name, false));
168 EXPECT_STREQ(future_name, "OB_BBBB");
169 /* Name too long, needs to be truncated. */
170 STRNCPY(future_name, "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
172 EXPECT_STREQ(id_a->name + 2, future_name);
173 EXPECT_STREQ(future_name, "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
174 EXPECT_TRUE(BKE_main_namemap_get_name(ctx.bmain, id_c, future_name, false));
175 EXPECT_STREQ(future_name, "OB_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
176}
177
178TEST(lib_id_main_unique_name, local_ids_rename_existing_always)
179{
181 EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
182
183 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
184 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
185 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
186 test_lib_id_main_sort_check_order({id_a, id_b, id_c});
187
188 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
189
191
192 /* Rename to different root name. */
193 result = change_name(ctx.bmain, id_c, "OB_A", IDNewNameMode::RenameExistingAlways);
194
196 EXPECT_EQ(result.other_id, id_a);
197 EXPECT_STREQ(id_c->name + 2, "OB_A");
198 EXPECT_STREQ(id_a->name + 2, "OB_A.001");
199 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
200 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
201 test_lib_id_main_sort_check_order({id_c, id_a, id_b});
202
203 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
204
205 /* Rename to same root name. */
206 result = change_name(ctx.bmain, id_a, "OB_A", IDNewNameMode::RenameExistingAlways);
207
209 EXPECT_EQ(result.other_id, id_c);
210 EXPECT_STREQ(id_c->name + 2, "OB_A.001");
211 EXPECT_STREQ(id_a->name + 2, "OB_A");
212 EXPECT_TRUE(ctx.bmain->objects.first == id_a);
213 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
214 test_lib_id_main_sort_check_order({id_a, id_c, id_b});
215
216 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
217
218 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
219}
220
221TEST(lib_id_main_unique_name, local_ids_rename_existing_same_root)
222{
224 EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
225
226 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
227 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
228 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
229 test_lib_id_main_sort_check_order({id_a, id_b, id_c});
230
231 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
232
234
235 /* Rename to different root name. */
236 result = change_name(ctx.bmain, id_c, "OB_A", IDNewNameMode::RenameExistingSameRoot);
237
239 // EXPECT_EQ(result.other_id, id_a); /* other_id purposely not looked-up currently. */
240 EXPECT_EQ(result.other_id, nullptr);
241 EXPECT_STREQ(id_c->name + 2, "OB_A.001");
242 EXPECT_STREQ(id_a->name + 2, "OB_A");
243 EXPECT_TRUE(ctx.bmain->objects.first == id_a);
244 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
245 test_lib_id_main_sort_check_order({id_a, id_c, id_b});
246
247 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
248
249 /* Rename to same root name. */
250 result = change_name(ctx.bmain, id_c, "OB_A", IDNewNameMode::RenameExistingSameRoot);
251
253 EXPECT_EQ(result.other_id, id_a);
254 EXPECT_STREQ(id_c->name + 2, "OB_A");
255 EXPECT_STREQ(id_a->name + 2, "OB_A.001");
256 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
257 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
258 test_lib_id_main_sort_check_order({id_c, id_a, id_b});
259
260 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
261
262 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
263}
264
265TEST(lib_id_main_unique_name, linked_ids_1)
266{
268 EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
269
270 Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A"));
271 Library *lib_b = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_B"));
272 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
273 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
274 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
275
276 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
277
278 change_lib(ctx.bmain, id_a, lib_a);
279 id_sort_by_name(&ctx.bmain->objects, id_a, nullptr);
280 change_lib(ctx.bmain, id_b, lib_a);
281 id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
282
284 EXPECT_STREQ(id_b->name + 2, "OB_A.001");
285 EXPECT_STREQ(id_a->name + 2, "OB_A");
286 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
287 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
288 test_lib_id_main_sort_check_order({id_c, id_a, id_b});
289
290 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
291
292 change_lib(ctx.bmain, id_b, lib_b);
293 id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
295 EXPECT_STREQ(id_b->name + 2, "OB_A");
296 EXPECT_STREQ(id_a->name + 2, "OB_A");
297 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
298 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
299 test_lib_id_main_sort_check_order({id_c, id_a, id_b});
300
301 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
302
303 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
304}
305
306static void change_name_global(Main *bmain, ID *id, const char *name)
307{
308 BKE_main_namemap_remove_name(bmain, id, id->name + 2);
309 BLI_strncpy(id->name + 2, name, MAX_NAME);
310
311 BKE_main_namemap_get_name(bmain, id, id->name + 2, true);
312
313 id_sort_by_name(&bmain->objects, id, nullptr);
314}
315
316TEST(lib_id_main_global_unique_name, linked_ids_1)
317{
319 EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
320
321 Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A"));
322 Library *lib_b = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_B"));
323 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
324 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
325 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
326
327 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
328
329 change_lib(ctx.bmain, id_a, lib_a);
330 id_sort_by_name(&ctx.bmain->objects, id_a, nullptr);
331 change_lib(ctx.bmain, id_b, lib_b);
332 id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
333
334 change_name_global(ctx.bmain, id_b, "OB_A");
335 EXPECT_NE(ctx.bmain->name_map_global, nullptr);
336 EXPECT_STREQ(id_b->name + 2, "OB_A.001");
337 EXPECT_STREQ(id_a->name + 2, "OB_A");
338 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
339 EXPECT_TRUE(ctx.bmain->objects.last == id_b);
340 test_lib_id_main_sort_check_order({id_c, id_a, id_b});
341
342 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
343
344 change_lib(ctx.bmain, id_b, lib_a);
345 id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
346 change_name_global(ctx.bmain, id_b, "OB_C");
347 EXPECT_STREQ(id_b->name + 2, "OB_C.001");
348 EXPECT_STREQ(id_a->name + 2, "OB_A");
349 EXPECT_STREQ(id_c->name + 2, "OB_C");
350 change_name_global(ctx.bmain, id_a, "OB_C");
351 EXPECT_STREQ(id_b->name + 2, "OB_C.001");
352 EXPECT_STREQ(id_a->name + 2, "OB_C.002");
353 EXPECT_STREQ(id_c->name + 2, "OB_C");
354 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
355 EXPECT_TRUE(ctx.bmain->objects.last == id_a);
356 test_lib_id_main_sort_check_order({id_c, id_b, id_a});
357
358 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
359
361 EXPECT_STREQ(id_b->name + 2, "OB_C");
362 EXPECT_STREQ(id_a->name + 2, "OB_C.002");
363 EXPECT_STREQ(id_c->name + 2, "OB_C");
364 EXPECT_TRUE(ctx.bmain->objects.first == id_c);
365 EXPECT_TRUE(ctx.bmain->objects.last == id_a);
366 test_lib_id_main_sort_check_order({id_c, id_b, id_a});
367
368 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
369}
370
371TEST(lib_id_main_unique_name, ids_sorted_by_default)
372{
374
375 ID *id_foo = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
376 ID *id_bar = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar"));
377 ID *id_baz = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Baz"));
378 ID *id_yes = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Yes"));
379 test_lib_id_main_sort_check_order({id_bar, id_baz, id_foo, id_yes});
380
381 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
382
383 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
384}
385
386static ID *add_id_in_library(Main *bmain, const char *name, Library *lib)
387{
388 ID *id = static_cast<ID *>(BKE_id_new(bmain, ID_OB, name));
389 change_lib(bmain, id, lib);
390 id_sort_by_name(&bmain->objects, id, nullptr);
391 return id;
392}
393
394TEST(lib_id_main_unique_name, ids_sorted_by_default_with_libraries)
395{
397
398 Library *lib_one = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LibOne"));
399 Library *lib_two = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LibTwo"));
400
401 ID *id_foo = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
402 ID *id_bar = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar"));
403
404 ID *id_l1c = add_id_in_library(ctx.bmain, "C", lib_one);
405 ID *id_l2b = add_id_in_library(ctx.bmain, "B", lib_two);
406 ID *id_l1a = add_id_in_library(ctx.bmain, "A", lib_one);
407
408 ID *id_baz = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Baz"));
409 ID *id_yes = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Yes"));
410
411 test_lib_id_main_sort_check_order({id_bar, id_baz, id_foo, id_yes, id_l1a, id_l1c, id_l2b});
412
413 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
414
415 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
416}
417
418TEST(lib_id_main_unique_name, name_too_long_handling)
419{
421 const char *name_a = "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated";
422 const char *name_b = "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123456";
423 const char *name_c = "Name_That_Has_Too_Long_Number_Suffix.1234567890";
424
425 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_a));
426 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_b));
427 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_c));
428
429 EXPECT_STREQ(id_a->name + 2, "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_");
430 EXPECT_STREQ(id_b->name + 2, "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123");
431 EXPECT_STREQ(id_c->name + 2, "Name_That_Has_Too_Long_Number_Suffix.1234567890"); /* Unchanged */
432
433 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
434
435 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
436}
437
438TEST(lib_id_main_unique_name, create_equivalent_numeric_suffixes)
439{
441
442 /* Create names where many of their numeric suffixes are
443 * the same number, yet the names are different and thus
444 * should be allowed as-is. */
445 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123"));
446 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.000"));
447 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.003"));
448 ID *id_d = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.3"));
449 ID *id_e = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0"));
450 ID *id_f = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo."));
451 ID *id_g = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0123"));
452 ID *id_h = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
453 ID *id_i = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.."));
454 ID *id_j = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..001"));
455 ID *id_k = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..000"));
456
457 EXPECT_STREQ(id_a->name + 2, "Foo.123");
458 EXPECT_STREQ(id_b->name + 2, "Foo.000");
459 EXPECT_STREQ(id_c->name + 2, "Foo.003");
460 EXPECT_STREQ(id_d->name + 2, "Foo.3");
461 EXPECT_STREQ(id_e->name + 2, "Foo.0");
462 EXPECT_STREQ(id_f->name + 2, "Foo.");
463 EXPECT_STREQ(id_g->name + 2, "Foo.0123");
464 EXPECT_STREQ(id_h->name + 2, "Foo");
465 EXPECT_STREQ(id_i->name + 2, "Foo..");
466 EXPECT_STREQ(id_j->name + 2, "Foo..001");
467 EXPECT_STREQ(id_k->name + 2, "Foo..000");
468
469 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
470
471 /* Now create their exact duplicates again, and check what happens. */
472 id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123"));
473 id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.000"));
474 id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.003"));
475 id_d = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.3"));
476 id_e = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0"));
477 id_f = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo."));
478 id_g = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0123"));
479 id_h = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
480 id_i = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.."));
481 id_j = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..001"));
482 id_k = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..000"));
483
484 EXPECT_STREQ(id_a->name + 2, "Foo.001");
485 EXPECT_STREQ(id_b->name + 2, "Foo.002");
486 EXPECT_STREQ(id_c->name + 2, "Foo.004");
487 EXPECT_STREQ(id_d->name + 2, "Foo.005");
488 EXPECT_STREQ(id_e->name + 2, "Foo.006");
489 EXPECT_STREQ(id_f->name + 2, "Foo..002");
490 EXPECT_STREQ(id_g->name + 2, "Foo.007");
491 EXPECT_STREQ(id_h->name + 2, "Foo.008");
492 EXPECT_STREQ(id_i->name + 2, "Foo...001");
493 EXPECT_STREQ(id_j->name + 2, "Foo..003");
494 EXPECT_STREQ(id_k->name + 2, "Foo..004");
495
496 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
497
498 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
499}
500
501TEST(lib_id_main_unique_name, zero_suffix_is_never_assigned)
502{
504
505 /* Creating these should assign 002 to the first one, but the next
506 * ones should start numbers starting from 1: 001 and 003. */
507 ID *id_002 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002"));
508 ID *id_001 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002"));
509 ID *id_003 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002"));
510
511 EXPECT_STREQ(id_002->name + 2, "Foo.002");
512 EXPECT_STREQ(id_001->name + 2, "Foo.001");
513 EXPECT_STREQ(id_003->name + 2, "Foo.003");
514
515 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
516
517 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
518}
519
520TEST(lib_id_main_unique_name, remove_after_dup_get_original_name)
521{
523
524 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
525 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
526
527 EXPECT_STREQ(id_a->name + 2, "Foo");
528 EXPECT_STREQ(id_b->name + 2, "Foo.001");
529 BKE_id_free(ctx.bmain, id_a);
530
531 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
532
533 id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
534 EXPECT_STREQ(id_a->name + 2, "Foo");
535
536 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
537
538 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
539}
540
541TEST(lib_id_main_unique_name, name_number_suffix_assignment)
542{
544
545 /* Create <1k objects first. */
546 const int total_object_count = 1200;
547 ID *ids[total_object_count] = {};
548 for (int i = 0; i < total_object_count / 2; ++i) {
549 ids[i] = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
550 }
551
552 /* They should get assigned sequential numeric suffixes. */
553 EXPECT_STREQ(ids[0]->name + 2, "Foo");
554 EXPECT_STREQ(ids[1]->name + 2, "Foo.001");
555 EXPECT_STREQ(ids[total_object_count / 2 - 1]->name + 2, "Foo.599");
556
557 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
558
559 /* Free some of the objects. */
560 BKE_id_free(ctx.bmain, ids[10]);
561 BKE_id_free(ctx.bmain, ids[20]);
562 BKE_id_free(ctx.bmain, ids[30]);
563
564 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
565
566 /* Create objects again; they should get suffixes that were just freed up. */
567 ID *id_010 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
568 EXPECT_STREQ(id_010->name + 2, "Foo.010");
569 ID *id_020 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123"));
570 EXPECT_STREQ(id_020->name + 2, "Foo.020");
571 /* Suffixes >1k do not get the "use the most proper free one" treatment. */
572 ID *id_2000 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.2000"));
573 EXPECT_STREQ(id_2000->name + 2, "Foo.2000");
574 /* But smaller than 1k suffixes do get proper empty spots. */
575 ID *id_030 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
576 EXPECT_STREQ(id_030->name + 2, "Foo.030");
577 ID *id_600 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
578 EXPECT_STREQ(id_600->name + 2, "Foo.600");
579
580 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
581
582 /* Max possible numeric suffix. */
583 ID *id_max = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999"));
584 EXPECT_STREQ(id_max->name + 2, "Foo.999999999");
585 /* Try with max. possible suffix again: will assign free suffix under 1k. */
586 ID *id_max1 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999"));
587 EXPECT_STREQ(id_max1->name + 2, "Foo.601");
588
589 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
590
591 /* Now create the rest of objects, to use all the suffixes up to 1k.
592 * Once all the ones up to 1k are used, the logic will fall back to
593 * "use largest number seen + 1", but the largest one is already the max
594 * possible. So it will shorten the name part and restart the counter,
595 * i.e. "Fo.001". */
596 for (int i = total_object_count / 2; i < total_object_count; ++i) {
597 ids[i] = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
598 }
599 /* At this point creating "Foo" based objects will fall always
600 * result in shortened name to "Fo". */
601 ID *id_fo178 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
602 EXPECT_STREQ(id_fo178->name + 2, "Fo.178");
603 ID *id_fo179 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.2000"));
604 EXPECT_STREQ(id_fo179->name + 2, "Fo.179");
605 ID *id_fo180 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999"));
606 EXPECT_STREQ(id_fo180->name + 2, "Fo.180");
607
608 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
609
610 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
611}
612
613TEST(lib_id_main_unique_name, renames_with_duplicates)
614{
616
617 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
618 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
619 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar"));
620
621 EXPECT_STREQ(id_a->name + 2, "Foo");
622 EXPECT_STREQ(id_b->name + 2, "Foo.001");
623 EXPECT_STREQ(id_c->name + 2, "Bar");
624
625 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
626
627 BKE_libblock_rename(*ctx.bmain, *id_a, "Foo.002");
628 EXPECT_STREQ(id_a->name + 2, "Foo.002");
629 BKE_libblock_rename(*ctx.bmain, *id_b, "Bar");
630 EXPECT_STREQ(id_b->name + 2, "Bar.001");
631 BKE_libblock_rename(*ctx.bmain, *id_c, "Foo");
632 EXPECT_STREQ(id_c->name + 2, "Foo");
633 BKE_libblock_rename(*ctx.bmain, *id_b, "Bar");
634 EXPECT_STREQ(id_b->name + 2, "Bar");
635
636 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
637
638 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
639}
640
641TEST(lib_id_main_unique_name, names_are_unique_per_id_type)
642{
644
645 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
646 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_CA, "Foo"));
647 ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
648
649 EXPECT_STREQ(id_a->name + 2, "Foo");
650 EXPECT_STREQ(id_b->name + 2, "Foo"); /* Different types (OB & CA) can have the same name. */
651 EXPECT_STREQ(id_c->name + 2, "Foo.001");
652
653 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
654
655 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
656}
657
658TEST(lib_id_main_unique_name, name_huge_number_suffix)
659{
661
662 /* Use numeric suffix that is really large: should come through
663 * fine, since no duplicates with other names. */
664 ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "SuperLong.1234567890"));
665 EXPECT_STREQ(id_a->name + 2, "SuperLong.1234567890");
666 /* Now create with the same name again: should get 001 suffix. */
667 ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "SuperLong.1234567890"));
668 EXPECT_STREQ(id_b->name + 2, "SuperLong.001");
669
670 EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
671
672 EXPECT_EQ(ctx.bmain->name_map_global, nullptr);
673}
674
675} // namespace blender::bke::tests
void BKE_idtype_init()
Definition idtype.cc:127
IDNewNameMode
void BKE_id_free(Main *bmain, void *idv)
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
Definition lib_id.cc:1737
IDNewNameResult BKE_libblock_rename(Main &bmain, ID &id, blender::StringRefNull name, const IDNewNameMode mode=IDNewNameMode::RenameExistingNever)
Definition lib_id.cc:2316
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
Main * BKE_main_new(void)
Definition main.cc:45
void BKE_main_free(Main *bmain)
Definition main.cc:175
bool BKE_main_namemap_get_name(Main *bmain, ID *id, char *name, const bool do_unique_in_bmain) ATTR_NONNULL()
void BKE_main_namemap_remove_name(Main *bmain, ID *id, const char *name) ATTR_NONNULL()
bool BKE_main_namemap_validate(Main *bmain) ATTR_NONNULL()
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
ID and Library types, which are fundamental for SDNA.
#define MAX_ID_NAME
Definition DNA_ID.h:377
@ ID_CA
@ ID_LI
@ ID_OB
#define MAX_NAME
Definition DNA_defs.h:50
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
static ID * add_id_in_library(Main *bmain, const char *name, Library *lib)
static void change_lib(Main *bmain, ID *id, Library *lib)
TEST(action_groups, ReconstructGroupsWithReordering)
static void change_name_global(Main *bmain, ID *id, const char *name)
static IDNewNameResult change_name(Main *bmain, ID *id, const char *name, const IDNewNameMode mode)
static void test_lib_id_main_sort_check_order(std::initializer_list< ID * > list)
Definition DNA_ID.h:413
void * next
Definition DNA_ID.h:416
char name[66]
Definition DNA_ID.h:425
void * last
void * first
UniqueName_Map * name_map_global
Definition BKE_main.hh:270
ListBase libraries
Definition BKE_main.hh:211
ListBase objects
Definition BKE_main.hh:212
static DynamicLibrary lib