xref: /aosp_15_r20/external/icu/icu4c/source/test/cintltst/chashtst.c (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *   Copyright (C) 2000-2009, International Business Machines
6 *   Corporation and others.  All Rights Reserved.
7 *******************************************************************************
8 *   Date        Name        Description
9 *   03/22/00    aliu        Creation.
10 *   07/13/00    Madhu       Added more tests
11 *******************************************************************************
12 */
13 
14 #include <stdbool.h>
15 #include "cintltst.h"
16 #include "uhash.h"
17 #include "unicode/ctest.h"
18 #include "unicode/ustring.h"
19 #include "cstring.h"
20 
21 /**********************************************************************
22  * Prototypes
23  *********************************************************************/
24 
25 static void TestBasic(void);
26 static void TestAllowZero(void);
27 static void TestOtherAPI(void);
28 static void hashIChars(void);
29 
30 static int32_t U_EXPORT2 U_CALLCONV hashChars(const UHashTok key);
31 
32 static UBool U_EXPORT2 U_CALLCONV isEqualChars(const UHashTok key1, const UHashTok key2);
33 
34 static void _put(UHashtable* hash,
35                  const char* key,
36                  int32_t value,
37                  int32_t expectedOldValue);
38 
39 static void _get(UHashtable* hash,
40           const char* key,
41           int32_t expectedValue);
42 
43 static void _remove(UHashtable* hash,
44              const char* key,
45              int32_t expectedValue);
46 
47 void addHashtableTest(TestNode** root);
48 
49 /**********************************************************************
50  * UHashTok wrapper functions
51  *********************************************************************/
52 
53 static UBool
_compareChars(const void * a,const void * b)54 _compareChars(const void* a, const void* b) {
55     UHashTok s, t;
56     s.pointer = (void *)a;
57     t.pointer = (void *)b;
58     return uhash_compareChars(s, t);
59 }
60 
61 static UBool
_compareIChars(const void * a,const void * b)62 _compareIChars(const void* a, const void* b) {
63     UHashTok s, t;
64     s.pointer = (void *)a;
65     t.pointer = (void *)b;
66     return uhash_compareIChars(s, t);
67 }
68 
69 static UBool
_compareUChars(const void * a,const void * b)70 _compareUChars(const void* a, const void* b) {
71     UHashTok s, t;
72     s.pointer = (void *)a;
73     t.pointer = (void *)b;
74     return uhash_compareUChars(s, t);
75 }
76 
77 static UBool
_compareLong(int32_t a,int32_t b)78 _compareLong(int32_t a, int32_t b) {
79     UHashTok s, t;
80     s.integer = a;
81     t.integer = b;
82     return uhash_compareLong(s, t);
83 }
84 
85 /**********************************************************************
86  * FW Registration
87  *********************************************************************/
88 
addHashtableTest(TestNode ** root)89 void addHashtableTest(TestNode** root) {
90 
91     addTest(root, &TestBasic,   "tsutil/chashtst/TestBasic");
92     addTest(root, &TestAllowZero, "tsutil/chashtst/TestAllowZero");
93     addTest(root, &TestOtherAPI, "tsutil/chashtst/TestOtherAPI");
94     addTest(root, &hashIChars, "tsutil/chashtst/hashIChars");
95 
96 }
97 
98 /**********************************************************************
99  * Test Functions
100  *********************************************************************/
101 
TestBasic(void)102 static void TestBasic(void) {
103     static const char one[4] =   {0x6F, 0x6E, 0x65, 0}; /* "one" */
104     static const char one2[4] =  {0x6F, 0x6E, 0x65, 0}; /* Get around compiler optimizations */
105     static const char two[4] =   {0x74, 0x77, 0x6F, 0}; /* "two" */
106     static const char three[6] = {0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* "three" */
107     static const char omega[6] = {0x6F, 0x6D, 0x65, 0x67, 0x61, 0}; /* "omega" */
108     UErrorCode status = U_ZERO_ERROR;
109     UHashtable *hash;
110 
111     hash = uhash_open(hashChars, isEqualChars, NULL,  &status);
112     if (U_FAILURE(status)) {
113         log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
114                 u_errorName(status), hash);
115         return;
116     }
117     if (hash == NULL) {
118         log_err("FAIL: uhash_open returned NULL\n");
119         return;
120     }
121     log_verbose("Ok: uhash_open returned 0x%08X\n", hash);
122 
123     _put(hash, one, 1, 0);
124     _put(hash, omega, 24, 0);
125     _put(hash, two, 2, 0);
126     _put(hash, three, 3, 0);
127     _put(hash, one, -1, 1);
128     _put(hash, two, -2, 2);
129     _put(hash, omega, 48, 24);
130     _put(hash, one, 100, -1);
131     _get(hash, three, 3);
132     _remove(hash, two, -2);
133     _get(hash, two, 0);
134     _get(hash, one, 100);
135     _put(hash, two, 200, 0);
136     _get(hash, omega, 48);
137     _get(hash, two, 200);
138 
139     // puti(key, value==0) removes the key's element.
140     _put(hash, two, 0, 200);
141 
142     if(_compareChars((void*)one, (void*)three) == true ||
143         _compareChars((void*)one, (void*)one2) != true ||
144         _compareChars((void*)one, (void*)one) != true ||
145         _compareChars((void*)one, NULL) == true  )  {
146         log_err("FAIL: compareChars failed\n");
147     }
148     if(_compareIChars((void*)one, (void*)three) == true ||
149         _compareIChars((void*)one, (void*)one) != true ||
150         _compareIChars((void*)one, (void*)one2) != true ||
151         _compareIChars((void*)one, NULL) == true  )  {
152         log_err("FAIL: compareIChars failed\n");
153     }
154 
155     uhash_close(hash);
156 }
157 
TestAllowZero(void)158 static void TestAllowZero(void) {
159     UErrorCode status = U_ZERO_ERROR;
160     UHashtable *hash = uhash_open(hashChars, isEqualChars, NULL,  &status);
161     if (U_FAILURE(status)) {
162         log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
163                 u_errorName(status), hash);
164         return;
165     }
166     if (hash == NULL) {
167         log_err("FAIL: uhash_open returned NULL\n");
168         return;
169     }
170     log_verbose("Ok: uhash_open returned 0x%08X\n", hash);
171 
172     int32_t oldValue = uhash_putiAllowZero(hash, (char *)"one", 1, &status);
173     UBool found = false;
174     if (U_FAILURE(status) || oldValue != 0 || !uhash_containsKey(hash, "one") ||
175             uhash_geti(hash, "one") != 1 ||
176             uhash_getiAndFound(hash, "one", &found) != 1 || !found) {
177         log_err("FAIL: uhash_putiAllowZero(one, 1)");
178     }
179     oldValue = uhash_putiAllowZero(hash, (char *)"zero", 0, &status);
180     found = false;
181     if (U_FAILURE(status) || oldValue != 0 || !uhash_containsKey(hash, "zero") ||
182             uhash_geti(hash, "zero") != 0 ||
183             uhash_getiAndFound(hash, "zero", &found) != 0 || !found) {
184         log_err("FAIL: uhash_putiAllowZero(zero, 0)");
185     }
186     // Overwrite "one" to 0.
187     oldValue = uhash_putiAllowZero(hash, (char *)"one", 0, &status);
188     found = false;
189     if (U_FAILURE(status) || oldValue != 1 || !uhash_containsKey(hash, "one") ||
190             uhash_geti(hash, "one") != 0 ||
191             uhash_getiAndFound(hash, "one", &found) != 0 || !found) {
192         log_err("FAIL: uhash_putiAllowZero(one, 0)");
193     }
194     // Remove "zero" using puti(zero, 0).
195     oldValue = uhash_puti(hash, (char *)"zero", 0, &status);
196     found = true;
197     if (U_FAILURE(status) || oldValue != 0 || uhash_containsKey(hash, "zero") ||
198             uhash_geti(hash, "zero") != 0 ||
199             uhash_getiAndFound(hash, "zero", &found) != 0 || found) {
200         log_err("FAIL: uhash_puti(zero, 0)");
201     }
202 
203     uhash_close(hash);
204 }
205 
TestOtherAPI(void)206 static void TestOtherAPI(void){
207 
208     UErrorCode status = U_ZERO_ERROR;
209     UHashtable *hash;
210 
211     /* Use the correct type when cast to void * */
212     static const UChar one[4]   = {0x006F, 0x006E, 0x0065, 0}; /* L"one" */
213     static const UChar one2[4]  = {0x006F, 0x006E, 0x0065, 0}; /* Get around compiler optimizations */
214     static const UChar two[4]   = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */
215     static const UChar two2[4]  = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */
216     static const UChar three[6] = {0x0074, 0x0068, 0x0072, 0x0065, 0x0065, 0}; /* L"three" */
217     static const UChar four[6]  = {0x0066, 0x006F, 0x0075, 0x0072, 0}; /* L"four" */
218     static const UChar five[6]  = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */
219     static const UChar five2[6] = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */
220 
221     hash = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL,  &status);
222     if (U_FAILURE(status)) {
223         log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
224                 u_errorName(status), hash);
225         return;
226     }
227     if (hash == NULL) {
228         log_err("FAIL: uhash_open returned NULL\n");
229         return;
230     }
231     log_verbose("Ok: uhash_open returned 0x%08X\n", hash);
232 
233     uhash_puti(hash, (void*)one, 1, &status);
234     if(uhash_count(hash) != 1){
235          log_err("FAIL: uhas_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
236     }
237     if(uhash_find(hash, (void*)two) != NULL){
238         log_err("FAIL: uhash_find failed\n");
239     }
240     uhash_puti(hash, (void*)two, 2, &status);
241     uhash_puti(hash, (void*)three, 3, &status);
242     uhash_puti(hash, (void*)four, 4, &status);
243     uhash_puti(hash, (void*)five, 5, &status);
244 
245     if(uhash_count(hash) != 5){
246         log_err("FAIL: uhas_count() failed. Expected: 5, Got: %d\n", uhash_count(hash));
247     }
248 
249     if(uhash_geti(hash, (void*)two2) != 2){
250         log_err("FAIL: uhash_geti failed\n");
251     }
252 
253     if(uhash_find(hash, (void*)two2) == NULL){
254         log_err("FAIL: uhash_find of \"two\" failed\n");
255     }
256 
257     if(uhash_removei(hash, (void*)five2) != 5){
258         log_err("FAIL: uhash_remove() failed\n");
259     }
260     if(uhash_count(hash) != 4){
261         log_err("FAIL: uhas_count() failed. Expected: 4, Got: %d\n", uhash_count(hash));
262     }
263 
264     uhash_put(hash, (void*)one, NULL, &status);
265     if(uhash_count(hash) != 3){
266         log_err("FAIL: uhash_put() with value=NULL didn't remove the key value pair\n");
267     }
268     status=U_ILLEGAL_ARGUMENT_ERROR;
269     uhash_puti(hash, (void*)one, 1, &status);
270     if(uhash_count(hash) != 3){
271         log_err("FAIL: uhash_put() with value!=NULL should fail when status != U_ZERO_ERROR \n");
272     }
273 
274     status=U_ZERO_ERROR;
275     uhash_puti(hash, (void*)one, 1, &status);
276     if(uhash_count(hash) != 4){
277         log_err("FAIL: uhash_put() with value!=NULL didn't replace the key value pair\n");
278     }
279 
280     if(_compareUChars((void*)one, (void*)two) == true ||
281         _compareUChars((void*)one, (void*)one) != true ||
282         _compareUChars((void*)one, (void*)one2) != true ||
283         _compareUChars((void*)one, NULL) == true  )  {
284         log_err("FAIL: compareUChars failed\n");
285     }
286 
287     uhash_removeAll(hash);
288     if(uhash_count(hash) != 0){
289         log_err("FAIL: uhas_count() failed. Expected: 0, Got: %d\n", uhash_count(hash));
290     }
291 
292     uhash_setKeyComparator(hash, uhash_compareLong);
293     uhash_setKeyHasher(hash, uhash_hashLong);
294     uhash_iputi(hash, 1001, 1, &status);
295     uhash_iputi(hash, 1002, 2, &status);
296     uhash_iputi(hash, 1003, 3, &status);
297     if(_compareLong(1001, 1002) == true ||
298         _compareLong(1001, 1001) != true ||
299         _compareLong(1001, 0) == true  )  {
300         log_err("FAIL: compareLong failed\n");
301     }
302     /*set the resize policy to just GROW and SHRINK*/
303          /*how to test this??*/
304     uhash_setResizePolicy(hash, U_GROW_AND_SHRINK);
305     uhash_iputi(hash, 1004, 4, &status);
306     uhash_iputi(hash, 1005, 5, &status);
307     uhash_iputi(hash, 1006, 6, &status);
308     if(uhash_count(hash) != 6){
309         log_err("FAIL: uhash_count() failed. Expected: 6, Got: %d\n", uhash_count(hash));
310     }
311     if(uhash_iremovei(hash, 1004) != 4){
312         log_err("FAIL: uhash_remove failed\n");
313     }
314     if(uhash_iremovei(hash, 1004) != 0){
315         log_err("FAIL: uhash_remove failed\n");
316     }
317 
318     uhash_removeAll(hash);
319     uhash_iput(hash, 2004, (void*)one, &status);
320     uhash_iput(hash, 2005, (void*)two, &status);
321     if(uhash_count(hash) != 2){
322         log_err("FAIL: uhash_count() failed. Expected: 2, Got: %d\n", uhash_count(hash));
323     }
324     if(uhash_iremove(hash, 2004) != (void*)one){
325         log_err("FAIL: uhash_remove failed\n");
326     }
327     if(uhash_iremove(hash, 2004) != NULL){
328         log_err("FAIL: uhash_remove failed\n");
329     }
330     if(uhash_count(hash) != 1){
331         log_err("FAIL: uhash_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
332     }
333 
334     uhash_close(hash);
335 
336 }
337 
hashIChars(void)338 static void hashIChars(void) {
339     static const char which[] = "which";
340     static const char WHICH2[] = "WHICH";
341     static const char where[] = "where";
342     UErrorCode status = U_ZERO_ERROR;
343     UHashtable *hash;
344 
345     hash = uhash_open(uhash_hashIChars, uhash_compareIChars, NULL, &status);
346     if (U_FAILURE(status)) {
347         log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
348                 u_errorName(status), hash);
349         return;
350     }
351     if (hash == NULL) {
352         log_err("FAIL: uhash_open returned NULL\n");
353         return;
354     }
355     log_verbose("Ok: uhash_open returned 0x%08X\n", hash);
356 
357     _put(hash, which, 1, 0);
358     _put(hash, WHICH2, 2, 1);
359     _put(hash, where, 3, 0);
360     if(uhash_count(hash) != 2){
361          log_err("FAIL: uhas_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
362     }
363     _remove(hash, which, 2);
364 
365     uhash_close(hash);
366 }
367 
368 
369 /**********************************************************************
370  * uhash Callbacks
371  *********************************************************************/
372 
373 /**
374  * This hash function is designed to collide a lot to test key equality
375  * resolution.  It only uses the first char.
376  */
hashChars(const UHashTok key)377 static int32_t U_EXPORT2 U_CALLCONV hashChars(const UHashTok key) {
378     return *(const char*) key.pointer;
379 }
380 
isEqualChars(const UHashTok key1,const UHashTok key2)381 static UBool U_EXPORT2 U_CALLCONV isEqualChars(const UHashTok key1, const UHashTok key2) {
382     return (UBool)((key1.pointer != NULL) &&
383         (key2.pointer != NULL) &&
384         (uprv_strcmp((const char*)key1.pointer, (const char*)key2.pointer) == 0));
385 }
386 
387 /**********************************************************************
388  * Wrapper Functions
389  *********************************************************************/
390 
_put(UHashtable * hash,const char * key,int32_t value,int32_t expectedOldValue)391 static void _put(UHashtable* hash,
392           const char* key,
393           int32_t value,
394           int32_t expectedOldValue) {
395     UErrorCode status = U_ZERO_ERROR;
396     int32_t oldValue =
397         uhash_puti(hash, (void*) key, value, &status);
398     if (U_FAILURE(status)) {
399         log_err("FAIL: uhash_puti(%s) failed with %s and returned %ld\n",
400                 key, u_errorName(status), oldValue);
401     } else if (oldValue != expectedOldValue) {
402         log_err("FAIL: uhash_puti(%s) returned old value %ld; expected %ld\n",
403                 key, oldValue, expectedOldValue);
404     } else {
405         log_verbose("Ok: uhash_puti(%s, %d) returned old value %ld\n",
406                     key, value, oldValue);
407     }
408     int32_t newValue = uhash_geti(hash, key);
409     if (newValue != value) {
410         log_err("FAIL: uhash_puti(%s) failed to set the intended value %ld: "
411                 "uhash_geti() returns %ld\n",
412                 key, value, newValue);
413     }
414     UBool contained = uhash_containsKey(hash, key);
415     if (value == 0) {
416         if (contained) {
417             log_err("FAIL: uhash_puti(%s, zero) failed to remove the key item: "
418                     "uhash_containsKey() returns true\n",
419                     key);
420         }
421     } else {
422         if (!contained) {
423             log_err("FAIL: uhash_puti(%s, not zero) appears to have removed the key item: "
424                     "uhash_containsKey() returns false\n",
425                     key);
426         }
427     }
428 }
429 
_get(UHashtable * hash,const char * key,int32_t expectedValue)430 static void _get(UHashtable* hash,
431           const char* key,
432           int32_t expectedValue) {
433     int32_t value = uhash_geti(hash, key);
434     if (value != expectedValue) {
435         log_err("FAIL: uhash_geti(%s) returned %ld; expected %ld\n",
436                 key, value, expectedValue);
437     } else {
438         log_verbose("Ok: uhash_geti(%s) returned value %ld\n",
439                     key, value);
440     }
441 }
442 
_remove(UHashtable * hash,const char * key,int32_t expectedValue)443 static void _remove(UHashtable* hash,
444              const char* key,
445              int32_t expectedValue) {
446     int32_t value = uhash_removei(hash, key);
447     if (value != expectedValue) {
448         log_err("FAIL: uhash_removei(%s) returned %ld; expected %ld\n",
449                 key, value, expectedValue);
450     } else {
451         log_verbose("Ok: uhash_removei(%s) returned old value %ld\n",
452                     key, value);
453     }
454     if (uhash_containsKey(hash, key)) {
455         log_err("FAIL: uhash_removei(%s) failed to remove the key item: "
456                 "uhash_containsKey() returns false\n",
457                 key);
458     }
459 }
460