LCOV - code coverage report
Current view: top level - lib/ldb/tests - ldb_msg.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 212 212 100.0 %
Date: 2024-05-31 13:13:24 Functions: 8 8 100.0 %

          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             : }

Generated by: LCOV version 1.14