Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * Copyright (C) 2018 Andreas Schneider <asn@samba.org>
5 : * Copyright (C) 2024 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 "ldb.h"
28 : #include "ldb_private.h"
29 : #include "ldb_handlers.h"
30 : #include "util/tsort.h"
31 : #include "ldb-samba/ldb_wrap.h"
32 :
33 :
34 : #define debug_message(...) do { \
35 : if (isatty(1)) { \
36 : print_message(__VA_ARGS__); \
37 : } \
38 : } while(0)
39 :
40 : /*
41 : * We use sets of string values paired with integer rankings and make every
42 : * pair-wise comparison (both ways: cmp(a,b) and cmp(b,a)). The strings should
43 : * be consistently ordered in the same way as the integers.
44 : *
45 : * There are separate sets for the default ldb ASCII comparison, and for
46 : * Samba's utf-8 aware comparisons, and a common set that both of them should
47 : * pass.
48 : */
49 :
50 : struct ranked_value {
51 : struct ldb_val val;
52 : int rank;
53 : };
54 :
55 : #define STR_VAL(s, r) { { discard_const(s), sizeof(s) - 1 }, r}
56 :
57 : static const struct ranked_value values_common[] = {
58 : STR_VAL("", 0),
59 : STR_VAL(" ", 0),
60 : STR_VAL("a", 10),
61 : STR_VAL(" A\0 ignored-post-zero", 10),
62 : STR_VAL("a b", 15),
63 : STR_VAL("a B ", 15),
64 : STR_VAL(" A b", 15),
65 :
66 : STR_VAL("a\xc2\xfe", 30),
67 : STR_VAL("a\xc2\xfe a", 32),
68 : STR_VAL("a\xc2\xfe A", 32),
69 : STR_VAL("a\xc2\xfe Ā", 35),
70 : STR_VAL("A\xc2\xfe Ā", 35),
71 : STR_VAL("a\xc2\xfe ā", 37),
72 : STR_VAL("a\xff\xfe ā", 40),
73 :
74 : STR_VAL("b", 50),
75 :
76 : STR_VAL("\xff\xfe", 1000),
77 : };
78 :
79 : static const struct ranked_value values_default_ascii[] = {
80 : STR_VAL(" a", 1),
81 :
82 : STR_VAL("b", 50),
83 : STR_VAL("Ā", 256),
84 : STR_VAL(" Ā", 256),
85 : STR_VAL("ā", 257),
86 : STR_VAL("ā ", 257),
87 :
88 : STR_VAL("Ʊ", 433),
89 : STR_VAL("\xc8\xfe", 500),
90 : STR_VAL("ʊ", 650),
91 :
92 : STR_VAL("\xff\xfe", 1000),
93 : };
94 :
95 : static const struct ranked_value values_utf8[] = {
96 : STR_VAL(" a", 1),
97 :
98 : STR_VAL("b", 50),
99 : STR_VAL("Ā", 256),
100 : STR_VAL(" Ā", 256),
101 : STR_VAL("ā", 256),
102 : STR_VAL("ā ", 256),
103 :
104 : STR_VAL("Ʊ", 433),
105 : STR_VAL("ʊ", 433),
106 : STR_VAL("\xc8\xfe", 900),
107 :
108 : STR_VAL("\xff\xfe", 1000),
109 : };
110 :
111 :
112 :
113 : #undef STR_VAL
114 :
115 :
116 4 : static void _test_ldb_comparison_fold_set(struct ldb_context *ldb,
117 : const struct ranked_value *values,
118 : size_t n)
119 : {
120 4 : size_t i, j;
121 4 : size_t n_errors = 0;
122 :
123 56 : for (i = 0; i < n; i++) {
124 52 : struct ranked_value a = values[i];
125 764 : for (j = 0; j < n; j++) {
126 712 : struct ranked_value b = values[j];
127 712 : int ret = ldb_comparison_fold(ldb, NULL, &a.val, &b.val);
128 712 : if ((ret < 0 && a.rank < b.rank) ||
129 405 : (ret == 0 && a.rank == b.rank) ||
130 307 : (ret > 0 && a.rank > b.rank)) {
131 712 : continue;
132 : }
133 0 : debug_message("A {'%s', %zu} vs B {'%s', %zu} returned %d,"
134 : "should be %d (%d - %d)\n",
135 : a.val.data, a.val.length, b.val.data, b.val.length, ret,
136 : NUMERIC_CMP(a.rank, b.rank), a.rank, b.rank);
137 :
138 0 : n_errors++;
139 : }
140 : }
141 4 : debug_message("%zu errors out of %zu\n", n_errors, n * n);
142 :
143 4 : assert_int_equal(n_errors, 0);
144 4 : }
145 :
146 :
147 : /*
148 : * These tests are for the specific behaviour of the default ASCII-only
149 : * casefold.
150 : */
151 1 : static void test_ldb_comparison_fold_default_ascii(void **state)
152 : {
153 1 : struct ldb_context *ldb = ldb_init(NULL, NULL);
154 1 : _test_ldb_comparison_fold_set(ldb,
155 : values_default_ascii,
156 : ARRAY_SIZE(values_default_ascii));
157 1 : }
158 :
159 :
160 : /*
161 : * These tests are for behaviour with the default comparison, that should work
162 : * the same with the Samba utf-8 comparison.
163 : */
164 1 : static void test_ldb_comparison_fold_default_common(void **state)
165 : {
166 1 : struct ldb_context *ldb = ldb_init(NULL, NULL);
167 1 : _test_ldb_comparison_fold_set(ldb,
168 : values_common,
169 : ARRAY_SIZE(values_common));
170 1 : }
171 :
172 :
173 : /*
174 : * These tests are for behaviour with the Samba utf-8 comparison, that should
175 : * work the same with the default ASCII comparison.
176 : */
177 1 : static void test_ldb_comparison_fold_utf8_common(void **state)
178 : {
179 1 : struct ldb_context *ldb = ldb_init(NULL, NULL);
180 1 : ldb_set_utf8_functions(ldb, NULL, wrap_casefold, ldb_comparison_fold_utf8);
181 1 : _test_ldb_comparison_fold_set(ldb,
182 : values_common,
183 : ARRAY_SIZE(values_common));
184 1 : }
185 :
186 : /*
187 : * These tests are for the specific behaviour of the default ASCII-only
188 : * casefold.
189 : */
190 1 : static void test_ldb_comparison_fold_utf8(void **state)
191 : {
192 1 : struct ldb_context *ldb = ldb_init(NULL, NULL);
193 1 : ldb_set_utf8_functions(ldb, NULL, wrap_casefold, ldb_comparison_fold_utf8);
194 1 : _test_ldb_comparison_fold_set(ldb,
195 : values_utf8,
196 : ARRAY_SIZE(values_utf8));
197 1 : }
198 :
199 :
200 :
201 :
202 1 : int main(void) {
203 1 : const struct CMUnitTest tests[] = {
204 : cmocka_unit_test(test_ldb_comparison_fold_default_common),
205 : cmocka_unit_test(test_ldb_comparison_fold_default_ascii),
206 : cmocka_unit_test(test_ldb_comparison_fold_utf8_common),
207 : cmocka_unit_test(test_ldb_comparison_fold_utf8),
208 : };
209 1 : if (!isatty(1)) {
210 1 : cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
211 : }
212 1 : return cmocka_run_group_tests(tests, NULL, NULL);
213 : }
|