replace all at_travelunit code with travelthru_map calls.

welcome to callback hell.
this should stop the buffer for travelthru from running over.
tests for this should be hell, and I still owe writing them.
This commit is contained in:
Enno Rehling 2015-08-19 14:37:51 +02:00
parent ebe365fd6e
commit a9ecd1f55e
13 changed files with 374 additions and 186 deletions

View File

@ -6947,14 +6947,9 @@
<text locale="en">is helping</text> <text locale="en">is helping</text>
</string> </string>
<string name="has_moved_one"> <string name="travelthru_header">
<text locale="de">hat die Region durchquert.</text> <text locale="de">Die Region wurde durchquert von </text>
<text locale="en">passed through the region.</text> <text locale="en">The region was crossed by </text>
</string>
<string name="has_moved_many">
<text locale="de">haben die Region durchquert.</text>
<text locale="en">passed through the region.</text>
</string> </string>
<string name="see_travel"> <string name="see_travel">

View File

@ -181,6 +181,7 @@ set(TESTS_SRC
vortex.test.c vortex.test.c
tests.test.c tests.test.c
reports.test.c reports.test.c
travelthru.test.c
callback.test.c callback.test.c
direction.test.c direction.test.c
economy.test.c economy.test.c

View File

@ -1190,7 +1190,7 @@ static void
cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) cr_output_resources(FILE * F, report_context * ctx, seen_region * sr)
{ {
char cbuf[BUFFERSIZE], *pos = cbuf; char cbuf[BUFFERSIZE], *pos = cbuf;
region *r = sr->r; const region *r = sr->r;
faction *f = ctx->f; faction *f = ctx->f;
resource_report result[MAX_RAWMATERIALS]; resource_report result[MAX_RAWMATERIALS];
int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f);
@ -1236,6 +1236,49 @@ cr_region_header(FILE * F, int plid, int nx, int ny, int uid)
fprintf(F, "%d;id\n", uid); fprintf(F, "%d;id\n", uid);
} }
typedef struct travel_data {
const faction *f;
FILE *file;
int n;
} travel_data;
static void cb_cr_travelthru_ship(const region *r, unit *u, void *cbdata) {
travel_data *data = (travel_data *)cbdata;
const faction *f = data->f;
FILE *F = data->file;
if (u->ship && travelthru_cansee(r, f, u)) {
if (data->n++ == 0) {
fprintf(F, "DURCHSCHIFFUNG\n");
}
fprintf(F, "\"%s\"\n", shipname(u->ship));
}
}
static void cb_cr_travelthru_unit(const region *r, unit *u, void *cbdata) {
travel_data *data = (travel_data *)cbdata;
const faction *f = data->f;
FILE *F = data->file;
if (!u->ship && travelthru_cansee(r, f, u)) {
if (data->n++ == 0) {
fprintf(F, "DURCHREISE\n");
}
fprintf(F, "\"%s\"\n", unitname(u));
}
}
static void cr_output_travelthru(FILE *F, region *r, const faction *f) {
/* describe both passed and inhabited regions */
travel_data cbdata = { 0 };
cbdata.f = f;
cbdata.file = F;
cbdata.n = 0;
travelthru_map(r, cb_cr_travelthru_ship, &cbdata);
cbdata.n = 0;
travelthru_map(r, cb_cr_travelthru_unit, &cbdata);
}
static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr)
{ {
faction *f = ctx->f; faction *f = ctx->f;
@ -1410,38 +1453,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr)
} }
} }
/* describe both passed and inhabited regions */ cr_output_travelthru(F, r, f);
if (fval(r, RF_TRAVELUNIT)) {
bool seeunits = false, seeships = false;
const attrib *ru;
/* show units pulled through region */
for (ru = a_find(r->attribs, &at_travelunit);
ru && ru->type == &at_travelunit; ru = ru->next) {
unit *u = (unit *)ru->data.v;
if (cansee_durchgezogen(f, r, u, 0) && r != u->region) {
if (u->ship && ship_owner(u->ship) == u) {
if (!seeships) {
fprintf(F, "DURCHSCHIFFUNG\n");
}
seeships = true;
fprintf(F, "\"%s\"\n", shipname(u->ship));
}
}
}
for (ru = a_find(r->attribs, &at_travelunit);
ru && ru->type == &at_travelunit; ru = ru->next) {
unit *u = (unit *)ru->data.v;
if (cansee_durchgezogen(f, r, u, 0) && r != u->region) {
if (!u->ship) {
if (!seeunits) {
fprintf(F, "DURCHREISE\n");
}
seeunits = true;
fprintf(F, "\"%s\"\n", unitname(u));
}
}
}
}
if (sr->mode == see_unit || sr->mode == see_travel) { if (sr->mode == see_unit || sr->mode == see_travel) {
message_list *mlist = r_getmessages(r, f); message_list *mlist = r_getmessages(r, f);
cr_output_messages(F, r->msgs, f); cr_output_messages(F, r->msgs, f);

View File

@ -567,12 +567,12 @@ static void leave_trail(ship * sh, region * from, region_list * route)
} }
static void static void
mark_travelthru(const unit * u, region * r, const region_list * route, mark_travelthru(unit * u, region * r, const region_list * route,
const region_list * route_end) const region_list * route_end)
{ {
/* kein travelthru in der letzten region! */ /* kein travelthru in der letzten region! */
while (route != route_end) { while (route != route_end) {
travelthru(u, r); travelthru_add(r, u);
r = route->data; r = route->data;
route = route->next; route = route->next;
} }

View File

@ -141,6 +141,7 @@ void write_spaces(stream *out, size_t num) {
} }
} }
static void centre(stream *out, const char *s, bool breaking) static void centre(stream *out, const char *s, bool breaking)
{ {
/* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme
@ -164,7 +165,7 @@ static void centre(stream *out, const char *s, bool breaking)
} }
} }
void static void
paragraph(stream *out, const char *str, ptrdiff_t indent, int hanging_indent, paragraph(stream *out, const char *str, ptrdiff_t indent, int hanging_indent,
char marker) char marker)
{ {
@ -1929,6 +1930,104 @@ static void nr_paragraph(stream *out, message * m, faction * f)
paragraph(out, buf, 0, 0, 0); paragraph(out, buf, 0, 0, 0);
} }
typedef struct cb_data {
stream *out;
char *start, *writep;
size_t size;
const faction *f;
int maxtravel, counter;
} cb_data;
static void init_cb(cb_data *data, stream *out, char *buffer, size_t size, const faction *f) {
data->out = out;
data->writep = buffer;
data->start = buffer;
data->size = size;
data->f = f;
data->maxtravel = 0;
data->counter = 0;
}
static void cb_write_travelthru(region *r, unit *u, void *cbdata) {
cb_data *data = (cb_data *)cbdata;
const faction *f = data->f;
if (data->counter >= data->maxtravel) {
return;
}
if (travelthru_cansee(r, f, u)) {
++data->counter;
do {
size_t len, size = data->size - (data->writep - data->start);
const char *str;
char *writep = data->writep;
if (u->ship != NULL) {
str = shipname(u->ship);
}
else {
str = unitname(u);
}
len = strlen(str);
if (len < size && data->counter <= data->maxtravel) {
memcpy(writep, str, len);
writep += len;
size -= len;
if (data->counter == data->maxtravel) {
str = ".";
}
else if (data->counter + 1 == data->maxtravel) {
str = LOC(f->locale, "list_and");
}
else {
str = ", ";
}
len = strlen(str);
if (len < size) {
memcpy(writep, str, len);
writep += len;
size -= len;
data->writep = writep;
}
}
if (len >= size || data->counter == data->maxtravel) {
// buffer is full
*writep = 0;
paragraph(data->out, data->start, 0, 0, 0);
data->writep = data->start;
if (data->counter == data->maxtravel) {
break;
}
}
} while (data->writep == data->start);
}
}
void write_travelthru(stream *out, region * r, const faction * f)
{
int maxtravel;
char buf[8192];
assert(r);
assert(f);
if (!fval(r, RF_TRAVELUNIT)) {
return;
}
/* How many are we listing? For grammar. */
maxtravel = count_travelthru(r, f);
if (maxtravel > 0) {
cb_data cbdata;
init_cb(&cbdata, out, buf, sizeof(buf), f);
cbdata.maxtravel = maxtravel;
cbdata.writep +=
strlcpy(buf, LOC(f->locale, "travelthru_header"), sizeof(buf));
travelthru_map(r, cb_write_travelthru, &cbdata);
return;
}
}
int int
report_plaintext(const char *filename, report_context * ctx, report_plaintext(const char *filename, report_context * ctx,
const char *charset) const char *charset)

View File

@ -25,8 +25,7 @@ extern "C" {
void register_nr(void); void register_nr(void);
void report_cleanup(void); void report_cleanup(void);
void write_spaces(struct stream *out, size_t num); void write_spaces(struct stream *out, size_t num);
void write_travelthru(struct stream *out, const struct region * r, const struct faction * f);
void paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_indent, char marker);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -982,6 +982,38 @@ void add_seen_faction(faction *self, faction *seen) {
add_seen_faction_i(&self->seen_factions, seen); add_seen_faction_i(&self->seen_factions, seen);
} }
typedef struct address_data {
faction *f, *lastf;
quicklist **flist;
int stealthmod;
} address_data;
static void cb_add_address(const region *r, unit *ut, void *cbdata) {
address_data *data = (address_data *)cbdata;
faction *f = data->f;
if (ut->faction==f) {
unit *u;
for (u = r->units; u; u = u->next) {
faction *sf = visible_faction(f, u);
assert(u->faction != f); /* if this is see_travel only, then I shouldn't be here. */
if (data->lastf != sf && cansee_unit(u, ut, data->stealthmod)) {
add_seen_faction_i(data->flist, sf);
data->lastf = sf;
break;
}
}
}
}
static void add_travelthru_addresses(region *r, faction *f, quicklist **flist, int stealthmod) {
// for each traveling unit: add the faction of any unit is can see
address_data cbdata = { 0 };
cbdata.f = f;
cbdata.flist = flist;
cbdata.stealthmod = stealthmod;
travelthru_map(r, cb_add_address, &cbdata);
}
static void get_addresses(report_context * ctx) static void get_addresses(report_context * ctx)
{ {
@ -1026,26 +1058,9 @@ static void get_addresses(report_context * ctx)
} }
} }
else if (sr->mode == see_travel) { else if (sr->mode == see_travel) {
unit *u = r->units; /* when we travel through a region, then we must add
while (u) { * the factions of any units we saw */
faction *sf = visible_faction(ctx->f, u); add_travelthru_addresses(r, ctx->f, &flist, stealthmod);
assert(u->faction != ctx->f); /* if this is see_travel only, then I shouldn't be here. */
if (lastf != sf) {
attrib *a = a_find(r->attribs, &at_travelunit);
while (a && a->type == &at_travelunit) {
unit *u2 = (unit *)a->data.v;
if (u2->faction == ctx->f) {
if (cansee_unit(u2, u, stealthmod)) {
add_seen_faction_i(&flist, sf);
lastf = sf;
break;
}
}
a = a->next;
}
}
u = u->next;
}
} }
else if (sr->mode > see_travel) { else if (sr->mode > see_travel) {
const unit *u = r->units; const unit *u = r->units;
@ -1466,6 +1481,13 @@ void reorder_units(region * r)
} }
} }
static void cb_add_seen(region *r, unit *u, void *cbdata) {
unused_arg(cbdata);
if (u->faction) {
add_seen(u->faction->seen, r, see_travel, false);
}
}
static void prepare_reports(void) static void prepare_reports(void)
{ {
region *r; region *r;
@ -1479,7 +1501,6 @@ static void prepare_reports(void)
} }
for (r = regions; r; r = r->next) { for (r = regions; r; r = r->next) {
attrib *ru;
unit *u; unit *u;
plane *p = rplane(r); plane *p = rplane(r);
@ -1533,16 +1554,15 @@ static void prepare_reports(void)
if (fval(r, RF_TRAVELUNIT)) { if (fval(r, RF_TRAVELUNIT)) {
for (ru = a_find(r->attribs, &at_travelunit); travelthru_map(r, cb_add_seen, r);
ru && ru->type == &at_travelunit; ru = ru->next) { }
unit *u = (unit *)ru->data.v; }
}
/* make sure the faction has not been removed this turn: */ static void cb_set_last(region *r, unit *u, void *cbdata) {
if (u->faction) { faction *f = (faction *)cbdata;
add_seen(u->faction->seen, r, see_travel, false); if (u->faction == f) {
} f->last = r;
}
}
} }
} }
@ -1572,15 +1592,7 @@ static region *lastregion(faction * f)
/* search the region for travelthru-attributes: */ /* search the region for travelthru-attributes: */
if (fval(r, RF_TRAVELUNIT)) { if (fval(r, RF_TRAVELUNIT)) {
attrib *ru = a_find(r->attribs, &at_travelunit); travelthru_map(r, cb_set_last, f);
while (ru && ru->type == &at_travelunit) {
u = (unit *)ru->data.v;
if (u->faction == f) {
f->last = r;
break;
}
ru = ru->next;
}
} }
if (f->last == r) if (f->last == r)
continue; continue;
@ -2379,6 +2391,28 @@ int stream_printf(struct stream * out, const char *format, ...) {
return result; return result;
} }
typedef struct count_data {
int n;
const struct faction *f;
} count_data;
static void count_cb(const region *r, unit *u, void *cbdata) {
count_data *data = (count_data *)cbdata;
const struct faction *f = data->f;
if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) {
if (cansee_durchgezogen(f, r, u, 0)) {
++data->n;
}
}
}
int count_travelthru(struct region *r, const struct faction *f) {
count_data data = { 0 };
data.f = f;
travelthru_map(r, count_cb, &data);
return data.n;
}
void register_reports(void) void register_reports(void)
{ {
/* register datatypes for the different message objects */ /* register datatypes for the different message objects */

View File

@ -157,6 +157,8 @@ extern "C" {
int stream_printf(struct stream * out, const char *format, ...); int stream_printf(struct stream * out, const char *format, ...);
int count_travelthru(struct region *r, const struct faction *f);
#define GR_PLURAL 0x01 /* grammar: plural */ #define GR_PLURAL 0x01 /* grammar: plural */
#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ #define MAX_INVENTORY 128 /* maimum number of different items in an inventory */
#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ #define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */

View File

@ -13,6 +13,8 @@
#include <kernel/ship.h> #include <kernel/ship.h>
#include <kernel/unit.h> #include <kernel/unit.h>
#include <util/language.h>
#include <quicklist.h> #include <quicklist.h>
#include <stream.h> #include <stream.h>
#include <memstream.h> #include <memstream.h>
@ -180,6 +182,11 @@ static void test_cr_unit(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void reset_stream(stream *out) {
out->api->rewind(out->handle);
out->api->write(out->handle, "", 0);
}
static void test_write_travelthru(CuTest *tc) { static void test_write_travelthru(CuTest *tc) {
stream out = { 0 }; stream out = { 0 };
char buf[1024]; char buf[1024];
@ -187,30 +194,39 @@ static void test_write_travelthru(CuTest *tc) {
region *r; region *r;
faction *f; faction *f;
unit *u; unit *u;
struct locale *lang;
test_cleanup(); test_cleanup();
lang = get_or_create_locale("de");
locale_setstring(lang, "travelthru_header", "Durchreise: ");
mstream_init(&out); mstream_init(&out);
r = test_create_region(0, 0, 0); r = test_create_region(0, 0, 0);
r->flags |= RF_TRAVELUNIT; r->flags |= RF_TRAVELUNIT;
f = test_create_faction(0); f = test_create_faction(0);
f->locale = lang;
u = test_create_unit(f, 0); u = test_create_unit(f, 0);
unit_setname(u, "Hodor");
unit_setid(u, 1);
write_travelthru(&out, r, f); write_travelthru(&out, r, f);
out.api->rewind(out.handle); out.api->rewind(out.handle);
len = out.api->read(out.handle, buf, sizeof(buf)); len = out.api->read(out.handle, buf, sizeof(buf));
CuAssertIntEquals_Msg(tc, "no travelers, no report", 0, (int)len); CuAssertIntEquals_Msg(tc, "no travelers, no report", 0, (int)len);
travelthru(u, r); reset_stream(&out);
out.api->rewind(out.handle); travelthru_add(r, u);
write_travelthru(&out, r, f); write_travelthru(&out, r, f);
out.api->rewind(out.handle);
len = out.api->read(out.handle, buf, sizeof(buf)); len = out.api->read(out.handle, buf, sizeof(buf));
CuAssertIntEquals_Msg(tc, "report units that moved through", 0, (int)len); buf[len] = '\0';
CuAssertStrEquals_Msg(tc, "list one unit", "Durchreise: Hodor (1).\n", buf);
reset_stream(&out);
move_unit(u, r, 0); move_unit(u, r, 0);
out.api->rewind(out.handle);
write_travelthru(&out, r, f); write_travelthru(&out, r, f);
out.api->rewind(out.handle);
len = out.api->read(out.handle, buf, sizeof(buf)); len = out.api->read(out.handle, buf, sizeof(buf));
CuAssertPtrNotNull(tc, strstr(buf, unitname(u))); CuAssertIntEquals_Msg(tc, "do not list units that stopped in the region", 0, len);
mstream_done(&out); mstream_done(&out);
test_cleanup(); test_cleanup();

View File

@ -79,6 +79,7 @@ int RunAllTests(void)
RUN_TESTS(suite, messages); RUN_TESTS(suite, messages);
/* gamecode */ /* gamecode */
RUN_TESTS(suite, battle); RUN_TESTS(suite, battle);
RUN_TESTS(suite, travelthru);
RUN_TESTS(suite, economy); RUN_TESTS(suite, economy);
RUN_TESTS(suite, give); RUN_TESTS(suite, give);
RUN_TESTS(suite, laws); RUN_TESTS(suite, laws);

View File

@ -31,7 +31,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <util/bsdstring.h> #include <util/bsdstring.h>
#include <util/log.h> #include <util/log.h>
#include <util/language.h> #include <util/language.h>
#include <stream.h> #include <stream.h>
#include <quicklist.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@ -48,92 +50,6 @@ attrib_type at_travelunit = {
NO_READ NO_READ
}; };
static int count_travelthru(const struct region *r, const struct faction *f, attrib *alist) {
int maxtravel = 0;
attrib *a;
for (a = alist; a && a->type == &at_travelunit; a = a->next) {
unit *u = (unit *)a->data.v;
if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) {
if (cansee_durchgezogen(f, r, u, 0)) {
++maxtravel;
}
}
}
return maxtravel;
}
void write_travelthru(stream *out, const region * r, const faction * f)
{
attrib *abegin, *a;
int counter = 0, maxtravel = 0;
char buf[8192];
char *bufp = buf;
int bytes;
size_t size = sizeof(buf) - 1;
assert(r);
assert(f);
if (!fval(r, RF_TRAVELUNIT)) {
return;
}
abegin = a_find(r->attribs, &at_travelunit);
/* How many are we listing? For grammar. */
maxtravel = count_travelthru(r, f, abegin);
if (maxtravel == 0) {
return;
}
/* Auflisten. */
for (a = abegin; a && a->type == &at_travelunit; a = a->next) {
unit *u = (unit *)a->data.v;
if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) {
if (cansee_durchgezogen(f, r, u, 0)) {
++counter;
if (u->ship != NULL) {
bytes = (int)strlcpy(bufp, shipname(u->ship), size);
}
else {
bytes = (int)strlcpy(bufp, unitname(u), size);
}
if (wrptr(&bufp, &size, bytes) != 0) {
INFO_STATIC_BUFFER();
break;
}
if (counter + 1 < maxtravel) {
bytes = (int)strlcpy(bufp, ", ", size);
if (wrptr(&bufp, &size, bytes) != 0) {
INFO_STATIC_BUFFER();
break;
}
}
else if (counter + 1 == maxtravel) {
bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size);
if (wrptr(&bufp, &size, bytes) != 0) {
INFO_STATIC_BUFFER();
break;
}
}
}
}
}
if (size > 0) {
if (maxtravel == 1) {
bytes = _snprintf(bufp, size, " %s", LOC(f->locale, "has_moved_one"));
}
else {
bytes = _snprintf(bufp, size, " %s", LOC(f->locale, "has_moved_many"));
}
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER_EX("write_travelthru");
}
*bufp = 0;
paragraph(out, buf, 0, 0, 0);
}
/** sets a marker in the region telling that the unit has travelled through it /** sets a marker in the region telling that the unit has travelled through it
* this is used for two distinctly different purposes: * this is used for two distinctly different purposes:
* - to report that a unit has travelled through. the report function * - to report that a unit has travelled through. the report function
@ -141,19 +57,51 @@ void write_travelthru(stream *out, const region * r, const faction * f)
* themselves * themselves
* - to report the region to the traveller * - to report the region to the traveller
*/ */
void travelthru(const unit * u, region * r) void travelthru_add(region * r, unit * u)
{ {
attrib *ru = a_add(&r->attribs, a_new(&at_travelunit)); attrib *a;
quicklist *ql;
assert(r);
assert(u);
a = a_find(r->attribs, &at_travelunit);
if (!a) {
a = a_add(&r->attribs, a_new(&at_travelunit));
}
ql = (quicklist *)a->data.v;
fset(r, RF_TRAVELUNIT); fset(r, RF_TRAVELUNIT);
ql_push(&ql, u);
a->data.v = ql;
ru->data.v = (void *)u; #ifdef SMART_INTERVALS
/* the first and last region of the faction gets reset, because travelthrough /* the first and last region of the faction gets reset, because travelthrough
* could be in regions that are located before the [first, last] interval, * could be in regions that are located before the [first, last] interval,
* and recalculation is needed */ * and recalculation is needed */
#ifdef SMART_INTERVALS
update_interval(u->faction, r); update_interval(u->faction, r);
#endif #endif
} }
bool travelthru_cansee(const struct region *r, const struct faction *f, const struct unit *u) {
if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) {
return cansee_durchgezogen(f, r, u, 0);
}
return false;
}
void travelthru_map(region * r, void(*cb)(region *, struct unit *, void *), void *cbdata)
{
attrib *a;
assert(r);
a = a_find(r->attribs, &at_travelunit);
if (a) {
quicklist *ql;
ql_iter qi;
ql = (quicklist *)a->data.v;
for (qi = qli_init(&ql); qli_more(qi);) {
unit *u = (unit *)qli_next(&qi);
cb(r, u, cbdata);
}
}
}

View File

@ -6,13 +6,14 @@
extern "C" { extern "C" {
#endif #endif
extern struct attrib_type at_travelunit; struct attrib;
struct stream; struct stream;
struct region; struct region;
struct faction; struct faction;
void write_travelthru(struct stream *out, const struct region * r, const struct faction * f); struct unit;
void travelthru(const struct unit * u, struct region * r); void travelthru_map(struct region * r, void(*cb)(struct region *r, struct unit *, void *), void *cbdata);
bool travelthru_cansee(const struct region *r, const struct faction *f, const struct unit *u);
void travelthru_add(struct region * r, struct unit * u);
#ifdef __cplusplus #ifdef __cplusplus
} }

80
src/travelthru.test.c Normal file
View File

@ -0,0 +1,80 @@
#include <platform.h>
#include <kernel/config.h>
#include <kernel/region.h>
#include <kernel/unit.h>
#include <kernel/faction.h>
#include <util/attrib.h>
#include "travelthru.h"
#include "reports.h"
#include "tests.h"
#include <CuTest.h>
struct attrib;
static void count_travelers(const region *r, unit *u, void *cbdata) {
int *n = (int *)cbdata;
unused_arg(r);
*n += u->number;
}
typedef struct travel_fixture {
region *r;
faction *f;
} travel_fixture;
static void setup_travelthru(travel_fixture *fix, int nunits) {
region *r;
faction *f;
test_cleanup();
r = test_create_region(0, 0, 0);
while (r->attribs) {
a_remove(&r->attribs, r->attribs);
}
f = test_create_faction(0);
while (nunits--) {
unit *u = test_create_unit(f, 0);
travelthru_add(r, u);
}
fix->r = r;
fix->f = f;
}
static void test_travelthru_count(CuTest *tc) {
travel_fixture fix;
setup_travelthru(&fix, 0);
CuAssertIntEquals(tc, 0, count_travelthru(fix.r, fix.f));
setup_travelthru(&fix, 1);
CuAssertIntEquals(tc, 1, count_travelthru(fix.r, fix.f));
setup_travelthru(&fix, 2);
CuAssertIntEquals(tc, 2, count_travelthru(fix.r, fix.f));
test_cleanup();
}
static void test_travelthru_map(CuTest *tc) {
int n = 0;
travel_fixture fix;
setup_travelthru(&fix, 0);
travelthru_map(fix.r, count_travelers, &n);
CuAssertIntEquals(tc, 0, n);
setup_travelthru(&fix, 1);
travelthru_map(fix.r, count_travelers, &n);
CuAssertIntEquals(tc, 1, n);
test_cleanup();
}
CuSuite *get_travelthru_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_travelthru_count);
SUITE_ADD_TEST(suite, test_travelthru_map);
return suite;
}