Fix a crash in TARNE <race>

this was complicated to test, and I had to rewrite how races and their names are registered by test_create_locale.
This commit is contained in:
Enno Rehling 2017-04-17 20:11:44 +02:00
parent b06e93db7a
commit 635ec6d6c6
8 changed files with 114 additions and 57 deletions

View File

@ -365,13 +365,26 @@ void init_options_translation(const struct locale * lang) {
} }
} }
void init_locale(struct locale *lang) void init_races(struct locale *lang)
{ {
variant var;
int i;
const struct race *rc; const struct race *rc;
void **tokens; void **tokens;
tokens = get_translations(lang, UT_RACES);
for (rc = races; rc; rc = rc->next) {
const char *name;
variant var;
var.v = (void *)rc;
name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false);
if (name) addtoken((struct tnode **)tokens, name, var);
name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
if (name) addtoken((struct tnode **)tokens, name, var);
}
}
static void init_magic(struct locale *lang)
{
void **tokens;
tokens = get_translations(lang, UT_MAGIC); tokens = get_translations(lang, UT_MAGIC);
if (tokens) { if (tokens) {
const char *str = config_get("rules.magic.playerschools"); const char *str = config_get("rules.magic.playerschools");
@ -383,7 +396,9 @@ void init_locale(struct locale *lang)
sstr = strdup(str); sstr = strdup(str);
tok = strtok(sstr, " "); tok = strtok(sstr, " ");
while (tok) { while (tok) {
variant var;
const char *name; const char *name;
int i;
for (i = 0; i != MAXMAGIETYP; ++i) { for (i = 0; i != MAXMAGIETYP; ++i) {
if (strcmp(tok, magic_school[i]) == 0) break; if (strcmp(tok, magic_school[i]) == 0) break;
} }
@ -400,21 +415,14 @@ void init_locale(struct locale *lang)
} }
free(sstr); free(sstr);
} }
}
void init_locale(struct locale *lang)
{
init_magic(lang);
init_directions(lang); init_directions(lang);
init_keywords(lang); init_keywords(lang);
init_skills(lang); init_skills(lang);
init_races(lang);
tokens = get_translations(lang, UT_RACES);
for (rc = races; rc; rc = rc->next) {
const char *name;
var.v = (void *)rc;
name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false);
if (name) addtoken((struct tnode **)tokens, name, var);
name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
if (name) addtoken((struct tnode **)tokens, name, var);
}
init_parameters(lang); init_parameters(lang);
init_options_translation(lang); init_options_translation(lang);

View File

@ -56,6 +56,7 @@ extern "C" {
/* returns a value between [0..xpct_2], generated with two dice */ /* returns a value between [0..xpct_2], generated with two dice */
void init_locale(struct locale *lang); void init_locale(struct locale *lang);
void init_races(struct locale *lang);
int forbiddenid(int id); int forbiddenid(int id);
int newcontainerid(void); int newcontainerid(void);

View File

@ -65,7 +65,7 @@ race *races;
int num_races = 0; int num_races = 0;
static int rc_changes = 1; static int rc_changes = 1;
static const char *racenames[MAXRACES] = { const char *racenames[MAXRACES] = {
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
"halfling", "cat", "aquarian", "orc", "snotling", "undead", NULL, "halfling", "cat", "aquarian", "orc", "snotling", "undead", NULL,
"youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid",
@ -168,6 +168,7 @@ const struct race *findrace(const char *s, const struct locale *lang)
const struct race *get_race(race_t rt) { const struct race *get_race(race_t rt) {
const char * name; const char * name;
assert(rt >= 0);
assert(rt < MAXRACES); assert(rt < MAXRACES);
name = racenames[rt]; name = racenames[rt];
if (!name) { if (!name) {
@ -484,11 +485,9 @@ void rc_set_param(struct race *rc, const char *key, const char *value) {
} }
} }
const char* rc_name(const race * rc, name_t n, char *name, size_t size) { const char* rc_key(const char *rcname, name_t n, char *name, size_t size)
{
const char * postfix = 0; const char * postfix = 0;
if (!rc) {
return NULL;
}
switch (n) { switch (n) {
case NAME_SINGULAR: postfix = ""; break; case NAME_SINGULAR: postfix = ""; break;
case NAME_PLURAL: postfix = "_p"; break; case NAME_PLURAL: postfix = "_p"; break;
@ -497,12 +496,20 @@ const char* rc_name(const race * rc, name_t n, char *name, size_t size) {
default: assert(!"invalid name_t enum in rc_name_s"); default: assert(!"invalid name_t enum in rc_name_s");
} }
if (postfix) { if (postfix) {
snprintf(name, size, "race::%s%s", rc->_name, postfix); snprintf(name, size, "race::%s%s", rcname, postfix);
return name; return name;
} }
return NULL; return NULL;
} }
const char* rc_name(const race * rc, name_t n, char *name, size_t size)
{
if (!rc) {
return NULL;
}
return rc_key(rc->_name, n, name, size);
}
const char *rc_name_s(const race * rc, name_t n) const char *rc_name_s(const race * rc, name_t n)
{ {
static char name[64]; /* FIXME: static return value */ static char name[64]; /* FIXME: static return value */

View File

@ -50,8 +50,6 @@ extern "C" {
struct rcoption; struct rcoption;
struct item_type; struct item_type;
extern int num_races;
typedef enum { typedef enum {
RC_DWARF, /* 0 - Zwerg */ RC_DWARF, /* 0 - Zwerg */
RC_ELF, RC_ELF,
@ -103,6 +101,9 @@ extern "C" {
NORACE = -1 NORACE = -1
} race_t; } race_t;
extern int num_races;
extern const char *racenames[MAXRACES];
typedef struct att { typedef struct att {
int type; int type;
union { union {
@ -180,6 +181,7 @@ extern "C" {
typedef enum name_t { NAME_SINGULAR, NAME_PLURAL, NAME_DEFINITIVE, NAME_CATEGORY } name_t; typedef enum name_t { NAME_SINGULAR, NAME_PLURAL, NAME_DEFINITIVE, NAME_CATEGORY } name_t;
const char * rc_name_s(const race *rc, name_t n); const char * rc_name_s(const race *rc, name_t n);
const char * rc_key(const char *rcname, name_t n, char *name, size_t size);
const char * rc_name(const race *rc, name_t n, char *name, size_t size); const char * rc_name(const race *rc, name_t n, char *name, size_t size);
void rc_set_param(struct race *rc, const char *key, const char *value); void rc_set_param(struct race *rc, const char *key, const char *value);

View File

@ -153,23 +153,18 @@ static void test_unit_name(CuTest *tc) {
static void test_unit_name_from_race(CuTest *tc) { static void test_unit_name_from_race(CuTest *tc) {
unit *u; unit *u;
struct locale *lang;
test_cleanup(); test_setup();
test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), test_create_region(0, 0, NULL));
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
renumber_unit(u, 666); renumber_unit(u, 666);
unit_setname(u, NULL); unit_setname(u, NULL);
lang = get_or_create_locale("de");
locale_setstring(lang, rc_name_s(u->_race, NAME_SINGULAR), "Mensch");
locale_setstring(lang, rc_name_s(u->_race, NAME_PLURAL), "Menschen");
CuAssertStrEquals(tc, "Mensch (ii)", unitname(u)); CuAssertStrEquals(tc, "human (ii)", unitname(u));
CuAssertStrEquals(tc, "Mensch", unit_getname(u)); CuAssertStrEquals(tc, "human", unit_getname(u));
u->number = 2; u->number = 2;
CuAssertStrEquals(tc, "Menschen (ii)", unitname(u)); CuAssertStrEquals(tc, "human_p (ii)", unitname(u));
CuAssertStrEquals(tc, "Menschen", unit_getname(u)); CuAssertStrEquals(tc, "human_p", unit_getname(u));
test_cleanup(); test_cleanup();
} }
@ -177,18 +172,20 @@ static void test_unit_name_from_race(CuTest *tc) {
static void test_update_monster_name(CuTest *tc) { static void test_update_monster_name(CuTest *tc) {
unit *u; unit *u;
struct locale *lang; struct locale *lang;
race *rc;
test_cleanup(); test_setup();
test_create_world(); rc = test_create_race("human");
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); lang = test_create_locale();
lang = get_or_create_locale("de"); u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL));
locale_setstring(lang, rc_name_s(u->_race, NAME_SINGULAR), "Mensch");
locale_setstring(lang, rc_name_s(u->_race, NAME_PLURAL), "Menschen");
unit_setname(u, "Hodor"); unit_setname(u, "Hodor");
CuAssertTrue(tc, !unit_name_equals_race(u)); CuAssertTrue(tc, !unit_name_equals_race(u));
unit_setname(u, "Menschling"); unit_setname(u, "humanitarian");
CuAssertTrue(tc, !unit_name_equals_race(u));
unit_setname(u, "huma");
CuAssertTrue(tc, !unit_name_equals_race(u)); CuAssertTrue(tc, !unit_name_equals_race(u));
unit_setname(u, rc_name_s(u->_race, NAME_SINGULAR)); unit_setname(u, rc_name_s(u->_race, NAME_SINGULAR));
@ -197,12 +194,6 @@ static void test_update_monster_name(CuTest *tc) {
unit_setname(u, rc_name_s(u->_race, NAME_PLURAL)); unit_setname(u, rc_name_s(u->_race, NAME_PLURAL));
CuAssertTrue(tc, unit_name_equals_race(u)); CuAssertTrue(tc, unit_name_equals_race(u));
unit_setname(u, "Mensch");
CuAssertTrue(tc, unit_name_equals_race(u));
unit_setname(u, "Menschen");
CuAssertTrue(tc, unit_name_equals_race(u));
test_cleanup(); test_cleanup();
} }

View File

@ -255,7 +255,7 @@ int setstealth_cmd(unit * u, struct order *ord)
for (i = 0; allowed[i] != NORACE; ++i) for (i = 0; allowed[i] != NORACE; ++i)
if (get_race(allowed[i]) == trace) if (get_race(allowed[i]) == trace)
break; break;
if (get_race(allowed[i]) == trace) { if (allowed[i]!=NORACE && get_race(allowed[i]) == trace) {
u->irace = trace; u->irace = trace;
if (u_race(u)->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) if (u_race(u)->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs))
set_racename(&u->attribs, NULL); set_racename(&u->attribs, NULL);

View File

@ -3,6 +3,7 @@
#include <magic.h> #include <magic.h>
#include <kernel/config.h> #include <kernel/config.h>
#include <kernel/types.h> #include <kernel/types.h>
#include <kernel/race.h>
#include <kernel/region.h> #include <kernel/region.h>
#include <kernel/unit.h> #include <kernel/unit.h>
#include <kernel/faction.h> #include <kernel/faction.h>
@ -148,6 +149,40 @@ static void test_setstealth_cmd(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_setstealth_demon(CuTest *tc) {
unit *u;
struct locale *lang;
struct race *rc;
test_setup();
lang = test_create_locale();
rc = test_create_race("demon");
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
rc = test_create_race("dwarf");
init_races(lang);
u->thisorder = create_order(K_SETSTEALTH, lang, racename(lang, u, rc));
setstealth_cmd(u, u->thisorder);
CuAssertPtrEquals(tc, (void *)rc, (void *)u->irace);
test_cleanup();
}
static void test_setstealth_demon_bad(CuTest *tc) {
unit *u;
struct locale *lang;
struct race *rc;
test_setup();
lang = test_create_locale();
rc = test_create_race("demon");
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
rc = test_create_race("smurf");
init_races(lang);
u->thisorder = create_order(K_SETSTEALTH, lang, racename(lang, u, rc));
setstealth_cmd(u, u->thisorder);
CuAssertPtrEquals(tc, NULL, (void *)u->irace);
test_cleanup();
}
static void test_sabotage_other_success(CuTest *tc) { static void test_sabotage_other_success(CuTest *tc) {
unit *u, *u2; unit *u, *u2;
region *r; region *r;
@ -180,6 +215,8 @@ CuSuite *get_spy_suite(void)
SUITE_ADD_TEST(suite, test_all_spy_message); SUITE_ADD_TEST(suite, test_all_spy_message);
SUITE_ADD_TEST(suite, test_sabotage_self); SUITE_ADD_TEST(suite, test_sabotage_self);
SUITE_ADD_TEST(suite, test_setstealth_cmd); SUITE_ADD_TEST(suite, test_setstealth_cmd);
SUITE_ADD_TEST(suite, test_setstealth_demon);
SUITE_ADD_TEST(suite, test_setstealth_demon_bad);
SUITE_ADD_TEST(suite, test_sabotage_other_fail); SUITE_ADD_TEST(suite, test_sabotage_other_fail);
SUITE_ADD_TEST(suite, test_sabotage_other_success); SUITE_ADD_TEST(suite, test_sabotage_other_success);
return suite; return suite;

View File

@ -96,8 +96,19 @@ struct locale * test_create_locale(void) {
locale_setstring(loc, "stone_p", "Steine"); locale_setstring(loc, "stone_p", "Steine");
locale_setstring(loc, "plain", "Ebene"); locale_setstring(loc, "plain", "Ebene");
locale_setstring(loc, "ocean", "Ozean"); locale_setstring(loc, "ocean", "Ozean");
locale_setstring(loc, "race::human", "Mensch"); for (i = 0; i < MAXRACES; ++i) {
locale_setstring(loc, "race::human_p", "Menschen"); if (racenames[i]) {
char name[64];
rc_key(racenames[i], NAME_PLURAL, name, sizeof(name));
if (!locale_getstring(loc, name)) {
locale_setstring(loc, name, name + 6);
}
rc_key(racenames[i], NAME_SINGULAR, name, sizeof(name));
if (!locale_getstring(loc, name)) {
locale_setstring(loc, name, name + 6);
}
}
}
for (i = 0; i < MAXSKILLS; ++i) { for (i = 0; i < MAXSKILLS; ++i) {
if (!locale_getstring(loc, mkname("skill", skillnames[i]))) if (!locale_getstring(loc, mkname("skill", skillnames[i])))
locale_setstring(loc, mkname("skill", skillnames[i]), skillnames[i]); locale_setstring(loc, mkname("skill", skillnames[i]), skillnames[i]);