mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
4c16618ee3
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>
383 lines
12 KiB
C
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);
|
|
}
|