simple tests for build().

cleaning up the code to give it a common setup function.
change the golem code to use flag, not hard-coded race.
unify the golems, make code more readable, kill a block of unused code.
This commit is contained in:
Enno Rehling 2014-08-24 17:09:32 +02:00
parent 9db6826662
commit 7d17cafdd6
5 changed files with 267 additions and 235 deletions

View File

@ -79,8 +79,7 @@ extern "C" {
void sunhash(struct ship *sh); void sunhash(struct ship *sh);
extern int roqf_factor(void); extern int roqf_factor(void);
extern int build(struct unit *u, const construction * ctype, int completed, int build(struct unit *u, const construction * ctype, int completed, int want);
int want);
extern int maxbuild(const struct unit *u, const construction * cons); extern int maxbuild(const struct unit *u, const construction * cons);
extern struct message *msg_materials_required(struct unit *u, extern struct message *msg_materials_required(struct unit *u,
struct order *ord, const struct construction *ctype, int multi); struct order *ord, const struct construction *ctype, int multi);

View File

@ -13,86 +13,110 @@
#include <CuTest.h> #include <CuTest.h>
#include <tests.h> #include <tests.h>
#include <stdlib.h>
#include <assert.h> #include <assert.h>
static void test_build_building_no_materials(CuTest *tc) { typedef struct build_fixture {
faction *f;
unit *u; unit *u;
region *r; region *r;
faction *f;
race *rc; race *rc;
const building_type *btype; } build_fixture;
static unit * setup_build(build_fixture *bf) {
test_cleanup(); test_cleanup();
test_create_world(); test_create_world();
bf->rc = test_create_race("human");
bf->r = findregion(0, 0);
bf->f = test_create_faction(bf->rc);
assert(bf->rc && bf->f && bf->r);
bf->u = test_create_unit(bf->f, bf->r);
assert(bf->u);
return bf->u;
}
rc = test_create_race("human"); static void test_build(CuTest *tc) {
r = findregion(0, 0); build_fixture bf;
f = test_create_faction(rc); unit *u;
assert(rc && f && r); construction cons = { 0 };
u = test_create_unit(f, r); const struct resource_type *rtype;
u = setup_build(&bf);
rtype = get_resourcetype(R_SILVER);
assert(rtype);
cons.materials = calloc(2, sizeof(requirement));
cons.materials[0].number = 1;
cons.materials[0].rtype = rtype;
cons.skill = SK_ARMORER;
cons.minskill = 2;
cons.reqsize = 1;
CuAssertIntEquals(tc, ENEEDSKILL, build(u, &cons, 1, 1));
set_level(u, SK_ARMORER, 1);
CuAssertIntEquals(tc, ELOWSKILL, build(u, &cons, 1, 1));
set_level(u, SK_ARMORER, 2);
CuAssertIntEquals(tc, ENOMATERIALS, build(u, &cons, 1, 1));
i_change(&u->items, rtype->itype, 1);
CuAssertIntEquals(tc, 1, build(u, &cons, 1, 1));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
scale_number(u, 2);
i_change(&u->items, rtype->itype, 2);
CuAssertIntEquals(tc, 2, build(u, &cons, 2, 2));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
test_cleanup();
}
static void test_build_building_no_materials(CuTest *tc) {
const building_type *btype;
build_fixture bf = { 0 };
unit *u;
u = setup_build(&bf);
btype = bt_find("castle"); btype = bt_find("castle");
assert(u && btype); assert(btype);
set_level(u, SK_BUILDING, 1); set_level(bf.u, SK_BUILDING, 1);
CuAssertIntEquals(tc, ENOMATERIALS, build_building(u, btype, 0, 4, 0)); CuAssertIntEquals(tc, ENOMATERIALS, build_building(bf.u, btype, 0, 4, 0));
CuAssertPtrEquals(tc, 0, r->buildings); CuAssertPtrEquals(tc, 0, bf.r->buildings);
CuAssertPtrEquals(tc, 0, u->building); CuAssertPtrEquals(tc, 0, bf.u->building);
} }
static void test_build_building_with_golem(CuTest *tc) { static void test_build_building_with_golem(CuTest *tc) {
unit *u; unit *u;
region *r; build_fixture bf;
faction *f;
race *rc;
const building_type *btype; const building_type *btype;
test_cleanup(); u = setup_build(&bf);
test_create_world(); bf.rc->flags |= RCF_STONEGOLEM;
rc = test_create_race("stonegolem");
rc->flags |= RCF_STONEGOLEM;
btype = bt_find("castle"); btype = bt_find("castle");
assert(btype && rc); assert(btype);
assert(btype->construction); assert(btype->construction);
r = findregion(0, 0);
assert(!r->buildings); set_level(bf.u, SK_BUILDING, 1);
f = test_create_faction(rc);
assert(r && f);
u = test_create_unit(f, r);
assert(u);
set_level(u, SK_BUILDING, 1);
CuAssertIntEquals(tc, 1, build_building(u, btype, 0, 4, 0)); CuAssertIntEquals(tc, 1, build_building(u, btype, 0, 4, 0));
CuAssertPtrNotNull(tc, r->buildings); CuAssertPtrNotNull(tc, u->region->buildings);
CuAssertIntEquals(tc, 1, r->buildings->size); CuAssertIntEquals(tc, 1, u->region->buildings->size);
CuAssertIntEquals(tc, 0, u->number); CuAssertIntEquals(tc, 0, u->number);
} }
static void test_build_building_success(CuTest *tc) { static void test_build_building_success(CuTest *tc) {
unit *u; unit *u;
region *r; build_fixture bf = { 0 };
faction *f;
race *rc;
const building_type *btype; const building_type *btype;
const resource_type *rtype; const resource_type *rtype;
test_cleanup(); u = setup_build(&bf);
test_create_world();
rc = test_create_race("human");
rtype = get_resourcetype(R_STONE); rtype = get_resourcetype(R_STONE);
btype = bt_find("castle"); btype = bt_find("castle");
assert(btype && rc && rtype && rtype->itype); assert(btype && rtype && rtype->itype);
assert(btype->construction); assert(btype->construction);
r = findregion(0, 0); assert(!u->region->buildings);
assert(!r->buildings);
f = test_create_faction(rc); i_change(&bf.u->items, rtype->itype, 1);
assert(r && f);
u = test_create_unit(f, r);
assert(u);
i_change(&u->items, rtype->itype, 1);
set_level(u, SK_BUILDING, 1); set_level(u, SK_BUILDING, 1);
CuAssertIntEquals(tc, 1, build_building(u, btype, 0, 4, 0)); CuAssertIntEquals(tc, 1, build_building(u, btype, 0, 4, 0));
CuAssertPtrNotNull(tc, r->buildings); CuAssertPtrNotNull(tc, u->region->buildings);
CuAssertPtrEquals(tc, r->buildings, u->building); CuAssertPtrEquals(tc, u->region->buildings, u->building);
CuAssertIntEquals(tc, 1, u->building->size); CuAssertIntEquals(tc, 1, u->building->size);
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
} }
@ -100,6 +124,7 @@ static void test_build_building_success(CuTest *tc) {
CuSuite *get_build_suite(void) CuSuite *get_build_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_build);
SUITE_ADD_TEST(suite, test_build_building_success); SUITE_ADD_TEST(suite, test_build_building_success);
SUITE_ADD_TEST(suite, test_build_building_with_golem); SUITE_ADD_TEST(suite, test_build_building_with_golem);
SUITE_ADD_TEST(suite, test_build_building_no_materials); SUITE_ADD_TEST(suite, test_build_building_no_materials);

View File

@ -101,24 +101,29 @@ static int res_changepeasants(unit * u, const resource_type * rtype, int delta)
return u->region->land->peasants; return u->region->land->peasants;
} }
static int golem_factor(const unit *u, const resource_type *rtype) {
if (rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) {
return GOLEM_STONE;
}
if (rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) {
return GOLEM_IRON;
}
return 0;
}
static int res_changeitem(unit * u, const resource_type * rtype, int delta) static int res_changeitem(unit * u, const resource_type * rtype, int delta)
{ {
int num; int num;
if (rtype == get_resourcetype(R_STONE) && u_race(u) == get_race(RC_STONEGOLEM) int gf = (delta>0) ? 0 : golem_factor(u, rtype);
&& delta <= 0) { if (gf>0) {
int reduce = delta / GOLEM_STONE; if (delta != 0) {
if (delta % GOLEM_STONE != 0) int reduce = delta / gf;
if (delta % gf != 0) {
--reduce; --reduce;
scale_number(u, u->number + reduce);
num = u->number * GOLEM_STONE;
} }
else if (rtype == get_resourcetype(R_IRON) if (reduce) scale_number(u, u->number + reduce);
&& u_race(u) == get_race(RC_IRONGOLEM) && delta <= 0) { }
int reduce = delta / GOLEM_IRON; num = u->number * gf;
if (delta % GOLEM_IRON != 0)
--reduce;
scale_number(u, u->number + reduce);
num = u->number * GOLEM_IRON;
} }
else { else {
const item_type *itype = resource2item(rtype); const item_type *itype = resource2item(rtype);

View File

@ -53,18 +53,14 @@ int get_resource(const unit * u, const resource_type * rtype)
return i; return i;
} }
if (rtype->itype) { if (rtype->itype) {
if (rtype == get_resourcetype(R_STONE) && (u_race(u)->flags & RCF_STONEGOLEM)) {
return u->number * GOLEM_STONE;
} else if (rtype == get_resourcetype(R_IRON) && (u_race(u)->flags & RCF_IRONGOLEM)) {
return u->number * GOLEM_IRON;
} else {
return i_get(u->items, rtype->itype); return i_get(u->items, rtype->itype);
} }
} if (rtype == get_resourcetype(R_AURA)) {
if (rtype == get_resourcetype(R_AURA))
return get_spellpoints(u); return get_spellpoints(u);
if (rtype == get_resourcetype(R_PERMAURA)) }
if (rtype == get_resourcetype(R_PERMAURA)) {
return max_spellpoints(u->region, u); return max_spellpoints(u->region, u);
}
log_error("trying to get unknown resource '%s'.\n", rtype->_name[0]); log_error("trying to get unknown resource '%s'.\n", rtype->_name[0]);
return 0; return 0;
} }
@ -118,11 +114,13 @@ int change_reservation(unit * u, const resource_type * rtype, int value)
*rp = res = calloc(sizeof(reservation), 1); *rp = res = calloc(sizeof(reservation), 1);
res->type = rtype; res->type = rtype;
res->value = value; res->value = value;
} else if (res && res->value + value <= 0) { }
else if (res && res->value + value <= 0) {
*rp = res->next; *rp = res->next;
free(res); free(res);
return 0; return 0;
} else { }
else {
res->value += value; res->value += value;
} }
return res->value; return res->value;
@ -141,11 +139,13 @@ int set_resvalue(unit * u, const resource_type * rtype, int value)
*rp = res = calloc(sizeof(reservation), 1); *rp = res = calloc(sizeof(reservation), 1);
res->type = rtype; res->type = rtype;
res->value = value; res->value = value;
} else if (res && value <= 0) { }
else if (res && value <= 0) {
*rp = res->next; *rp = res->next;
free(res); free(res);
return 0; return 0;
} else { }
else {
res->value = value; res->value = value;
} }
return res->value; return res->value;
@ -187,7 +187,8 @@ get_pooled(const unit * u, const resource_type * rtype, unsigned int mode,
if (v->faction == f) { if (v->faction == f) {
mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); mask = (mode >> 3) & (GET_SLACK | GET_RESERVE);
} else if (alliedunit(v, f, HELP_MONEY)) }
else if (alliedunit(v, f, HELP_MONEY))
mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); mask = (mode >> 6) & (GET_SLACK | GET_RESERVE);
else else
continue; continue;
@ -212,14 +213,16 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count)
if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { if ((mode & GET_SLACK) && (mode & GET_RESERVE)) {
n = _min(use, have); n = _min(use, have);
} else { }
else {
int reserve = get_reservation(u, rtype); int reserve = get_reservation(u, rtype);
int slack = _max(0, have - reserve); int slack = _max(0, have - reserve);
if (mode & GET_RESERVE) { if (mode & GET_RESERVE) {
n = have - slack; n = have - slack;
n = _min(use, n); n = _min(use, n);
change_reservation(u, rtype, -n); change_reservation(u, rtype, -n);
} else if (mode & GET_SLACK) { }
else if (mode & GET_SLACK) {
n = _min(use, slack); n = _min(use, slack);
} }
} }
@ -239,7 +242,8 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count)
if (v->faction == f) { if (v->faction == f) {
mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); mask = (mode >> 3) & (GET_SLACK | GET_RESERVE);
} else if (alliedunit(v, f, HELP_MONEY)) }
else if (alliedunit(v, f, HELP_MONEY))
mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); mask = (mode >> 6) & (GET_SLACK | GET_RESERVE);
else else
continue; continue;

View File

@ -16,7 +16,6 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/ **/
#include <autoconf.h>
#include <platform.h> #include <platform.h>
#include <util/log.h> #include <util/log.h>