1 /*
2  * ProFTPD - FTP server testsuite
3  * Copyright (c) 2008-2017 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Table API tests */
26 
27 #include "tests.h"
28 
29 static pool *p = NULL;
30 
31 /* Fixtures */
32 
set_up(void)33 static void set_up(void) {
34   if (p == NULL) {
35     p = make_sub_pool(NULL);
36   }
37 }
38 
tear_down(void)39 static void tear_down(void) {
40   if (p) {
41     destroy_pool(p);
42     p = NULL;
43   }
44 }
45 
46 /* Helper functions */
47 
48 static unsigned int b_val_count = 0;
49 
do_cb(const void * key,size_t keysz,const void * value,size_t valuesz,void * user_data)50 static int do_cb(const void *key, size_t keysz, const void *value,
51     size_t valuesz, void *user_data) {
52 
53   if (*((const char *) value) == 'b') {
54     b_val_count++;
55   }
56 
57   return -1;
58 }
59 
do_with_remove_cb(const void * key,size_t keysz,const void * value,size_t valuesz,void * user_data)60 static int do_with_remove_cb(const void *key, size_t keysz, const void *value,
61     size_t valuesz, void *user_data) {
62   pr_table_t *tab;
63 
64   tab = user_data;
65 
66   if (*((const char *) value) == 'b') {
67     b_val_count++;
68   }
69 
70   pr_table_kremove(tab, key, keysz, NULL);
71   return 0;
72 }
73 
table_dump(const char * fmt,...)74 static void table_dump(const char *fmt, ...) {
75 }
76 
77 /* Tests */
78 
START_TEST(table_alloc_test)79 START_TEST (table_alloc_test) {
80   pr_table_t *tab;
81 
82   tab = pr_table_alloc(NULL, 0);
83   fail_unless(tab == NULL, "Failed to handle null arguments");
84   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
85 
86   tab = pr_table_alloc(p, 0);
87   fail_unless(tab != NULL, "Failed to allocate table: %s", strerror(errno));
88 }
89 END_TEST
90 
START_TEST(table_nalloc_test)91 START_TEST (table_nalloc_test) {
92   pr_table_t *tab;
93 
94   tab = pr_table_nalloc(NULL, 0, 0);
95   fail_unless(tab == NULL, "Failed to handle null arguments");
96   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
97 
98   tab = pr_table_nalloc(p, 0, 0);
99   fail_unless(tab == NULL, "Failed to handle zero chains");
100   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
101 
102   tab = pr_table_nalloc(p, 0, 1);
103   fail_unless(tab != NULL, "Failed to allocate table: %s", strerror(errno));
104 }
105 END_TEST
106 
START_TEST(table_add_test)107 START_TEST (table_add_test) {
108   int res;
109   pr_table_t *tab;
110 
111   res = pr_table_add(NULL, NULL, NULL, 0);
112   fail_unless(res == -1, "Failed to handle null arguments");
113   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
114 
115   tab = pr_table_alloc(p, 0);
116   fail_unless(tab != NULL, "Failed to allocate table: %s", strerror(errno));
117 
118   res = pr_table_add(tab, NULL, NULL, 0);
119   fail_unless(res == -1, "Failed to handle null key");
120   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
121 
122   res = pr_table_add(tab, "", NULL, 0);
123   fail_unless(res == 0, "Failed to add null value (len 0) for empty key");
124 
125   res = pr_table_add(tab, "", NULL, 1);
126   fail_unless(res == -1, "Failed to handle null value (len 1) for empty key");
127   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
128 
129   res = pr_table_add(tab, "", NULL, 0);
130   fail_unless(res == -1, "Failed to handle duplicate (empty) key");
131   fail_unless(errno == EEXIST, "Failed to set errno to EEXIST");
132 }
133 END_TEST
134 
START_TEST(table_add_dup_test)135 START_TEST (table_add_dup_test) {
136   int res;
137   pr_table_t *tab;
138 
139   res = pr_table_add_dup(NULL, NULL, NULL, 0);
140   fail_unless(res == -1, "Failed to handle null arguments");
141   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
142 
143   tab = pr_table_alloc(p, 0);
144   fail_unless(tab != NULL, "Failed to allocate table: %s", strerror(errno));
145 
146   res = pr_table_add_dup(tab, NULL, NULL, 0);
147   fail_unless(res == -1, "Failed to handle null key");
148   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
149 
150   res = pr_table_add_dup(tab, "", NULL, 0);
151   fail_unless(res == 0, "Failed to add null value (len 0) for empty key");
152 
153   res = pr_table_add_dup(tab, "", NULL, 1);
154   fail_unless(res == -1, "Failed to handle null value (len 1) for empty key");
155   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
156 
157   res = pr_table_add_dup(tab, "", NULL, 0);
158   fail_unless(res == -1, "Failed to handle duplicate (empty) key");
159   fail_unless(errno == EEXIST, "Failed to set errno to EEXIST");
160 
161   mark_point();
162   res = pr_table_add_dup(tab, "foo", "bar", 0);
163   fail_unless(res == 0, "Failed to add 'foo': %s", strerror(errno));
164 }
165 END_TEST
166 
START_TEST(table_count_test)167 START_TEST (table_count_test) {
168   int res, ok;
169   pr_table_t *tab;
170 
171   res = pr_table_count(NULL);
172   fail_unless(res == -1, "Failed to handle null arguments");
173   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
174 
175   tab = pr_table_alloc(p, 0);
176 
177   ok = 0;
178   res = pr_table_count(tab);
179   fail_unless(res == ok, "Expected count %d, got %d", ok, res);
180 
181   res = pr_table_add(tab, "foo", NULL, 0);
182   fail_unless(res == 0, "Failed to add item to table: %s", strerror(errno));
183 
184   ok = 1;
185   res = pr_table_count(tab);
186   fail_unless(res == ok, "Expected count %d, got %d", ok, res);
187 
188   res = pr_table_add(tab, "bar", NULL, 0);
189   fail_unless(res == 0, "Failed to add item to table: %s", strerror(errno));
190 
191   ok = 2;
192   res = pr_table_count(tab);
193   fail_unless(res == ok, "Expected count %d, got %d", ok, res);
194 }
195 END_TEST
196 
START_TEST(table_exists_test)197 START_TEST (table_exists_test) {
198   int res, ok;
199   pr_table_t *tab;
200 
201   res = pr_table_exists(NULL, NULL);
202   fail_unless(res == -1, "Failed to handle null arguments");
203   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
204 
205   tab = pr_table_alloc(p, PR_TABLE_FL_MULTI_VALUE);
206   fail_unless(tab != NULL, "Failed to allocate table: %s", strerror(errno));
207 
208   res = pr_table_exists(tab, NULL);
209   fail_unless(res == -1, "Failed to handle null key");
210   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
211 
212   res = pr_table_exists(NULL, "foo");
213   fail_unless(res == -1, "Failed to handle null table");
214   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
215 
216   ok = -1;
217   res = pr_table_exists(tab, "foo");
218   fail_unless(res == ok, "Expected value count %d, got %d", ok, res);
219   fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");
220 
221   res = pr_table_add(tab, "foo", "a", 0);
222   fail_unless(res == 0, "Failed to add key to table: %s", strerror(errno));
223 
224   ok = 1;
225   res = pr_table_exists(tab, "foo");
226   fail_unless(res == ok, "Expected value count %d, got %d", ok, res);
227 
228   res = pr_table_add(tab, "foo", "b", 0);
229   fail_unless(res == 0, "Failed to add key to table: %s", strerror(errno));
230 
231   ok = 2;
232   res = pr_table_exists(tab, "foo");
233   fail_unless(res == ok, "Expected value count %d, got %d", ok, res);
234 
235   mark_point();
236   res = pr_table_kexists(NULL, NULL, 0);
237   fail_unless(res < 0, "Failed to handle null table");
238   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
239     strerror(errno), errno);
240 
241   mark_point();
242   res = pr_table_kexists(tab, NULL, 0);
243   fail_unless(res < 0, "Failed to handle null key_data");
244   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
245     strerror(errno), errno);
246 }
247 END_TEST
248 
START_TEST(table_empty_test)249 START_TEST (table_empty_test) {
250   int res;
251   pr_table_t *tab;
252 
253   res = pr_table_empty(NULL);
254   fail_unless(res == -1, "Failed to handle null table");
255   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
256 
257   tab = pr_table_alloc(p, 0);
258 
259   res = pr_table_empty(tab);
260   fail_unless(res == 0, "Failed to empty table: %s", strerror(errno));
261 
262   res = pr_table_add(tab, "foo", NULL, 0);
263   fail_unless(res == 0, "Failed to add key to table: %s", strerror(errno));
264 
265   res = pr_table_count(tab);
266   fail_unless(res == 1, "Expected table item count of 1, got %d", res);
267 
268   res = pr_table_empty(tab);
269   fail_unless(res == 0, "Failed to empty table: %s", strerror(errno));
270 
271   res = pr_table_count(tab);
272   fail_unless(res == 0, "Expected table item count of 0, got %d", res);
273 }
274 END_TEST
275 
START_TEST(table_free_test)276 START_TEST (table_free_test) {
277   int res;
278   pr_table_t *tab;
279 
280   res = pr_table_free(NULL);
281   fail_unless(res == -1, "Failed to handle null table");
282   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
283 
284   tab = pr_table_alloc(p, 0);
285 
286   res = pr_table_free(tab);
287   fail_unless(res == 0, "Failed to free table: %s", strerror(errno));
288 
289   tab = pr_table_alloc(p, 0);
290   res = pr_table_add(tab, "foo", "bar", 0);
291   fail_unless(res == 0, "Failed to add item to table: %s", strerror(errno));
292 
293   res = pr_table_free(tab);
294   fail_unless(res == -1, "Failed to handle non-empty table");
295   fail_unless(errno == EPERM, "Failed to set errno to EPERM");
296 }
297 END_TEST
298 
START_TEST(table_get_test)299 START_TEST (table_get_test) {
300   int ok, xerrno;
301   const void *res;
302   pr_table_t *tab;
303   char *str;
304   size_t sz;
305 
306   res = pr_table_get(NULL, NULL, NULL);
307   fail_unless(res == NULL, "Failed to handle null arguments");
308   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
309 
310   tab = pr_table_alloc(p, 0);
311 
312   res = pr_table_get(tab, NULL, NULL);
313   fail_unless(res == NULL, "Failed to handle null key");
314   fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");
315 
316   ok = pr_table_add(tab, "foo", NULL, 0);
317   fail_unless(ok == 0, "Failed to add null value to table: %s",
318     strerror(errno));
319 
320   errno = xerrno = 0;
321   res = pr_table_get(tab, "foo", &sz);
322   xerrno = errno;
323 
324   fail_unless(res == NULL, "Failed to lookup null value: %s", strerror(errno));
325   fail_unless(xerrno == 0, "Expected errno 0, got %d (%s)", xerrno,
326     strerror(xerrno));
327 
328   ok = pr_table_add(tab, "bar", "baz", 0);
329   fail_unless(ok == 0, "Failed to add 'bar' to table: %s", strerror(errno));
330 
331   res = pr_table_get(tab, "bar", &sz);
332   fail_unless(res != NULL, "Failed to lookup value for 'bar': %s",
333     strerror(errno));
334   fail_unless(sz == 4, "Expected result len of 4, got %u", sz);
335 
336   str = pcalloc(p, sz);
337   memcpy(str, res, sz);
338 
339   fail_unless(strcmp(str, "baz") == 0,
340     "Expected value '%s', got '%s'", "baz", str);
341 
342   mark_point();
343   res = pr_table_kget(NULL, NULL, 0, NULL);
344   fail_unless(res == NULL, "Failed to handle null table");
345   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
346     strerror(errno), errno);
347 }
348 END_TEST
349 
cache_key_hash(const void * key,size_t keysz)350 static unsigned int cache_key_hash(const void *key, size_t keysz) {
351   return 1;
352 }
353 
START_TEST(table_get_use_cache_test)354 START_TEST (table_get_use_cache_test) {
355   int ok, xerrno;
356   const void *res;
357   pr_table_t *tab;
358   const char *key = "bar";
359   char *str;
360   size_t sz;
361 
362   res = pr_table_get(NULL, NULL, NULL);
363   fail_unless(res == NULL, "Failed to handle null arguments");
364   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
365 
366   tab = pr_table_alloc(p, PR_TABLE_FL_USE_CACHE);
367 
368   /* We use this specific key hash function to ensure that all of the keys we
369    * add to this table end up in the same linked-list chain.
370    */
371 
372   ok = pr_table_ctl(tab, PR_TABLE_CTL_SET_KEY_HASH, cache_key_hash);
373   fail_unless(ok == 0, "Failed to set key hash function for table: %s",
374     strerror(errno));
375 
376   res = pr_table_get(tab, NULL, NULL);
377   fail_unless(res == NULL, "Failed to handle null key");
378   fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");
379 
380   ok = pr_table_add(tab, key, "baz", 0);
381   fail_unless(ok == 0, "Failed to add 'bar' to table: %s", strerror(errno));
382 
383   res = pr_table_get(tab, key, &sz);
384   fail_unless(res != NULL, "Failed to lookup value for 'bar': %s",
385     strerror(errno));
386   fail_unless(sz == 4, "Expected result len of 4, got %u", sz);
387 
388   str = pcalloc(p, sz);
389   memcpy(str, res, sz);
390 
391   fail_unless(strcmp(str, "baz") == 0,
392     "Expected value '%s', got '%s'", "baz", str);
393 
394   /* With the USE_CACHE flag on, we should still receive NULL here. */
395   errno = xerrno = 0;
396   res = pr_table_get(tab, key, &sz);
397   fail_unless(res == NULL, "Failed to return null next value: %s",
398     strerror(errno));
399   fail_unless(xerrno == 0, "Expected errno 0, got %d (%s)", xerrno,
400     strerror(xerrno));
401 
402 }
403 END_TEST
404 
START_TEST(table_next_test)405 START_TEST (table_next_test) {
406   int ok;
407   const char *res;
408   size_t sz = 0;
409   pr_table_t *tab;
410 
411   res = pr_table_next(NULL);
412   fail_unless(res == NULL, "Failed to handle null table");
413   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
414 
415   tab = pr_table_alloc(p, 0);
416 
417   res = pr_table_next(tab);
418   fail_unless(res == NULL, "Failed to handle empty table");
419   fail_unless(errno == EPERM, "Failed to set errno to EPERM");
420 
421   ok = pr_table_add(tab, "foo", NULL, 0);
422   fail_unless(ok == 0, "Failed to add 'foo' to table: %s", strerror(errno));
423 
424   res = pr_table_next(tab);
425   fail_unless(res != NULL, "Failed to get next key: %s", strerror(errno));
426   fail_unless(strcmp(res, "foo") == 0,
427     "Expected key '%s', got '%s'", "foo", res);
428 
429   res = pr_table_next(tab);
430   fail_unless(res == NULL, "Expected no more keys, got '%s'", res);
431 
432   pr_table_rewind(tab);
433 
434   res = pr_table_knext(tab, &sz);
435   fail_unless(res != NULL, "Failed to get next key: %s", strerror(errno));
436   fail_unless(sz == 4, "Expected 4, got %lu", (unsigned long) sz);
437   fail_unless(strcmp(res, "foo") == 0,
438     "Expected key '%s', got '%s'", "foo", res);
439 
440   sz = 0;
441   res = pr_table_knext(tab, &sz);
442   fail_unless(res == NULL, "Expected no more keys, got '%s'", res);
443 }
444 END_TEST
445 
START_TEST(table_rewind_test)446 START_TEST (table_rewind_test) {
447   int res;
448   const char *key;
449   pr_table_t *tab;
450 
451   res = pr_table_rewind(NULL);
452   fail_unless(res == -1, "Failed to handle null table");
453   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
454 
455   tab = pr_table_alloc(p, 0);
456 
457   res = pr_table_rewind(tab);
458   fail_unless(res == 0, "Failed to handle empty table");
459 
460   res = pr_table_add(tab, "foo", NULL, 0);
461   fail_unless(res == 0, "Failed to add 'foo' to table: %s", strerror(errno));
462 
463   key = pr_table_next(tab);
464   fail_unless(key != NULL, "Failed to get next key: %s", strerror(errno));
465   fail_unless(strcmp(key, "foo") == 0,
466     "Expected key '%s', got '%s'", "foo", key);
467 
468   key = pr_table_next(tab);
469   fail_unless(key == NULL, "Expected no more keys, got '%s'", key);
470 
471   res = pr_table_rewind(tab);
472   fail_unless(res == 0, "Failed to rewind table: %s", strerror(errno));
473 
474   key = pr_table_next(tab);
475   fail_unless(key != NULL, "Failed to get next key: %s", strerror(errno));
476   fail_unless(strcmp(key, "foo") == 0,
477     "Expected key '%s', got '%s'", "foo", key);
478 
479   key = pr_table_next(tab);
480   fail_unless(key == NULL, "Expected no more keys, got '%s'", key);
481 }
482 END_TEST
483 
START_TEST(table_remove_test)484 START_TEST (table_remove_test) {
485   int ok;
486   const char *res;
487   char *str;
488   pr_table_t *tab;
489   size_t sz;
490 
491   res = pr_table_remove(NULL, NULL, NULL);
492   fail_unless(res == NULL, "Failed to handle null arguments");
493   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
494 
495   tab = pr_table_alloc(p, 0);
496 
497   res = pr_table_remove(tab, NULL, 0);
498   fail_unless(res == NULL, "Failed to handle null key");
499   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
500 
501   res = pr_table_remove(tab, "foo", &sz);
502   fail_unless(res == NULL, "Failed to handle absent value");
503   fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");
504 
505   ok = pr_table_add(tab, "foo", "bar baz", 0);
506   fail_unless(ok == 0, "Failed to add key to table: %s", strerror(errno));
507 
508   res = pr_table_remove(tab, "foo", &sz);
509   fail_unless(res != NULL, "Failed to remove 'foo': %s", strerror(errno));
510   fail_unless(sz == 8, "Expected value len of 8, got %u", sz);
511 
512   str = pcalloc(p, sz);
513   memcpy(str, res, sz);
514 
515   fail_unless(strcmp(str, "bar baz") == 0,
516     "Expected value of '%s', got '%s'", "bar baz", str);
517 
518   ok = pr_table_count(tab);
519   fail_unless(ok == 0, "Expected table count of 0, got %d", ok);
520 
521   res = pr_table_remove(tab, "foo", &sz);
522   fail_unless(res == NULL, "Failed to handle absent value");
523   fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");
524 
525   mark_point();
526   res = pr_table_kremove(NULL, NULL, 0, NULL);
527   fail_unless(res == NULL, "Failed to handle null table");
528   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
529     strerror(errno), errno);
530 
531   mark_point();
532   res = pr_table_kremove(tab, NULL, 0, NULL);
533   fail_unless(res == NULL, "Failed to handle null key data");
534   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
535     strerror(errno), errno);
536 }
537 END_TEST
538 
START_TEST(table_set_test)539 START_TEST (table_set_test) {
540   int res;
541   pr_table_t *tab;
542   const void *v;
543   char *str;
544   size_t sz;
545 
546   res = pr_table_set(NULL, NULL, NULL, 0);
547   fail_unless(res == -1, "Failed to handle null arguments");
548   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
549 
550   tab = pr_table_alloc(p, 0);
551 
552   res = pr_table_set(tab, NULL, NULL, 0);
553   fail_unless(res == -1, "Failed to handle null key");
554   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
555 
556   res = pr_table_set(tab, "foo", NULL, 1);
557   fail_unless(res == -1, "Failed to handle null value (len 1)");
558   fail_unless(errno == EINVAL, "Failed to handle null value (len 1)");
559 
560   mark_point();
561   res = pr_table_set(tab, "foo", "bar", 1);
562   fail_unless(res < 0, "Failed to handle empty table");
563   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
564     strerror(errno), errno);
565 
566   res = pr_table_add(tab, "foo", "bar", 0);
567   fail_unless(res == 0, "Failed to add 'foo' to table: %s", strerror(errno));
568 
569   res = pr_table_set(tab, "foo", "BAZ", 0);
570   fail_unless(res == 0, "Failed to set 'foo' in table: %s", strerror(errno));
571 
572   v = pr_table_get(tab, "foo", &sz);
573   fail_unless(v != NULL, "Failed to retrieve 'foo' from table: %s",
574     strerror(errno));
575   fail_unless(sz == 4, "Expected len 4, got %u", sz);
576 
577   str = pcalloc(p, sz);
578   memcpy(str, v, sz);
579 
580   fail_unless(strcmp(str, "BAZ") == 0,
581     "Expected value of '%s', got '%s'", "BAZ", str);
582 }
583 END_TEST
584 
START_TEST(table_do_test)585 START_TEST (table_do_test) {
586   int res;
587   pr_table_t *tab;
588 
589   res = pr_table_do(NULL, NULL, NULL, 0);
590   fail_unless(res == -1, "Failed to handle null arguments");
591   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
592 
593   tab = pr_table_alloc(p, 0);
594 
595   res = pr_table_do(tab, NULL, NULL, 0);
596   fail_unless(res == -1, "Failed to handle null arguments");
597   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
598 
599   res = pr_table_do(tab, do_cb, NULL, 0);
600   fail_unless(res == 0, "Failed to handle empty table");
601 
602   res = pr_table_add(tab, "foo", "bar", 0);
603   fail_unless(res == 0, "Failed to add 'foo' to table: %s", strerror(errno));
604 
605   res = pr_table_add(tab, "bar", "baz", 0);
606   fail_unless(res == 0, "Failed to add 'bar' to table: %s", strerror(errno));
607 
608   res = pr_table_do(tab, do_cb, NULL, 0);
609   fail_unless(res == -1, "Expected res %d, got %d", -1, res);
610   fail_unless(errno == EPERM, "Failed to set errno to EPERM");
611   fail_unless(b_val_count == 1, "Expected count %u, got %u", 1, b_val_count);
612 
613   b_val_count = 0;
614   res = pr_table_do(tab, do_cb, NULL, PR_TABLE_DO_FL_ALL);
615   fail_unless(res == 0, "Failed to do table: %s", strerror(errno));
616   fail_unless(b_val_count == 2, "Expected count %u, got %u", 2, b_val_count);
617 }
618 END_TEST
619 
START_TEST(table_do_with_remove_test)620 START_TEST (table_do_with_remove_test) {
621   int res;
622   pr_table_t *tab;
623 
624   tab = pr_table_alloc(p, 0);
625 
626   res = pr_table_add(tab, "foo", "bar", 0);
627   fail_unless(res == 0, "Failed to add 'foo' to table: %s", strerror(errno));
628 
629   res = pr_table_add(tab, "bar", "baz", 0);
630   fail_unless(res == 0, "Failed to add 'bar' to table: %s", strerror(errno));
631 
632   b_val_count = 0;
633   res = pr_table_do(tab, do_with_remove_cb, tab, PR_TABLE_DO_FL_ALL);
634   fail_unless(res == 0, "Failed to do table: %s", strerror(errno));
635   fail_unless(b_val_count == 2, "Expected count %u, got %u", 2, b_val_count);
636 }
637 END_TEST
638 
START_TEST(table_ctl_test)639 START_TEST (table_ctl_test) {
640   int res;
641   pr_table_t *tab;
642   unsigned long flags = 0;
643   unsigned int max_ents = 0, nchains = 0;
644 
645   res = pr_table_ctl(NULL, 0, NULL);
646   fail_unless(res == -1, "Failed to handle null table");
647   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
648 
649   tab = pr_table_alloc(p, 0);
650 
651   mark_point();
652   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_ENT_INSERT, NULL);
653   fail_unless(res == 0, "Failed to set entry insert callback: %s",
654     strerror(errno));
655 
656   mark_point();
657   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_ENT_REMOVE, NULL);
658   fail_unless(res == 0, "Failed to set entry removal callback: %s",
659     strerror(errno));
660 
661   res = pr_table_add(tab, "foo", "bar", 0);
662   fail_unless(res == 0, "Failed to add 'foo' to table: %s", strerror(errno));
663 
664   mark_point();
665   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_MAX_ENTS, 0);
666   fail_unless(res < 0, "Failed to handle SET_MAX_ENTS smaller than table");
667   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
668     strerror(errno), errno);
669 
670   res = pr_table_ctl(tab, 0, NULL);
671   fail_unless(res == -1, "Failed to handle non-empty table");
672   fail_unless(errno == EPERM, "Failed to set errno to EPERM");
673 
674   res = pr_table_empty(tab);
675   fail_unless(res == 0, "Failed to empty table: %s", strerror(errno));
676 
677   res = pr_table_ctl(tab, 0, NULL);
678   fail_unless(res == -1, "Failed to handle unknown ctl");
679   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
680 
681   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_FLAGS, NULL);
682   fail_unless(res == -1, "Failed to handle SET_FLAGS, null args");
683   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
684 
685   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_FLAGS, &flags);
686   fail_unless(res == 0, "Failed to handle SET_FLAGS: %s", strerror(errno));
687 
688   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_NCHAINS, NULL);
689   fail_unless(res == -1, "Failed to handle SET_NCHAINS, null args");
690   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
691 
692   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_NCHAINS, &nchains);
693   fail_unless(res == -1, "Failed to handle SET_NCHAINS, zero args");
694   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
695 
696   nchains = 1;
697   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_NCHAINS, &nchains);
698   fail_unless(res == 0, "Failed to handle SET_NCHAINS: %s", strerror(errno));
699 
700   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_MAX_ENTS, &max_ents);
701   fail_unless(res == -1, "Failed to handle SET_MAX_ENTS, zero args");
702   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
703 
704   /* Add two entries, then try to set MAX_ENTS to one.  We should get an
705    * EPERM back for that.
706    */
707   res = pr_table_add(tab, "foo", "bar", 0);
708   fail_unless(res == 0, "Failed to add 'foo' to table: %s", strerror(errno));
709 
710   res = pr_table_add(tab, "baz", "quxx", 0);
711   fail_unless(res == 0, "Failed to add 'baz' to table: %s", strerror(errno));
712 
713   max_ents = 1;
714   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_MAX_ENTS, &max_ents);
715   fail_unless(res == -1, "Failed to handle SET_MAX_ENTS on non-empty table");
716   fail_unless(errno == EPERM, "Failed to set errno to EPERM");
717 
718   /* Now empty the table, set the MAX_ENTS to one, then try add two entries. */
719 
720   res = pr_table_empty(tab);
721   fail_unless(res == 0, "Failed to empty table: %s", strerror(errno));
722 
723   max_ents = 1;
724   res = pr_table_ctl(tab, PR_TABLE_CTL_SET_MAX_ENTS, &max_ents);
725   fail_unless(res == 0, "Failed to handle SET_MAX_ENTS to %d: %s",
726     max_ents, strerror(errno));
727 
728   res = pr_table_add(tab, "foo", "bar", 0);
729   fail_unless(res == 0, "Failed to add 'foo' to table: %s", strerror(errno));
730 
731   res = pr_table_add(tab, "baz", "quxx", 0);
732   fail_unless(res == -1, "Added second entry unexpectedly");
733   fail_unless(errno == ENOSPC,
734     "Failed to set errno to ENOSPC, received %s (%d)", errno, strerror(errno));
735 }
736 END_TEST
737 
START_TEST(table_load_test)738 START_TEST (table_load_test) {
739   pr_table_t *tab = NULL;
740   float load;
741 
742   load = pr_table_load(tab);
743   fail_unless(load < 0, "Failed to handle NULL table argument");
744   fail_unless(errno == EINVAL,
745     "Failed to set errno to EINVAL; received %s (%d)", errno, strerror(errno));
746 
747   tab = pr_table_alloc(p, 0);
748   load = pr_table_load(tab);
749   fail_unless(load >= 0.0, "Failed to calculate load properly; load = %0.3f",
750     load);
751 }
752 END_TEST
753 
START_TEST(table_dump_test)754 START_TEST (table_dump_test) {
755   pr_table_t *tab;
756 
757   pr_table_dump(NULL, NULL);
758 
759   tab = pr_table_alloc(p, 0);
760 
761   pr_table_dump(NULL, tab);
762   pr_table_dump(table_dump, NULL);
763 }
764 END_TEST
765 
START_TEST(table_pcalloc_test)766 START_TEST (table_pcalloc_test) {
767   void *res;
768   pr_table_t *tab;
769 
770   res = pr_table_pcalloc(NULL, 0);
771   fail_unless(res == NULL, "Failed to handle null arguments");
772   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
773 
774   tab = pr_table_alloc(p, 0);
775 
776   res = pr_table_pcalloc(tab, 0);
777   fail_unless(res == NULL, "Failed to handle zero len argument");
778   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
779 
780   res = pr_table_pcalloc(NULL, 1);
781   fail_unless(res == NULL, "Failed to handle null table");
782   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
783 
784   res = pr_table_pcalloc(tab, 2);
785   fail_unless(res != NULL, "Failed to allocate len 2 from table: %s",
786     strerror(errno));
787 }
788 END_TEST
789 
tests_get_table_suite(void)790 Suite *tests_get_table_suite(void) {
791   Suite *suite;
792   TCase *testcase;
793 
794   suite = suite_create("table");
795   testcase = tcase_create("base");
796 
797   tcase_add_checked_fixture(testcase, set_up, tear_down);
798 
799   tcase_add_test(testcase, table_alloc_test);
800   tcase_add_test(testcase, table_nalloc_test);
801   tcase_add_test(testcase, table_add_test);
802   tcase_add_test(testcase, table_add_dup_test);
803   tcase_add_test(testcase, table_count_test);
804   tcase_add_test(testcase, table_exists_test);
805   tcase_add_test(testcase, table_empty_test);
806   tcase_add_test(testcase, table_free_test);
807   tcase_add_test(testcase, table_get_test);
808   tcase_add_test(testcase, table_get_use_cache_test);
809   tcase_add_test(testcase, table_next_test);
810   tcase_add_test(testcase, table_rewind_test);
811   tcase_add_test(testcase, table_remove_test);
812   tcase_add_test(testcase, table_set_test);
813   tcase_add_test(testcase, table_do_test);
814   tcase_add_test(testcase, table_do_with_remove_test);
815   tcase_add_test(testcase, table_ctl_test);
816   tcase_add_test(testcase, table_load_test);
817   tcase_add_test(testcase, table_dump_test);
818   tcase_add_test(testcase, table_pcalloc_test);
819 
820   suite_add_tcase(suite, testcase);
821   return suite;
822 }
823