diff options
Diffstat (limited to 'tests/gtopt.c')
-rw-r--r-- | tests/gtopt.c | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/tests/gtopt.c b/tests/gtopt.c new file mode 100644 index 0000000..13ad8cc --- /dev/null +++ b/tests/gtopt.c @@ -0,0 +1,414 @@ +/* This file is part of GDBM test suite. + Copyright (C) 2011 Free Software Foundation, Inc. + + GDBM is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GDBM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GDBM. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "autoconf.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include "gdbmdefs.h" +#include "progname.h" + +const char *progname; +const char *dbname; +int flags = 0; /* gdbm_open flags */ +int mode = GDBM_WRCREAT; /* gdbm_open mode */ +int block_size = 0; /* block size for the db. 0 means default */ +size_t mapped_size_max = 32768; /* size of the memory mapped region */ +size_t cache_size = 32; /* cache size */ + +static size_t +get_max_mmap_size (const char *arg) +{ + char *p; + size_t size; + + errno = 0; + size = strtoul (arg, &p, 10); + + if (errno) + { + fprintf (stderr, "%s: ", progname); + perror ("maxmap"); + exit (1); + } + + if (*p) + { + fprintf (stderr, "%s: bad maxmap\n", progname); + exit (1); + } + return size; +} + +/* Test results */ +#define RES_PASS 0 +#define RES_FAIL 1 +#define RES_XFAIL 2 +#define RES_SKIP 3 + +const char *resstr[] = { "PASS", "FAIL", "XFAIL", "SKIP" }; +static int _res_max = sizeof(resstr) / sizeof(resstr[0]); + +/* A single setopt testcase */ +struct optest +{ + char *group; /* Group this testcase belongs to */ + char *name; /* Testcase name */ + /* gdbm_setopt arguments: */ + int code; /* option code */ + void *valptr; /* points to the value */ + int valsize; /* size of the value */ + /* end of arguments */ + int xfail; /* if !0, expected value of gdbm_errno */ + int (*test) (void *valptr); /* Test function (can be NULL) */ + void (*init) (void *valptr, int valsize); /* Initialization function + (can be NULL) */ +}; + +/* Storage for the test value */ +char *string; +size_t size; +int intval; +int retbool; + +/* Individual test and initialization functions */ + +int +test_getflags (void *valptr) +{ + int expected = mode | flags; +#ifndef HAVE_MMAP + expected |= GDBM_NOMMAP; +#endif + return (*(int*) valptr == expected) ? RES_PASS : RES_FAIL; +} + +int +test_dbname (void *valptr) +{ + char *s = *(char**)valptr; + int rc = strcmp (string, dbname) == 0 ? RES_PASS : RES_FAIL; + if (rc != RES_PASS) + printf ("[got %s instead of %s] ", s, dbname); + free (s); + return rc; +} + +void +init_cachesize (void *valptr, int valsize) +{ + *(size_t*) valptr = cache_size; +} + +int +test_getcachesize (void *valptr) +{ + return *(size_t*) valptr == cache_size ? RES_PASS : RES_FAIL; +} + +void +init_true (void *valptr, int valsize) +{ + *(int*) valptr = 1; +} + +void +init_false (void *valptr, int valsize) +{ + *(int*) valptr = 0; +} + +void +init_negate_bool (void *valptr, int valsize) +{ + *(int*) valptr = !retbool; +} + +int +test_true (void *valptr) +{ + return *(int*) valptr == 1 ? RES_PASS : RES_FAIL; +} + +int +test_false (void *valptr) +{ + return *(int*) valptr == 0 ? RES_PASS : RES_FAIL; +} + +int +test_negate_bool (void *valptr) +{ + return *(int*) valptr == !retbool ? RES_PASS : RES_FAIL; +} + +int +test_bool (void *valptr) +{ + return *(int*) valptr == retbool ? RES_PASS : RES_FAIL; +} + +int +test_initial_maxmapsize(void *valptr) +{ + return *(size_t*) valptr == SIZE_T_MAX ? RES_PASS : RES_FAIL; +} + +void +init_maxmapsize (void *valptr, int valsize) +{ + *(size_t*)valptr = mapped_size_max; +} + +int +test_maxmapsize (void *valptr) +{ + size_t page_size = sysconf (_SC_PAGESIZE); + size_t expected_size = ((mapped_size_max + page_size - 1) / page_size) * + page_size; + return (*(size_t*) valptr == expected_size) ? RES_PASS : RES_FAIL; +} + +int +test_mmap_group (void *valptr) +{ +#ifdef HAVE_MMAP + return RES_PASS; +#else + return RES_SKIP; +#endif +} + +/* Create a group of testcases for testing a boolean option. + Arguments: + + grp - group name + set - GDBM_SETxxx option + get - GDBM_GETxxx option +*/ +#define TEST_BOOL_OPTION(grp, set,get) \ + { #grp, }, \ + { #grp, "initial " #get, get, &retbool, sizeof (retbool), \ + 0, NULL, NULL }, \ + { #grp, #set, set, &intval, sizeof (intval), \ + 0, NULL, init_negate_bool }, \ + { #grp, #get, get, &intval, sizeof (intval), \ + 0, test_negate_bool, NULL }, \ + { #grp, #set " true", set, &intval, sizeof (intval), \ + 0, NULL, init_true }, \ + { #grp, #get, get, &intval, sizeof (intval), \ + 0, test_true, NULL }, \ + { #grp, #set " false", set, &intval, sizeof (intval), \ + 0, NULL, init_false }, \ + { #grp, #get, get, &intval, sizeof (intval), \ + 0, test_false, NULL } + + +/* Table of testcases: */ +struct optest optest_tab[] = { + { "GETFLAGS", "GDBM_GETFLAGS", GDBM_GETFLAGS, &intval, sizeof (intval), + 0, test_getflags }, + + { "CACHESIZE" }, + { "CACHESIZE", "initial GDBM_SETCACHESIZE", GDBM_SETCACHESIZE, + &size, sizeof (size), 0, + NULL, init_cachesize }, + { "CACHESIZE", "GDBM_GETCACHESIZE", GDBM_GETCACHESIZE, + &size, sizeof (size), 0, + test_getcachesize }, + { "CACHESIZE", "second GDBM_SETCACHESIZE", GDBM_SETCACHESIZE, + &size, sizeof (size), + GDBM_OPT_ALREADY_SET, NULL, init_cachesize }, + + TEST_BOOL_OPTION (SYNCMODE, GDBM_SETSYNCMODE, GDBM_GETSYNCMODE), + TEST_BOOL_OPTION (CENTFREE, GDBM_SETCENTFREE, GDBM_GETCENTFREE), + TEST_BOOL_OPTION (COALESCEBLKS, GDBM_SETCOALESCEBLKS, GDBM_GETCOALESCEBLKS), + + /* MMAP group */ + { "MMAP", NULL, 0, NULL, 0, 0, test_mmap_group }, + + { "MMAP", "initial GDBM_GETMMAP", GDBM_GETMMAP, + &intval, sizeof (intval), 0, + test_true }, + { "MMAP", "GDBM_SETMMAP false", GDBM_SETMMAP, + &intval, sizeof (intval), 0, + NULL, init_false }, + { "MMAP", "GDBM_GETMMAP", GDBM_GETMMAP, + &intval, sizeof (intval), 0, + test_false }, + + { "MMAP", "initial GDBM_GETMAXMAPSIZE", GDBM_GETMAXMAPSIZE, + &size, sizeof (size), 0, + test_initial_maxmapsize, NULL }, + { "MMAP", "GDBM_SETMAXMAPSIZE", GDBM_SETMAXMAPSIZE, + &size, sizeof (size), 0, + NULL, init_maxmapsize }, + { "MMAP", "GDBM_GETMAXMAPSIZE", GDBM_GETMAXMAPSIZE, + &size, sizeof (size), 0, + test_maxmapsize, NULL }, + + + { "GETDBNAME", "GDBM_GETDBNAME", GDBM_GETDBNAME, + &string, sizeof (string), 0, + test_dbname, NULL }, + { NULL } +}; + +/* Use ARGV to determine whether to run the given GROUP of + testcases. + + ARGV is a NULL-terminated array of allowed group names. A "!" + prefix can be used to denote negation. */ +int +groupok (char **argv, const char *group) +{ + int retval = 1; + + if (*argv) + { + char *arg; + + while ((arg = *argv++)) + { + if (*arg == '!') + { + if (strcasecmp (arg + 1, group) == 0) + return 0; + retval = 1; + } + else + { + if (strcasecmp (arg, group) == 0) + return 1; + retval = 0; + } + } + } + + return retval; +} + +int +main (int argc, char **argv) +{ + GDBM_FILE dbf; + struct optest *op; + + progname = canonical_progname (argv[0]); + while (--argc) + { + char *arg = *++argv; + + if (strcmp (arg, "-h") == 0) + { + printf ("usage: %s [-blocksize=N] [-nolock] [-sync] [-maxmap=N] DBFILE [GROUP [GROUP...]\n", + progname); + exit (0); + } + else if (strcmp (arg, "-nolock") == 0) + flags |= GDBM_NOLOCK; + else if (strcmp (arg, "-sync") == 0) + flags |= GDBM_SYNC; + else if (strncmp (arg, "-blocksize=", 11) == 0) + block_size = atoi (arg + 11); + else if (strncmp (arg, "-maxmap=", 8) == 0) + mapped_size_max = get_max_mmap_size (arg + 8); + else if (strcmp (arg, "--") == 0) + { + --argc; + ++argv; + break; + } + else if (arg[0] == '-') + { + fprintf (stderr, "%s: unknown option %s\n", progname, arg); + exit (1); + } + else + break; + } + + if (argc == 0) + { + fprintf (stderr, "%s: wrong arguments\n", progname); + exit (1); + } + dbname = *argv; + ++argv; + --argc; + + dbf = gdbm_open (dbname, block_size, mode|flags, 00664, NULL); + if (!dbf) + { + fprintf (stderr, "gdbm_open failed: %s\n", gdbm_strerror (gdbm_errno)); + exit (1); + } + + for (op = optest_tab; op->group; op++) + { + int rc; + + if (!groupok (argv, op->group)) + continue; + + if (!op->name) + { + /* Group header */ + const char *grp = op->group; + + printf ("* %s:", grp); + if (op->test && (rc = op->test (NULL)) != RES_PASS) + { + printf (" %s", resstr[rc]); + for (op++; op->name && strcmp (op->group, grp) == 0; op++) + ; + op--; + } + putchar ('\n'); + continue; + } + + printf ("%s: ", op->name); + if (op->init) + op->init (op->valptr, op->valsize); + + rc = gdbm_setopt (dbf, op->code, op->valptr, op->valsize); + if (rc) + { + if (gdbm_errno == op->xfail) + puts (resstr[RES_XFAIL]); + else + printf ("%s: %s\n", resstr[RES_FAIL], + gdbm_strerror (gdbm_errno)); + } + else if (!op->test) + puts (resstr[RES_PASS]); + else + { + rc = op->test (op->valptr); + assert (rc >= 0 && rc < _res_max); + puts (resstr[rc]); + } + } + + gdbm_close (dbf); + exit (0); +} + + + |