diff --git a/src/kernel/item.c b/src/kernel/item.c index 178526933..1265a101d 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1203,13 +1203,16 @@ static void free_wtype(weapon_type *wtype) { int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) { resource_type *rtype; cb_get_kv(match, &rtype, sizeof(rtype)); - free(rtype->_name); - if (rtype->itype) { - free_itype(rtype->itype); - } if (rtype->wtype) { free_wtype(rtype->wtype); } + if (rtype->atype) { + free(rtype->atype); + } + if (rtype->itype) { + free_itype(rtype->itype); + } + free(rtype->_name); free(rtype); return 0; } diff --git a/src/spy.test.c b/src/spy.test.c index a4e2f1151..b843306f1 100644 --- a/src/spy.test.c +++ b/src/spy.test.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -90,7 +91,8 @@ static void setup_sabotage(void) { test_cleanup(); lang = get_or_create_locale("de"); locale_setstring(lang, parameters[P_SHIP], "SCHIFF"); - test_create_world(); + locale_setstring(lang, parameters[P_ANY], "ALLE"); + init_parameters(lang); init_locales(); } @@ -100,7 +102,7 @@ static void test_sabotage_self(CuTest *tc) { order *ord; setup_sabotage(); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); assert(r); u = test_create_unit(test_create_faction(NULL), r); assert(u && u->faction && u->region == r); @@ -122,7 +124,7 @@ static void test_sabotage_other_fail(CuTest *tc) { message *msg; setup_sabotage(); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); assert(r); u = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); @@ -151,7 +153,7 @@ static void test_sabotage_other_success(CuTest *tc) { order *ord; setup_sabotage(); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); assert(r); u = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); diff --git a/src/study.c b/src/study.c index d8dd6bb2e..3639eba44 100644 --- a/src/study.c +++ b/src/study.c @@ -824,9 +824,22 @@ void produceexp(struct unit *u, skill_t sk, int n) produceexp_ex(u, sk, n, learn_skill); } +#ifndef NO_TESTS +static learn_fun inject_learn_fun = 0; + +void inject_learn(learn_fun fun) { + inject_learn_fun = fun; +} +#endif + bool learn_skill(unit * u, skill_t sk, double learn_chance) { skill *sv = u->skills; +#ifndef NO_TESTS + if (inject_learn_fun) { + return inject_learn_fun(u, sk, learn_chance); + } +#endif if (learn_chance < 1.0 && rng_int() % 10000 >= learn_chance * 10000) if (!chance(learn_chance)) return false; diff --git a/src/study.h b/src/study.h index 037283a0b..a0c638fa2 100644 --- a/src/study.h +++ b/src/study.h @@ -26,6 +26,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + struct unit; + int teach_cmd(struct unit *u, struct order *ord); int study_cmd(struct unit *u, struct order *ord); @@ -33,7 +35,12 @@ extern "C" { bool is_migrant(struct unit *u); int study_cost(struct unit *u, skill_t talent); +#ifndef NO_TESTS + typedef bool(*learn_fun)(struct unit *u, skill_t sk, double ch); + void inject_learn(learn_fun fun); +#endif bool learn_skill(struct unit *u, skill_t sk, double chance); + void produceexp(struct unit *u, skill_t sk, int n); void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(struct unit *, skill_t, double)); #define MAXTEACHERS 20 diff --git a/src/study.test.c b/src/study.test.c index e79a35412..bd14096bf 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -30,6 +30,8 @@ static void setup_locale(struct locale *lang) { if (!locale_getstring(lang, mkname("skill", skillnames[i]))) locale_setstring(lang, mkname("skill", skillnames[i]), skillnames[i]); } + locale_setstring(lang, parameters[P_ANY], "ALLE"); + init_parameters(lang); init_skills(lang); } @@ -162,6 +164,71 @@ static void test_produceexp(CuTest *tc) { test_cleanup(); } +#define MAXLOG 4 +typedef struct log_entry { + unit *u; + skill_t sk; + double ch; +} log_entry; + +static log_entry log_learners[MAXLOG]; +static int log_size; + +static bool log_learn(unit *u, skill_t sk, double ch) { + if (log_size < MAXLOG) { + log_entry * entry = &log_learners[log_size++]; + entry->u = u; + entry->sk = sk; + entry->ch = ch; + } + return true; +} + +static void test_academy_building(CuTest *tc) { + unit *u, *u1, *u2; + struct locale * loc; + building * b; + message * msg; + + test_cleanup(); + mt_register(mt_new_va("teach_asgood", "unit:unit", "region:region", "command:order", "student:unit", 0)); + + random_source_inject_constant(0.0); + init_resources(); + loc = get_or_create_locale("de"); + setup_locale(loc); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + scale_number(u, 2); + set_level(u, SK_CROSSBOW, TEACHDIFFERENCE); + u->faction->locale = loc; + u1 = test_create_unit(u->faction, u->region); + scale_number(u1, 15); + u1->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]); + u2 = test_create_unit(u->faction, u->region); + scale_number(u2, 5); + u2->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]); + set_level(u2, SK_CROSSBOW, 1); + u->thisorder = create_order(K_TEACH, loc, "%s %s", itoa36(u1->no), itoa36(u2->no)); + b = test_create_building(u->region, test_create_buildingtype("academy")); + b->size = 22; + u_set_building(u, b); + u_set_building(u1, b); + u_set_building(u2, b); + i_change(&u1->items, get_resourcetype(R_SILVER)->itype, 50); + i_change(&u2->items, get_resourcetype(R_SILVER)->itype, 50); + b->flags = BLD_WORKING; + inject_learn(log_learn); + teach_cmd(u, u->thisorder); + inject_learn(0); + CuAssertPtrNotNull(tc, msg = test_find_messagetype(u->faction->msgs, "teach_asgood")); + CuAssertPtrEquals(tc, u, (unit *)(msg)->parameters[0].v); + CuAssertPtrEquals(tc, u2, (unit *)(msg)->parameters[3].v); + CuAssertPtrEquals(tc, u, log_learners[0].u); + CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); + CuAssertDblEquals(tc, 0.05, log_learners[0].ch, 0.001); + test_cleanup(); +} + CuSuite *get_study_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -169,6 +236,7 @@ CuSuite *get_study_suite(void) SUITE_ADD_TEST(suite, test_study_with_teacher); SUITE_ADD_TEST(suite, test_study_with_bad_teacher); SUITE_ADD_TEST(suite, test_produceexp); + SUITE_ADD_TEST(suite, test_academy_building); DISABLE_TEST(suite, test_study_bug_2194); return suite; } diff --git a/src/triggers/shock.test.c b/src/triggers/shock.test.c index eae2a5004..77bc192dc 100644 --- a/src/triggers/shock.test.c +++ b/src/triggers/shock.test.c @@ -24,6 +24,8 @@ static void test_shock(CuTest *tc) { CuAssertIntEquals(tc, 2, u->hp); CuAssertIntEquals(tc, 2, get_spellpoints(u)); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "shock")); + t_free(tt); + free(tt); test_cleanup(); } @@ -41,6 +43,8 @@ static void test_shock_low(CuTest *tc) { tt->type->handle(tt, u); CuAssertIntEquals(tc, 1, u->hp); CuAssertIntEquals(tc, 1, get_spellpoints(u)); + t_free(tt); + free(tt); test_cleanup(); }