You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
375 lines
8.7 KiB
375 lines
8.7 KiB
/**
|
|
@file
|
|
|
|
@ingroup st
|
|
|
|
@brief Simple test program of the st library.
|
|
|
|
@copyright@parblock
|
|
Copyright (c) 2015, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
@endparblock
|
|
|
|
*/
|
|
|
|
#include "util.h"
|
|
#include "st.h"
|
|
|
|
/**
|
|
@brief Just some struct type.
|
|
*/
|
|
typedef struct mys {
|
|
double a;
|
|
int b;
|
|
int c;
|
|
} mys_t;
|
|
|
|
|
|
/** \cond */
|
|
|
|
static int testString(void);
|
|
static int testStruct(void);
|
|
static int testUintPtr(void);
|
|
static int testInt(void);
|
|
static int testArg(void);
|
|
static int mys_cmp(void const * key1, void const * key2);
|
|
static int mys_hash(void const * key, int size);
|
|
static enum st_retval mys_accm(void * key, void * value, void * arg);
|
|
static int array_hash(void const * key, int modulus, void const * arg);
|
|
static int array_cmp(void const * key1, void const * key2, void const *arg);
|
|
|
|
/** \endcond */
|
|
|
|
/**
|
|
@brief Main program.
|
|
|
|
@return the number of failed tests.
|
|
|
|
@details Uses TAP (Test Anything Protocol) to report results.
|
|
*/
|
|
int
|
|
main(void)
|
|
{
|
|
int ret = 0;
|
|
printf("TAP version 13\n1..5\n");
|
|
|
|
if (testString() != 0) {
|
|
ret++;
|
|
printf("not ");
|
|
}
|
|
printf("ok 1 string table\n");
|
|
|
|
if (testStruct() != 0) {
|
|
ret++;
|
|
printf("not ");
|
|
}
|
|
printf("ok 2 struct-to-uintptr_t map\n");
|
|
|
|
if (testUintPtr() != 0) {
|
|
ret++;
|
|
printf("not ");
|
|
}
|
|
printf("ok 3 uintptr_t-to-string map\n");
|
|
|
|
if (testInt() != 0) {
|
|
ret++;
|
|
printf("not ");
|
|
}
|
|
printf("ok 4 int-to-int map\n");
|
|
|
|
if (testArg() != 0) {
|
|
ret++;
|
|
printf("not ");
|
|
}
|
|
printf("ok 5 table with arg\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Tests a table that stores C strings.
|
|
|
|
@return 0 if successful; the number of errors otherwise.
|
|
*/
|
|
static int
|
|
testString(void)
|
|
{
|
|
int error = 0;
|
|
char foo[] = "foo";
|
|
char *cp = foo;
|
|
char bar[] = "bar";
|
|
char foobar[] = "foobar";
|
|
st_table * tbl = st_init_table((st_compare_t) strcmp, st_strhash);
|
|
if (!tbl)
|
|
error++;
|
|
if (st_insert(tbl, foo, NULL) != 0)
|
|
error++;
|
|
if (st_insert(tbl, bar, NULL) != 0)
|
|
error++;
|
|
if (st_insert(tbl, foobar, NULL) != 0)
|
|
error++;
|
|
if (!st_is_member(tbl, "foo"))
|
|
error++;
|
|
if (!st_delete(tbl, (void **) &cp, NULL))
|
|
error++;
|
|
if (st_count(tbl) != 2)
|
|
error++;
|
|
if (st_insert(tbl, bar, NULL) != 1)
|
|
error++;
|
|
st_free_table(tbl);
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Tests a table that maps user-defined structs to uintptr_t.
|
|
|
|
@return 0 if successful; the number of errors otherwise.
|
|
*/
|
|
static int
|
|
testStruct(void)
|
|
{
|
|
int error = 0;
|
|
mys_t m1 = {3.5, 4, 11};
|
|
mys_t m2 = {6.7, 5, -2};
|
|
uintptr_t u;
|
|
st_table * tbl = st_init_table(mys_cmp, mys_hash);
|
|
if (!tbl)
|
|
error++;
|
|
if (st_insert(tbl, &m1, (void *)(uintptr_t) 2) != 0)
|
|
error++;
|
|
if (st_insert(tbl, &m2, (void *)(uintptr_t) 5) != 0)
|
|
error++;
|
|
if (st_lookup(tbl, &m1, (void **) &u) != 1)
|
|
error++;
|
|
if (u != 2)
|
|
error++;
|
|
u = 0;
|
|
if (st_foreach(tbl, mys_accm, &u) != 1)
|
|
error++;
|
|
if (u != 7)
|
|
error++;
|
|
st_free_table(tbl);
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Tests a table that maps values of type uintptr_t to strings.
|
|
|
|
@return 0 if successful; the number of errors otherwise.
|
|
*/
|
|
static int
|
|
testUintPtr(void)
|
|
{
|
|
int error = 0;
|
|
char foo[] = "foo";
|
|
char * cp;
|
|
st_table * tbl = st_init_table(st_numcmp, st_numhash);
|
|
if (!tbl)
|
|
error++;
|
|
if (st_insert(tbl, (void *)(uintptr_t) 2, foo) != 0)
|
|
error++;
|
|
if (st_lookup(tbl, (void *)(uintptr_t) 2, (void **) &cp) != 1)
|
|
error++;
|
|
if (strcmp(cp, "foo") != 0)
|
|
error++;
|
|
if (st_is_member(tbl, (void *)(uintptr_t) 76))
|
|
error++;
|
|
st_free_table(tbl);
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Tests a table that maps ints to ints.
|
|
|
|
@return 0 if successful; the number of errors otherwise.
|
|
*/
|
|
static int
|
|
testInt(void)
|
|
{
|
|
int error = 0;
|
|
int n1 = -2;
|
|
int n2;
|
|
void * e;
|
|
int i;
|
|
st_generator * gen;
|
|
st_table * tbl = st_init_table(st_numcmp, st_numhash);
|
|
if (!tbl)
|
|
error++;
|
|
if (st_insert(tbl, (void *)(intptr_t) n1, (void *)(intptr_t) 3) != 0)
|
|
error++;
|
|
if (st_lookup_int(tbl, (void *)(intptr_t) n1, &n2) != 1)
|
|
error++;
|
|
if (n2 != 3)
|
|
error++;
|
|
e = (void *)(intptr_t) n1;
|
|
if (st_delete_int(tbl, &e, &n2) != 1)
|
|
error++;
|
|
if ((int)(intptr_t) e != n1 || n2 != 3)
|
|
error++;
|
|
if (st_count(tbl) != 0)
|
|
error++;
|
|
for (i = 0; i < 100000; i++) {
|
|
if (st_insert(tbl, (void *)(intptr_t) i, (void *)(intptr_t) i) != 0)
|
|
error++;
|
|
}
|
|
st_foreach_item_int(tbl, gen, &e, &n1) {
|
|
if ((int)(intptr_t) e != n1)
|
|
error++;
|
|
}
|
|
st_free_table(tbl);
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Tests a table of arrays of ints.
|
|
|
|
@return 0 if successful; 1 otherwise.
|
|
*/
|
|
static int
|
|
testArg(void)
|
|
{
|
|
size_t const n = 5;
|
|
int error = 0;
|
|
int a1[] = {0,1,2,3,4};
|
|
int a2[] = {4,3,2,1,0};
|
|
int *a3 = a1;
|
|
intptr_t val = 0;
|
|
st_table *tbl = st_init_table_with_arg(array_cmp, array_hash, (void *) n);
|
|
if (!tbl)
|
|
error++;
|
|
if (st_insert(tbl, a1, (void *)(intptr_t) 1) != 0)
|
|
error++;
|
|
if (st_insert(tbl, a2, (void *)(intptr_t) 2) != 0)
|
|
error++;
|
|
if (!st_is_member(tbl, a1))
|
|
error++;
|
|
if (!st_delete(tbl, (void **) &a3, (void **) &val))
|
|
error++;
|
|
if (a3[0] != a1[0] || val != 1)
|
|
error++;
|
|
if (st_is_member(tbl, a1))
|
|
error++;
|
|
if (!st_is_member(tbl, a2))
|
|
error++;
|
|
st_free_table(tbl);
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Compares two items of type mys_t.
|
|
|
|
@return 0 if they compare equal and 1 otherwise.
|
|
*/
|
|
static int
|
|
mys_cmp(void const * key1, void const * key2)
|
|
{
|
|
mys_t const *m1 = (mys_t const *) key1;
|
|
mys_t const *m2 = (mys_t const *) key2;
|
|
|
|
return m1->b != m2->b || m1->c != m2->c;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Hashes one item of type mys_t.
|
|
|
|
@return the hash value.
|
|
*/
|
|
static int
|
|
mys_hash(void const * key, int size)
|
|
{
|
|
mys_t const *m = (mys_t const *) key;
|
|
return (int)((((unsigned) m->b >> 4) ^ ((unsigned) m->c >> 5)) % size);
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Accumulates the values associated to items of type mys_t.
|
|
|
|
@return ST_CONTINUE
|
|
*/
|
|
static enum st_retval
|
|
mys_accm(void * key, void * value, void * arg)
|
|
{
|
|
(void) key; /* avoid warning */
|
|
uintptr_t v = (uintptr_t) value;
|
|
uintptr_t * accum = (uintptr_t *) arg;
|
|
*accum += v;
|
|
return ST_CONTINUE;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Compares two arrays of ints.
|
|
|
|
@details The length of the two arrays is in `arg`.
|
|
|
|
@return 0 if they compare equal and 1 otherwise.
|
|
*/
|
|
static int
|
|
array_cmp(void const * key1, void const * key2, void const *arg)
|
|
{
|
|
int const *a1 = (int const *) key1;
|
|
int const *a2 = (int const *) key2;
|
|
size_t const size = (size_t const) arg;
|
|
size_t i;
|
|
for (i = 0; i < size; i++) {
|
|
if (a1[i] != a2[i])
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Hashes one array of ints.
|
|
|
|
@return the hash value.
|
|
*/
|
|
static int
|
|
array_hash(void const * key, int modulus, void const * arg)
|
|
{
|
|
int const *a = (int const *) key;
|
|
size_t const size = (size_t const) arg;
|
|
int val = 0;
|
|
size_t i;
|
|
for (i = 0; i < size; i++) {
|
|
val = val * 997 + a[i];
|
|
}
|
|
return ((val < 0) ? -val : val) % modulus;
|
|
}
|