LCOV - code coverage report
Current view: top level - lib/util/tests - test_stable_sort.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 143 143 100.0 %
Date: 2024-04-21 15:09:00 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  *
       4             :  * Copyright (C) 2018      Andreas Schneider <asn@samba.org>
       5             :  * Copyright (C) 2022      Douglas Bagnall   <dbagnall@samba.org>
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <stdarg.h>
      22             : #include <stddef.h>
      23             : #include <setjmp.h>
      24             : #include <cmocka.h>
      25             : #include <stdbool.h>
      26             : #include "replace.h"
      27             : #include <talloc.h>
      28             : 
      29             : #include "../stable_sort.h"
      30             : 
      31             : 
      32        9666 : static int cmp_integer(int *a, int *b)
      33             : {
      34        9666 :         if (a == NULL || b == NULL) {
      35             :                 return 0;
      36             :         }
      37             : 
      38        9666 :         if (*a > *b) {
      39             :                 return 1;
      40             :         }
      41             : 
      42        3762 :         if (*a < *b) {
      43        3762 :                 return -1;
      44             :         }
      45             : 
      46             :         return 0;
      47             : }
      48             : 
      49           1 : static void test_stable_sort(void **state)
      50             : {
      51           1 :         int a[6] = { 6, 3, 2, 7, 9, 4 };
      52           1 :         int tmp[6];
      53           1 :         bool ok;
      54           1 :         ok = stable_sort(a, tmp,
      55             :                          6, sizeof(int), (samba_compare_fn_t)cmp_integer);
      56             : 
      57           1 :         assert_true(ok);
      58           1 :         assert_int_equal(a[0], 2);
      59           1 :         assert_int_equal(a[1], 3);
      60           1 :         assert_int_equal(a[2], 4);
      61           1 :         assert_int_equal(a[3], 6);
      62           1 :         assert_int_equal(a[4], 7);
      63           1 :         assert_int_equal(a[5], 9);
      64           1 : }
      65             : 
      66           1 : static void test_stable_sort_talloc_short(void **state)
      67             : {
      68           1 :         int a[6] = { 6, 3, 2, 7, 9, 4 };
      69           1 :         int ret;
      70           1 :         ret = stable_sort_talloc(NULL, a, 6, sizeof(int),
      71             :                                  (samba_compare_fn_t)cmp_integer);
      72           1 :         assert_true(ret);
      73             : 
      74           1 :         assert_int_equal(a[0], 2);
      75           1 :         assert_int_equal(a[1], 3);
      76           1 :         assert_int_equal(a[2], 4);
      77           1 :         assert_int_equal(a[3], 6);
      78           1 :         assert_int_equal(a[4], 7);
      79           1 :         assert_int_equal(a[5], 9);
      80           1 : }
      81             : 
      82           1 : static void test_stable_sort_talloc_long(void **state)
      83             : {
      84           1 :         int i, ret;
      85           1 :         size_t n = 1500;
      86           1 :         TALLOC_CTX *mem_ctx = talloc_new(NULL);
      87           1 :         int *a = talloc_array(mem_ctx, int, n);
      88        1502 :         for (i = 0; i < n; i++) {
      89        1500 :                 a[i] = n - i;
      90             :         }
      91             : 
      92           1 :         ret = stable_sort_talloc(mem_ctx, a, n, sizeof(int),
      93             :                                      (samba_compare_fn_t)cmp_integer);
      94           1 :         assert_true(ret);
      95             : 
      96        1502 :         for (i = 0; i < n; i++) {
      97        1500 :                 assert_int_equal(a[i], 1 + i);
      98             :         }
      99           1 : }
     100             : 
     101             : 
     102             : /*
     103             :  * Sort an array of structs with:
     104             :  * - unwieldy uneven size
     105             :  * - sort key not at the start
     106             :  * - comparison depends on context
     107             :  *
     108             :  * which are things we sometimes do.
     109             :  */
     110             : 
     111             : struct contrived_struct {
     112             :         char padding_1[13];
     113             :         int key[3];
     114             :         char padding_2[18];
     115             :         size_t *index;
     116             : };
     117             : 
     118             : 
     119    42903256 : static int cmp_contrived_struct(struct contrived_struct *as,
     120             :                                 struct contrived_struct *bs)
     121             : {
     122    42903256 :         int i = *as->index;
     123    42903256 :         int a = as->key[i];
     124    42903256 :         int b = bs->key[i];
     125    42903256 :         return a - b;
     126             : }
     127             : 
     128    14959079 : static int cmp_contrived_struct_rev(struct contrived_struct *as,
     129             :                                     struct contrived_struct *bs)
     130             : {
     131             :         /* will sort in reverseo order */
     132    14959079 :         int i = *as->index;
     133    14959079 :         int a = as->key[i];
     134    14959079 :         int b = bs->key[i];
     135    14959079 :         return b - a;
     136             : }
     137             : 
     138             : 
     139           1 : static void test_stable_sort_talloc_contrived_struct(void **state)
     140             : {
     141           1 :         int i, ret, prev;
     142           1 :         size_t n = 800000;
     143           1 :         TALLOC_CTX *mem_ctx = talloc_new(NULL);
     144           1 :         size_t key_index = 0;
     145             : 
     146           1 :         struct contrived_struct *a = talloc_zero_array(mem_ctx,
     147             :                                                        struct contrived_struct,
     148             :                                                        n);
     149             : 
     150             :         /* we don't really want a good RNG, we want mess and repeated values. */
     151           1 :         uint32_t x = 89, y = (uint32_t)-6, z = 11;
     152      800002 :         for (i = 0; i < n; i++) {
     153      800000 :                 a[i].index = &key_index;
     154      800000 :                 a[i].key[0] = (x & 0xffff) - 0x8000;
     155      800000 :                 a[i].key[1] = z & 255;
     156             :                 /* key[2] is original order, useful for checking stability */
     157      800000 :                 a[i].key[2] = i;
     158      800000 :                 x += z ^ y;
     159      800000 :                 y *= z + (x + 0x5555);
     160      800000 :                 z -= x ^ i;
     161             :         }
     162             : 
     163             :         /* 1. sort by key[0] */
     164           1 :         ret = stable_sort_talloc(mem_ctx, a, n,
     165             :                                  sizeof(struct contrived_struct),
     166             :                                  (samba_compare_fn_t)cmp_contrived_struct);
     167           1 :         assert_true(ret);
     168           1 :         prev = a[0].key[0];
     169      800000 :         for (i = 1; i < n; i++) {
     170      799999 :                 int value = a[i].key[0];
     171      799999 :                 assert_true(value >= prev);
     172      799999 :                 if (value == prev) {
     173             :                         /* we can test the stability by comparing key[2] */
     174      769043 :                         assert_true(a[i].key[2] >= a[i - 1].key[2]);
     175             :                 }
     176      799999 :                 prev = value;
     177             :         }
     178             : 
     179             :         /* 2. sort by key[1]. key[0] now indicates stability. */
     180           1 :         key_index = 1;
     181           1 :         ret = stable_sort_talloc(mem_ctx, a, n,
     182             :                                  sizeof(struct contrived_struct),
     183             :                                  (samba_compare_fn_t)cmp_contrived_struct);
     184           1 :         assert_true(ret);
     185           1 :         prev = a[0].key[1];
     186      800000 :         for (i = 1; i < n; i++) {
     187      799999 :                 int value = a[i].key[1];
     188      799999 :                 assert_true(value >= prev);
     189      799999 :                 if (value == prev) {
     190      799887 :                         assert_true(a[i].key[0] >= a[i - 1].key[0]);
     191             :                 }
     192      799999 :                 prev = value;
     193             :         }
     194             : 
     195             :         /*
     196             :          * 3. sort by key[2]. key[1] would now indicate stability, but we know
     197             :          * that key[2] has no duplicates, so stability is moot.
     198             :          */
     199           1 :         key_index = 2;
     200           1 :         ret = stable_sort_talloc(mem_ctx, a, n,
     201             :                                  sizeof(struct contrived_struct),
     202             :                                  (samba_compare_fn_t)cmp_contrived_struct);
     203           1 :         assert_true(ret);
     204           1 :         prev = a[0].key[2];
     205      800000 :         for (i = 1; i < n; i++) {
     206      799999 :                 int value = a[i].key[2];
     207      799999 :                 assert_true(value > prev);
     208      799999 :                 prev = value;
     209             :         }
     210             : 
     211             :         /*
     212             :          * 4. sort by key[0] again, using descending sort order. key[2] should
     213             :          * still be in ascending order where there are duplicate key[0] values.
     214             :          */
     215           1 :         key_index = 0;
     216           1 :         ret = stable_sort_talloc(mem_ctx, a, n,
     217             :                                  sizeof(struct contrived_struct),
     218             :                                  (samba_compare_fn_t)cmp_contrived_struct_rev);
     219           1 :         assert_true(ret);
     220           1 :         prev = a[0].key[0];
     221      800000 :         for (i = 1; i < n; i++) {
     222      799999 :                 int value = a[i].key[0];
     223      799999 :                 assert_true(value <= prev);
     224      799999 :                 if (value == prev) {
     225      769043 :                         assert_true(a[i].key[2] >= a[i - 1].key[2]);
     226             :                 }
     227      799999 :                 prev = value;
     228             :         }
     229           1 : }
     230             : 
     231             : 
     232             : 
     233       13624 : static int cmp_integer_xor_blob(int *_a, int *_b, int *opaque)
     234             : {
     235       13624 :         int a = *_a ^ *opaque;
     236       13624 :         int b = *_b ^ *opaque;
     237             : 
     238       13624 :         if (a > b) {
     239             :                 return 1;
     240             :         }
     241             : 
     242        7489 :         if (a < b) {
     243        5477 :                 return -1;
     244             :         }
     245             : 
     246             :         return 0;
     247             : }
     248             : 
     249           1 : static void test_stable_sort_talloc_r(void **state)
     250             : {
     251           1 :         int i;
     252           1 :         size_t n = 1500;
     253           1 :         TALLOC_CTX *mem_ctx = talloc_new(NULL);
     254           1 :         int opaque = 42;
     255           1 :         bool ok;
     256           1 :         int *a = talloc_array(mem_ctx, int, n);
     257        1502 :         for (i = 0; i < n; i++) {
     258        1500 :                 a[i] = (i * 7) & 255;
     259             :         }
     260             : 
     261           1 :         ok = stable_sort_talloc_r(mem_ctx, a, n, sizeof(int),
     262             :                                   (samba_compare_with_context_fn_t)cmp_integer_xor_blob,
     263             :                                   &opaque);
     264           1 :         assert_true(ok);
     265             : 
     266        1501 :         for (i = 1; i < n; i++) {
     267        1499 :                 assert_true((a[i - 1] ^ opaque) <= (a[i] ^ opaque));
     268             :         }
     269           1 : }
     270             : 
     271             : 
     272           1 : static void test_stable_sort_silly_size(void **state)
     273             : {
     274           1 :         bool ok;
     275           1 :         int a[33] = {0};
     276           1 :         int b[33] = {0};
     277             : 
     278           1 :         ok = stable_sort(a,
     279             :                          b,
     280             :                          (SIZE_MAX / 2) + 2,
     281             :                          (SIZE_MAX / 2) + 2,
     282             :                          (samba_compare_fn_t)cmp_integer);
     283           1 :         assert_false(ok);
     284           1 : }
     285             : 
     286           1 : static void test_stable_sort_null_array(void **state)
     287             : {
     288           1 :         bool ok;
     289           1 :         int a[33] = {0};
     290             : 
     291           1 :         ok = stable_sort(a,
     292             :                          NULL,
     293             :                          33,
     294             :                          sizeof(int),
     295             :                          (samba_compare_fn_t)cmp_integer);
     296           1 :         assert_false(ok);
     297           1 : }
     298             : 
     299             : 
     300             : 
     301             : 
     302             : 
     303           1 : int main(void) {
     304           1 :         const struct CMUnitTest tests[] = {
     305             :                 cmocka_unit_test(test_stable_sort),
     306             :                 cmocka_unit_test(test_stable_sort_talloc_short),
     307             :                 cmocka_unit_test(test_stable_sort_talloc_long),
     308             :                 cmocka_unit_test(test_stable_sort_talloc_contrived_struct),
     309             :                 cmocka_unit_test(test_stable_sort_talloc_r),
     310             :                 cmocka_unit_test(test_stable_sort_silly_size),
     311             :                 cmocka_unit_test(test_stable_sort_null_array),
     312             :         };
     313           1 :         if (!isatty(1)) {
     314           1 :                 cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
     315             :         }
     316           1 :         return cmocka_run_group_tests(tests, NULL, NULL);
     317             : }

Generated by: LCOV version 1.14