Line data Source code
1 : /*
2 : * from cmocka.c:
3 : * These headers or their equivalents should be included prior to
4 : * including
5 : * this header file.
6 : *
7 : * #include <stdarg.h>
8 : * #include <stddef.h>
9 : * #include <setjmp.h>
10 : *
11 : * This allows test applications to use custom definitions of C standard
12 : * library functions and types.
13 : */
14 : #include <stdarg.h>
15 : #include <stddef.h>
16 : #include <stdint.h>
17 : #include <setjmp.h>
18 : #include <cmocka.h>
19 :
20 : #include <errno.h>
21 : #include <unistd.h>
22 : #include <talloc.h>
23 :
24 : #include <ldb.h>
25 : #include <ldb_private.h>
26 : #include <string.h>
27 : #include <ctype.h>
28 :
29 : struct test_ctx {
30 : struct ldb_message *msg;
31 : };
32 :
33 2 : static int ldb_msg_setup(void **state)
34 : {
35 2 : struct test_ctx *test_ctx;
36 :
37 2 : test_ctx = talloc_zero(NULL, struct test_ctx);
38 2 : assert_non_null(test_ctx);
39 :
40 2 : test_ctx->msg = ldb_msg_new(test_ctx);
41 :
42 2 : *state = test_ctx;
43 2 : return 0;
44 : }
45 :
46 2 : static int ldb_msg_teardown(void **state)
47 : {
48 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
49 : struct test_ctx);
50 :
51 2 : talloc_free(test_ctx);
52 2 : return 0;
53 : }
54 :
55 :
56 27 : static void add_uint_value(struct test_ctx *test_ctx,
57 : struct ldb_message *msg,
58 : const char *attr,
59 : unsigned int x)
60 : {
61 27 : int ret;
62 27 : struct ldb_val v, v_dup;
63 27 : char s[5];
64 27 : snprintf(s, sizeof(s), "%04x", x);
65 27 : v.data = (uint8_t *)s;
66 27 : v.length = 4;
67 27 : v_dup = ldb_val_dup(test_ctx, &v);
68 27 : assert_non_null(v_dup.data);
69 27 : assert_ptr_not_equal(v_dup.data, v.data);
70 27 : assert_int_equal(v_dup.length, 4);
71 :
72 27 : ret = ldb_msg_add_value(msg, attr, &v_dup, NULL);
73 27 : assert_int_equal(ret, LDB_SUCCESS);
74 27 : }
75 :
76 :
77 1 : static void test_ldb_msg_find_duplicate_val(void **state)
78 : {
79 1 : int ret;
80 1 : unsigned int i;
81 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
82 : struct test_ctx);
83 1 : struct ldb_message *msg = test_ctx->msg;
84 1 : struct ldb_message_element *el;
85 1 : struct ldb_val dummy;
86 1 : struct ldb_val *dupe = &dummy; /* so we can tell it was modified to NULL, not left as NULL */
87 :
88 1 : ret = ldb_msg_add_empty(msg, "el1", 0, &el);
89 1 : assert_int_equal(ret, LDB_SUCCESS);
90 :
91 : /* An empty message contains no duplicates */
92 1 : ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
93 1 : assert_int_equal(ret, LDB_SUCCESS);
94 1 : assert_null(dupe);
95 :
96 7 : for (i = 0; i < 5; i++) {
97 5 : add_uint_value(test_ctx, msg, "el1", i);
98 : }
99 : /* at this point there are no duplicates, and the check uses the naive
100 : quadratic path */
101 1 : ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
102 1 : assert_int_equal(ret, LDB_SUCCESS);
103 1 : assert_null(dupe);
104 :
105 : /* add a duplicate, still using quadratric path */
106 1 : add_uint_value(test_ctx, msg, "el1", 3);
107 1 : ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
108 1 : assert_int_equal(ret, LDB_SUCCESS);
109 1 : assert_non_null(dupe);
110 1 : assert_int_equal(dupe->length, 4);
111 1 : assert_memory_equal(dupe->data, "0003", 4);
112 :
113 : /* add some more, triggering algorithmic jump */
114 11 : for (i = 2; i < 11; i++) {
115 9 : add_uint_value(test_ctx, msg, "el1", i);
116 : }
117 1 : ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
118 1 : assert_int_equal(ret, LDB_SUCCESS);
119 1 : assert_non_null(dupe);
120 1 : assert_int_equal(dupe->length, 4);
121 : /*XXX not really guaranteed by the API */
122 1 : assert_memory_equal(dupe->data, "0002", 4);
123 :
124 : /* start a new element without duplicates, for the clever algorithm */
125 1 : ldb_msg_add_empty(msg, "el2", 0, &el);
126 14 : for (i = 0; i < 12; i++) {
127 12 : add_uint_value(test_ctx, msg, "el2", i);
128 : }
129 1 : ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
130 1 : assert_int_equal(ret, LDB_SUCCESS);
131 1 : assert_null(dupe);
132 1 : }
133 :
134 :
135 17 : static struct ldb_message_element *new_msg_element(TALLOC_CTX *mem_ctx,
136 : const char *name,
137 : unsigned int value_offset,
138 : unsigned int num_values)
139 : {
140 17 : unsigned int i, x;
141 17 : struct ldb_message_element *el = talloc_zero(mem_ctx,
142 : struct ldb_message_element);
143 :
144 17 : el->values = talloc_array(el, struct ldb_val, num_values);
145 125 : for (i = 0; i < num_values; i++) {
146 108 : struct ldb_val v;
147 108 : char s[50];
148 108 : v.data = (uint8_t *)s;
149 : /* % 3 is to ensure the values list is unsorted */
150 108 : x = i + value_offset;
151 108 : v.length = snprintf(s, sizeof(s), "%u %u", x % 3, x);
152 108 : el->values[i] = ldb_val_dup(mem_ctx, &v);
153 : }
154 17 : el->name = name;
155 17 : el->num_values = num_values;
156 17 : return el;
157 : }
158 :
159 22 : static void _assert_element_equal(struct ldb_message_element *a,
160 : struct ldb_message_element *b,
161 : const char * const file,
162 : const int line)
163 : {
164 22 : unsigned int i;
165 22 : _assert_int_equal(a->num_values, b->num_values, file, line);
166 22 : _assert_int_equal(a->flags, b->flags, file, line);
167 22 : _assert_string_equal(a->name, b->name, file, line);
168 208 : for (i = 0; i < a->num_values; i++) {
169 164 : struct ldb_val *v1 = &a->values[i];
170 164 : struct ldb_val *v2 = &b->values[i];
171 164 : _assert_int_equal(v1->length, v2->length, file, line);
172 164 : _assert_memory_equal(v1->data, v2->data, v1->length,
173 : file, line);
174 : }
175 22 : }
176 :
177 : #define assert_element_equal(a, b) \
178 : _assert_element_equal((a), (b), \
179 : __FILE__, __LINE__)
180 :
181 :
182 1 : static void test_ldb_msg_find_common_values(void **state)
183 : {
184 : /* we only use the state as a talloc context */
185 1 : struct ldb_message_element *el, *el2, *el3, *el4, *el2b, *empty;
186 1 : struct ldb_message_element *orig, *orig2, *orig3, *orig4;
187 1 : int ret;
188 1 : const uint32_t remove_dupes = LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
189 1 : el = new_msg_element(*state, "test", 0, 4);
190 1 : el2 = new_msg_element(*state, "test", 4, 4);
191 1 : el3 = new_msg_element(*state, "test", 6, 4);
192 1 : empty = new_msg_element(*state, "test", 0, 0);
193 1 : orig = new_msg_element(*state, "test", 0, 4);
194 1 : orig2 = new_msg_element(*state, "test", 4, 4);
195 1 : orig3 = new_msg_element(*state, "test", 6, 4);
196 :
197 : /* first round is with short value arrays, using quadratic method */
198 : /* we expect no collisions here */
199 1 : ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
200 1 : assert_int_equal(ret, LDB_SUCCESS);
201 :
202 : /*or here */
203 1 : ret = ldb_msg_find_common_values(NULL, *state, el, el3, 0);
204 1 : assert_int_equal(ret, LDB_SUCCESS);
205 :
206 : /* the same elements in reverse order */
207 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
208 1 : assert_int_equal(ret, LDB_SUCCESS);
209 :
210 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
211 1 : assert_int_equal(ret, LDB_SUCCESS);
212 :
213 : /* 6, 7 collide */
214 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
215 1 : assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
216 :
217 : /* and again */
218 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
219 1 : assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
220 :
221 : /* make sure the arrays haven't changed */
222 1 : assert_element_equal(el, orig);
223 1 : assert_element_equal(el2, orig2);
224 1 : assert_element_equal(el3, orig3);
225 :
226 : /* now with the control permisive flag, the first element should be
227 : modified to remove the overlap.*/
228 :
229 : /* 6, 7 collide, so el2 will only have 4 and 5 */
230 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
231 1 : assert_int_equal(ret, LDB_SUCCESS);
232 :
233 1 : assert_element_equal(el3, orig3);
234 1 : assert_int_not_equal(el2->num_values, orig2->num_values);
235 1 : assert_int_equal(el2->num_values, 2);
236 1 : el2b = new_msg_element(*state, "test", 4, 2);
237 1 : assert_element_equal(el2, el2b);
238 :
239 : /* now try the same things with a long and a short value list.
240 : this should still trigger the quadratic path.
241 : */
242 1 : el2 = new_msg_element(*state, "test", 4, 10);
243 1 : orig2 = new_msg_element(*state, "test", 4, 10);
244 :
245 : /* no collisions */
246 1 : ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
247 1 : assert_int_equal(ret, LDB_SUCCESS);
248 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
249 1 : assert_int_equal(ret, LDB_SUCCESS);
250 :
251 : /*collisions */
252 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
253 1 : assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
254 :
255 1 : assert_element_equal(el, orig);
256 1 : assert_element_equal(el2, orig2);
257 1 : assert_element_equal(el3, orig3);
258 :
259 : /*collisions with permissive flag*/
260 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
261 1 : assert_int_equal(ret, LDB_SUCCESS);
262 1 : assert_element_equal(el2, orig2);
263 1 : assert_int_equal(el3->num_values, 0);
264 :
265 : /* permutations involving empty elements.
266 : everything should succeed. */
267 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
268 1 : assert_int_equal(ret, LDB_SUCCESS);
269 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
270 1 : assert_int_equal(ret, LDB_SUCCESS);
271 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
272 1 : assert_int_equal(ret, LDB_SUCCESS);
273 1 : assert_int_equal(el2->num_values, orig2->num_values);
274 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
275 1 : assert_int_equal(ret, LDB_SUCCESS);
276 1 : assert_int_equal(el2->num_values, orig2->num_values);
277 1 : assert_int_equal(el3->num_values, 0); /* el3 is now empty */
278 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
279 1 : assert_int_equal(ret, LDB_SUCCESS);
280 1 : ret = ldb_msg_find_common_values(NULL, *state, el3, empty, 0);
281 1 : assert_int_equal(ret, LDB_SUCCESS);
282 1 : ret = ldb_msg_find_common_values(NULL, *state, empty, empty, 0);
283 1 : assert_int_equal(ret, LDB_SUCCESS);
284 1 : ret = ldb_msg_find_common_values(NULL, *state, empty, el3, 0);
285 1 : assert_int_equal(ret, LDB_SUCCESS);
286 :
287 1 : assert_element_equal(el2, orig2);
288 1 : assert_element_equal(el, orig);
289 1 : assert_int_equal(el3->num_values, 0);
290 :
291 : /* now with two large value lists */
292 1 : el = new_msg_element(*state, "test", 0, 12);
293 1 : orig = new_msg_element(*state, "test", 0, 12);
294 1 : el4 = new_msg_element(*state, "test", 12, 12);
295 1 : orig4 = new_msg_element(*state, "test", 12, 12);
296 :
297 : /* no collisions */
298 1 : ret = ldb_msg_find_common_values(NULL, *state, el, el4, 0);
299 1 : assert_int_equal(ret, LDB_SUCCESS);
300 :
301 1 : ret = ldb_msg_find_common_values(NULL, *state, el4, el, 0);
302 1 : assert_int_equal(ret, LDB_SUCCESS);
303 :
304 : /* collisions */
305 1 : ret = ldb_msg_find_common_values(NULL, *state, el4, el2, 0);
306 1 : assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
307 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el4, 0);
308 1 : assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
309 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
310 1 : assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
311 :
312 1 : assert_element_equal(el, orig);
313 1 : assert_element_equal(el2, orig2);
314 1 : assert_element_equal(el4, orig4);
315 :
316 : /* with permissive control, but no collisions */
317 1 : ret = ldb_msg_find_common_values(NULL, *state, el, el4, remove_dupes);
318 1 : assert_int_equal(ret, LDB_SUCCESS);
319 1 : ret = ldb_msg_find_common_values(NULL, *state, el4, el, remove_dupes);
320 1 : assert_int_equal(ret, LDB_SUCCESS);
321 :
322 1 : assert_element_equal(el, orig);
323 1 : assert_element_equal(el4, orig4);
324 :
325 : /* now with collisions, thus modifications.
326 : At this stage:
327 : el is 0-11 (inclusive)
328 : e2 is 4-13
329 : el3 is empty
330 : el4 is 12-23
331 : */
332 1 : ret = ldb_msg_find_common_values(NULL, *state, el4, el2, remove_dupes);
333 1 : assert_int_equal(ret, LDB_SUCCESS);
334 1 : assert_element_equal(el2, orig2);
335 1 : assert_int_not_equal(el4->num_values, orig4->num_values);
336 : /* 4 should start at 14 */
337 1 : orig4 = new_msg_element(*state, "test", 14, 10);
338 1 : assert_element_equal(el4, orig4);
339 :
340 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
341 1 : assert_int_equal(ret, LDB_SUCCESS);
342 1 : assert_element_equal(el, orig);
343 1 : assert_int_not_equal(el2->num_values, orig2->num_values);
344 1 : orig2 = new_msg_element(*state, "test", 12, 2);
345 1 : assert_element_equal(el2, orig2);
346 :
347 : /* test the empty el against the full elements */
348 1 : ret = ldb_msg_find_common_values(NULL, *state, el, empty, 0);
349 1 : assert_int_equal(ret, LDB_SUCCESS);
350 1 : ret = ldb_msg_find_common_values(NULL, *state, empty, el, 0);
351 1 : assert_int_equal(ret, LDB_SUCCESS);
352 1 : ret = ldb_msg_find_common_values(NULL, *state, el, empty, remove_dupes);
353 1 : assert_int_equal(ret, LDB_SUCCESS);
354 1 : ret = ldb_msg_find_common_values(NULL, *state, empty, el, remove_dupes);
355 1 : assert_int_equal(ret, LDB_SUCCESS);
356 1 : assert_element_equal(el, orig);
357 1 : assert_element_equal(empty, el3);
358 :
359 : /* make sure an identical element with a different name is rejected */
360 1 : el2 = new_msg_element(*state, "fish", 12, 2);
361 1 : ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
362 1 : assert_int_equal(ret, LDB_ERR_INAPPROPRIATE_MATCHING);
363 1 : }
364 :
365 :
366 :
367 1 : int main(int argc, const char **argv)
368 : {
369 1 : const struct CMUnitTest tests[] = {
370 : cmocka_unit_test_setup_teardown(test_ldb_msg_find_duplicate_val,
371 : ldb_msg_setup,
372 : ldb_msg_teardown),
373 : cmocka_unit_test_setup_teardown(
374 : test_ldb_msg_find_common_values,
375 : ldb_msg_setup,
376 : ldb_msg_teardown),
377 : };
378 :
379 1 : cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
380 :
381 1 : return cmocka_run_group_tests(tests, NULL, NULL);
382 : }
|