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;
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);
if (tokens) {
const char *str = config_get("rules.magic.playerschools");
@ -383,7 +396,9 @@ void init_locale(struct locale *lang)
sstr = strdup(str);
tok = strtok(sstr, " ");
while (tok) {
variant var;
const char *name;
int i;
for (i = 0; i != MAXMAGIETYP; ++i) {
if (strcmp(tok, magic_school[i]) == 0) break;
}
@ -400,21 +415,14 @@ void init_locale(struct locale *lang)
}
free(sstr);
}
}
void init_locale(struct locale *lang)
{
init_magic(lang);
init_directions(lang);
init_keywords(lang);
init_skills(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_races(lang);
init_parameters(lang);
init_options_translation(lang);

View File

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

View File

@ -65,7 +65,7 @@ race *races;
int num_races = 0;
static int rc_changes = 1;
static const char *racenames[MAXRACES] = {
const char *racenames[MAXRACES] = {
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
"halfling", "cat", "aquarian", "orc", "snotling", "undead", NULL,
"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 char * name;
assert(rt >= 0);
assert(rt < MAXRACES);
name = racenames[rt];
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;
if (!rc) {
return NULL;
}
switch (n) {
case NAME_SINGULAR: postfix = ""; 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");
}
if (postfix) {
snprintf(name, size, "race::%s%s", rc->_name, postfix);
snprintf(name, size, "race::%s%s", rcname, postfix);
return name;
}
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)
{
static char name[64]; /* FIXME: static return value */

View File

@ -50,8 +50,6 @@ extern "C" {
struct rcoption;
struct item_type;
extern int num_races;
typedef enum {
RC_DWARF, /* 0 - Zwerg */
RC_ELF,
@ -103,6 +101,9 @@ extern "C" {
NORACE = -1
} race_t;
extern int num_races;
extern const char *racenames[MAXRACES];
typedef struct att {
int type;
union {
@ -180,6 +181,7 @@ extern "C" {
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_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);
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) {
unit *u;
struct locale *lang;
test_cleanup();
test_create_world();
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
test_setup();
u = test_create_unit(test_create_faction(test_create_race("human")), test_create_region(0, 0, NULL));
renumber_unit(u, 666);
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, "Mensch", unit_getname(u));
CuAssertStrEquals(tc, "human (ii)", unitname(u));
CuAssertStrEquals(tc, "human", unit_getname(u));
u->number = 2;
CuAssertStrEquals(tc, "Menschen (ii)", unitname(u));
CuAssertStrEquals(tc, "Menschen", unit_getname(u));
CuAssertStrEquals(tc, "human_p (ii)", unitname(u));
CuAssertStrEquals(tc, "human_p", unit_getname(u));
test_cleanup();
}
@ -177,18 +172,20 @@ static void test_unit_name_from_race(CuTest *tc) {
static void test_update_monster_name(CuTest *tc) {
unit *u;
struct locale *lang;
race *rc;
test_cleanup();
test_create_world();
u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
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");
test_setup();
rc = test_create_race("human");
lang = test_create_locale();
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL));
unit_setname(u, "Hodor");
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));
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));
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();
}

View File

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

View File

@ -3,6 +3,7 @@
#include <magic.h>
#include <kernel/config.h>
#include <kernel/types.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/unit.h>
#include <kernel/faction.h>
@ -130,21 +131,55 @@ static void test_sabotage_other_fail(CuTest *tc) {
static void test_setstealth_cmd(CuTest *tc) {
unit *u;
const struct locale *lang;
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0,0,0));
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
lang = u->faction->locale;
u->flags = UFL_ANON_FACTION|UFL_SIEGE;
u->flags = UFL_ANON_FACTION | UFL_SIEGE;
u->thisorder = create_order(K_SETSTEALTH, lang, "%s %s",
LOC(lang, parameters[P_FACTION]),
LOC(lang, parameters[P_NOT]));
LOC(lang, parameters[P_FACTION]),
LOC(lang, parameters[P_NOT]));
setstealth_cmd(u, u->thisorder);
CuAssertIntEquals(tc, UFL_SIEGE, u->flags);
free_order(u->thisorder);
u->thisorder = create_order(K_SETSTEALTH, lang, "%s",
LOC(lang, parameters[P_FACTION]));
LOC(lang, parameters[P_FACTION]));
setstealth_cmd(u, u->thisorder);
CuAssertIntEquals(tc, UFL_SIEGE|UFL_ANON_FACTION, u->flags);
CuAssertIntEquals(tc, UFL_SIEGE | UFL_ANON_FACTION, u->flags);
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();
}
@ -180,6 +215,8 @@ CuSuite *get_spy_suite(void)
SUITE_ADD_TEST(suite, test_all_spy_message);
SUITE_ADD_TEST(suite, test_sabotage_self);
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_success);
return suite;

View File

@ -96,8 +96,19 @@ struct locale * test_create_locale(void) {
locale_setstring(loc, "stone_p", "Steine");
locale_setstring(loc, "plain", "Ebene");
locale_setstring(loc, "ocean", "Ozean");
locale_setstring(loc, "race::human", "Mensch");
locale_setstring(loc, "race::human_p", "Menschen");
for (i = 0; i < MAXRACES; ++i) {
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) {
if (!locale_getstring(loc, mkname("skill", skillnames[i])))
locale_setstring(loc, mkname("skill", skillnames[i]), skillnames[i]);