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 "cintltst.h"
15 #include "uhash.h"
16 #include "unicode/ctest.h"
17 #include "unicode/ustring.h"
18 #include "cstring.h"
19 
20 /**********************************************************************
21  * Prototypes
22  *********************************************************************/
23 
24 static void TestBasic(void);
25 static void TestOtherAPI(void);
26 static void hashIChars(void);
27 
28 static int32_t U_EXPORT2 U_CALLCONV hashChars(const UHashTok key);
29 
30 static UBool U_EXPORT2 U_CALLCONV isEqualChars(const UHashTok key1, const UHashTok key2);
31 
32 static void _put(UHashtable* hash,
33                  const char* key,
34                  int32_t value,
35                  int32_t expectedOldValue);
36 
37 static void _get(UHashtable* hash,
38           const char* key,
39           int32_t expectedValue);
40 
41 static void _remove(UHashtable* hash,
42              const char* key,
43              int32_t expectedValue);
44 
45 void addHashtableTest(TestNode** root);
46 
47 /**********************************************************************
48  * UHashTok wrapper functions
49  *********************************************************************/
50 
51 static UBool
_compareChars(const void * a,const void * b)52 _compareChars(const void* a, const void* b) {
53     UHashTok s, t;
54     s.pointer = (void *)a;
55     t.pointer = (void *)b;
56     return uhash_compareChars(s, t);
57 }
58 
59 static UBool
_compareIChars(const void * a,const void * b)60 _compareIChars(const void* a, const void* b) {
61     UHashTok s, t;
62     s.pointer = (void *)a;
63     t.pointer = (void *)b;
64     return uhash_compareIChars(s, t);
65 }
66 
67 static UBool
_compareUChars(const void * a,const void * b)68 _compareUChars(const void* a, const void* b) {
69     UHashTok s, t;
70     s.pointer = (void *)a;
71     t.pointer = (void *)b;
72     return uhash_compareUChars(s, t);
73 }
74 
75 static UBool
_compareLong(int32_t a,int32_t b)76 _compareLong(int32_t a, int32_t b) {
77     UHashTok s, t;
78     s.integer = a;
79     t.integer = b;
80     return uhash_compareLong(s, t);
81 }
82 
83 /**********************************************************************
84  * FW Registration
85  *********************************************************************/
86 
addHashtableTest(TestNode ** root)87 void addHashtableTest(TestNode** root) {
88 
89     addTest(root, &TestBasic,   "tsutil/chashtst/TestBasic");
90     addTest(root, &TestOtherAPI, "tsutil/chashtst/TestOtherAPI");
91     addTest(root, &hashIChars, "tsutil/chashtst/hashIChars");
92 
93 }
94 
95 /**********************************************************************
96  * Test Functions
97  *********************************************************************/
98 
TestBasic(void)99 static void TestBasic(void) {
100     static const char one[4] =   {0x6F, 0x6E, 0x65, 0}; /* "one" */
101     static const char one2[4] =  {0x6F, 0x6E, 0x65, 0}; /* Get around compiler optimizations */
102     static const char two[4] =   {0x74, 0x77, 0x6F, 0}; /* "two" */
103     static const char three[6] = {0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* "three" */
104     static const char omega[6] = {0x6F, 0x6D, 0x65, 0x67, 0x61, 0}; /* "omega" */
105     UErrorCode status = U_ZERO_ERROR;
106     UHashtable *hash;
107 
108     hash = uhash_open(hashChars, isEqualChars, NULL,  &status);
109     if (U_FAILURE(status)) {
110         log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
111                 u_errorName(status), hash);
112         return;
113     }
114     if (hash == NULL) {
115         log_err("FAIL: uhash_open returned NULL\n");
116         return;
117     }
118     log_verbose("Ok: uhash_open returned 0x%08X\n", hash);
119 
120     _put(hash, one, 1, 0);
121     _put(hash, omega, 24, 0);
122     _put(hash, two, 2, 0);
123     _put(hash, three, 3, 0);
124     _put(hash, one, -1, 1);
125     _put(hash, two, -2, 2);
126     _put(hash, omega, 48, 24);
127     _put(hash, one, 100, -1);
128     _get(hash, three, 3);
129     _remove(hash, two, -2);
130     _get(hash, two, 0);
131     _get(hash, one, 100);
132     _put(hash, two, 200, 0);
133     _get(hash, omega, 48);
134     _get(hash, two, 200);
135 
136     if(_compareChars((void*)one, (void*)three) == TRUE ||
137         _compareChars((void*)one, (void*)one2) != TRUE ||
138         _compareChars((void*)one, (void*)one) != TRUE ||
139         _compareChars((void*)one, NULL) == TRUE  )  {
140         log_err("FAIL: compareChars failed\n");
141     }
142     if(_compareIChars((void*)one, (void*)three) == TRUE ||
143         _compareIChars((void*)one, (void*)one) != TRUE ||
144         _compareIChars((void*)one, (void*)one2) != TRUE ||
145         _compareIChars((void*)one, NULL) == TRUE  )  {
146         log_err("FAIL: compareIChars failed\n");
147     }
148 
149     uhash_close(hash);
150 
151 }
152 
TestOtherAPI(void)153 static void TestOtherAPI(void){
154 
155     UErrorCode status = U_ZERO_ERROR;
156     UHashtable *hash;
157 
158     /* Use the correct type when cast to void * */
159     static const UChar one[4]   = {0x006F, 0x006E, 0x0065, 0}; /* L"one" */
160     static const UChar one2[4]  = {0x006F, 0x006E, 0x0065, 0}; /* Get around compiler optimizations */
161     static const UChar two[4]   = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */
162     static const UChar two2[4]  = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */
163     static const UChar three[6] = {0x0074, 0x0068, 0x0072, 0x0065, 0x0065, 0}; /* L"three" */
164     static const UChar four[6]  = {0x0066, 0x006F, 0x0075, 0x0072, 0}; /* L"four" */
165     static const UChar five[6]  = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */
166     static const UChar five2[6] = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */
167 
168     hash = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL,  &status);
169     if (U_FAILURE(status)) {
170         log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
171                 u_errorName(status), hash);
172         return;
173     }
174     if (hash == NULL) {
175         log_err("FAIL: uhash_open returned NULL\n");
176         return;
177     }
178     log_verbose("Ok: uhash_open returned 0x%08X\n", hash);
179 
180     uhash_puti(hash, (void*)one, 1, &status);
181     if(uhash_count(hash) != 1){
182          log_err("FAIL: uhas_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
183     }
184     if(uhash_find(hash, (void*)two) != NULL){
185         log_err("FAIL: uhash_find failed\n");
186     }
187     uhash_puti(hash, (void*)two, 2, &status);
188     uhash_puti(hash, (void*)three, 3, &status);
189     uhash_puti(hash, (void*)four, 4, &status);
190     uhash_puti(hash, (void*)five, 5, &status);
191 
192     if(uhash_count(hash) != 5){
193         log_err("FAIL: uhas_count() failed. Expected: 5, Got: %d\n", uhash_count(hash));
194     }
195 
196     if(uhash_geti(hash, (void*)two2) != 2){
197         log_err("FAIL: uhash_geti failed\n");
198     }
199 
200     if(uhash_find(hash, (void*)two2) == NULL){
201         log_err("FAIL: uhash_find of \"two\" failed\n");
202     }
203 
204     if(uhash_removei(hash, (void*)five2) != 5){
205         log_err("FAIL: uhash_remove() failed\n");
206     }
207     if(uhash_count(hash) != 4){
208         log_err("FAIL: uhas_count() failed. Expected: 4, Got: %d\n", uhash_count(hash));
209     }
210 
211     uhash_put(hash, (void*)one, NULL, &status);
212     if(uhash_count(hash) != 3){
213         log_err("FAIL: uhash_put() with value=NULL didn't remove the key value pair\n");
214     }
215     status=U_ILLEGAL_ARGUMENT_ERROR;
216     uhash_puti(hash, (void*)one, 1, &status);
217     if(uhash_count(hash) != 3){
218         log_err("FAIL: uhash_put() with value!=NULL should fail when status != U_ZERO_ERROR \n");
219     }
220 
221     status=U_ZERO_ERROR;
222     uhash_puti(hash, (void*)one, 1, &status);
223     if(uhash_count(hash) != 4){
224         log_err("FAIL: uhash_put() with value!=NULL didn't replace the key value pair\n");
225     }
226 
227     if(_compareUChars((void*)one, (void*)two) == TRUE ||
228         _compareUChars((void*)one, (void*)one) != TRUE ||
229         _compareUChars((void*)one, (void*)one2) != TRUE ||
230         _compareUChars((void*)one, NULL) == TRUE  )  {
231         log_err("FAIL: compareUChars failed\n");
232     }
233 
234     uhash_removeAll(hash);
235     if(uhash_count(hash) != 0){
236         log_err("FAIL: uhas_count() failed. Expected: 0, Got: %d\n", uhash_count(hash));
237     }
238 
239     uhash_setKeyComparator(hash, uhash_compareLong);
240     uhash_setKeyHasher(hash, uhash_hashLong);
241     uhash_iputi(hash, 1001, 1, &status);
242     uhash_iputi(hash, 1002, 2, &status);
243     uhash_iputi(hash, 1003, 3, &status);
244     if(_compareLong(1001, 1002) == TRUE ||
245         _compareLong(1001, 1001) != TRUE ||
246         _compareLong(1001, 0) == TRUE  )  {
247         log_err("FAIL: compareLong failed\n");
248     }
249     /*set the resize policy to just GROW and SHRINK*/
250          /*how to test this??*/
251     uhash_setResizePolicy(hash, U_GROW_AND_SHRINK);
252     uhash_iputi(hash, 1004, 4, &status);
253     uhash_iputi(hash, 1005, 5, &status);
254     uhash_iputi(hash, 1006, 6, &status);
255     if(uhash_count(hash) != 6){
256         log_err("FAIL: uhash_count() failed. Expected: 6, Got: %d\n", uhash_count(hash));
257     }
258     if(uhash_iremovei(hash, 1004) != 4){
259         log_err("FAIL: uhash_remove failed\n");
260     }
261     if(uhash_iremovei(hash, 1004) != 0){
262         log_err("FAIL: uhash_remove failed\n");
263     }
264 
265     uhash_removeAll(hash);
266     uhash_iput(hash, 2004, (void*)one, &status);
267     uhash_iput(hash, 2005, (void*)two, &status);
268     if(uhash_count(hash) != 2){
269         log_err("FAIL: uhash_count() failed. Expected: 2, Got: %d\n", uhash_count(hash));
270     }
271     if(uhash_iremove(hash, 2004) != (void*)one){
272         log_err("FAIL: uhash_remove failed\n");
273     }
274     if(uhash_iremove(hash, 2004) != NULL){
275         log_err("FAIL: uhash_remove failed\n");
276     }
277     if(uhash_count(hash) != 1){
278         log_err("FAIL: uhash_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
279     }
280 
281     uhash_close(hash);
282 
283 }
284 
hashIChars(void)285 static void hashIChars(void) {
286     static const char which[] = "which";
287     static const char WHICH2[] = "WHICH";
288     static const char where[] = "where";
289     UErrorCode status = U_ZERO_ERROR;
290     UHashtable *hash;
291 
292     hash = uhash_open(uhash_hashIChars, uhash_compareIChars, NULL, &status);
293     if (U_FAILURE(status)) {
294         log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
295                 u_errorName(status), hash);
296         return;
297     }
298     if (hash == NULL) {
299         log_err("FAIL: uhash_open returned NULL\n");
300         return;
301     }
302     log_verbose("Ok: uhash_open returned 0x%08X\n", hash);
303 
304     _put(hash, which, 1, 0);
305     _put(hash, WHICH2, 2, 1);
306     _put(hash, where, 3, 0);
307     if(uhash_count(hash) != 2){
308          log_err("FAIL: uhas_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
309     }
310     _remove(hash, which, 2);
311 
312     uhash_close(hash);
313 }
314 
315 
316 /**********************************************************************
317  * uhash Callbacks
318  *********************************************************************/
319 
320 /**
321  * This hash function is designed to collide a lot to test key equality
322  * resolution.  It only uses the first char.
323  */
hashChars(const UHashTok key)324 static int32_t U_EXPORT2 U_CALLCONV hashChars(const UHashTok key) {
325     return *(const char*) key.pointer;
326 }
327 
isEqualChars(const UHashTok key1,const UHashTok key2)328 static UBool U_EXPORT2 U_CALLCONV isEqualChars(const UHashTok key1, const UHashTok key2) {
329     return (UBool)((key1.pointer != NULL) &&
330         (key2.pointer != NULL) &&
331         (uprv_strcmp((const char*)key1.pointer, (const char*)key2.pointer) == 0));
332 }
333 
334 /**********************************************************************
335  * Wrapper Functions
336  *********************************************************************/
337 
_put(UHashtable * hash,const char * key,int32_t value,int32_t expectedOldValue)338 static void _put(UHashtable* hash,
339           const char* key,
340           int32_t value,
341           int32_t expectedOldValue) {
342     UErrorCode status = U_ZERO_ERROR;
343     int32_t oldValue =
344         uhash_puti(hash, (void*) key, value, &status);
345     if (U_FAILURE(status)) {
346         log_err("FAIL: uhash_put(%s) failed with %s and returned %ld\n",
347                 key, u_errorName(status), oldValue);
348     } else if (oldValue != expectedOldValue) {
349         log_err("FAIL: uhash_put(%s) returned old value %ld; expected %ld\n",
350                 key, oldValue, expectedOldValue);
351     } else {
352         log_verbose("Ok: uhash_put(%s, %d) returned old value %ld\n",
353                     key, value, oldValue);
354     }
355 }
356 
_get(UHashtable * hash,const char * key,int32_t expectedValue)357 static void _get(UHashtable* hash,
358           const char* key,
359           int32_t expectedValue) {
360     UErrorCode status = U_ZERO_ERROR;
361     int32_t value = uhash_geti(hash, key);
362     if (U_FAILURE(status)) {
363         log_err("FAIL: uhash_get(%s) failed with %s and returned %ld\n",
364                 key, u_errorName(status), value);
365     } else if (value != expectedValue) {
366         log_err("FAIL: uhash_get(%s) returned %ld; expected %ld\n",
367                 key, value, expectedValue);
368     } else {
369         log_verbose("Ok: uhash_get(%s) returned value %ld\n",
370                     key, value);
371     }
372 }
373 
_remove(UHashtable * hash,const char * key,int32_t expectedValue)374 static void _remove(UHashtable* hash,
375              const char* key,
376              int32_t expectedValue) {
377     int32_t value = uhash_removei(hash, key);
378     if (value != expectedValue) {
379         log_err("FAIL: uhash_remove(%s) returned %ld; expected %ld\n",
380                 key, value, expectedValue);
381     } else {
382         log_verbose("Ok: uhash_remove(%s) returned old value %ld\n",
383                     key, value);
384     }
385 }
386 
387