Tests: Use proper order for EXPECT_EQ()
[blender.git] / tests / gtests / blenlib / BLI_array_store_test.cc
1 /* Apache License, Version 2.0 */
2
3 #include "testing/testing.h"
4
5 extern "C" {
6 #include "BLI_array_store.h"
7
8 #include "MEM_guardedalloc.h"
9 #include "BLI_sys_types.h"
10 #include "BLI_utildefines.h"
11 #include "BLI_listbase.h"
12 #include "BLI_array_utils.h"
13 #include "BLI_string.h"
14 #include "BLI_rand.h"
15 #include "BLI_ressource_strings.h"
16 }
17
18 /* print memory savings */
19 // #define DEBUG_PRINT
20
21
22 /* -------------------------------------------------------------------- */
23 /* Helper functions */
24
25 #ifdef DEBUG_PRINT
26 static void print_mem_saved(const char *id, const BArrayStore *bs)
27 {
28         const double size_real   = BLI_array_store_calc_size_compacted_get(bs);
29         const double size_expand = BLI_array_store_calc_size_expanded_get(bs);
30         const double percent = size_expand ? ((size_real / size_expand) * 100.0) : -1.0;
31         printf("%s: %.8f%%\n", id, percent);
32 }
33 #endif
34
35
36 /* -------------------------------------------------------------------- */
37 /* Test Chunks (building data from list of chunks) */
38
39 typedef struct TestChunnk {
40         struct TestChunnk *next, *prev;
41         const void *data;
42         size_t data_len;
43 } TestChunnk;
44
45 static TestChunnk *testchunk_list_add(ListBase *lb, const void *data, size_t data_len)
46 {
47         TestChunnk *tc = (TestChunnk *)MEM_mallocN(sizeof(*tc), __func__);
48         tc->data = data;
49         tc->data_len = data_len;
50         BLI_addtail(lb, tc);
51
52         return tc;
53 }
54
55 #if 0
56 static TestChunnk *testchunk_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
57 {
58         void *data_copy = MEM_mallocN(data_len, __func__);
59         memcpy(data_copy, data, data_len);
60         return testchunk_list_add(lb, data_copy, data_len);
61 }
62 #endif
63
64 static void testchunk_list_free(ListBase *lb)
65 {
66         for (TestChunnk *tc = (TestChunnk *)lb->first, *tb_next; tc; tc = tb_next) {
67                 tb_next = tc->next;
68                 MEM_freeN((void *)tc->data);
69                 MEM_freeN(tc);
70         }
71         BLI_listbase_clear(lb);
72 }
73
74 #if 0
75 static char *testchunk_as_data(
76         ListBase *lb,
77         size_t *r_data_len)
78 {
79         size_t data_len = 0;
80         for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) {
81                 data_len += tc->data_len;
82         }
83         char *data = (char *)MEM_mallocN(data_len, __func__);
84         size_t i = 0;
85         for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) {
86                 memcpy(&data[i], tc->data, tc->data_len);
87                 data_len += tc->data_len;
88                 i += tc->data_len;
89         }
90         if (r_data_len) {
91                 *r_data_len = i;
92         }
93         return data;
94 }
95 #endif
96
97 static char *testchunk_as_data_array(
98         TestChunnk **tc_array, int tc_array_len,
99         size_t *r_data_len)
100 {
101         size_t data_len = 0;
102         for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
103                 data_len += tc_array[tc_index]->data_len;
104         }
105         char *data = (char *)MEM_mallocN(data_len, __func__);
106         size_t i = 0;
107         for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
108                 TestChunnk *tc = tc_array[tc_index];
109                 memcpy(&data[i], tc->data, tc->data_len);
110                 i += tc->data_len;
111         }
112         if (r_data_len) {
113                 *r_data_len = i;
114         }
115         return data;
116 }
117
118
119 /* -------------------------------------------------------------------- */
120 /* Test Buffer */
121
122 /* API to handle local allocation of data so we can compare it with the data in the array_store */
123 typedef struct TestBuffer {
124         struct TestBuffer *next, *prev;
125         const void *data;
126         size_t data_len;
127
128         /* for reference */
129         BArrayState *state;
130 } TestBuffer;
131
132 static TestBuffer *testbuffer_list_add(ListBase *lb, const void *data, size_t data_len)
133 {
134         TestBuffer *tb = (TestBuffer *)MEM_mallocN(sizeof(*tb), __func__);
135         tb->data = data;
136         tb->data_len = data_len;
137         tb->state = NULL;
138         BLI_addtail(lb, tb);
139         return tb;
140 }
141
142 static TestBuffer *testbuffer_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
143 {
144         void *data_copy = MEM_mallocN(data_len, __func__);
145         memcpy(data_copy, data, data_len);
146         return testbuffer_list_add(lb, data_copy, data_len);
147 }
148
149 static void testbuffer_list_state_from_data(
150         ListBase *lb,
151         const char *data, const size_t data_len)
152 {
153         testbuffer_list_add_copydata(lb, (const void *)data, data_len);
154 }
155
156 /**
157  * A version of testbuffer_list_state_from_data that expand data by stride,
158  * handy so we can test data at different strides.
159  */
160 static void testbuffer_list_state_from_data__stride_expand(
161         ListBase *lb,
162         const char *data, const size_t data_len,
163         const size_t stride)
164 {
165         if (stride == 1) {
166                 testbuffer_list_state_from_data(lb, data, data_len);
167         }
168         else {
169                 const size_t data_stride_len = data_len  * stride;
170                 char *data_stride = (char *)MEM_mallocN(data_stride_len, __func__);
171
172                 for (size_t i = 0, i_stride = 0; i < data_len; i += 1, i_stride += stride) {
173                         memset(&data_stride[i_stride], data[i], stride);
174                 }
175
176                 testbuffer_list_add(lb, (const void *)data_stride, data_stride_len);
177         }
178 }
179
180 #define testbuffer_list_state_from_string_array(lb, data_array) \
181 { \
182         unsigned int i_ = 0; \
183         const char *data; \
184         while ((data = data_array[i_++])) { \
185                 testbuffer_list_state_from_data(lb, data, strlen(data)); \
186         } \
187 } ((void)0)
188
189 //
190
191 #define TESTBUFFER_STRINGS_CREATE(lb, ...) \
192 { \
193         BLI_listbase_clear(lb); \
194         const char *data_array[] = {__VA_ARGS__ NULL}; \
195         testbuffer_list_state_from_string_array((lb), data_array); \
196 } ((void)0)
197
198 /* test in both directions */
199 #define TESTBUFFER_STRINGS_EX(bs, ...) \
200 { \
201         ListBase lb; \
202         TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
203         \
204         testbuffer_run_tests(bs, &lb); \
205         \
206         testbuffer_list_free(&lb); \
207 } ((void)0)
208
209 #define TESTBUFFER_STRINGS(stride, chunk_count, ...) \
210 { \
211         ListBase lb; \
212         TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
213         \
214         testbuffer_run_tests_simple(&lb, stride, chunk_count); \
215         \
216         testbuffer_list_free(&lb); \
217 } ((void)0)
218
219 static bool testbuffer_item_validate(TestBuffer *tb)
220 {
221         size_t data_state_len;
222         bool ok = true;
223         void *data_state = BLI_array_store_state_data_get_alloc(tb->state, &data_state_len);
224         if (tb->data_len != data_state_len) {
225                 ok = false;
226         }
227         else if (memcmp(data_state, tb->data, data_state_len) != 0) {
228                 ok = false;
229         }
230         MEM_freeN(data_state);
231         return ok;
232 }
233
234 static bool testbuffer_list_validate(const ListBase *lb)
235 {
236         for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
237                 if (!testbuffer_item_validate(tb)) {
238                         return false;
239                 }
240         }
241
242         return true;
243 }
244
245 static void testbuffer_list_data_randomize(ListBase *lb, unsigned int random_seed)
246 {
247         for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
248                 BLI_array_randomize((void *)tb->data, 1, tb->data_len, random_seed++);
249         }
250 }
251
252 static void testbuffer_list_store_populate(
253         BArrayStore *bs, ListBase *lb)
254 {
255         for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_prev = NULL; tb; tb_prev = tb, tb = tb->next) {
256                 tb->state = BLI_array_store_state_add(bs, tb->data, tb->data_len, (tb_prev ? tb_prev->state : NULL));
257         }
258 }
259
260 static void testbuffer_list_store_clear(
261         BArrayStore *bs, ListBase *lb)
262 {
263         for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
264                 BLI_array_store_state_remove(bs, tb->state);
265                 tb->state = NULL;
266         }
267 }
268
269 static void testbuffer_list_free(ListBase *lb)
270 {
271         for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_next; tb; tb = tb_next) {
272                 tb_next = tb->next;
273                 MEM_freeN((void *)tb->data);
274                 MEM_freeN(tb);
275         }
276         BLI_listbase_clear(lb);
277 }
278
279 static void testbuffer_run_tests_single(
280         BArrayStore *bs, ListBase *lb)
281 {
282         testbuffer_list_store_populate(bs, lb);
283         EXPECT_TRUE(testbuffer_list_validate(lb));
284         EXPECT_TRUE(BLI_array_store_is_valid(bs));
285 #ifdef DEBUG_PRINT
286         print_mem_saved("data", bs);
287 #endif
288 }
289
290 /* avoid copy-paste code to run tests */
291 static void testbuffer_run_tests(
292         BArrayStore *bs, ListBase *lb)
293 {
294         /* forwards */
295         testbuffer_run_tests_single(bs, lb);
296         testbuffer_list_store_clear(bs, lb);
297
298         BLI_listbase_reverse(lb);
299
300         /* backwards */
301         testbuffer_run_tests_single(bs, lb);
302         testbuffer_list_store_clear(bs, lb);
303 }
304
305 static void testbuffer_run_tests_simple(
306         ListBase *lb,
307         const int stride, const int chunk_count)
308 {
309         BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
310         testbuffer_run_tests(bs, lb);
311         BLI_array_store_destroy(bs);
312 }
313
314
315 /* -------------------------------------------------------------------- */
316 /* Basic Tests */
317
318 TEST(array_store, Nop)
319 {
320         BArrayStore *bs = BLI_array_store_create(1, 32);
321         BLI_array_store_destroy(bs);
322 }
323
324 TEST(array_store, NopState)
325 {
326         BArrayStore *bs = BLI_array_store_create(1, 32);
327         const unsigned char data[] = "test";
328         BArrayState *state = BLI_array_store_state_add(bs, data, sizeof(data) - 1, NULL);
329         EXPECT_EQ(BLI_array_store_state_size_get(state), sizeof(data) - 1);
330         BLI_array_store_state_remove(bs, state);
331         BLI_array_store_destroy(bs);
332 }
333
334 TEST(array_store, Single)
335 {
336         BArrayStore *bs = BLI_array_store_create(1, 32);
337         const char data_src[] = "test";
338         const char *data_dst;
339         BArrayState *state = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
340         size_t data_dst_len;
341         data_dst = (char *)BLI_array_store_state_data_get_alloc(state, &data_dst_len);
342         EXPECT_STREQ(data_src, data_dst);
343         EXPECT_EQ(data_dst_len, sizeof(data_src));
344         BLI_array_store_destroy(bs);
345         MEM_freeN((void *)data_dst);
346 }
347
348 TEST(array_store, DoubleNop)
349 {
350         BArrayStore *bs = BLI_array_store_create(1, 32);
351         const char data_src[] = "test";
352         const char *data_dst;
353
354         BArrayState *state_a = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
355         BArrayState *state_b = BLI_array_store_state_add(bs, data_src, sizeof(data_src), state_a);
356
357         EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), sizeof(data_src));
358         EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src) * 2);
359
360         size_t data_dst_len;
361
362         data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
363         EXPECT_STREQ(data_src, data_dst);
364         MEM_freeN((void *)data_dst);
365
366         data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
367         EXPECT_STREQ(data_src, data_dst);
368         MEM_freeN((void *)data_dst);
369
370         EXPECT_EQ(data_dst_len, sizeof(data_src));
371         BLI_array_store_destroy(bs);
372 }
373
374 TEST(array_store, DoubleDiff)
375 {
376         BArrayStore *bs = BLI_array_store_create(1, 32);
377         const char data_src_a[] = "test";
378         const char data_src_b[] = "####";
379         const char *data_dst;
380
381         BArrayState *state_a = BLI_array_store_state_add(bs, data_src_a, sizeof(data_src_a), NULL);
382         BArrayState *state_b = BLI_array_store_state_add(bs, data_src_b, sizeof(data_src_b), state_a);
383         size_t data_dst_len;
384
385         EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), sizeof(data_src_a) * 2);
386         EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src_a) * 2);
387
388         data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
389         EXPECT_STREQ(data_src_a, data_dst);
390         MEM_freeN((void *)data_dst);
391
392         data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
393         EXPECT_STREQ(data_src_b, data_dst);
394         MEM_freeN((void *)data_dst);
395
396         BLI_array_store_destroy(bs);
397 }
398
399 TEST(array_store, TextMixed)
400 {
401         TESTBUFFER_STRINGS(1, 4, "",);
402         TESTBUFFER_STRINGS(1, 4, "test",);
403         TESTBUFFER_STRINGS(1, 4, "", "test",);
404         TESTBUFFER_STRINGS(1, 4, "test", "",);
405         TESTBUFFER_STRINGS(1, 4, "test", "", "test",);
406         TESTBUFFER_STRINGS(1, 4, "", "test", "",);
407 }
408
409 TEST(array_store, TextDupeIncreaseDecrease)
410 {
411         ListBase lb;
412
413 #define D "#1#2#3#4"
414         TESTBUFFER_STRINGS_CREATE(
415             &lb,
416             D,
417             D D,
418             D D D,
419             D D D D,
420             );
421
422         BArrayStore *bs = BLI_array_store_create(1, 8);
423
424         /* forward */
425         testbuffer_list_store_populate(bs, &lb);
426         EXPECT_TRUE(testbuffer_list_validate(&lb));
427         EXPECT_TRUE(BLI_array_store_is_valid(bs));
428         EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), strlen(D));
429
430         testbuffer_list_store_clear(bs, &lb);
431         BLI_listbase_reverse(&lb);
432
433         /* backwards */
434         testbuffer_list_store_populate(bs, &lb);
435         EXPECT_TRUE(testbuffer_list_validate(&lb));
436         EXPECT_TRUE(BLI_array_store_is_valid(bs));
437         /* larger since first block doesn't de-duplicate */
438         EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), strlen(D) * 4);
439
440 #undef D
441         testbuffer_list_free(&lb); \
442
443         BLI_array_store_destroy(bs);
444 }
445
446
447 /* -------------------------------------------------------------------- */
448 /* Plain Text Tests */
449
450 /**
451  * Test that uses text input with different params for the array-store
452  * to ensure no corner cases fail.
453  */
454 static void plain_text_helper(
455         const char *words, int words_len, const char word_delim,
456         const int stride, const int chunk_count, const int random_seed)
457 {
458
459         ListBase lb;
460         BLI_listbase_clear(&lb);
461
462         for (int i = 0, i_prev = 0; i < words_len; i++) {
463                 if (ELEM(words[i], word_delim, '\0')) {
464                         if (i != i_prev) {
465                                 testbuffer_list_state_from_data__stride_expand(&lb, &words[i_prev], i - i_prev, stride);
466                         }
467                         i_prev = i;
468                 }
469         }
470
471         if (random_seed) {
472                 testbuffer_list_data_randomize(&lb, random_seed);
473         }
474
475         testbuffer_run_tests_simple(&lb, stride, chunk_count);
476
477         testbuffer_list_free(&lb);
478 }
479
480 /* split by '.' (multiple words) */
481 #define WORDS words10k, sizeof(words10k)
482 TEST(array_store, TextSentences_Chunk1)    { plain_text_helper(WORDS, '.', 1,    1, 0); }
483 TEST(array_store, TextSentences_Chunk2)    { plain_text_helper(WORDS, '.', 1,    2, 0); }
484 TEST(array_store, TextSentences_Chunk8)    { plain_text_helper(WORDS, '.', 1,    8, 0); }
485 TEST(array_store, TextSentences_Chunk32)   { plain_text_helper(WORDS, '.', 1,   32, 0); }
486 TEST(array_store, TextSentences_Chunk128)  { plain_text_helper(WORDS, '.', 1,  128, 0); }
487 TEST(array_store, TextSentences_Chunk1024) { plain_text_helper(WORDS, '.', 1, 1024, 0); }
488 /* odd numbers */
489 TEST(array_store, TextSentences_Chunk3)   { plain_text_helper(WORDS, '.', 1,   3, 0); }
490 TEST(array_store, TextSentences_Chunk13)  { plain_text_helper(WORDS, '.', 1,  13, 0); }
491 TEST(array_store, TextSentences_Chunk131) { plain_text_helper(WORDS, '.', 1, 131, 0); }
492
493 /* split by ' ', individual words */
494 TEST(array_store, TextWords_Chunk1)    { plain_text_helper(WORDS, ' ', 1,    1, 0); }
495 TEST(array_store, TextWords_Chunk2)    { plain_text_helper(WORDS, ' ', 1,    2, 0); }
496 TEST(array_store, TextWords_Chunk8)    { plain_text_helper(WORDS, ' ', 1,    8, 0); }
497 TEST(array_store, TextWords_Chunk32)   { plain_text_helper(WORDS, ' ', 1,   32, 0); }
498 TEST(array_store, TextWords_Chunk128)  { plain_text_helper(WORDS, ' ', 1,  128, 0); }
499 TEST(array_store, TextWords_Chunk1024) { plain_text_helper(WORDS, ' ', 1, 1024, 0); }
500 /* odd numbers */
501 TEST(array_store, TextWords_Chunk3)   { plain_text_helper(WORDS, ' ', 1,   3, 0); }
502 TEST(array_store, TextWords_Chunk13)  { plain_text_helper(WORDS, ' ', 1,  13, 0); }
503 TEST(array_store, TextWords_Chunk131) { plain_text_helper(WORDS, ' ', 1, 131, 0); }
504
505 /* various tests with different strides & randomizing */
506 TEST(array_store, TextSentencesRandom_Stride3_Chunk3)    { plain_text_helper(WORDS, 'q',   3,   3, 7337); }
507 TEST(array_store, TextSentencesRandom_Stride8_Chunk8)    { plain_text_helper(WORDS, 'n',   8,   8, 5667); }
508 TEST(array_store, TextSentencesRandom_Stride32_Chunk1)   { plain_text_helper(WORDS, 'a',   1,  32, 1212); }
509 TEST(array_store, TextSentencesRandom_Stride12_Chunk512) { plain_text_helper(WORDS, 'g',  12, 512, 9999); }
510 TEST(array_store, TextSentencesRandom_Stride128_Chunk6)  { plain_text_helper(WORDS, 'b',  20,   6, 1000); }
511
512 #undef WORDS
513
514
515 /* -------------------------------------------------------------------- */
516 /* Random Data Tests */
517
518 static unsigned int rand_range_i(RNG *rng, unsigned int min_i, unsigned int max_i, unsigned int step)
519 {
520         if (min_i == max_i) {
521                 return min_i;
522         }
523         BLI_assert(min_i <= max_i);
524         BLI_assert(((min_i % step) == 0) && ((max_i % step) == 0));
525         unsigned int range = (max_i - min_i);
526         unsigned int value = BLI_rng_get_uint(rng) % range;
527         value = (value / step) * step;
528         return min_i + value;
529 }
530
531 static void testbuffer_list_state_random_data(
532         ListBase *lb,
533         const size_t stride,
534         const size_t data_min_len, const size_t data_max_len,
535
536         const unsigned int mutate, RNG *rng)
537 {
538         size_t data_len = rand_range_i(rng, data_min_len, data_max_len + stride, stride);
539         char *data = (char *)MEM_mallocN(data_len, __func__);
540
541         if (lb->last == NULL) {
542                 BLI_rng_get_char_n(rng, data, data_len);
543         }
544         else {
545                 TestBuffer *tb_last = (TestBuffer *)lb->last;
546                 if (tb_last->data_len >= data_len) {
547                         memcpy(data, tb_last->data, data_len);
548                 }
549                 else {
550                         memcpy(data, tb_last->data, tb_last->data_len);
551                         BLI_rng_get_char_n(rng, &data[tb_last->data_len], data_len - tb_last->data_len);
552                 }
553
554                 /* perform multiple small mutations to the array. */
555                 for (int i = 0; i < mutate; i++) {
556                         enum {
557                                 MUTATE_NOP = 0,
558                                 MUTATE_ADD,
559                                 MUTATE_REMOVE,
560                                 MUTATE_ROTATE,
561                                 MUTATE_RANDOMIZE,
562                                 MUTATE_TOTAL,
563                         };
564
565                         switch ((BLI_rng_get_uint(rng) % MUTATE_TOTAL)) {
566                                 case MUTATE_NOP:
567                                 {
568                                         break;
569                                 }
570                                 case MUTATE_ADD:
571                                 {
572                                         const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
573                                         if (data_len < data_max_len) {
574                                                 data_len += stride;
575                                                 data = (char *)MEM_reallocN((void *)data, data_len);
576                                                 memmove(&data[offset + stride], &data[offset], data_len - (offset + stride));
577                                                 BLI_rng_get_char_n(rng, &data[offset], stride);
578                                         }
579                                         break;
580                                 }
581                                 case MUTATE_REMOVE:
582                                 {
583                                         const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
584                                         if (data_len > data_min_len) {
585                                                 memmove(&data[offset], &data[offset + stride], data_len - (offset + stride));
586                                                 data_len -= stride;
587                                         }
588                                         break;
589                                 }
590                                 case MUTATE_ROTATE:
591                                 {
592                                         int items = data_len / stride;
593                                         if (items > 1) {
594                                                 _bli_array_wrap(data, items, stride, (BLI_rng_get_uint(rng) % 2) ? -1 : 1);
595                                         }
596                                         break;
597                                 }
598                                 case MUTATE_RANDOMIZE:
599                                 {
600                                         if (data_len > 0) {
601                                                 const unsigned int offset = rand_range_i(rng, 0, data_len - stride, stride);
602                                                 BLI_rng_get_char_n(rng, &data[offset], stride);
603                                         }
604                                         break;
605                                 }
606                                 default:
607                                         BLI_assert(0);
608                         }
609                 }
610         }
611
612         testbuffer_list_add(lb, (const void *)data, data_len);
613 }
614
615 static void random_data_mutate_helper(
616         const int items_size_min, const int items_size_max, const int items_total,
617         const int stride, const int chunk_count,
618         const int random_seed, const int mutate)
619 {
620
621
622         ListBase lb;
623         BLI_listbase_clear(&lb);
624
625         const size_t data_min_len = items_size_min * stride;
626         const size_t data_max_len = items_size_max * stride;
627
628         {
629                 RNG *rng = BLI_rng_new(random_seed);
630                 for (int i = 0; i < items_total; i++) {
631                         testbuffer_list_state_random_data(&lb, stride, data_min_len, data_max_len, mutate, rng);
632                 }
633                 BLI_rng_free(rng);
634         }
635
636         testbuffer_run_tests_simple(&lb, stride, chunk_count);
637
638         testbuffer_list_free(&lb);
639 }
640
641 TEST(array_store, TestData_Stride1_Chunk32_Mutate2)  { random_data_mutate_helper(0,   100,  400,  1,  32,  9779, 2); }
642 TEST(array_store, TestData_Stride8_Chunk512_Mutate2) { random_data_mutate_helper(0,   128,  400,  8, 512,  1001, 2); }
643 TEST(array_store, TestData_Stride12_Chunk48_Mutate2) { random_data_mutate_helper(200, 256,  400, 12,  48,  1331, 2); }
644 TEST(array_store, TestData_Stride32_Chunk64_Mutate1) { random_data_mutate_helper(0,   256,  200, 32,  64,  3112, 1); }
645 TEST(array_store, TestData_Stride32_Chunk64_Mutate8) { random_data_mutate_helper(0,   256,  200, 32,  64,  7117, 8); }
646
647
648 /* -------------------------------------------------------------------- */
649 /* Randomized Chunks Test */
650
651 static void random_chunk_generate(
652         ListBase *lb,
653         const int chunks_per_buffer,
654         const int stride, const int chunk_count,
655         const int random_seed)
656 {
657         RNG *rng = BLI_rng_new(random_seed);
658         const size_t chunk_size_bytes = stride * chunk_count;
659         for (int i = 0; i < chunks_per_buffer; i++) {
660                 char *data_chunk = (char *)MEM_mallocN(chunk_size_bytes, __func__);
661                 BLI_rng_get_char_n(rng, data_chunk, chunk_size_bytes);
662                 testchunk_list_add(lb, data_chunk, chunk_size_bytes);
663         }
664         BLI_rng_free(rng);
665 }
666
667 /**
668  * Add random chunks, then re-order them to ensure chunk de-duplication is working.
669  */
670 static void random_chunk_mutate_helper(
671         const int chunks_per_buffer, const int items_total,
672         const int stride, const int chunk_count,
673         const int random_seed)
674 {
675         /* generate random chunks */
676
677         ListBase random_chunks;
678         BLI_listbase_clear(&random_chunks);
679         random_chunk_generate(&random_chunks, chunks_per_buffer, stride, chunk_count, random_seed);
680         TestChunnk **chunks_array = (TestChunnk **)MEM_mallocN(chunks_per_buffer * sizeof(TestChunnk *), __func__);
681         {
682                 TestChunnk *tc = (TestChunnk *)random_chunks.first;
683                 for (int i = 0; i < chunks_per_buffer; i++, tc = tc->next) {
684                         chunks_array[i] = tc;
685                 }
686         }
687
688         /* add and re-order each time */
689         ListBase lb;
690         BLI_listbase_clear(&lb);
691
692         {
693                 RNG *rng = BLI_rng_new(random_seed);
694                 for (int i = 0; i < items_total; i++) {
695                         BLI_rng_shuffle_array(rng, chunks_array, sizeof(TestChunnk *), chunks_per_buffer);
696                         size_t data_len;
697                         char *data = testchunk_as_data_array(chunks_array, chunks_per_buffer, &data_len);
698                         BLI_assert(data_len == chunks_per_buffer * chunk_count * stride);
699                         testbuffer_list_add(&lb, (const void *)data, data_len);
700                 }
701                 BLI_rng_free(rng);
702         }
703
704         testchunk_list_free(&random_chunks);
705         MEM_freeN(chunks_array);
706
707         BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
708         testbuffer_run_tests_single(bs, &lb);
709
710         size_t expected_size = chunks_per_buffer * chunk_count * stride;
711         EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), expected_size);
712
713         BLI_array_store_destroy(bs);
714
715         testbuffer_list_free(&lb);
716
717 }
718
719 TEST(array_store, TestChunk_Rand8_Stride1_Chunk64)   { random_chunk_mutate_helper(8,  100,  1, 64, 9779); }
720 TEST(array_store, TestChunk_Rand32_Stride1_Chunk64)  { random_chunk_mutate_helper(32, 100,  1, 64, 1331); }
721 TEST(array_store, TestChunk_Rand64_Stride8_Chunk32)  { random_chunk_mutate_helper(64, 100,  8, 32, 2772); }
722 TEST(array_store, TestChunk_Rand31_Stride11_Chunk21) { random_chunk_mutate_helper(31, 100, 11, 21, 7117); }
723
724
725 #if 0
726 /* -------------------------------------------------------------------- */
727
728 /* Test From Files (disabled, keep for local tests.) */
729
730 void *file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
731 {
732         FILE *fp = fopen(filepath, "rb");
733         void *mem = NULL;
734
735         if (fp) {
736                 long int filelen_read;
737                 fseek(fp, 0L, SEEK_END);
738                 const long int filelen = ftell(fp);
739                 if (filelen == -1) {
740                         goto finally;
741                 }
742                 fseek(fp, 0L, SEEK_SET);
743
744                 mem = MEM_mallocN(filelen + pad_bytes, __func__);
745                 if (mem == NULL) {
746                         goto finally;
747                 }
748
749                 filelen_read = fread(mem, 1, filelen, fp);
750                 if ((filelen_read != filelen) || ferror(fp)) {
751                         MEM_freeN(mem);
752                         mem = NULL;
753                         goto finally;
754                 }
755
756                 *r_size = filelen_read;
757
758 finally:
759                 fclose(fp);
760         }
761
762         return mem;
763 }
764
765
766 TEST(array_store, PlainTextFiles)
767 {       ListBase lb;
768         BLI_listbase_clear(&lb);
769         BArrayStore *bs = BLI_array_store_create(1, 128);
770
771         for (int i = 0; i < 629; i++) {
772                 char str[512];
773                 BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/xz_data/%04d.c.xz", i);
774                 // BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/c_code/%04d.c", i);
775                 // printf("%s\n", str);
776                 size_t data_len;
777                 void *data;
778                 data = file_read_binary_as_mem(str, 0, &data_len);
779
780                 testbuffer_list_add(&lb, (const void *)data, data_len);
781         }
782
783         /* forwards */
784         testbuffer_list_store_populate(bs, &lb);
785         EXPECT_TRUE(testbuffer_list_validate(&lb));
786         EXPECT_TRUE(BLI_array_store_is_valid(bs));
787 #ifdef DEBUG_PRINT
788         print_mem_saved("source code forward", bs);
789 #endif
790
791         testbuffer_list_store_clear(bs, &lb);
792         BLI_listbase_reverse(&lb);
793
794         /* backwards */
795         testbuffer_list_store_populate(bs, &lb);
796         EXPECT_TRUE(testbuffer_list_validate(&lb));
797         EXPECT_TRUE(BLI_array_store_is_valid(bs));
798 #ifdef DEBUG_PRINT
799         print_mem_saved("source code backwards", bs);
800 #endif
801
802
803         testbuffer_list_free(&lb);
804         BLI_array_store_destroy(bs);
805 }
806 #endif