1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00
samba-mirror/lib/ldb/tests/ldb_msg.c
Andrew Bartlett 4c16618ee3 ldb: Prepare ldb tests for subunit output
These tests now print subunit rather than the default output
as this is what the Samba selftest system needs.

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
2024-03-01 02:41:36 +00:00

383 lines
12 KiB
C

/*
* 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),
};
cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
return cmocka_run_group_tests(tests, NULL, NULL);
}