From 81a2dd9d213e4ce56ac8e1ab72f2c1f7766b4ee9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 25 Feb 2016 19:12:38 +0100 Subject: [PATCH 1/6] extract read_game and write_game (take a gamedata argument, not filenames) --- src/kernel/group.test.c | 71 ++++++++-- src/kernel/save.c | 303 +++++++++++++++++++++------------------- src/kernel/save.h | 3 + 3 files changed, 219 insertions(+), 158 deletions(-) diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index c30e16f98..4dc9799a5 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -1,4 +1,5 @@ #include +#include "config.h" #include "types.h" #include "ally.h" #include "group.h" @@ -15,40 +16,81 @@ #include #include #include +#include #include #include #include #include +static void test_group_readwrite_dead_faction(CuTest *tc) { + faction *f, *f2; + unit * u; + group *g; + ally *al; + int fno; + + test_cleanup(); + f = test_create_faction(0); + fno = f->no; + CuAssertPtrEquals(tc, f, factions); + CuAssertPtrEquals(tc, 0, f->next); + f2 = test_create_faction(0); + CuAssertPtrEquals(tc, f2, factions->next); + u = test_create_unit(f2, test_create_region(0, 0, 0)); + CuAssertPtrNotNull(tc, u); + g = join_group(u, "group"); + CuAssertPtrNotNull(tc, g); + al = ally_add(&g->allies, f); + CuAssertPtrNotNull(tc, al); + + CuAssertPtrEquals(tc, f, factions); + destroyfaction(&factions); + CuAssertTrue(tc, !f->_alive); + CuAssertPtrEquals(tc, f2, factions); + writegame("test.dat"); + free_gamedata(); + f = f2 = NULL; + readgame("test.dat", false); + CuAssertPtrEquals(tc, 0, findfaction(fno)); + f2 = factions; + CuAssertPtrNotNull(tc, f2); + u = f2->units; + CuAssertPtrNotNull(tc, u); + g = get_group(u); + CuAssertPtrNotNull(tc, g); + CuAssertPtrEquals(tc, 0, g->allies); + test_cleanup(); +} + static void test_group_readwrite(CuTest * tc) { faction * f; group *g; ally *al; int i; - gamedata *data; + gamedata data; + storage store; test_cleanup(); - data = gamedata_open("test.dat", "wb", RELEASE_VERSION); - CuAssertPtrNotNull(tc, data); + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); f = test_create_faction(0); g = new_group(f, "NW", 42); g = new_group(f, "Egoisten", 43); key_set(&g->attribs, 44); al = ally_add(&g->allies, f); al->status = HELP_GIVE; - write_groups(data->store, f); - WRITE_INT(data->store, 47); - binstore_done(data->store); - gamedata_close(data); + write_groups(&store, f); + WRITE_INT(&store, 47); - f->groups = 0; free_group(g); - data = gamedata_open("test.dat", "rb", RELEASE_VERSION); - read_groups(data, f); - READ_INT(data->store, &i); - gamedata_close(data); + f->groups = 0; + data.strm.api->rewind(data.strm.handle); + read_groups(&data, f); + READ_INT(&store, &i); + mstream_done(&data.strm); + gamedata_done(&data); CuAssertIntEquals(tc, 47, i); CuAssertPtrNotNull(tc, f->groups); @@ -64,7 +106,6 @@ static void test_group_readwrite(CuTest * tc) CuAssertPtrEquals(tc, 0, g->allies->next); CuAssertPtrEquals(tc, f, g->allies->faction); CuAssertIntEquals(tc, HELP_GIVE, g->allies->status); - remove("test.dat"); test_cleanup(); } @@ -76,8 +117,7 @@ static void test_group(CuTest * tc) group *g; test_cleanup(); - test_create_world(); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); f = test_create_faction(0); assert(r && f); u = test_create_unit(f, r); @@ -100,6 +140,7 @@ CuSuite *get_group_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_group); SUITE_ADD_TEST(suite, test_group_readwrite); + SUITE_ADD_TEST(suite, test_group_readwrite_dead_faction); return suite; } diff --git a/src/kernel/save.c b/src/kernel/save.c index aa6f85d83..783cee890 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1461,16 +1461,8 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) { int readgame(const char *filename, bool backup) { - int n, p, nread; - faction *f, **fp; - region *r; - building *b, **bp; - ship **shp; - unit *u; - int rmax = maxregions; + int n; char path[MAX_PATH]; - char name[DISPLAYSIZE]; - const struct building_type *bt_lighthouse = bt_find("lighthouse"); gamedata gdata = { 0 }; storage store; stream strm; @@ -1508,10 +1500,27 @@ int readgame(const char *filename, bool backup) READ_INT(&store, &build); log_debug("data in %s created with build %d.", filename, build); } - if (gdata.version >= SAVEGAMEID_VERSION) { + n = read_game(&gdata); + binstore_done(&store); + fstream_done(&strm); + return n; +} + +int read_game(gamedata *data) { + char name[DISPLAYSIZE]; + int n, p, nread; + faction *f, **fp; + region *r; + building *b, **bp; + ship **shp; + unit *u; + int rmax = maxregions; + const struct building_type *bt_lighthouse = bt_find("lighthouse"); + storage * store = data->store; + if (data->version >= SAVEGAMEID_VERSION) { int gameid; - READ_INT(&store, &gameid); + READ_INT(store, &gameid); if (gameid != game_id()) { int c; log_warning("game mismatch: datafile contains game %d, but config is for %d", gameid, game_id()); @@ -1524,25 +1533,25 @@ int readgame(const char *filename, bool backup) } } else { - READ_STR(&store, NULL, 0); + READ_STR(store, NULL, 0); } - read_attribs(&gdata, &global.attribs, NULL); - READ_INT(&store, &turn); + read_attribs(data, &global.attribs, NULL); + READ_INT(store, &turn); global.data_turn = turn; log_debug(" - reading turn %d\n", turn); rng_init(turn); - READ_INT(&store, &nread); /* max_unique_id = ignore */ - READ_INT(&store, &nextborder); + READ_INT(store, &nread); /* max_unique_id = ignore */ + READ_INT(store, &nextborder); /* Planes */ planes = NULL; - READ_INT(&store, &nread); + READ_INT(store, &nread); while (--nread >= 0) { int id; variant fno; plane *pl; - READ_INT(&store, &id); + READ_INT(store, &id); pl = getplanebyid(id); if (pl == NULL) { @@ -1552,20 +1561,20 @@ int readgame(const char *filename, bool backup) log_warning("the plane with id=%d already exists.\n", id); } pl->id = id; - READ_STR(&store, name, sizeof(name)); + READ_STR(store, name, sizeof(name)); pl->name = _strdup(name); - READ_INT(&store, &pl->minx); - READ_INT(&store, &pl->maxx); - READ_INT(&store, &pl->miny); - READ_INT(&store, &pl->maxy); - READ_INT(&store, &pl->flags); + READ_INT(store, &pl->minx); + READ_INT(store, &pl->maxx); + READ_INT(store, &pl->miny); + READ_INT(store, &pl->maxy); + READ_INT(store, &pl->flags); /* read watchers */ - if (gdata.version < FIX_WATCHERS_VERSION) { + if (data->version < FIX_WATCHERS_VERSION) { char rname[64]; /* before this version, watcher storage was pretty broken. we are incompatible and don't read them */ for (;;) { - READ_TOK(&store, rname, sizeof(rname)); + READ_TOK(store, rname, sizeof(rname)); if (strcmp(rname, "end") == 0) { break; /* this is most likely the end of the list */ } @@ -1577,29 +1586,29 @@ int readgame(const char *filename, bool backup) } else { /* WATCHERS - eliminated in February 2016, ca. turn 966 */ - if (gdata.version < NOWATCH_VERSION) { - fno = read_faction_reference(&gdata); + if (data->version < NOWATCH_VERSION) { + fno = read_faction_reference(data); while (fno.i) { - fno = read_faction_reference(&gdata); + fno = read_faction_reference(data); } } } - read_attribs(&gdata, &pl->attribs, pl); + read_attribs(data, &pl->attribs, pl); if (pl->id != 1094969858) { // Regatta addlist(&planes, pl); } } /* Read factions */ - read_alliances(&gdata); - READ_INT(&store, &nread); + read_alliances(data); + READ_INT(store, &nread); log_debug(" - Einzulesende Parteien: %d\n", nread); fp = &factions; while (*fp) fp = &(*fp)->next; while (--nread >= 0) { - faction *f = readfaction(&gdata); + faction *f = readfaction(data); *fp = f; fp = &f->next; @@ -1609,7 +1618,7 @@ int readgame(const char *filename, bool backup) /* Regionen */ - READ_INT(&store, &nread); + READ_INT(store, &nread); assert(nread < MAXREGIONS); if (rmax < 0) { rmax = nread; @@ -1618,67 +1627,67 @@ int readgame(const char *filename, bool backup) while (--nread >= 0) { unit **up; int x, y; - READ_INT(&store, &x); - READ_INT(&store, &y); + READ_INT(store, &x); + READ_INT(store, &y); if ((nread & 0x3FF) == 0) { /* das spart extrem Zeit */ log_debug(" - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, nread, x, y); } --rmax; - r = readregion(&gdata, x, y); + r = readregion(data, x, y); /* Burgen */ - READ_INT(&store, &p); + READ_INT(store, &p); bp = &r->buildings; while (--p >= 0) { b = (building *)calloc(1, sizeof(building)); - READ_INT(&store, &b->no); + READ_INT(store, &b->no); *bp = b; bp = &b->next; bhash(b); - READ_STR(&store, name, sizeof(name)); + READ_STR(store, name, sizeof(name)); b->name = _strdup(name); if (lomem) { - READ_STR(gdata.store, NULL, 0); + READ_STR(store, NULL, 0); } else { - READ_STR(&store, name, sizeof(name)); + READ_STR(store, name, sizeof(name)); b->display = _strdup(name); } - READ_INT(&store, &b->size); - READ_STR(&store, name, sizeof(name)); + READ_INT(store, &b->size); + READ_STR(store, name, sizeof(name)); b->type = bt_find(name); b->region = r; - read_attribs(&gdata, &b->attribs, b); + read_attribs(data, &b->attribs, b); if (b->type == bt_lighthouse) { r->flags |= RF_LIGHTHOUSE; } } /* Schiffe */ - READ_INT(&store, &p); + READ_INT(store, &p); shp = &r->ships; while (--p >= 0) { ship *sh = (ship *)calloc(1, sizeof(ship)); sh->region = r; - READ_INT(&store, &sh->no); + READ_INT(store, &sh->no); *shp = sh; shp = &sh->next; shash(sh); - READ_STR(&store, name, sizeof(name)); + READ_STR(store, name, sizeof(name)); sh->name = _strdup(name); if (lomem) { - READ_STR(&store, NULL, 0); + READ_STR(store, NULL, 0); } else { - READ_STR(&store, name, sizeof(name)); + READ_STR(store, name, sizeof(name)); sh->display = _strdup(name); } - READ_STR(&store, name, sizeof(name)); + READ_STR(store, name, sizeof(name)); sh->type = st_find(name); if (sh->type == NULL) { /* old datafiles */ @@ -1686,33 +1695,33 @@ int readgame(const char *filename, bool backup) } assert(sh->type || !"ship_type not registered!"); - READ_INT(&store, &sh->size); - READ_INT(&store, &sh->damage); - if (gdata.version >= FOSS_VERSION) { - READ_INT(&store, &sh->flags); + READ_INT(store, &sh->size); + READ_INT(store, &sh->damage); + if (data->version >= FOSS_VERSION) { + READ_INT(store, &sh->flags); } /* Attribute rekursiv einlesen */ - READ_INT(&store, &n); + READ_INT(store, &n); sh->coast = (direction_t)n; if (sh->type->flags & SFL_NOCOAST) { sh->coast = NODIRECTION; } - read_attribs(&gdata, &sh->attribs, sh); + read_attribs(data, &sh->attribs, sh); } *shp = 0; /* Einheiten */ - READ_INT(&store, &p); + READ_INT(store, &p); up = &r->units; while (--p >= 0) { - unit *u = read_unit(&gdata); + unit *u = read_unit(data); - if (gdata.version < JSON_REPORT_VERSION) { + if (data->version < JSON_REPORT_VERSION) { if (u->_name && fval(u->faction, FFL_NPC)) { if (!u->_name[0] || unit_name_equals_race(u)) { unit_setname(u, NULL); @@ -1727,10 +1736,8 @@ int readgame(const char *filename, bool backup) update_interval(u->faction, u->region); } } - read_borders(&gdata); + read_borders(data); - binstore_done(&store); - fstream_done(&strm); /* Unaufgeloeste Zeiger initialisieren */ log_debug("fixing unresolved references.\n"); resolve(); @@ -1758,7 +1765,7 @@ int readgame(const char *filename, bool backup) } else { for (u = f->units; u; u = u->nextF) { - if (gdata.version < SPELL_LEVEL_VERSION) { + if (data->version < SPELL_LEVEL_VERSION) { sc_mage *mage = get_mage(u); if (mage) { faction *f = u->faction; @@ -1777,12 +1784,12 @@ int readgame(const char *filename, bool backup) } if (u->number > 0) { f->_alive = true; - if (gdata.version >= SPELL_LEVEL_VERSION) { + if (data->version >= SPELL_LEVEL_VERSION) { break; } } } - if (gdata.version < SPELL_LEVEL_VERSION && f->spellbook) { + if (data->version < SPELL_LEVEL_VERSION && f->spellbook) { spellbook_foreach(f->spellbook, cb_sb_maxlevel, f); } } @@ -1808,12 +1815,6 @@ static void clear_npc_orders(faction *f) int writegame(const char *filename) { int n; - faction *f; - region *r; - building *b; - ship *sh; - unit *u; - plane *pl; char path[MAX_PATH]; gamedata gdata; storage store; @@ -1834,121 +1835,137 @@ int writegame(const char *filename) gdata.store = &store; gdata.version = RELEASE_VERSION; - n = STREAM_VERSION; fwrite(&gdata.version, sizeof(int), 1, F); + n = STREAM_VERSION; fwrite(&n, sizeof(int), 1, F); fstream_init(&strm, F); binstore_init(&store, &strm); + n = write_game(&gdata); + binstore_done(&store); + fstream_done(&strm); + return n; +} + +void write_planes(storage *store) { + plane *pl; + for (pl = planes; pl; pl = pl->next) { + WRITE_INT(store, pl->id); + WRITE_STR(store, pl->name); + WRITE_INT(store, pl->minx); + WRITE_INT(store, pl->maxx); + WRITE_INT(store, pl->miny); + WRITE_INT(store, pl->maxy); + WRITE_INT(store, pl->flags); +#if RELEASE_VERSION < NOWATCH_VERSION + write_faction_reference(NULL, store); /* mark the end of pl->watchers (gone since T966) */ +#endif + a_write(store, pl->attribs, pl); + WRITE_SECTION(store); + } +} + +int write_game(gamedata *data) { + storage * store = data->store; + region *r; + faction *f; + int n; + /* globale Variablen */ + assert(data->version <= MAX_VERSION && data->version >= MIN_VERSION); - WRITE_INT(&store, VERSION_BUILD); - WRITE_INT(&store, game_id()); - WRITE_SECTION(&store); + WRITE_INT(store, VERSION_BUILD); + WRITE_INT(store, game_id()); + WRITE_SECTION(store); - write_attribs(&store, global.attribs, NULL); - WRITE_SECTION(&store); + write_attribs(store, global.attribs, NULL); + WRITE_SECTION(store); - WRITE_INT(&store, turn); - WRITE_INT(&store, 0 /*max_unique_id */); - WRITE_INT(&store, nextborder); + WRITE_INT(store, turn); + WRITE_INT(store, 0 /*max_unique_id */); + WRITE_INT(store, nextborder); /* Write planes */ - WRITE_SECTION(&store); - WRITE_INT(&store, listlen(planes)); - WRITE_SECTION(&store); + WRITE_SECTION(store); + WRITE_INT(store, listlen(planes)); + WRITE_SECTION(store); - for (pl = planes; pl; pl = pl->next) { - WRITE_INT(&store, pl->id); - WRITE_STR(&store, pl->name); - WRITE_INT(&store, pl->minx); - WRITE_INT(&store, pl->maxx); - WRITE_INT(&store, pl->miny); - WRITE_INT(&store, pl->maxy); - WRITE_INT(&store, pl->flags); -#if RELEASE_VERSION < NOWATCH_VERSION - write_faction_reference(NULL, &store); /* mark the end of pl->watchers (gone since T966) */ -#endif - a_write(&store, pl->attribs, pl); - WRITE_SECTION(&store); - } - - /* Write factions */ - write_alliances(&gdata); + write_planes(store); + write_alliances(data); n = listlen(factions); - WRITE_INT(&store, n); - WRITE_SECTION(&store); + WRITE_INT(store, n); + WRITE_SECTION(store); log_debug(" - Schreibe %d Parteien...\n", n); for (f = factions; f; f = f->next) { if (fval(f, FFL_NPC)) { clear_npc_orders(f); } - writefaction(&gdata, f); - WRITE_SECTION(&store); + writefaction(data, f); + WRITE_SECTION(store); } /* Write regions */ n = listlen(regions); - WRITE_INT(&store, n); - WRITE_SECTION(&store); + WRITE_INT(store, n); + WRITE_SECTION(store); log_debug(" - Schreibe Regionen: %d", n); for (r = regions; r; r = r->next, --n) { + ship *sh; + building *b; + unit *u; /* plus leerzeile */ if ((n % 1024) == 0) { /* das spart extrem Zeit */ log_debug(" - Schreibe Regionen: %d", n); } - WRITE_SECTION(&store); - WRITE_INT(&store, r->x); - WRITE_INT(&store, r->y); - writeregion(&gdata, r); + WRITE_SECTION(store); + WRITE_INT(store, r->x); + WRITE_INT(store, r->y); + writeregion(data, r); - WRITE_INT(&store, listlen(r->buildings)); - WRITE_SECTION(&store); + WRITE_INT(store, listlen(r->buildings)); + WRITE_SECTION(store); for (b = r->buildings; b; b = b->next) { - write_building_reference(b, &store); - WRITE_STR(&store, b->name); - WRITE_STR(&store, b->display ? b->display : ""); - WRITE_INT(&store, b->size); - WRITE_TOK(&store, b->type->_name); - WRITE_SECTION(&store); - write_attribs(&store, b->attribs, b); - WRITE_SECTION(&store); + write_building_reference(b, store); + WRITE_STR(store, b->name); + WRITE_STR(store, b->display ? b->display : ""); + WRITE_INT(store, b->size); + WRITE_TOK(store, b->type->_name); + WRITE_SECTION(store); + write_attribs(store, b->attribs, b); + WRITE_SECTION(store); } - WRITE_INT(&store, listlen(r->ships)); - WRITE_SECTION(&store); + WRITE_INT(store, listlen(r->ships)); + WRITE_SECTION(store); for (sh = r->ships; sh; sh = sh->next) { assert(sh->region == r); - write_ship_reference(sh, &store); - WRITE_STR(&store, (const char *)sh->name); - WRITE_STR(&store, sh->display ? (const char *)sh->display : ""); - WRITE_TOK(&store, sh->type->_name); - WRITE_INT(&store, sh->size); - WRITE_INT(&store, sh->damage); - WRITE_INT(&store, sh->flags & SFL_SAVEMASK); + write_ship_reference(sh, store); + WRITE_STR(store, (const char *)sh->name); + WRITE_STR(store, sh->display ? (const char *)sh->display : ""); + WRITE_TOK(store, sh->type->_name); + WRITE_INT(store, sh->size); + WRITE_INT(store, sh->damage); + WRITE_INT(store, sh->flags & SFL_SAVEMASK); assert((sh->type->flags & SFL_NOCOAST) == 0 || sh->coast == NODIRECTION); - WRITE_INT(&store, sh->coast); - WRITE_SECTION(&store); - write_attribs(&store, sh->attribs, sh); - WRITE_SECTION(&store); + WRITE_INT(store, sh->coast); + WRITE_SECTION(store); + write_attribs(store, sh->attribs, sh); + WRITE_SECTION(store); } - WRITE_INT(&store, listlen(r->units)); - WRITE_SECTION(&store); + WRITE_INT(store, listlen(r->units)); + WRITE_SECTION(store); for (u = r->units; u; u = u->next) { - write_unit(&gdata, u); + write_unit(data, u); } } - WRITE_SECTION(&store); - write_borders(&store); - WRITE_SECTION(&store); - - binstore_done(&store); - fstream_done(&strm); + WRITE_SECTION(store); + write_borders(store); + WRITE_SECTION(store); return 0; } diff --git a/src/kernel/save.h b/src/kernel/save.h index a606b8ad4..3d47fe612 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -78,6 +78,9 @@ extern "C" { void create_backup(char *file); + int write_game(gamedata *data); + int read_game(gamedata *data); + /* test-only functions that give access to internal implementation details (BAD) */ void _test_write_password(struct gamedata *data, const struct faction *f); void _test_read_password(struct gamedata *data, struct faction *f); From ce867af34f7e79cd8ba7681ceb7256c39e8e7a57 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 25 Feb 2016 23:11:44 +0100 Subject: [PATCH 2/6] this is a static variable, and it is bad --- s/cmake-init | 1 + src/kernel/curse.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/s/cmake-init b/s/cmake-init index 05bae5540..35378d6a5 100755 --- a/s/cmake-init +++ b/s/cmake-init @@ -16,6 +16,7 @@ MACHINE=`uname -m` [ -z "$CC" ] && [ ! -z `which cc` ] && CC="cc" BIN_DIR="$ROOT/build-$MACHINE-$CC-$BUILD" mkdir -p $BIN_DIR +rm -f $BUILD ln -sf $BIN_DIR $BUILD MACHINE=$(gcc -dumpmachine) diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 66890475e..597b7340d 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -57,7 +57,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #define MAXENTITYHASH 7919 -curse *cursehash[MAXENTITYHASH]; +static curse *cursehash[MAXENTITYHASH]; void c_setflag(curse * c, unsigned int flags) { @@ -829,4 +829,4 @@ void free_curses(void) { for (i = 0; i != MAXCTHASH; ++i) { ql_free(cursetypes[i]); } -} \ No newline at end of file +} From 3c272fd53f19dd8f759b280c8e017ff52c0dedf0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 26 Feb 2016 17:54:25 +0100 Subject: [PATCH 3/6] fix reading and writing curses from test (crash) fix read_game/write_game incomaptibility. --- src/eressea.c | 2 +- src/kernel/curse.c | 13 ++++++++----- src/kernel/curse.h | 2 +- src/kernel/curse.test.c | 35 ++++++++++++++++++++++++++--------- src/kernel/save.c | 2 +- src/kernel/save.test.c | 12 ++++++++++-- 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/eressea.c b/src/eressea.c index d08a60df6..2b137cb0a 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -49,7 +49,7 @@ void game_done(void) calendar_cleanup(); #endif free_functions(); - free_curses(); + curses_done(); kernel_done(); } diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 597b7340d..d018ec117 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -74,17 +74,19 @@ void c_clearflag(curse * c, unsigned int flags) void chash(curse * c) { - curse *old = cursehash[c->no % MAXENTITYHASH]; + int i = c->no % MAXENTITYHASH; - cursehash[c->no % MAXENTITYHASH] = c; - c->nexthash = old; + c->nexthash = cursehash[i]; + cursehash[i] = c; + assert(c->nexthash != c); } static void cunhash(curse * c) { curse **show; + int i = c->no % MAXENTITYHASH; - for (show = &cursehash[c->no % MAXENTITYHASH]; *show; + for (show = &cursehash[i]; *show; show = &(*show)->nexthash) { if ((*show)->no == c->no) break; @@ -195,6 +197,7 @@ int curse_read(attrib * a, void *owner, gamedata *data) int flags; float flt; + assert(!c->no); READ_INT(store, &c->no); chash(c); READ_TOK(store, cursename, sizeof(cursename)); @@ -824,7 +827,7 @@ double destr_curse(curse * c, int cast_level, double force) return force; } -void free_curses(void) { +void curses_done(void) { int i; for (i = 0; i != MAXCTHASH; ++i) { ql_free(cursetypes[i]); diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 77da43451..817b48ad3 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -216,7 +216,7 @@ extern "C" { int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ } curse; - void free_curses(void); /* de-register all curse-types */ + void curses_done(void); /* de-register all curse-types */ void curse_write(const struct attrib *a, const void *owner, struct storage *store); diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c index b8d765f72..2be81b19c 100644 --- a/src/kernel/curse.test.c +++ b/src/kernel/curse.test.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,11 @@ static void setup_curse(curse_fixture *fix, const char *name) { fix->c = create_curse(fix->u, &fix->r->attribs, ct_find(name), 1.0, 1, 1.0, 0); } +static void cleanup_curse(curse_fixture *fix) { + // destroy_curse(fix->c); + test_cleanup(); +} + static void test_magicstreet(CuTest *tc) { curse_fixture fix; message *msg; @@ -61,7 +67,7 @@ static void test_magicstreet(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::magicstreet", test_get_messagetype(msg)); msg_release(msg); - test_cleanup(); + cleanup_curse(&fix); } static void test_magicstreet_warning(CuTest *tc) { @@ -72,7 +78,7 @@ static void test_magicstreet_warning(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::magicstreetwarn", test_get_messagetype(msg)); msg_release(msg); - test_cleanup(); + cleanup_curse(&fix); } static void test_good_dreams(CuTest *tc) { @@ -83,7 +89,7 @@ static void test_good_dreams(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::gooddream", test_get_messagetype(msg)); msg_release(msg); - test_cleanup(); + cleanup_curse(&fix); } static void test_bad_dreams(CuTest *tc) { @@ -94,7 +100,7 @@ static void test_bad_dreams(CuTest *tc) { msg = fix.c->type->curseinfo(fix.r, TYP_REGION, fix.c, 0); CuAssertStrEquals(tc, "curseinfo::baddream", test_get_messagetype(msg)); msg_release(msg); - test_cleanup(); + cleanup_curse(&fix); } static void test_memstream(CuTest *tc) { @@ -125,20 +131,31 @@ static void test_write_flag(CuTest *tc) { curse_fixture fix; gamedata data; storage store; + region * r; + curse * c; + int uid; mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); setup_curse(&fix, "gbdream"); - fix.c->flags = 42 | CURSE_ISNEW; - curse_write(fix.r->attribs, fix.r, &store); + c = fix.c; + r = fix.r; + uid = r->uid; + c->flags = CURSE_ISNEW; + write_game(&data); + free_gamedata(); data.strm.api->rewind(data.strm.handle); - curse_read(fix.r->attribs, fix.r, &data); - CuAssertIntEquals(tc, 42 | CURSE_ISNEW, ((curse *) fix.r->attribs->data.v)->flags); + read_game(&data); + r = findregionbyid(uid); + CuAssertPtrNotNull(tc, r); + CuAssertPtrNotNull(tc, r->attribs); + c = (curse *)r->attribs->data.v; + CuAssertIntEquals(tc, CURSE_ISNEW, c->flags); mstream_done(&data.strm); gamedata_done(&data); - test_cleanup(); + cleanup_curse(&fix); } CuSuite *get_curse_suite(void) diff --git a/src/kernel/save.c b/src/kernel/save.c index 783cee890..829ef0829 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1842,6 +1842,7 @@ int writegame(const char *filename) fstream_init(&strm, F); binstore_init(&store, &strm); + WRITE_INT(&store, VERSION_BUILD); n = write_game(&gdata); binstore_done(&store); fstream_done(&strm); @@ -1875,7 +1876,6 @@ int write_game(gamedata *data) { /* globale Variablen */ assert(data->version <= MAX_VERSION && data->version >= MIN_VERSION); - WRITE_INT(store, VERSION_BUILD); WRITE_INT(store, game_id()); WRITE_SECTION(store); diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 4d8176756..8f1021a7b 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -107,6 +107,11 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { group *g; ally *al; int fno; + gamedata data; + storage store; + + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); test_cleanup(); f = test_create_faction(0); @@ -126,10 +131,11 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { destroyfaction(&factions); CuAssertTrue(tc, !f->_alive); CuAssertPtrEquals(tc, f2, factions); - writegame("test.dat"); + write_game(&data); free_gamedata(); f = f2 = NULL; - readgame("test.dat", false); + data.strm.api->rewind(data.strm.handle); + read_game(&data); CuAssertPtrEquals(tc, 0, findfaction(fno)); f2 = factions; CuAssertPtrNotNull(tc, f2); @@ -138,6 +144,8 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { g = get_group(u); CuAssertPtrNotNull(tc, g); CuAssertPtrEquals(tc, 0, g->allies); + mstream_done(&data.strm); + gamedata_done(&data); test_cleanup(); } From 63408501b9d1da6f8b720788a6c204ec6133ed4c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 26 Feb 2016 19:01:28 +0100 Subject: [PATCH 4/6] convert another test to read_/write_game --- src/kernel/save.c | 10 +++++----- src/kernel/save.test.c | 12 ++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 829ef0829..f6b9f779b 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1540,8 +1540,8 @@ int read_game(gamedata *data) { global.data_turn = turn; log_debug(" - reading turn %d\n", turn); rng_init(turn); - READ_INT(store, &nread); /* max_unique_id = ignore */ - READ_INT(store, &nextborder); + READ_INT(store, NULL); /* max_unique_id = ignore */ + READ_INT(store, NULL); /* Planes */ planes = NULL; @@ -1619,7 +1619,7 @@ int read_game(gamedata *data) { /* Regionen */ READ_INT(store, &nread); - assert(nread < MAXREGIONS); + assert(nread < MAXREGIONS && nread>=0); if (rmax < 0) { rmax = nread; } @@ -1883,8 +1883,8 @@ int write_game(gamedata *data) { WRITE_SECTION(store); WRITE_INT(store, turn); - WRITE_INT(store, 0 /*max_unique_id */); - WRITE_INT(store, nextborder); + WRITE_INT(store, 0 /* max_unique_id */); + WRITE_INT(store, 0 /* nextborder */); /* Write planes */ WRITE_SECTION(store); diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 8f1021a7b..040e7be3b 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -152,6 +152,11 @@ static void test_readwrite_dead_faction_group(CuTest *tc) { static void test_readwrite_dead_faction_regionowner(CuTest *tc) { faction *f; region *r; + gamedata data; + storage store; + + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); test_cleanup(); config_set("rules.region_owners", "1"); @@ -161,10 +166,13 @@ static void test_readwrite_dead_faction_regionowner(CuTest *tc) { destroyfaction(&factions); CuAssertTrue(tc, !f->_alive); remove_empty_units(); - writegame("test.dat"); + write_game(&data); free_gamedata(); f = NULL; - readgame("test.dat", false); + data.strm.api->rewind(data.strm.handle); + read_game(&data); + mstream_done(&data.strm); + gamedata_done(&data); f = factions; CuAssertPtrEquals(tc, 0, f); r = regions; From 5f923295e6b1f20853cb826ce356e381fdf32d4d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 26 Feb 2016 19:49:58 +0100 Subject: [PATCH 5/6] remove datafiles from save.test.c this should fix intermittent tests on windows. --- src/kernel/save.test.c | 69 ++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 040e7be3b..83866273b 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -182,6 +182,8 @@ static void test_readwrite_dead_faction_regionowner(CuTest *tc) { } static void test_readwrite_dead_faction_changefaction(CuTest *tc) { + gamedata data; + storage store; faction *f, *f2; region *r; trigger *tr; @@ -197,10 +199,15 @@ static void test_readwrite_dead_faction_changefaction(CuTest *tc) { destroyfaction(&factions); CuAssertTrue(tc, !f->_alive); remove_empty_units(); - writegame("test.dat"); + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); + write_game(&data); free_gamedata(); f = NULL; - readgame("test.dat", false); + data.strm.api->rewind(data.strm.handle); + read_game(&data); + mstream_done(&data.strm); + gamedata_done(&data); f = factions; CuAssertPtrNotNull(tc, f); r = regions; @@ -212,6 +219,8 @@ static void test_readwrite_dead_faction_changefaction(CuTest *tc) { } static void test_readwrite_dead_faction_createunit(CuTest *tc) { + gamedata data; + storage store; faction *f, *f2; region *r; trigger *tr; @@ -227,10 +236,15 @@ static void test_readwrite_dead_faction_createunit(CuTest *tc) { destroyfaction(&factions); CuAssertTrue(tc, !f->_alive); remove_empty_units(); - writegame("test.dat"); + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); + write_game(&data); free_gamedata(); f = NULL; - readgame("test.dat", false); + data.strm.api->rewind(data.strm.handle); + read_game(&data); + mstream_done(&data.strm); + gamedata_done(&data); f = factions; CuAssertPtrNotNull(tc, f); r = regions; @@ -242,26 +256,26 @@ static void test_readwrite_dead_faction_createunit(CuTest *tc) { } static void test_read_password(CuTest *tc) { - const char *path = "test.dat"; - gamedata *data; + gamedata data; + storage store; faction *f; + f = test_create_faction(0); faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); - data = gamedata_open(path, "wb", RELEASE_VERSION); - CuAssertPtrNotNull(tc, data); - _test_write_password(data, f); - gamedata_close(data); - data = gamedata_open(path, "rb", RELEASE_VERSION); - CuAssertPtrNotNull(tc, data); - _test_read_password(data, f); - gamedata_close(data); + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); + _test_write_password(&data, f); + data.strm.api->rewind(data.strm.handle); + _test_read_password(&data, f); + mstream_done(&data.strm); + gamedata_done(&data); CuAssertTrue(tc, checkpasswd(f, "secret")); - CuAssertIntEquals(tc, 0, remove(path)); } static void test_read_password_external(CuTest *tc) { - const char *path = "test.dat", *pwfile = "passwords.txt"; - gamedata *data; + gamedata data; + storage store; + const char *pwfile = "passwords.txt"; faction *f; FILE * F; @@ -269,24 +283,21 @@ static void test_read_password_external(CuTest *tc) { f = test_create_faction(0); faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT)); CuAssertPtrNotNull(tc, f->_password); - data = gamedata_open(path, "wb", RELEASE_VERSION); - CuAssertPtrNotNull(tc, data); - WRITE_TOK(data->store, (const char *)f->_password); - WRITE_TOK(data->store, (const char *)f->_password); - gamedata_close(data); - data = gamedata_open(path, "rb", RELEASE_VERSION); - CuAssertPtrNotNull(tc, data); - data->version = BADCRYPT_VERSION; - _test_read_password(data, f); + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); + WRITE_TOK(data.store, (const char *)f->_password); + WRITE_TOK(data.store, (const char *)f->_password); + data.strm.api->rewind(data.strm.handle); + data.version = BADCRYPT_VERSION; + _test_read_password(&data, f); CuAssertPtrEquals(tc, 0, f->_password); F = fopen(pwfile, "wt"); fprintf(F, "%s:secret\n", itoa36(f->no)); fclose(F); - _test_read_password(data, f); + _test_read_password(&data, f); CuAssertPtrNotNull(tc, f->_password); - gamedata_close(data); + gamedata_done(&data); CuAssertTrue(tc, checkpasswd(f, "secret")); - CuAssertIntEquals(tc, 0, remove(path)); CuAssertIntEquals(tc, 0, remove(pwfile)); } From fcc846da956fc5ce6e4832b8cf957b19c17ac662 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 26 Feb 2016 20:07:51 +0100 Subject: [PATCH 6/6] all of the easy external file tests are eliminated --- src/kernel/group.test.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index 4dc9799a5..7fa7fa234 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -24,6 +24,8 @@ #include static void test_group_readwrite_dead_faction(CuTest *tc) { + gamedata data; + storage store; faction *f, *f2; unit * u; group *g; @@ -48,10 +50,15 @@ static void test_group_readwrite_dead_faction(CuTest *tc) { destroyfaction(&factions); CuAssertTrue(tc, !f->_alive); CuAssertPtrEquals(tc, f2, factions); - writegame("test.dat"); + mstream_init(&data.strm); + gamedata_init(&data, &store, RELEASE_VERSION); + write_game(&data); free_gamedata(); f = f2 = NULL; - readgame("test.dat", false); + data.strm.api->rewind(data.strm.handle); + read_game(&data); + mstream_done(&data.strm); + gamedata_done(&data); CuAssertPtrEquals(tc, 0, findfaction(fno)); f2 = factions; CuAssertPtrNotNull(tc, f2);