From 27835dc4e12ca9bbdb4abe3516ce32dec4639680 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 9 Jul 2015 13:24:21 +0200 Subject: [PATCH 1/3] unit tests for STUDY and TEACH commands. --- src/CMakeLists.txt | 1 + src/bind_process.c | 2 +- src/laws.c | 2 +- src/study.c | 2 +- src/study.h | 3 +- src/study.test.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++ src/test_eressea.c | 1 + src/tests.c | 15 ++++--- 8 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 src/study.test.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0bbe4f45b..ae4b6c287 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -192,6 +192,7 @@ set(TESTS_SRC skill.test.c spells.test.c spy.test.c + study.test.c upkeep.test.c spells/magicresistance.test.c ${ATTRIBUTES_TESTS} diff --git a/src/bind_process.c b/src/bind_process.c index c411e257a..2e883d38a 100755 --- a/src/bind_process.c +++ b/src/bind_process.c @@ -159,7 +159,7 @@ void process_quit(void) { void process_study(void) { process_cmd(K_TEACH, teach_cmd, PROC_LONG_ORDER); - process_cmd(K_STUDY, learn_cmd, PROC_LONG_ORDER); + process_cmd(K_STUDY, study_cmd, PROC_LONG_ORDER); } void process_movement(void) { diff --git a/src/laws.c b/src/laws.c index 6a18dc84e..558b95323 100755 --- a/src/laws.c +++ b/src/laws.c @@ -4489,7 +4489,7 @@ void init_processor(void) add_proc_order(p, K_TEACH, teach_cmd, PROC_THISORDER | PROC_LONGORDER, "Lehren"); p += 10; - add_proc_order(p, K_STUDY, learn_cmd, PROC_THISORDER | PROC_LONGORDER, + add_proc_order(p, K_STUDY, study_cmd, PROC_THISORDER | PROC_LONGORDER, "Lernen"); p += 10; diff --git a/src/study.c b/src/study.c index ec377f0f7..dac5134d5 100644 --- a/src/study.c +++ b/src/study.c @@ -527,7 +527,7 @@ static double study_speedup(unit * u, skill_t s, study_rule_t rule) return 1.0; } -int learn_cmd(unit * u, order * ord) +int study_cmd(unit * u, order * ord) { region *r = u->region; int p; diff --git a/src/study.h b/src/study.h index d5d664fd2..d4a49ab20 100644 --- a/src/study.h +++ b/src/study.h @@ -20,13 +20,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define H_KRNL_STUDY #include "skill.h" +#include #ifdef __cplusplus extern "C" { #endif extern int teach_cmd(struct unit *u, struct order *ord); - extern int learn_cmd(struct unit *u, struct order *ord); + extern int study_cmd(struct unit *u, struct order *ord); extern magic_t getmagicskill(const struct locale *lang); extern bool is_migrant(struct unit *u); diff --git a/src/study.test.c b/src/study.test.c new file mode 100644 index 000000000..58614d37c --- /dev/null +++ b/src/study.test.c @@ -0,0 +1,99 @@ +#include + +#include "study.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +typedef struct { + unit *u; + unit *teachers[2]; +} study_fixture; + +static void setup_study(study_fixture *fix, skill_t sk) { + struct region * r; + struct faction *f; + struct locale *lang; + + assert(fix); + test_cleanup(); + test_create_world(); + r = test_create_region(0, 0, 0); + f = test_create_faction(0); + lang = get_or_create_locale(locale_name(f->locale)); + locale_setstring(lang, mkname("skill", skillnames[sk]), skillnames[sk]); + init_skills(lang); + fix->u = test_create_unit(f, r); + assert(fix->u); + fix->u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[sk]); + + fix->teachers[0] = test_create_unit(f, r); + assert(fix->teachers[0]); + fix->teachers[0]->thisorder = create_order(K_TEACH, f->locale, "%s", itoa36(fix->u->no)); + + fix->teachers[1] = test_create_unit(f, r); + assert(fix->teachers[1]); + fix->teachers[1]->thisorder = create_order(K_TEACH, f->locale, "%s", itoa36(fix->u->no)); +} + +static void test_study_no_teacher(CuTest *tc) { + study_fixture fix; + skill *sv; + + setup_study(&fix, SK_CROSSBOW); + study_cmd(fix.u, fix.u->thisorder); + CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW)); + CuAssertIntEquals(tc, 1, sv->level); + CuAssertIntEquals(tc, 2, sv->weeks); + CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs)); + test_cleanup(); +} + +static void test_study_with_teacher(CuTest *tc) { + study_fixture fix; + skill *sv; + + setup_study(&fix, SK_CROSSBOW); + set_level(fix.teachers[0], SK_CROSSBOW, TEACHDIFFERENCE); + teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder); + CuAssertPtrEquals(tc, 0, test_get_last_message(fix.u->faction->msgs)); + study_cmd(fix.u, fix.u->thisorder); + CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW)); + CuAssertIntEquals(tc, 1, sv->level); + CuAssertIntEquals(tc, 1, sv->weeks); + test_cleanup(); +} + +static void test_study_with_bad_teacher(CuTest *tc) { + study_fixture fix; + skill *sv; + message *msg; + + setup_study(&fix, SK_CROSSBOW); + teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder); + CuAssertPtrNotNull(tc, msg = test_get_last_message(fix.u->faction->msgs)); + CuAssertStrEquals(tc, "teach_asgood", test_get_messagetype(msg)); + study_cmd(fix.u, fix.u->thisorder); + CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW)); + CuAssertIntEquals(tc, 1, sv->level); + CuAssertIntEquals(tc, 2, sv->weeks); + test_cleanup(); +} + +CuSuite *get_study_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_study_no_teacher); + SUITE_ADD_TEST(suite, test_study_with_teacher); + SUITE_ADD_TEST(suite, test_study_with_bad_teacher); + return suite; +} diff --git a/src/test_eressea.c b/src/test_eressea.c index b5a2e2a42..e434f6c7f 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -89,6 +89,7 @@ int RunAllTests(void) RUN_TESTS(suite, vortex); RUN_TESTS(suite, wormhole); RUN_TESTS(suite, spy); + RUN_TESTS(suite, study); printf("\ntest summary: %d tests, %d failed\n", suite->count, suite->failCount); log_flags = flags; diff --git a/src/tests.c b/src/tests.c index 9c03e1e18..5a19ce9c0 100644 --- a/src/tests.c +++ b/src/tests.c @@ -209,15 +209,20 @@ void test_create_world(void) } message * test_get_last_message(message_list *msgs) { - struct mlist *iter = msgs->begin; - while (iter->next) { - iter = iter->next; + if (msgs) { + struct mlist *iter = msgs->begin; + while (iter->next) { + iter = iter->next; + } + return iter->msg; } - return iter->msg; + return 0; } const char * test_get_messagetype(const message *msg) { - const char * name = msg->type->name; + const char * name; + assert(msg); + name = msg->type->name; if (strcmp(name, "missing_message") == 0) { name = (const char *)msg->parameters[0].v; } From 6d4f05fad830c0c58e4398d15e439189a7ce51b0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 11 Jul 2015 12:48:03 +0200 Subject: [PATCH 2/3] quicklist updates --- quicklist | 2 +- scripts/tests/study.lua | 69 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/quicklist b/quicklist index 40ae38310..45f4577b8 160000 --- a/quicklist +++ b/quicklist @@ -1 +1 @@ -Subproject commit 40ae383100a8f012393ab29bc3d98e182fe57c19 +Subproject commit 45f4577b8205d87b78d2b1f30b5c9baa25c86779 diff --git a/scripts/tests/study.lua b/scripts/tests/study.lua index e5ab84018..9185535d7 100644 --- a/scripts/tests/study.lua +++ b/scripts/tests/study.lua @@ -6,13 +6,19 @@ function setup() conf = [[{ "races" : { "human" : {} }, "terrains" : { "plain" : { "flags" : [ "land" ] } }, - "keywords" : { "de" : { "study": "LERNEN" } }, - "skills" : { "de": { "alchemy" : "Alchemie", "crossbow" : "Armbrust" } }, + "keywords" : { "de" : { "study": "LERNEN", "teach": "LEHREN" } }, + "skills" : { "de": { + "tactics" : "Taktik", + "alchemy" : "Alchemie", + "crossbow" : "Armbrust" + } }, "spells" : { "fireball" : { "syntax" : "u+" } } }]] eressea.game.reset() eressea.config.reset(); eressea.settings.set('rules.magic.playerschools', '') + eressea.settings.set("rules.economy.food", "4") + eressea.settings.set('study.random_progress', '0') eressea.config.parse(conf) end @@ -51,3 +57,62 @@ function test_unit_spells() assert_equal("fireball", sp.name) assert_equal(2, sp.level) end + +local function make_teacher(student, f, skill) + f = f or student.faction + local u = unit.create(f, student.region, 1) + u:clear_orders() + u:add_order("LEHRE " .. itoa36(student.id)) + u:set_skill(skill or "crossbow", 10) + return u +end + +local function make_student(f, r, num, skill) + local u = unit.create(f, r, num or 1) + u:clear_orders() + u:add_order("LERNE " .. (skill or "Armbrust")) + return u +end + +function test_study_no_teacher() + local r = region.create(0, 0, "plain") + local f = faction.create("test@example.com", "human", "de") + local u1 = make_student(f, r, 1) + u1:set_skill("crossbow", 1) + process_orders() + assert_equal(1, u1:get_skill("crossbow")) +end + +function test_study_with_teacher() + local r = region.create(0, 0, "plain") + local f = faction.create("test@example.com", "human", "de") + local u1 = make_student(f, r, 1) + + make_teacher(u1) + u1:set_skill("crossbow", 1) + process_orders() + assert_equal(2, u1:get_skill("crossbow")) +end + +function test_study_too_many_students() + local r = region.create(0, 0, "plain") + local f = faction.create("test@example.com", "human", "de") + local u1 = make_student(f, r, 20, "Taktik") + u1.name = "Student" + u1:add_item("money", 201*u1.number) + make_teacher(u1, f, "tactics") + process_orders() + assert_equal(u1.number, u1:get_item("money")) +end + +function test_study_multiple_teachers() + local r = region.create(0, 0, "plain") + local f = faction.create("test@example.com", "human", "de") + local u1 = make_student(f, r, 20, "Taktik") + u1.name = "Student" + u1:add_item("money", 201*u1.number) + make_teacher(u1, f, "tactics") + make_teacher(u1, f, "tactics") + process_orders() + assert_equal(u1.number, u1:get_item("money")) +end From 1e6a83f35754b2882e74ebd2e8cdc6445cd04db3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 6 Aug 2015 16:52:24 +0200 Subject: [PATCH 3/3] resize buffer in eval_command, it was too small for many commands. increase MAXTEACHERS. eliminate oldterrain warning in json_report. --- src/jsreport.c | 6 ++++-- src/kernel/order.c | 4 +++- src/kernel/terrain.c | 3 +-- src/reports.c | 2 +- src/study.c | 2 +- src/study.h | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/jsreport.c b/src/jsreport.c index 6d9f710c2..44f015053 100644 --- a/src/jsreport.c +++ b/src/jsreport.c @@ -59,9 +59,11 @@ static int report_json(const char *filename, report_context * ctx, const char *c if (sr) { terrain_t ter = oldterrain(r->terrain); if (ter == NOTERRAIN) { - log_warning("report_json: %s has no terrain id\n", r->terrain->_name); + data = 1 + r->terrain->_name[0]; + } + else { + data = 1 + (int)ter; } - data = 1 + (int)ter; } } fprintf(F, "%d", data); diff --git a/src/kernel/order.c b/src/kernel/order.c index 20cce5853..9ade22fff 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -115,7 +115,9 @@ char* get_command(const order *ord, char *sbuffer, size_t size) { assert(str); if (text) --size; bytes = (int)strlcpy(bufp, str, size); - if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); + } if (text) *bufp++ = ' '; } else { diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 36efb3591..f27fe1bd0 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -127,8 +127,7 @@ const struct terrain_type *newterrain(terrain_t t) terrain_t oldterrain(const struct terrain_type * terrain) { terrain_t t; - if (terrain == NULL) - return NOTERRAIN; + assert(terrain); for (t = 0; t != MAXTERRAINS; ++t) { if (newterrains[t] == terrain) return t; diff --git a/src/reports.c b/src/reports.c index 128815f71..f086c878e 100644 --- a/src/reports.c +++ b/src/reports.c @@ -2291,7 +2291,7 @@ static void eval_race(struct opstack **stack, const void *userdata) static void eval_order(struct opstack **stack, const void *userdata) { /* order -> string */ const struct order *ord = (const struct order *)opop(stack).v; - char buf[512]; + char buf[4096]; size_t len; variant var; diff --git a/src/study.c b/src/study.c index dac5134d5..08bb749b2 100644 --- a/src/study.c +++ b/src/study.c @@ -222,7 +222,7 @@ bool report, int *academy) teach->teachers[index] = NULL; } else { - log_warning("MAXTEACHERS is too low at %d", MAXTEACHERS); + log_error("MAXTEACHERS=%d is too low for student %s, teacher %s", MAXTEACHERS, unitname(student), unitname(teacher)); } teach->value += n; diff --git a/src/study.h b/src/study.h index d4a49ab20..1feb55921 100644 --- a/src/study.h +++ b/src/study.h @@ -33,7 +33,7 @@ extern "C" { extern bool is_migrant(struct unit *u); extern int study_cost(struct unit *u, skill_t talent); -#define MAXTEACHERS 16 +#define MAXTEACHERS 20 typedef struct teaching_info { struct unit *teachers[MAXTEACHERS]; int value;