summaryrefslogtreecommitdiffstats
path: root/lib/ldb/tests/ldb_msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ldb/tests/ldb_msg.c')
-rw-r--r--lib/ldb/tests/ldb_msg.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/lib/ldb/tests/ldb_msg.c b/lib/ldb/tests/ldb_msg.c
new file mode 100644
index 0000000..31786a9
--- /dev/null
+++ b/lib/ldb/tests/ldb_msg.c
@@ -0,0 +1,380 @@
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+
+#include <ldb.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+struct test_ctx {
+ struct ldb_message *msg;
+};
+
+static int ldb_msg_setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->msg = ldb_msg_new(test_ctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldb_msg_teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ talloc_free(test_ctx);
+ return 0;
+}
+
+
+static void add_uint_value(struct test_ctx *test_ctx,
+ struct ldb_message *msg,
+ const char *attr,
+ unsigned int x)
+{
+ int ret;
+ struct ldb_val v, v_dup;
+ char s[5];
+ snprintf(s, sizeof(s), "%04x", x);
+ v.data = (uint8_t *)s;
+ v.length = 4;
+ v_dup = ldb_val_dup(test_ctx, &v);
+ assert_non_null(v_dup.data);
+ assert_ptr_not_equal(v_dup.data, v.data);
+ assert_int_equal(v_dup.length, 4);
+
+ ret = ldb_msg_add_value(msg, attr, &v_dup, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+}
+
+
+static void test_ldb_msg_find_duplicate_val(void **state)
+{
+ int ret;
+ unsigned int i;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_message *msg = test_ctx->msg;
+ struct ldb_message_element *el;
+ struct ldb_val dummy;
+ struct ldb_val *dupe = &dummy; /* so we can tell it was modified to NULL, not left as NULL */
+
+ ret = ldb_msg_add_empty(msg, "el1", 0, &el);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* An empty message contains no duplicates */
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+
+ for (i = 0; i < 5; i++) {
+ add_uint_value(test_ctx, msg, "el1", i);
+ }
+ /* at this point there are no duplicates, and the check uses the naive
+ quadratic path */
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+
+ /* add a duplicate, still using quadratric path */
+ add_uint_value(test_ctx, msg, "el1", 3);
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(dupe);
+ assert_int_equal(dupe->length, 4);
+ assert_memory_equal(dupe->data, "0003", 4);
+
+ /* add some more, triggering algorithmic jump */
+ for (i = 2; i < 11; i++) {
+ add_uint_value(test_ctx, msg, "el1", i);
+ }
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(dupe);
+ assert_int_equal(dupe->length, 4);
+ /*XXX not really guaranteed by the API */
+ assert_memory_equal(dupe->data, "0002", 4);
+
+ /* start a new element without duplicates, for the clever algorithm */
+ ldb_msg_add_empty(msg, "el2", 0, &el);
+ for (i = 0; i < 12; i++) {
+ add_uint_value(test_ctx, msg, "el2", i);
+ }
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+}
+
+
+static struct ldb_message_element *new_msg_element(TALLOC_CTX *mem_ctx,
+ const char *name,
+ unsigned int value_offset,
+ unsigned int num_values)
+{
+ unsigned int i, x;
+ struct ldb_message_element *el = talloc_zero(mem_ctx,
+ struct ldb_message_element);
+
+ el->values = talloc_array(el, struct ldb_val, num_values);
+ for (i = 0; i < num_values; i++) {
+ struct ldb_val v;
+ char s[50];
+ v.data = (uint8_t *)s;
+ /* % 3 is to ensure the values list is unsorted */
+ x = i + value_offset;
+ v.length = snprintf(s, sizeof(s), "%u %u", x % 3, x);
+ el->values[i] = ldb_val_dup(mem_ctx, &v);
+ }
+ el->name = name;
+ el->num_values = num_values;
+ return el;
+}
+
+static void _assert_element_equal(struct ldb_message_element *a,
+ struct ldb_message_element *b,
+ const char * const file,
+ const int line)
+{
+ unsigned int i;
+ _assert_int_equal(a->num_values, b->num_values, file, line);
+ _assert_int_equal(a->flags, b->flags, file, line);
+ _assert_string_equal(a->name, b->name, file, line);
+ for (i = 0; i < a->num_values; i++) {
+ struct ldb_val *v1 = &a->values[i];
+ struct ldb_val *v2 = &b->values[i];
+ _assert_int_equal(v1->length, v2->length, file, line);
+ _assert_memory_equal(v1->data, v2->data, v1->length,
+ file, line);
+ }
+}
+
+#define assert_element_equal(a, b) \
+ _assert_element_equal((a), (b), \
+ __FILE__, __LINE__)
+
+
+static void test_ldb_msg_find_common_values(void **state)
+{
+ /* we only use the state as a talloc context */
+ struct ldb_message_element *el, *el2, *el3, *el4, *el2b, *empty;
+ struct ldb_message_element *orig, *orig2, *orig3, *orig4;
+ int ret;
+ const uint32_t remove_dupes = LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
+ el = new_msg_element(*state, "test", 0, 4);
+ el2 = new_msg_element(*state, "test", 4, 4);
+ el3 = new_msg_element(*state, "test", 6, 4);
+ empty = new_msg_element(*state, "test", 0, 0);
+ orig = new_msg_element(*state, "test", 0, 4);
+ orig2 = new_msg_element(*state, "test", 4, 4);
+ orig3 = new_msg_element(*state, "test", 6, 4);
+
+ /* first round is with short value arrays, using quadratic method */
+ /* we expect no collisions here */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*or here */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* the same elements in reverse order */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* 6, 7 collide */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ /* and again */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ /* make sure the arrays haven't changed */
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el3, orig3);
+
+ /* now with the control permisive flag, the first element should be
+ modified to remove the overlap.*/
+
+ /* 6, 7 collide, so el2 will only have 4 and 5 */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el3, orig3);
+ assert_int_not_equal(el2->num_values, orig2->num_values);
+ assert_int_equal(el2->num_values, 2);
+ el2b = new_msg_element(*state, "test", 4, 2);
+ assert_element_equal(el2, el2b);
+
+ /* now try the same things with a long and a short value list.
+ this should still trigger the quadratic path.
+ */
+ el2 = new_msg_element(*state, "test", 4, 10);
+ orig2 = new_msg_element(*state, "test", 4, 10);
+
+ /* no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el3, orig3);
+
+ /*collisions with permissive flag*/
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el2, orig2);
+ assert_int_equal(el3->num_values, 0);
+
+ /* permutations involving empty elements.
+ everything should succeed. */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(el2->num_values, orig2->num_values);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(el2->num_values, orig2->num_values);
+ assert_int_equal(el3->num_values, 0); /* el3 is now empty */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el, orig);
+ assert_int_equal(el3->num_values, 0);
+
+ /* now with two large value lists */
+ el = new_msg_element(*state, "test", 0, 12);
+ orig = new_msg_element(*state, "test", 0, 12);
+ el4 = new_msg_element(*state, "test", 12, 12);
+ orig4 = new_msg_element(*state, "test", 12, 12);
+
+ /* no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el4, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el4, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el4, orig4);
+
+ /* with permissive control, but no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el4, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el4, orig4);
+
+ /* now with collisions, thus modifications.
+ At this stage:
+ el is 0-11 (inclusive)
+ e2 is 4-13
+ el3 is empty
+ el4 is 12-23
+ */
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el2, orig2);
+ assert_int_not_equal(el4->num_values, orig4->num_values);
+ /* 4 should start at 14 */
+ orig4 = new_msg_element(*state, "test", 14, 10);
+ assert_element_equal(el4, orig4);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el, orig);
+ assert_int_not_equal(el2->num_values, orig2->num_values);
+ orig2 = new_msg_element(*state, "test", 12, 2);
+ assert_element_equal(el2, orig2);
+
+ /* test the empty el against the full elements */
+ ret = ldb_msg_find_common_values(NULL, *state, el, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el, empty, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el, orig);
+ assert_element_equal(empty, el3);
+
+ /* make sure an identical element with a different name is rejected */
+ el2 = new_msg_element(*state, "fish", 12, 2);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
+ assert_int_equal(ret, LDB_ERR_INAPPROPRIATE_MATCHING);
+}
+
+
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_ldb_msg_find_duplicate_val,
+ ldb_msg_setup,
+ ldb_msg_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_msg_find_common_values,
+ ldb_msg_setup,
+ ldb_msg_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}