Fixed license declaration at spec file
[platform/upstream/gdbm.git] / tests / gtopt.c
1 /* This file is part of GDBM test suite.
2    Copyright (C) 2011 Free Software Foundation, Inc.
3
4    GDBM is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    GDBM is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with GDBM. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "autoconf.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include "gdbmdefs.h"
24 #include "progname.h"
25
26 const char *progname;
27 const char *dbname;
28 int flags = 0;                  /* gdbm_open flags */
29 int mode = GDBM_WRCREAT;        /* gdbm_open mode */
30 int block_size = 0;             /* block size for the db. 0 means default */
31 size_t mapped_size_max = 32768; /* size of the memory mapped region */
32 size_t cache_size = 32;         /* cache size */
33
34 static size_t
35 get_max_mmap_size (const char *arg)
36 {
37   char *p;
38   size_t size;
39   
40   errno = 0;
41   size = strtoul (arg, &p, 10);
42           
43   if (errno)
44     {
45       fprintf (stderr, "%s: ", progname);
46       perror ("maxmap");
47       exit (1);
48     }
49   
50   if (*p)
51     {
52       fprintf (stderr, "%s: bad maxmap\n", progname);
53       exit (1);
54     }
55   return size;
56 }
57
58 /* Test results */
59 #define RES_PASS  0
60 #define RES_FAIL  1
61 #define RES_XFAIL 2
62 #define RES_SKIP  3
63
64 const char *resstr[] = { "PASS", "FAIL", "XFAIL", "SKIP" };
65 static int _res_max = sizeof(resstr) / sizeof(resstr[0]);
66
67 /* A single setopt testcase */
68 struct optest
69 {
70   char *group;       /* Group this testcase belongs to */
71   char *name;        /* Testcase name */  
72   /* gdbm_setopt arguments: */
73   int code;          /* option code */
74   void *valptr;      /* points to the value */
75   int valsize;       /* size of the value */
76   /* end of arguments */
77   int xfail;         /* if !0, expected value of gdbm_errno */
78   int (*test) (void *valptr);   /* Test function (can be NULL) */
79   void (*init) (void *valptr, int valsize); /* Initialization function
80                                                (can be NULL) */
81 };
82 \f
83 /* Storage for the test value */
84 char *string;
85 size_t size;
86 int intval;
87 int retbool;
88 \f
89 /* Individual test and initialization functions */
90
91 int
92 test_getflags (void *valptr)
93 {
94   int expected = mode | flags;
95 #ifndef HAVE_MMAP
96   expected |= GDBM_NOMMAP;
97 #endif
98   return (*(int*) valptr == expected) ? RES_PASS : RES_FAIL;
99 }
100
101 int
102 test_dbname (void *valptr)
103 {
104   char *s = *(char**)valptr;
105   int rc = strcmp (string, dbname) == 0 ? RES_PASS : RES_FAIL;
106   if (rc != RES_PASS)
107     printf ("[got %s instead of %s] ", s, dbname);
108   free (s);
109   return rc;
110 }
111
112 void
113 init_cachesize (void *valptr, int valsize)
114 {
115   *(size_t*) valptr = cache_size;
116 }
117
118 int
119 test_getcachesize (void *valptr)
120 {
121   return *(size_t*) valptr == cache_size ? RES_PASS : RES_FAIL;
122 }
123
124 void
125 init_true (void *valptr, int valsize)
126 {
127   *(int*) valptr = 1;
128 }
129
130 void
131 init_false (void *valptr, int valsize)
132 {
133   *(int*) valptr = 0;
134 }
135
136 void
137 init_negate_bool (void *valptr, int valsize)
138 {
139   *(int*) valptr = !retbool;
140 }
141
142 int
143 test_true (void *valptr)
144 {
145   return *(int*) valptr == 1 ? RES_PASS : RES_FAIL;
146 }
147
148 int
149 test_false (void *valptr)
150 {
151   return *(int*) valptr == 0 ? RES_PASS : RES_FAIL;
152 }
153
154 int
155 test_negate_bool (void *valptr)
156 {
157   return *(int*) valptr == !retbool ? RES_PASS : RES_FAIL;
158 }
159
160 int
161 test_bool (void *valptr)
162 {
163   return *(int*) valptr == retbool ? RES_PASS : RES_FAIL;
164 }
165
166 int
167 test_initial_maxmapsize(void *valptr)
168 {
169   return *(size_t*) valptr == SIZE_T_MAX ? RES_PASS : RES_FAIL;
170 }
171
172 void
173 init_maxmapsize (void *valptr, int valsize)
174 {
175   *(size_t*)valptr = mapped_size_max;
176 }
177
178 int
179 test_maxmapsize (void *valptr)
180 {
181   size_t page_size = sysconf (_SC_PAGESIZE);
182   size_t expected_size = ((mapped_size_max + page_size - 1) / page_size) *
183                                   page_size;
184   return (*(size_t*) valptr == expected_size) ? RES_PASS : RES_FAIL;
185 }
186
187 int
188 test_mmap_group (void *valptr)
189 {
190 #ifdef HAVE_MMAP
191   return RES_PASS;
192 #else
193   return RES_SKIP;
194 #endif
195 }
196
197 /* Create a group of testcases for testing a boolean option.
198    Arguments:
199
200      grp  -  group name
201      set  -  GDBM_SETxxx option
202      get  -  GDBM_GETxxx option
203 */
204 #define TEST_BOOL_OPTION(grp, set,get)                          \
205   { #grp, },                                                    \
206   { #grp, "initial " #get, get, &retbool, sizeof (retbool),     \
207       0, NULL, NULL },                                          \
208   { #grp, #set, set, &intval, sizeof (intval),                  \
209       0, NULL, init_negate_bool },                              \
210   { #grp, #get, get, &intval, sizeof (intval),                  \
211       0, test_negate_bool, NULL },                              \
212   { #grp, #set " true", set, &intval, sizeof (intval),          \
213       0, NULL, init_true },                                     \
214   { #grp, #get, get, &intval, sizeof (intval),                  \
215       0, test_true, NULL },                                     \
216   { #grp, #set " false", set, &intval, sizeof (intval),         \
217       0, NULL, init_false },                                    \
218   { #grp, #get, get, &intval, sizeof (intval),                  \
219       0, test_false, NULL }
220
221 \f
222 /* Table of testcases: */
223 struct optest optest_tab[] = {
224   { "GETFLAGS", "GDBM_GETFLAGS", GDBM_GETFLAGS, &intval, sizeof (intval),
225     0, test_getflags },
226
227   { "CACHESIZE" },
228   { "CACHESIZE", "initial GDBM_SETCACHESIZE", GDBM_SETCACHESIZE,
229     &size, sizeof (size), 0,
230     NULL, init_cachesize },
231   { "CACHESIZE", "GDBM_GETCACHESIZE", GDBM_GETCACHESIZE,
232     &size, sizeof (size), 0,
233     test_getcachesize },
234   { "CACHESIZE", "second GDBM_SETCACHESIZE", GDBM_SETCACHESIZE,
235     &size, sizeof (size),
236     GDBM_OPT_ALREADY_SET, NULL, init_cachesize },
237
238   TEST_BOOL_OPTION (SYNCMODE, GDBM_SETSYNCMODE, GDBM_GETSYNCMODE),
239   TEST_BOOL_OPTION (CENTFREE, GDBM_SETCENTFREE, GDBM_GETCENTFREE),
240   TEST_BOOL_OPTION (COALESCEBLKS, GDBM_SETCOALESCEBLKS, GDBM_GETCOALESCEBLKS),
241
242   /* MMAP group */
243   { "MMAP", NULL, 0, NULL, 0, 0, test_mmap_group }, 
244
245   { "MMAP", "initial GDBM_GETMMAP", GDBM_GETMMAP,
246     &intval, sizeof (intval), 0,
247     test_true },
248   { "MMAP", "GDBM_SETMMAP false", GDBM_SETMMAP,
249     &intval, sizeof (intval), 0,
250     NULL, init_false },
251   { "MMAP", "GDBM_GETMMAP", GDBM_GETMMAP,
252     &intval, sizeof (intval), 0,
253     test_false },
254
255   { "MMAP", "initial GDBM_GETMAXMAPSIZE", GDBM_GETMAXMAPSIZE,
256     &size, sizeof (size), 0,
257     test_initial_maxmapsize, NULL },
258   { "MMAP", "GDBM_SETMAXMAPSIZE", GDBM_SETMAXMAPSIZE,
259     &size, sizeof (size), 0,
260     NULL, init_maxmapsize },
261   { "MMAP", "GDBM_GETMAXMAPSIZE", GDBM_GETMAXMAPSIZE,
262     &size, sizeof (size), 0,
263     test_maxmapsize, NULL },
264   
265   
266   { "GETDBNAME", "GDBM_GETDBNAME", GDBM_GETDBNAME,
267     &string, sizeof (string), 0,
268     test_dbname, NULL },
269   { NULL }
270 };
271
272 /* Use ARGV to determine whether to run the given GROUP of
273    testcases.
274
275    ARGV is a NULL-terminated array of allowed group names.  A "!"
276    prefix can be used to denote negation. */
277 int
278 groupok (char **argv, const char *group)
279 {
280   int retval = 1;
281   
282   if (*argv)
283     {
284       char *arg;
285     
286       while ((arg = *argv++))
287         {
288           if (*arg == '!')
289             {
290               if (strcasecmp (arg + 1, group) == 0)
291                 return 0;
292               retval = 1;
293             }
294           else
295             {
296               if (strcasecmp (arg, group) == 0)
297                 return 1;
298               retval = 0;
299             }
300         }
301     }
302
303   return retval;
304 }
305 \f
306 int
307 main (int argc, char **argv)
308 {
309   GDBM_FILE dbf;
310   struct optest *op;
311   
312   progname = canonical_progname (argv[0]);
313   while (--argc)
314     {
315       char *arg = *++argv;
316
317       if (strcmp (arg, "-h") == 0)
318         {
319           printf ("usage: %s [-blocksize=N] [-nolock] [-sync] [-maxmap=N] DBFILE [GROUP [GROUP...]\n",
320                   progname);
321           exit (0);
322         }
323       else if (strcmp (arg, "-nolock") == 0)
324         flags |= GDBM_NOLOCK;
325       else if (strcmp (arg, "-sync") == 0)
326         flags |= GDBM_SYNC;
327       else if (strncmp (arg, "-blocksize=", 11) == 0)
328         block_size = atoi (arg + 11);
329       else if (strncmp (arg, "-maxmap=", 8) == 0)
330         mapped_size_max = get_max_mmap_size (arg + 8);
331       else if (strcmp (arg, "--") == 0)
332         {
333           --argc;
334           ++argv;
335           break;
336         }
337       else if (arg[0] == '-')
338         {
339           fprintf (stderr, "%s: unknown option %s\n", progname, arg);
340           exit (1);
341         }
342       else
343         break;
344     }
345
346   if (argc == 0)
347     {
348       fprintf (stderr, "%s: wrong arguments\n", progname);
349       exit (1);
350     }
351   dbname = *argv;
352   ++argv;
353   --argc;
354   
355   dbf = gdbm_open (dbname, block_size, mode|flags, 00664, NULL);
356   if (!dbf)
357     {
358       fprintf (stderr, "gdbm_open failed: %s\n", gdbm_strerror (gdbm_errno));
359       exit (1);
360     }
361
362   for (op = optest_tab; op->group; op++)
363     {
364       int rc;
365
366       if (!groupok (argv, op->group))
367         continue;
368
369       if (!op->name)
370         {
371           /* Group header */
372           const char *grp = op->group;
373
374           printf ("* %s:", grp);
375           if (op->test && (rc = op->test (NULL)) != RES_PASS)
376             {
377               printf (" %s", resstr[rc]);
378               for (op++; op->name && strcmp (op->group, grp) == 0; op++)
379                 ;
380               op--;
381             }
382           putchar ('\n');
383           continue;
384         }
385         
386       printf ("%s: ", op->name);
387       if (op->init)
388         op->init (op->valptr, op->valsize);
389       
390       rc = gdbm_setopt (dbf, op->code, op->valptr, op->valsize);
391       if (rc)
392         {
393           if (gdbm_errno == op->xfail)
394             puts (resstr[RES_XFAIL]);
395           else
396             printf ("%s: %s\n", resstr[RES_FAIL],
397                     gdbm_strerror (gdbm_errno));
398         }
399       else if (!op->test)
400         puts (resstr[RES_PASS]);
401       else
402         {
403           rc = op->test (op->valptr);
404           assert (rc >= 0 && rc < _res_max);
405           puts (resstr[rc]);
406         }
407     }
408   
409   gdbm_close (dbf);
410   exit (0);
411 }
412   
413           
414