The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rb_tests.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Tests for rbtrees
18  *
19  * @file src/lib/util/rb_tests.c
20  *
21  * @copyright 2021 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  */
23 #include <freeradius-devel/util/acutest.h>
24 #include <freeradius-devel/util/acutest_helpers.h>
25 #include <freeradius-devel/util/rand.h>
26 #include <freeradius-devel/util/rb.h>
27 
28 #define MAXSIZE 128
29 
30 typedef struct {
34 
35 static int8_t fr_rb_tree_test_cmp(void const *one, void const *two)
36 {
37  fr_rb_tree_test_node_t const *a = one, *b = two;
38  return CMP(a->num, b->num);
39 }
40 
41 static int fr_rb_qsort_cmp(void const *one, void const *two)
42 {
43  fr_rb_tree_test_node_t const *a = one, *b = two;
44  return CMP(a->num, b->num);
45 }
46 
47 static void test_fr_rb_iter_inorder(void)
48 {
49  fr_rb_tree_t *t;
52  size_t n, i;
54 
55  TEST_CASE("in-order iterator");
57  TEST_CHECK(t != NULL);
58 
59  n = (fr_rand() % MAXSIZE) + 1;
60 
61  /*
62  * Initialise the test nodes
63  * with random numbers.
64  */
65  for (i = 0; i < n; i++) {
66  p = talloc(t, fr_rb_tree_test_node_t);
67  p->num = fr_rand();
68  sorted[i].num = p->num;
69  fr_rb_insert(t, p);
70  }
71 
72  qsort(sorted, n, sizeof(fr_rb_tree_test_node_t), fr_rb_qsort_cmp);
73 
74  for (p = fr_rb_iter_init_inorder(&iter, t), i = 0;
75  p;
76  p = fr_rb_iter_next_inorder(&iter), i++) {
77  TEST_MSG("Checking sorted[%zu] s = %u vs n = %u", i, sorted[i].num, p->num);
78  TEST_CHECK(sorted[i].num == p->num);
79  }
80 
81  talloc_free(t);
82 }
83 
84 /*
85  * There's no natural test for pre- and post-order traversal
86  * as there is for in-order, so we must content ourselves
87  * with static test data.
88  */
89 static uint32_t pre_post_input[] = {0, 15, 256, 49, 3, 8192, 144, 4, 4096, 25194};
90 static uint32_t pre_output[] = {15, 3, 0, 4, 256, 49, 144, 8192, 4096, 25194};
91 static uint32_t post_output[] = {0, 4, 3, 144, 49, 4096, 25194, 8192, 256, 15};
92 
93 static void test_fr_rb_iter_preorder(void)
94 {
95  fr_rb_tree_t *t;
97  size_t i;
99 
100  TEST_CASE("pre-order iterator");
101  /*
102  * Build a tree from pre_post_input.
103  */
105  TEST_CHECK(t != NULL);
106 
107  for (i = 0; i < sizeof(pre_post_input) / sizeof(uint32_t); i++) {
108  p = talloc(t, fr_rb_tree_test_node_t);
109  p->num = pre_post_input[i];
110  fr_rb_insert(t, p);
111  }
112 
113  for (p = fr_rb_iter_init_preorder(&iter, t), i = 0;
114  p;
115  p = fr_rb_iter_next_preorder(&iter), i++) {
116  TEST_MSG("Checking pre_output[%zu] = %u vs n = %u", i, pre_output[i], p->num);
117  TEST_CHECK(pre_output[i] == p->num);
118  }
119 
120  talloc_free(t);
121 }
122 
123 static void test_fr_rb_iter_postorder(void)
124 {
125  fr_rb_tree_t *t;
127  size_t i;
129 
130  TEST_CASE("post-order iterator");
131  /*
132  * Build a tree from pre_post_input.
133  */
135  TEST_CHECK(t != NULL);
136 
137  for (i = 0; i < sizeof(pre_post_input) / sizeof(uint32_t); i++) {
138  p = talloc(t, fr_rb_tree_test_node_t);
139  p->num = pre_post_input[i];
140  fr_rb_insert(t, p);
141  }
142 
143  for (p = fr_rb_iter_init_postorder(&iter, t), i = 0;
144  p;
145  p = fr_rb_iter_next_postorder(&iter), i++) {
146  TEST_MSG("Checking post_output[%zu] s = %u vs n = %u", i, post_output[i], p->num);
147  TEST_CHECK(post_output[i] == p->num);
148  }
149 
150  talloc_free(t);
151 }
152 
153 /*
154  * primality test used in fr_rb_delete_iter() test.
155  */
156 static bool is_prime(uint32_t n)
157 {
158  uint32_t i, q;
159 
160  if (n < 2) return false;
161 
162  for (i = 2; (q = n / i) >= i; i++) {
163  if (i * q == n) return false;
164  }
165  return true;
166 }
167 
168 static uint32_t non_primes[] = { 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28,
169  30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49, 50};
170 
171 static void test_fr_rb_iter_delete(void)
172 {
173  fr_rb_tree_t *t;
174  size_t i;
177 
179  TEST_CHECK(t != NULL);
180 
181  /*
182  * Initialise the test nodes
183  * with integers from 1 to 50.
184  */
185  for (i = 1; i <= 50; i++) {
186  p = talloc(t, fr_rb_tree_test_node_t);
187  p->num = i;
188  fr_rb_insert(t, p);
189  }
190 
191  /*
192  * Remove the primes.
193  */
194  for (p = fr_rb_iter_init_inorder(&iter, t);
195  p;
196  p = fr_rb_iter_next_inorder(&iter)) {
197  if (is_prime(p->num)) fr_rb_iter_delete_inorder(&iter);
198  }
199 
200  /*
201  * Check that all the non-primes are still there.
202  */
203  for (p = fr_rb_iter_init_inorder(&iter, t), i = 0;
204  p;
205  p = fr_rb_iter_next_inorder(&iter), i++) {
206  TEST_MSG("Checking non_primes[%zu] = %u vs p->num = %u", i, non_primes[i], p->num);
207  TEST_CHECK(non_primes[i] == p->num);
208  }
209 
210  talloc_free(t);
211 }
212 
214  { "fr_rb_iter_inorder", test_fr_rb_iter_inorder },
215  { "fr_rb_iter_preorder", test_fr_rb_iter_preorder },
216  { "fr_rb_iter_postorder", test_fr_rb_iter_postorder },
217  { "fr_rb_iter_delete", test_fr_rb_iter_delete },
218 
219  { NULL }
220 };
#define TEST_CHECK(cond)
Definition: acutest.h:85
int n
Definition: acutest.h:577
#define TEST_CASE(name)
Definition: acutest.h:184
#define TEST_MSG(...)
Definition: acutest.h:215
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
talloc_free(reap)
unsigned int uint32_t
Definition: merged_model.c:33
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
void * fr_rb_iter_init_preorder(fr_rb_iter_preorder_t *iter, fr_rb_tree_t *tree)
Initialise a pre-order iterator.
Definition: rb.c:911
void * fr_rb_iter_init_postorder(fr_rb_iter_postorder_t *iter, fr_rb_tree_t *tree)
Initialise a post-order iterator.
Definition: rb.c:988
void fr_rb_iter_delete_inorder(fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
Definition: rb.c:892
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition: rb.c:844
void * fr_rb_iter_next_preorder(fr_rb_iter_preorder_t *iter)
Return the next node.
Definition: rb.c:935
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition: rb.c:624
void * fr_rb_iter_next_postorder(fr_rb_iter_postorder_t *iter)
Return the next node.
Definition: rb.c:1019
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition: rb.c:818
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition: rb.h:271
Iterator structure for in-order traversal of an rbtree.
Definition: rb.h:321
Iterator structure for post-order traversal of an rbtree.
Definition: rb.h:356
Iterator structure for pre-order traversal of an rbtree.
Definition: rb.h:340
The main red black tree structure.
Definition: rb.h:73
static int8_t fr_rb_tree_test_cmp(void const *one, void const *two)
Definition: rb_tests.c:35
TEST_LIST
Definition: rb_tests.c:213
static void test_fr_rb_iter_postorder(void)
Definition: rb_tests.c:123
static uint32_t non_primes[]
Definition: rb_tests.c:168
static uint32_t pre_output[]
Definition: rb_tests.c:90
static void test_fr_rb_iter_inorder(void)
Definition: rb_tests.c:47
#define MAXSIZE
Definition: rb_tests.c:28
static int fr_rb_qsort_cmp(void const *one, void const *two)
Definition: rb_tests.c:41
static uint32_t pre_post_input[]
Definition: rb_tests.c:89
static bool is_prime(uint32_t n)
Definition: rb_tests.c:156
static void test_fr_rb_iter_delete(void)
Definition: rb_tests.c:171
static void test_fr_rb_iter_preorder(void)
Definition: rb_tests.c:93
static uint32_t post_output[]
Definition: rb_tests.c:91
fr_rb_node_t node
Definition: rb_tests.c:32