BLI_listbase_test.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /* Apache License, Version 2.0 */
  2. #include "testing/testing.h"
  3. extern "C" {
  4. #include "BLI_array_utils.h"
  5. #include "BLI_listbase.h"
  6. #include "MEM_guardedalloc.h"
  7. #include "BLI_string.h"
  8. #include "BLI_path_util.h"
  9. #include "BLI_ressource_strings.h"
  10. }
  11. /* local validation function */
  12. static bool listbase_is_valid(const ListBase *listbase)
  13. {
  14. #define TESTFAIL(test) \
  15. if (!(test)) \
  16. goto fail;
  17. if (listbase->first) {
  18. const Link *prev, *link;
  19. link = (Link *)listbase->first;
  20. TESTFAIL(link->prev == NULL);
  21. link = (Link *)listbase->last;
  22. TESTFAIL(link->next == NULL);
  23. prev = NULL;
  24. link = (Link *)listbase->first;
  25. do {
  26. TESTFAIL(link->prev == prev);
  27. } while ((prev = link), (link = link->next));
  28. TESTFAIL(prev == listbase->last);
  29. prev = NULL;
  30. link = (Link *)listbase->last;
  31. do {
  32. TESTFAIL(link->next == prev);
  33. } while ((prev = link), (link = link->prev));
  34. TESTFAIL(prev == listbase->first);
  35. }
  36. else {
  37. TESTFAIL(listbase->last == NULL);
  38. }
  39. #undef TESTFAIL
  40. return true;
  41. fail:
  42. return false;
  43. }
  44. static int char_switch(char *string, char ch_src, char ch_dst)
  45. {
  46. int tot = 0;
  47. while (*string != 0) {
  48. if (*string == ch_src) {
  49. *string = ch_dst;
  50. tot++;
  51. }
  52. string++;
  53. }
  54. return tot;
  55. }
  56. TEST(listbase, FindLinkOrIndex)
  57. {
  58. ListBase lb;
  59. void *link1 = MEM_callocN(sizeof(Link), "link1");
  60. void *link2 = MEM_callocN(sizeof(Link), "link2");
  61. /* Empty list */
  62. BLI_listbase_clear(&lb);
  63. EXPECT_EQ(BLI_findlink(&lb, -1), (void *)NULL);
  64. EXPECT_EQ(BLI_findlink(&lb, 0), (void *)NULL);
  65. EXPECT_EQ(BLI_findlink(&lb, 1), (void *)NULL);
  66. EXPECT_EQ(BLI_rfindlink(&lb, -1), (void *)NULL);
  67. EXPECT_EQ(BLI_rfindlink(&lb, 0), (void *)NULL);
  68. EXPECT_EQ(BLI_rfindlink(&lb, 1), (void *)NULL);
  69. EXPECT_EQ(BLI_findindex(&lb, link1), -1);
  70. /* One link */
  71. BLI_addtail(&lb, link1);
  72. EXPECT_EQ(BLI_findlink(&lb, 0), link1);
  73. EXPECT_EQ(BLI_rfindlink(&lb, 0), link1);
  74. EXPECT_EQ(BLI_findindex(&lb, link1), 0);
  75. /* Two links */
  76. BLI_addtail(&lb, link2);
  77. EXPECT_EQ(BLI_findlink(&lb, 1), link2);
  78. EXPECT_EQ(BLI_rfindlink(&lb, 0), link2);
  79. EXPECT_EQ(BLI_findindex(&lb, link2), 1);
  80. BLI_freelistN(&lb);
  81. }
  82. /* -------------------------------------------------------------------- */
  83. /* Sort utilities & test */
  84. static int testsort_array_str_cmp(const void *a, const void *b)
  85. {
  86. int i = strcmp(*(const char **)a, *(const char **)b);
  87. return (i > 0) ? 1 : (i < 0) ? -1 : 0;
  88. }
  89. static int testsort_listbase_str_cmp(const void *a, const void *b)
  90. {
  91. const LinkData *link_a = (LinkData *)a;
  92. const LinkData *link_b = (LinkData *)b;
  93. int i = strcmp((const char *)link_a->data, (const char *)link_b->data);
  94. return (i > 0) ? 1 : (i < 0) ? -1 : 0;
  95. }
  96. static int testsort_array_str_cmp_reverse(const void *a, const void *b)
  97. {
  98. return -testsort_array_str_cmp(a, b);
  99. }
  100. static int testsort_listbase_str_cmp_reverse(const void *a, const void *b)
  101. {
  102. return -testsort_listbase_str_cmp(a, b);
  103. }
  104. /* check array and listbase compare */
  105. static bool testsort_listbase_array_str_cmp(ListBase *lb, char **arr, int arr_tot)
  106. {
  107. LinkData *link_step;
  108. int i;
  109. link_step = (LinkData *)lb->first;
  110. for (i = 0; i < arr_tot; i++) {
  111. if (strcmp(arr[i], (char *)link_step->data) != 0) {
  112. return false;
  113. }
  114. link_step = link_step->next;
  115. }
  116. if (link_step) {
  117. return false;
  118. }
  119. return true;
  120. }
  121. /* assumes nodes are allocated in-order */
  122. static bool testsort_listbase_sort_is_stable(ListBase *lb, bool forward)
  123. {
  124. LinkData *link_step;
  125. link_step = (LinkData *)lb->first;
  126. while (link_step && link_step->next) {
  127. if (strcmp((const char *)link_step->data, (const char *)link_step->next->data) == 0) {
  128. if ((link_step < link_step->next) != forward) {
  129. return false;
  130. }
  131. }
  132. link_step = link_step->next;
  133. }
  134. return true;
  135. }
  136. TEST(listbase, Sort)
  137. {
  138. const int words_len = sizeof(words10k) - 1;
  139. char *words = BLI_strdupn(words10k, words_len);
  140. int words_tot;
  141. char **words_arr; /* qsort for comparison */
  142. int i;
  143. char *w_step;
  144. ListBase words_lb;
  145. LinkData *words_linkdata_arr;
  146. /* delimit words */
  147. words_tot = 1 + char_switch(words, ' ', '\0');
  148. words_arr = (char **)MEM_mallocN(sizeof(*words_arr) * words_tot, __func__);
  149. words_linkdata_arr = (LinkData *)MEM_mallocN(sizeof(*words_linkdata_arr) * words_tot, __func__);
  150. /* create array */
  151. w_step = words;
  152. for (i = 0; i < words_tot; i++) {
  153. words_arr[i] = w_step;
  154. w_step += strlen(w_step) + 1;
  155. }
  156. /* sort empty list */
  157. {
  158. BLI_listbase_clear(&words_lb);
  159. BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp);
  160. EXPECT_TRUE(listbase_is_valid(&words_lb));
  161. }
  162. /* sort single single */
  163. {
  164. LinkData link;
  165. link.data = words;
  166. BLI_addtail(&words_lb, &link);
  167. BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp);
  168. EXPECT_TRUE(listbase_is_valid(&words_lb));
  169. BLI_listbase_clear(&words_lb);
  170. }
  171. /* create listbase */
  172. BLI_listbase_clear(&words_lb);
  173. w_step = words;
  174. for (i = 0; i < words_tot; i++) {
  175. LinkData *link = &words_linkdata_arr[i];
  176. link->data = w_step;
  177. BLI_addtail(&words_lb, link);
  178. w_step += strlen(w_step) + 1;
  179. }
  180. EXPECT_TRUE(listbase_is_valid(&words_lb));
  181. /* sort (forward) */
  182. {
  183. qsort(words_arr, words_tot, sizeof(*words_arr), testsort_array_str_cmp);
  184. BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp);
  185. EXPECT_TRUE(listbase_is_valid(&words_lb));
  186. EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
  187. EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, true));
  188. }
  189. /* sort (reverse) */
  190. {
  191. qsort(words_arr, words_tot, sizeof(*words_arr), testsort_array_str_cmp_reverse);
  192. BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp_reverse);
  193. EXPECT_TRUE(listbase_is_valid(&words_lb));
  194. EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
  195. EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, true));
  196. }
  197. /* sort (forward but after reversing, test stability in alternate direction) */
  198. {
  199. BLI_array_reverse(words_arr, words_tot);
  200. BLI_listbase_reverse(&words_lb);
  201. EXPECT_TRUE(listbase_is_valid(&words_lb));
  202. EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
  203. EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, false));
  204. /* and again */
  205. BLI_array_reverse(words_arr, words_tot);
  206. BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp_reverse);
  207. EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
  208. EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, false));
  209. }
  210. MEM_freeN(words);
  211. MEM_freeN(words_arr);
  212. MEM_freeN(words_linkdata_arr);
  213. }