From 74a6bd72c24fad6c43ef84198c1367223a8a0b43 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 14:16:26 +0200 Subject: [PATCH] additional testing. --- src/kernel/save.c | 2 - src/test_eressea.c | 1 + src/tests.h | 31 +-- src/util/CMakeLists.txt | 1 + src/util/attrib.c | 473 ++++++++++++++++++++-------------------- src/util/attrib.h | 99 ++++----- src/util/attrib.test.c | 36 +++ 7 files changed, 345 insertions(+), 298 deletions(-) create mode 100644 src/util/attrib.test.c diff --git a/src/kernel/save.c b/src/kernel/save.c index 9ec7d2622..7febc0d23 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -113,8 +113,6 @@ char *rns(FILE * f, char *c, size_t size) return c; } -extern unsigned int __at_hashkey(const char *s); - static unit *unitorders(FILE * F, int enc, struct faction *f) { diff --git a/src/test_eressea.c b/src/test_eressea.c index ca9b298cd..94f8d6c67 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -30,6 +30,7 @@ int RunAllTests(void) ADD_TESTS(suite, race); /* util */ ADD_TESTS(suite, config); + ADD_TESTS(suite, attrib); ADD_TESTS(suite, base36); ADD_TESTS(suite, bsdstring); ADD_TESTS(suite, functions); diff --git a/src/tests.h b/src/tests.h index 9cbcbcac1..fca8353fb 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,25 +1,28 @@ #ifndef ERESSEA_TESTS_H #define ERESSEA_TESTS_H + +#include + #ifdef __cplusplus extern "C" { #endif - void test_cleanup(void); + void test_cleanup(void); - struct terrain_type * test_create_terrain(const char * name, unsigned int flags); - struct race *test_create_race(const char *name); - struct region *test_create_region(int x, int y, - const struct terrain_type *terrain); - struct faction *test_create_faction(const struct race *rc); - struct unit *test_create_unit(struct faction *f, struct region *r); - void test_create_world(void); - struct building * test_create_building(struct region * r, const struct building_type * btype); - struct ship * test_create_ship(struct region * r, const struct ship_type * stype); - struct item_type * test_create_itemtype(const char * name); - struct ship_type *test_create_shiptype(const char * name); - struct building_type *test_create_buildingtype(const char *name); + struct terrain_type * test_create_terrain(const char * name, unsigned int flags); + struct race *test_create_race(const char *name); + struct region *test_create_region(int x, int y, + const struct terrain_type *terrain); + struct faction *test_create_faction(const struct race *rc); + struct unit *test_create_unit(struct faction *f, struct region *r); + void test_create_world(void); + struct building * test_create_building(struct region * r, const struct building_type * btype); + struct ship * test_create_ship(struct region * r, const struct ship_type * stype); + struct item_type * test_create_itemtype(const char * name); + struct ship_type *test_create_shiptype(const char * name); + struct building_type *test_create_buildingtype(const char *name); - int RunAllTests(void); + int RunAllTests(void); #ifdef __cplusplus } diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index c4b51250c..51ceadac7 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -2,6 +2,7 @@ project(util C) SET(_TEST_FILES base36.test.c +attrib.test.c strings.test.c bsdstring.test.c functions.test.c diff --git a/src/util/attrib.c b/src/util/attrib.c index 8c8bf9d35..2b83b60ec 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -1,7 +1,7 @@ /* Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -29,322 +29,329 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #define MAXATHASH 61 -attrib_type *at_hash[MAXATHASH]; +static attrib_type *at_hash[MAXATHASH]; static unsigned int __at_hashkey(const char *s) { - int key = 0; - size_t i = strlen(s); + int key = 0; + size_t i = strlen(s); - while (i > 0) { - key = (s[--i] + key * 37); - } - return key & 0x7fffffff; + while (i > 0) { + key = (s[--i] + key * 37); + } + return key & 0x7fffffff; } void at_register(attrib_type * at) { - attrib_type *find; + attrib_type *find; - if (at->read == NULL) { - log_warning("registering non-persistent attribute %s.\n", at->name); - } - at->hashkey = __at_hashkey(at->name); - find = at_hash[at->hashkey % MAXATHASH]; - while (find && at->hashkey != find->hashkey) - find = find->nexthash; - if (find && find == at) { - log_warning("attribute '%s' was registered more than once\n", at->name); - return; - } else { - assert(!find || !"hashkey is already in use"); - } - at->nexthash = at_hash[at->hashkey % MAXATHASH]; - at_hash[at->hashkey % MAXATHASH] = at; + if (at->read == NULL) { + log_warning("registering non-persistent attribute %s.\n", at->name); + } + at->hashkey = __at_hashkey(at->name); + find = at_hash[at->hashkey % MAXATHASH]; + while (find && at->hashkey != find->hashkey) { + find = find->nexthash; + } + if (find && find == at) { + log_warning("attribute '%s' was registered more than once\n", at->name); + return; + } + else { + assert(!find || !"hashkey is already in use"); + } + at->nexthash = at_hash[at->hashkey % MAXATHASH]; + at_hash[at->hashkey % MAXATHASH] = at; } static attrib_type *at_find(unsigned int hk) { - const char *translate[3][2] = { - {"zielregion", "targetregion"}, /* remapping: from 'zielregion, heute targetregion */ - {"verzaubert", "curse"}, /* remapping: früher verzaubert, jetzt curse */ - {NULL, NULL} - }; - attrib_type *find = at_hash[hk % MAXATHASH]; - while (find && hk != find->hashkey) - find = find->nexthash; - if (!find) { - int i = 0; - while (translate[i][0]) { - if (__at_hashkey(translate[i][0]) == hk) - return at_find(__at_hashkey(translate[i][1])); - ++i; + const char *translate[3][2] = { + { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ + { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ + { NULL, NULL } + }; + attrib_type *find = at_hash[hk % MAXATHASH]; + while (find && hk != find->hashkey) + find = find->nexthash; + if (!find) { + int i = 0; + while (translate[i][0]) { + if (__at_hashkey(translate[i][0]) == hk) + return at_find(__at_hashkey(translate[i][1])); + ++i; + } } - } - return find; + return find; } attrib *a_select(attrib * a, const void *data, - bool(*compare) (const attrib *, const void *)) + bool(*compare) (const attrib *, const void *)) { - while (a && !compare(a, data)) - a = a->next; - return a; + while (a && !compare(a, data)) + a = a->next; + return a; } attrib *a_find(attrib * a, const attrib_type * at) { - while (a && a->type != at) - a = a->nexttype; - return a; + while (a && a->type != at) + a = a->nexttype; + return a; } const attrib *a_findc(const attrib * a, const attrib_type * at) { - while (a && a->type != at) - a = a->nexttype; - return a; + while (a && a->type != at) + a = a->nexttype; + return a; } static attrib *a_insert(attrib * head, attrib * a) { - attrib **pa = &head->next; + attrib **pa = &head->next; - assert(!(a->type->flags & ATF_UNIQUE)); - assert(head && head->type == a->type); + assert(!(a->type->flags & ATF_UNIQUE)); + assert(head && head->type == a->type); - while (*pa && (*pa)->type == a->type) { - pa = &(*pa)->next; - } - a->next = *pa; - return *pa = a; + while (*pa && (*pa)->type == a->type) { + pa = &(*pa)->next; + } + a->next = *pa; + return *pa = a; } attrib *a_add(attrib ** pa, attrib * a) { - attrib *first = *pa; - assert(a->next == NULL && a->nexttype == NULL); + attrib *first = *pa; + assert(a->next == NULL && a->nexttype == NULL); - if (first == NULL) - return *pa = a; - if (first->type == a->type) { - return a_insert(first, a); - } - for (;;) { - attrib *next = first->nexttype; - if (next == NULL) { - /* the type is not in the list, append it behind the last type */ - attrib **insert = &first->next; - first->nexttype = a; - while (*insert) - insert = &(*insert)->next; - *insert = a; - break; + if (first == NULL) + return *pa = a; + if (first->type == a->type) { + return a_insert(first, a); } - if (next->type == a->type) { - return a_insert(next, a); + for (;;) { + attrib *next = first->nexttype; + if (next == NULL) { + /* the type is not in the list, append it behind the last type */ + attrib **insert = &first->next; + first->nexttype = a; + while (*insert) + insert = &(*insert)->next; + *insert = a; + break; + } + if (next->type == a->type) { + return a_insert(next, a); + } + first = next; } - first = next; - } - return a; + return a; } void a_free(attrib * a) { - const attrib_type *at = a->type; - if (at->finalize) - at->finalize(a); - free(a); + const attrib_type *at = a->type; + if (at->finalize) + at->finalize(a); + free(a); } static int a_unlink(attrib ** pa, attrib * a) { - attrib **pnexttype = pa; - attrib **pnext = NULL; + attrib **pnexttype = pa; + attrib **pnext = NULL; - assert(a != NULL); - while (*pnexttype) { - attrib *next = *pnexttype; - if (next->type == a->type) - break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type == a->type) { - if (*pnexttype == a) { - *pnexttype = a->next; - if (a->next != a->nexttype) { - a->next->nexttype = a->nexttype; - } - if (pnext == NULL) - return 1; - while (*pnext && (*pnext)->type != a->type) - pnext = &(*pnext)->next; - } else { - pnext = &(*pnexttype)->next; + assert(a != NULL); + while (*pnexttype) { + attrib *next = *pnexttype; + if (next->type == a->type) + break; + pnexttype = &next->nexttype; + pnext = &next->next; } - while (*pnext && (*pnext)->type == a->type) { - if (*pnext == a) { - *pnext = a->next; - return 1; - } - pnext = &(*pnext)->next; + if (*pnexttype && (*pnexttype)->type == a->type) { + if (*pnexttype == a) { + *pnexttype = a->next; + if (a->next != a->nexttype) { + a->next->nexttype = a->nexttype; + } + if (pnext == NULL) + return 1; + while (*pnext && (*pnext)->type != a->type) + pnext = &(*pnext)->next; + } + else { + pnext = &(*pnexttype)->next; + } + while (*pnext && (*pnext)->type == a->type) { + if (*pnext == a) { + *pnext = a->next; + return 1; + } + pnext = &(*pnext)->next; + } } - } - return 0; + return 0; } int a_remove(attrib ** pa, attrib * a) { - int ok; - assert(a != NULL); - ok = a_unlink(pa, a); - if (ok) - a_free(a); - return ok; + int ok; + assert(a != NULL); + ok = a_unlink(pa, a); + if (ok) + a_free(a); + return ok; } void a_removeall(attrib ** pa, const attrib_type * at) { - attrib **pnexttype = pa; - attrib **pnext = NULL; + attrib **pnexttype = pa; + attrib **pnext = NULL; - while (*pnexttype) { - attrib *next = *pnexttype; - if (next->type == at) - break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type == at) { - attrib *a = *pnexttype; + while (*pnexttype) { + attrib *next = *pnexttype; + if (next->type == at) + break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type == at) { + attrib *a = *pnexttype; - *pnexttype = a->nexttype; - if (pnext) { - while (*pnext && (*pnext)->type != at) - pnext = &(*pnext)->next; - *pnext = a->nexttype; + *pnexttype = a->nexttype; + if (pnext) { + while (*pnext && (*pnext)->type != at) + pnext = &(*pnext)->next; + *pnext = a->nexttype; + } + while (a && a->type == at) { + attrib *ra = a; + a = a->next; + a_free(ra); + } } - while (a && a->type == at) { - attrib *ra = a; - a = a->next; - a_free(ra); - } - } } attrib *a_new(const attrib_type * at) { - attrib *a = (attrib *) calloc(1, sizeof(attrib)); - assert(at != NULL); - a->type = at; - if (at->initialize) - at->initialize(a); - return a; + attrib *a = (attrib *)calloc(1, sizeof(attrib)); + assert(at != NULL); + a->type = at; + if (at->initialize) + at->initialize(a); + return a; } int a_age(attrib ** p) { - attrib **ap = p; - /* Attribute altern, und die Entfernung (age()==0) eines Attributs - * hat Einfluß auf den Besitzer */ - while (*ap) { - attrib *a = *ap; - if (a->type->age) { - int result = a->type->age(a); - assert(result >= 0 || !"age() returned a negative value"); - if (result == 0) { - a_remove(p, a); - continue; - } + attrib **ap = p; + /* Attribute altern, und die Entfernung (age()==0) eines Attributs + * hat Einfluß auf den Besitzer */ + while (*ap) { + attrib *a = *ap; + if (a->type->age) { + int result = a->type->age(a); + assert(result >= 0 || !"age() returned a negative value"); + if (result == 0) { + a_remove(p, a); + continue; + } + } + ap = &a->next; } - ap = &a->next; - } - return (*p != NULL); + return (*p != NULL); } static critbit_tree cb_deprecated = { 0 }; -void at_deprecate(const char * name, int (*reader)(attrib *, void *, struct storage *)) +void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct storage *)) { - char buffer[64]; - size_t len = strlen(name); - len = cb_new_kv(name, len, &reader, sizeof(reader), buffer); - cb_insert(&cb_deprecated, buffer, len); + char buffer[64]; + size_t len = strlen(name); + len = cb_new_kv(name, len, &reader, sizeof(reader), buffer); + cb_insert(&cb_deprecated, buffer, len); } int a_read(struct storage *store, attrib ** attribs, void *owner) { - int key, retval = AT_READ_OK; - char zText[128]; - - zText[0] = 0; - key = -1; - READ_TOK(store, zText, sizeof(zText)); - if (strcmp(zText, "end") == 0) - return retval; - else - key = __at_hashkey(zText); - - while (key != -1) { - int (*reader)(attrib *, void *, struct storage *) = 0; - attrib_type *at = at_find(key); - attrib * na = 0; - - if (at) { - reader = at->read; - na = a_new(at); - } else { - const void * kv; - cb_find_prefix(&cb_deprecated, zText, strlen(zText)+1, &kv, 1, 0); - if (kv) { - cb_get_kv(kv, &reader, sizeof(reader)); - } else { - fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); - assert(at || !"attribute not registered"); - } - } - if (reader) { - int i = reader(na, owner, store); - if (na) { - switch (i) { - case AT_READ_OK: - a_add(attribs, na); - break; - case AT_READ_FAIL: - retval = AT_READ_FAIL; - a_free(na); - break; - default: - assert(!"invalid return value"); - break; - } - } - } else { - assert(!"error: no registered callback can read attribute"); - } + int key, retval = AT_READ_OK; + char zText[128]; + zText[0] = 0; + key = -1; READ_TOK(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) - break; - key = __at_hashkey(zText); - } - return retval; + if (strcmp(zText, "end") == 0) + return retval; + else + key = __at_hashkey(zText); + + while (key != -1) { + int(*reader)(attrib *, void *, struct storage *) = 0; + attrib_type *at = at_find(key); + attrib * na = 0; + + if (at) { + reader = at->read; + na = a_new(at); + } + else { + const void * kv; + cb_find_prefix(&cb_deprecated, zText, strlen(zText) + 1, &kv, 1, 0); + if (kv) { + cb_get_kv(kv, &reader, sizeof(reader)); + } + else { + fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); + assert(at || !"attribute not registered"); + } + } + if (reader) { + int i = reader(na, owner, store); + if (na) { + switch (i) { + case AT_READ_OK: + a_add(attribs, na); + break; + case AT_READ_FAIL: + retval = AT_READ_FAIL; + a_free(na); + break; + default: + assert(!"invalid return value"); + break; + } + } + } + else { + assert(!"error: no registered callback can read attribute"); + } + + READ_TOK(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) + break; + key = __at_hashkey(zText); + } + return retval; } void a_write(struct storage *store, const attrib * attribs, const void *owner) { - const attrib *na = attribs; + const attrib *na = attribs; - while (na) { - if (na->type->write) { - assert(na->type->hashkey || !"attribute not registered"); - WRITE_TOK(store, na->type->name); - na->type->write(na, owner, store); - na = na->next; - } else { - na = na->nexttype; + while (na) { + if (na->type->write) { + assert(na->type->hashkey || !"attribute not registered"); + WRITE_TOK(store, na->type->name); + na->type->write(na, owner, store); + na = na->next; + } + else { + na = na->nexttype; + } } - } - WRITE_TOK(store, "end"); + WRITE_TOK(store, "end"); } diff --git a/src/util/attrib.h b/src/util/attrib.h index 8a8650467..2bea8d2b8 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -1,7 +1,7 @@ /* Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -18,66 +18,67 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef ATTRIB_H #define ATTRIB_H + #ifdef __cplusplus extern "C" { #endif - struct gamedata; - struct storage; - typedef void (*afun) (void); + struct gamedata; + struct storage; + typedef void(*afun) (void); - typedef struct attrib { - const struct attrib_type *type; - union { - afun f; - void *v; - int i; - float flt; - char c; - short s; - short sa[2]; - char ca[4]; - } data; - /* internal data, do not modify: */ - struct attrib *next; /* next attribute in the list */ - struct attrib *nexttype; /* skip to attribute of a different type */ - } attrib; + typedef struct attrib { + const struct attrib_type *type; + union { + afun f; + void *v; + int i; + float flt; + char c; + short s; + short sa[2]; + char ca[4]; + } data; + /* internal data, do not modify: */ + struct attrib *next; /* next attribute in the list */ + struct attrib *nexttype; /* skip to attribute of a different type */ + } attrib; #define ATF_UNIQUE (1<<0) /* only one per attribute-list */ #define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ #define ATF_USER_DEFINED (1<<2) /* use this to make udf */ - typedef struct attrib_type { - const char *name; - void (*initialize) (struct attrib *); - void (*finalize) (struct attrib *); - int (*age) (struct attrib *); - /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ - void(*write) (const struct attrib *, const void *owner, struct storage *); - int(*read) (struct attrib *, void *owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ - unsigned int flags; - /* ---- internal data, do not modify: ---- */ - struct attrib_type *nexthash; - unsigned int hashkey; - } attrib_type; + typedef struct attrib_type { + const char *name; + void(*initialize) (struct attrib *); + void(*finalize) (struct attrib *); + int(*age) (struct attrib *); + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + void(*write) (const struct attrib *, const void *owner, struct storage *); + int(*read) (struct attrib *, void *owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ + unsigned int flags; + /* ---- internal data, do not modify: ---- */ + struct attrib_type *nexthash; + unsigned int hashkey; + } attrib_type; - extern void at_register(attrib_type * at); - extern void at_deprecate(const char * name, int (*reader)(attrib *, void *, struct storage *)); + extern void at_register(attrib_type * at); + extern void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct storage *)); - extern attrib *a_select(attrib * a, const void *data, - bool(*compare) (const attrib *, const void *)); - extern attrib *a_find(attrib * a, const attrib_type * at); - extern const attrib *a_findc(const attrib * a, const attrib_type * at); - extern attrib *a_add(attrib ** pa, attrib * at); - extern int a_remove(attrib ** pa, attrib * at); - extern void a_removeall(attrib ** a, const attrib_type * at); - extern attrib *a_new(const attrib_type * at); - extern void a_free(attrib * a); + extern attrib *a_select(attrib * a, const void *data, + bool(*compare) (const attrib *, const void *)); + extern attrib *a_find(attrib * a, const attrib_type * at); + extern const attrib *a_findc(const attrib * a, const attrib_type * at); + extern attrib *a_add(attrib ** pa, attrib * at); + extern int a_remove(attrib ** pa, attrib * at); + extern void a_removeall(attrib ** a, const attrib_type * at); + extern attrib *a_new(const attrib_type * at); + extern void a_free(attrib * a); - extern int a_age(attrib ** attribs); - extern int a_read(struct storage *store, attrib ** attribs, void *owner); - extern void a_write(struct storage *store, const attrib * attribs, - const void *owner); + extern int a_age(attrib ** attribs); + extern int a_read(struct storage *store, attrib ** attribs, void *owner); + extern void a_write(struct storage *store, const attrib * attribs, + const void *owner); #define DEFAULT_AGE NULL #define DEFAULT_INIT NULL diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c new file mode 100644 index 000000000..aba7b25db --- /dev/null +++ b/src/util/attrib.test.c @@ -0,0 +1,36 @@ +#include +#include "attrib.h" + +#include +#include + +static void test_attrib_new(CuTest * tc) +{ + attrib_type at_test = { "test" }; + attrib * a; + CuAssertPtrNotNull(tc, (a = a_new(&at_test))); + CuAssertPtrEquals(tc, 0, a->next); + CuAssertPtrEquals(tc, 0, a->nexttype); + CuAssertPtrEquals(tc, (void *)a->type, (void *)&at_test); +} + + +static void test_attrib_add(CuTest * tc) +{ + attrib_type at_test = { "test" }; + attrib *a, *alist = 0; + CuAssertPtrNotNull(tc, (a = a_new(&at_test))); + CuAssertPtrEquals(tc, a, a_add(&alist, a)); + CuAssertPtrEquals(tc, a, alist); + + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_test)))); + CuAssertPtrEquals(tc, alist->next, a); + CuAssertPtrEquals(tc, alist->nexttype, a); +} + +CuSuite *get_attrib_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_attrib_new); + return suite; +}