diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml
index d5b6dba34..ffd0f82dd 100644
--- a/res/core/de/strings.xml
+++ b/res/core/de/strings.xml
@@ -6947,14 +6947,9 @@
is helping
-
- hat die Region durchquert.
- passed through the region.
-
-
-
- haben die Region durchquert.
- passed through the region.
+
+ Die Region wurde durchquert von
+ The region was crossed by
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b04631e6a..a67ad35b4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -181,6 +181,7 @@ set(TESTS_SRC
vortex.test.c
tests.test.c
reports.test.c
+ travelthru.test.c
callback.test.c
direction.test.c
economy.test.c
diff --git a/src/creport.c b/src/creport.c
index 6794c33d6..cbfd0f181 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -1190,7 +1190,7 @@ static void
cr_output_resources(FILE * F, report_context * ctx, seen_region * sr)
{
char cbuf[BUFFERSIZE], *pos = cbuf;
- region *r = sr->r;
+ const region *r = sr->r;
faction *f = ctx->f;
resource_report result[MAX_RAWMATERIALS];
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);
}
+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)
{
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 */
- 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));
- }
- }
- }
- }
+ cr_output_travelthru(F, r, f);
if (sr->mode == see_unit || sr->mode == see_travel) {
message_list *mlist = r_getmessages(r, f);
cr_output_messages(F, r->msgs, f);
diff --git a/src/move.c b/src/move.c
index de1cb05bd..f775acb79 100644
--- a/src/move.c
+++ b/src/move.c
@@ -567,12 +567,12 @@ static void leave_trail(ship * sh, region * from, region_list * route)
}
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)
{
/* kein travelthru in der letzten region! */
while (route != route_end) {
- travelthru(u, r);
+ travelthru_add(r, u);
r = route->data;
route = route->next;
}
diff --git a/src/report.c b/src/report.c
index d02d9a7fc..b63b45755 100644
--- a/src/report.c
+++ b/src/report.c
@@ -141,6 +141,7 @@ void write_spaces(stream *out, size_t num) {
}
}
+
static void centre(stream *out, const char *s, bool breaking)
{
/* 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,
char marker)
{
@@ -1929,6 +1930,104 @@ static void nr_paragraph(stream *out, message * m, faction * f)
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
report_plaintext(const char *filename, report_context * ctx,
const char *charset)
@@ -2040,7 +2139,7 @@ const char *charset)
}
if (no_people != f->num_people) {
f->num_people = no_people;
- }
+}
#else
no_units = count_units(f);
no_people = count_all(f);
diff --git a/src/report.h b/src/report.h
index 69f64702c..657bef36b 100644
--- a/src/report.h
+++ b/src/report.h
@@ -25,8 +25,7 @@ extern "C" {
void register_nr(void);
void report_cleanup(void);
void write_spaces(struct stream *out, size_t num);
-
- void paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_indent, char marker);
+ void write_travelthru(struct stream *out, const struct region * r, const struct faction * f);
#ifdef __cplusplus
}
#endif
diff --git a/src/reports.c b/src/reports.c
index 7cd67d010..6612c5d48 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -982,6 +982,38 @@ void add_seen_faction(faction *self, faction *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)
{
@@ -1026,26 +1058,9 @@ static void get_addresses(report_context * ctx)
}
}
else if (sr->mode == see_travel) {
- unit *u = r->units;
- while (u) {
- faction *sf = visible_faction(ctx->f, u);
- 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;
- }
+ /* when we travel through a region, then we must add
+ * the factions of any units we saw */
+ add_travelthru_addresses(r, ctx->f, &flist, stealthmod);
}
else if (sr->mode > see_travel) {
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)
{
region *r;
@@ -1479,7 +1501,6 @@ static void prepare_reports(void)
}
for (r = regions; r; r = r->next) {
- attrib *ru;
unit *u;
plane *p = rplane(r);
@@ -1533,19 +1554,18 @@ static void prepare_reports(void)
if (fval(r, RF_TRAVELUNIT)) {
- for (ru = a_find(r->attribs, &at_travelunit);
- ru && ru->type == &at_travelunit; ru = ru->next) {
- unit *u = (unit *)ru->data.v;
-
- /* make sure the faction has not been removed this turn: */
- if (u->faction) {
- add_seen(u->faction->seen, r, see_travel, false);
- }
- }
+ travelthru_map(r, cb_add_seen, r);
}
}
}
+static void cb_set_last(region *r, unit *u, void *cbdata) {
+ faction *f = (faction *)cbdata;
+ if (u->faction == f) {
+ f->last = r;
+ }
+}
+
static region *lastregion(faction * f)
{
#ifdef SMART_INTERVALS
@@ -1572,15 +1592,7 @@ static region *lastregion(faction * f)
/* search the region for travelthru-attributes: */
if (fval(r, RF_TRAVELUNIT)) {
- attrib *ru = a_find(r->attribs, &at_travelunit);
- while (ru && ru->type == &at_travelunit) {
- u = (unit *)ru->data.v;
- if (u->faction == f) {
- f->last = r;
- break;
- }
- ru = ru->next;
- }
+ travelthru_map(r, cb_set_last, f);
}
if (f->last == r)
continue;
@@ -2379,6 +2391,28 @@ int stream_printf(struct stream * out, const char *format, ...) {
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)
{
/* register datatypes for the different message objects */
diff --git a/src/reports.h b/src/reports.h
index ed0687985..c72cebab1 100644
--- a/src/reports.h
+++ b/src/reports.h
@@ -157,6 +157,8 @@ extern "C" {
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 MAX_INVENTORY 128 /* maimum number of different items in an inventory */
#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */
diff --git a/src/reports.test.c b/src/reports.test.c
index c9679827e..90e21e89a 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -13,6 +13,8 @@
#include
#include
+#include
+
#include
#include
#include
@@ -180,6 +182,11 @@ static void test_cr_unit(CuTest *tc) {
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) {
stream out = { 0 };
char buf[1024];
@@ -187,30 +194,39 @@ static void test_write_travelthru(CuTest *tc) {
region *r;
faction *f;
unit *u;
+ struct locale *lang;
test_cleanup();
+ lang = get_or_create_locale("de");
+ locale_setstring(lang, "travelthru_header", "Durchreise: ");
mstream_init(&out);
r = test_create_region(0, 0, 0);
r->flags |= RF_TRAVELUNIT;
f = test_create_faction(0);
+ f->locale = lang;
u = test_create_unit(f, 0);
+ unit_setname(u, "Hodor");
+ unit_setid(u, 1);
write_travelthru(&out, r, f);
out.api->rewind(out.handle);
len = out.api->read(out.handle, buf, sizeof(buf));
CuAssertIntEquals_Msg(tc, "no travelers, no report", 0, (int)len);
- travelthru(u, r);
- out.api->rewind(out.handle);
+ reset_stream(&out);
+ travelthru_add(r, u);
write_travelthru(&out, r, f);
+ out.api->rewind(out.handle);
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);
- out.api->rewind(out.handle);
write_travelthru(&out, r, f);
+ out.api->rewind(out.handle);
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);
test_cleanup();
diff --git a/src/test_eressea.c b/src/test_eressea.c
index e434f6c7f..cef5193cd 100644
--- a/src/test_eressea.c
+++ b/src/test_eressea.c
@@ -79,6 +79,7 @@ int RunAllTests(void)
RUN_TESTS(suite, messages);
/* gamecode */
RUN_TESTS(suite, battle);
+ RUN_TESTS(suite, travelthru);
RUN_TESTS(suite, economy);
RUN_TESTS(suite, give);
RUN_TESTS(suite, laws);
diff --git a/src/travelthru.c b/src/travelthru.c
index bbb4674b9..754a93530 100644
--- a/src/travelthru.c
+++ b/src/travelthru.c
@@ -31,7 +31,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include
#include
#include
+
#include
+#include
#include
#include
@@ -48,92 +50,6 @@ attrib_type at_travelunit = {
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
* this is used for two distinctly different purposes:
* - 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
* - 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);
+ 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
* could be in regions that are located before the [first, last] interval,
* and recalculation is needed */
-#ifdef SMART_INTERVALS
update_interval(u->faction, r);
#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);
+ }
+ }
+}
diff --git a/src/travelthru.h b/src/travelthru.h
index 29ecf4261..4e43dd25a 100644
--- a/src/travelthru.h
+++ b/src/travelthru.h
@@ -6,13 +6,14 @@
extern "C" {
#endif
- extern struct attrib_type at_travelunit;
-
+ struct attrib;
struct stream;
struct region;
struct faction;
- void write_travelthru(struct stream *out, const struct region * r, const struct faction * f);
- void travelthru(const struct unit * u, struct region * r);
+ struct unit;
+ 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
}
diff --git a/src/travelthru.test.c b/src/travelthru.test.c
new file mode 100644
index 000000000..9f735fbe3
--- /dev/null
+++ b/src/travelthru.test.c
@@ -0,0 +1,80 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "travelthru.h"
+#include "reports.h"
+#include "tests.h"
+
+#include
+
+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;
+}