Crossfire Server, Trunk
check_c_object.cpp
Go to the documentation of this file.
1 /*
2  * static char *rcsid_check_c_object_c =
3  * "$Id$";
4  */
5 
6 /*
7  * CrossFire, A Multiplayer game for X-windows
8  *
9  * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10  * Copyright (C) 1992 Frank Tore Johansen
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * The authors can be reached via e-mail at crossfire-devel@real-time.com
27  */
28 
29 /*
30  * This is the unit tests file for server/c_object.c
31  */
32 
33 #include <global.h>
34 #include <stdlib.h>
35 #include <check.h>
36 #include <loader.h>
37 #include <toolkit_common.h>
38 #include <sproto.h>
39 
40 static void setup(void) {
41 }
42 
43 static void teardown(void) {
44  /* put any cleanup steps here, they will be run after each testcase */
45 }
46 
47 static object *find_best_apply_object_match(object *start, object *pl, const char *params, int aflag) {
48  object *tmp, *best = NULL;
49  int match_val = 0, tmpmatch;
50 
51  for (tmp = start; tmp; tmp = tmp->below) {
52  if (tmp->invisible)
53  continue;
54  if ((tmpmatch = object_matches_string(pl, tmp, params)) > match_val) {
55  if ((aflag == AP_APPLY) && (QUERY_FLAG(tmp, FLAG_APPLIED)))
56  continue;
57  if ((aflag == AP_UNAPPLY) && (!QUERY_FLAG(tmp, FLAG_APPLIED)))
58  continue;
59  match_val = tmpmatch;
60  best = tmp;
61  }
62  }
63  return best;
64 }
65 
66 START_TEST(test_find_best_apply_object_match) {
67  object *pl, *found;
68  object *gorokh, *cloak, *other;
69 
70  pl = create_archetype("kobold");
71  FAIL_UNLESS(pl != NULL, "can't find kobold archetype.");
72 
73  gorokh = create_archetype("cloak");
74  gorokh->title = add_string("of Gorokh");
75  CLEAR_FLAG(gorokh, FLAG_IDENTIFIED);
76  object_insert_in_ob(gorokh, pl);
77 
78  cloak = create_archetype("cloak");
79  object_insert_in_ob(cloak, pl);
80 
81  other = create_archetype("gem");
82  object_insert_in_ob(other, pl);
83 
84  found = find_best_apply_object_match(pl->inv, pl, "all", 0);
85  FAIL_UNLESS(found == other, "not found gem but %s", found ? found->name : "nothing");
86 
87  found = find_best_apply_object_match(pl->inv, pl, "cloak", 0);
88  FAIL_UNLESS(found == cloak, "didn't find cloak but %s", found ? found->name : "nothing");
89 
90  found = find_best_apply_object_match(pl->inv, pl, "Gorokh", 0);
91  FAIL_UNLESS(found == NULL, "Gorokh found %s instead of nothing", found ? found->name : "nothing??");
92 }
93 END_TEST
94 
95 START_TEST(test_put_object_in_sack) {
97  object *sack, *obj, *sack2, *dummy;
98 
99  dummy = create_archetype("orc");
100 
101  test_map = get_empty_map(5, 5);
102  FAIL_UNLESS(test_map != NULL, "can't create test map");
103 
104  sack = create_archetype("gem");
105  object_insert_in_map_at(sack, test_map, NULL, 0, 0, 0);
106  FAIL_UNLESS(GET_MAP_OB(test_map, 0, 0) == sack, "item isn't sack");
107 
108  obj = create_archetype("gem");
109  obj->nrof = 1;
110  object_insert_in_map_at(obj, test_map, NULL, 0, 1, 0);
111  put_object_in_sack(dummy, sack, obj, 1);
112  FAIL_UNLESS(GET_MAP_OB(test_map, 1, 0) == obj, "object was removed from map?");
113  FAIL_UNLESS(sack->inv == NULL, "sack's inventory isn't null?");
114 
115  object_remove(sack);
117 
118  /* basic insertion */
119  sack = create_archetype("sack");
120  sack->nrof = 1;
121  FAIL_UNLESS(sack->type == CONTAINER, "sack isn't a container?");
122  object_insert_in_map_at(sack, test_map, NULL, 0, 0, 0);
123  FAIL_UNLESS(GET_MAP_OB(test_map, 0, 0) == sack, "sack not put on map?");
124 
125  SET_FLAG(sack, FLAG_APPLIED);
126  put_object_in_sack(dummy, sack, obj, 1);
127  FAIL_UNLESS(sack->inv == obj, "object not inserted into sack?");
128  FAIL_UNLESS(GET_MAP_OB(test_map, 1, 0) == NULL, "object wasn't removed from map?");
129 
131  object_insert_in_map_at(obj, test_map, NULL, 0, 1, 0);
132  sack->weight_limit = 1;
133  obj->weight = 5;
134 
135  put_object_in_sack(dummy, sack, obj, 1);
136  FAIL_UNLESS(sack->inv == NULL, "item was put in sack even if too heavy?");
137  FAIL_UNLESS(GET_MAP_OB(test_map, 1, 0) == obj, "object was removed from map?");
138 
139  /* now for sack splitting */
140  sack->nrof = 2;
141  obj->weight = 1;
142 
143  put_object_in_sack(dummy, sack, obj, 1);
144  FAIL_UNLESS(sack->nrof == 1, "sack wasn't split?");
145  FAIL_UNLESS(sack->above != NULL, "no new sack created?");
146  FAIL_UNLESS(sack->inv == obj, "object not inserted in old sack?");
147  FAIL_UNLESS(sack == obj->env, "object's env not updated?");
148 
149  /* now moving to/from containers */
150  obj->nrof = 2;
151  sack2 = sack->above;
152  SET_FLAG(sack2, FLAG_APPLIED);
153  dummy->container = sack;
154  put_object_in_sack(dummy, sack, sack2, 1);
155  FAIL_UNLESS(sack2->inv == NULL, "sack2's not empty?");
156  FAIL_UNLESS(sack->inv == obj, "obj wasn't transferred?");
157 
158  /* move between containers and split containers */
159  object_remove(sack2);
160  object_insert_in_map_at(sack2, test_map, NULL, 0, 2, 0);
161  SET_FLAG(sack2, FLAG_APPLIED);
162  sack2->nrof = 2;
163  dummy->container = sack2;
164  put_object_in_sack(dummy, sack2, sack, 0);
165  FAIL_UNLESS(sack->inv == NULL, "sack wasn't put into sack2?");
166  FAIL_UNLESS(sack2->inv != NULL, "sack2 wasn't filled?");
167  FAIL_UNLESS(sack2->above != NULL, "sack2 wasn't split?");
168  FAIL_UNLESS(sack2->above->inv == NULL, "sack2's split was filled?");
169 
171 }
172 END_TEST
173 
174 #define TEST_ITEMS_COUNT 11
175 static const char *test_items[TEST_ITEMS_COUNT] = {
176  "sword",
177  "broadsword",
178  "power_crystal",
179  "plate_mail",
180  "full_helmet",
181  "ring",
182  "amulet",
183  "rod_light",
184  "platinacoin",
185  "gem",
186  "dungeon_magic" // Keep last to have contiguous indexes in checks - never picked up
187 };
188 
189 #define DO_TAKE 1
190 #define DO_DROP 2
191 
203 static void do_test(const int do_what, const char *param, ...) {
205  object *items[TEST_ITEMS_COUNT], *monster;
206  int check[TEST_ITEMS_COUNT];
207  const char *action = do_what == DO_TAKE ? "picked" : "dropped";
208 
209  test_map = get_empty_map(1, 1);
210  FAIL_UNLESS(test_map != NULL, "couldn't create map");
211  monster = create_archetype("kobold");
212  FAIL_UNLESS(monster != NULL, "couldn't create kobold");
213 
214  object_insert_in_map_at(monster, test_map, NULL, 0, 0, 0);
215 
216  object *top = monster;
217  for (int i = 0; i < TEST_ITEMS_COUNT; i++) {
219  FAIL_UNLESS(arch != NULL, "couldn't find arch %s", test_items[i]);
220  items[i] = arch_to_object(arch);
221  FAIL_UNLESS(items[i] != NULL, "couldn't create %s", test_items[i]);
222  if (do_what == DO_TAKE) {
224  } else {
225  object_insert_in_ob(items[i], monster);
226  }
227  top = items[i];
228  }
229 
230  va_list args;
231  va_start(args, param);
232  int idx;
233  while ((idx = va_arg(args, int)) != -1) {
234  SET_FLAG(items[idx], FLAG_INV_LOCKED);
235  }
236  while ((idx = va_arg(args, int)) != -1) {
237  SET_FLAG(items[idx], FLAG_NO_PICK);
238  }
239 
240  if (do_what == DO_TAKE) {
241  command_take(monster, param);
242  } else {
243  command_drop(monster, param);
244  }
245 
246  memset(check, do_what == DO_TAKE ? 0 : 1, sizeof(check));
247  while ((idx = va_arg(args, int)) != -1) {
248  check[idx] = do_what == DO_TAKE ? 1 : 0;
249  }
250  for (int i = 0; i < TEST_ITEMS_COUNT; i++) {
251  if (do_what == DO_TAKE) {
252  if (check[i]) {
253  FAIL_UNLESS(items[i]->env == monster, "%s wasn't %s up with %s!", test_items[i], action, param);
254  } else {
255  FAIL_UNLESS(items[i]->env == NULL && items[i]->map == test_map, "%s was %s up with %s!", test_items[i], action, param);
256  }
257  } else {
258  if (!check[i]) {
259  FAIL_UNLESS(items[i]->env == NULL && items[i]->map == test_map, "%s wasn't %s up with %s!", test_items[i], action, param);
260  } else {
261  FAIL_UNLESS(items[i]->env == monster, "%s was %s up with %s!", test_items[i], action, param);
262  }
263  }
264  }
265 
266  va_end(args);
267 }
268 
269 START_TEST(test_command_take) {
270  do_test(DO_TAKE, "", -1, -1, 0, -1); // First item below
271  do_test(DO_TAKE, "", -1, 0, -1, 1, -1); // First pickable item below
272  do_test(DO_TAKE, "azer", -1, -1, -1); // Nothing
273  do_test(DO_TAKE, "swo", -1, -1, 0, 1, -1);
274  do_test(DO_TAKE, "broad", -1, -1, 1, -1);
275  do_test(DO_TAKE, "glow", -1, -1, 2, -1);
276  do_test(DO_TAKE, "plate", -1, -1, 3, -1);
277  do_test(DO_TAKE, "full", -1, -1, 4, -1);
278  do_test(DO_TAKE, "rod", -1, -1, 7, -1);
279  do_test(DO_TAKE, "ing", -1, -1, 2, 5, -1);
280  do_test(DO_TAKE, "coin", -1, -1, 8, -1);
281  do_test(DO_TAKE, "all", -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1); // Special versions
282  do_test(DO_TAKE, "*", -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1); // Special versions
283 
284  // By index
285  do_test(DO_TAKE, "#aze", -1, -1, -1);
286  do_test(DO_TAKE, "#0", -1, -1, -1);
287  do_test(DO_TAKE, "#-7", -1, -1, -1);
288  do_test(DO_TAKE, "#3", -1, -1, 2, -1);
289 
290  // By item type
291  do_test(DO_TAKE, "*melee", -1, -1, 0, 1, -1);
292  do_test(DO_TAKE, "*armour", -1, -1, 3, -1);
293  do_test(DO_TAKE, "*valuables", -1, -1, 8, 9, -1);
294  do_test(DO_TAKE, "*jewels", -1, -1, 5, 6, -1);
295 }
296 END_TEST
297 
298 START_TEST(test_command_drop) {
299  do_test(DO_DROP, "", -1, -1, -1);
300  do_test(DO_DROP, "azer", -1, -1, -1);
301  do_test(DO_DROP, "sword", 1, -1, -1, 0, -1);
302 
303  // By index: items are inserted in reverse order, and invisible ones (dungeon_magic) aren't counted
304  do_test(DO_DROP, "#aze", -1, -1, -1);
305  do_test(DO_DROP, "#0", -1, -1, -1);
306  do_test(DO_DROP, "#-7", -1, -1, -1);
307  do_test(DO_DROP, "#8", -1, -1, 2, -1);
308 
309  // By item type
310  do_test(DO_DROP, "*melee", 0, -1, -1, 1, -1);
311  do_test(DO_DROP, "*melee", 0, 1, -1, -1, -1);
312  do_test(DO_DROP, "*armour", -1, -1, 3, -1);
313  do_test(DO_DROP, "*valuables", 9, -1, -1, 8, -1);
314  do_test(DO_DROP, "*jewels", -1, -1, 5, 6, -1);
315 }
316 END_TEST
317 
318 static Suite *c_object_suite(void) {
319  Suite *s = suite_create("c_object");
320  TCase *tc_core = tcase_create("Core");
321 
322  /*setup and teardown will be called before each test in testcase 'tc_core' */
323  tcase_add_checked_fixture(tc_core, setup, teardown);
324 
325  suite_add_tcase(s, tc_core);
326  tcase_add_test(tc_core, test_find_best_apply_object_match);
327  tcase_add_test(tc_core, test_put_object_in_sack);
328  tcase_add_test(tc_core, test_command_take);
329  tcase_add_test(tc_core, test_command_drop);
330 
331  return s;
332 }
333 
334 int main(void) {
335  int nf;
336  Suite *s = c_object_suite();
337  SRunner *sr = srunner_create(s);
338 
340  cctk_setdatadir(SOURCE_ROOT "lib");
341  init(0, NULL);
342 
343  srunner_set_fork_status (sr, CK_NOFORK);
344 
345  srunner_set_xml(sr, LOGDIR "/unit/server/c_object.xml");
346  srunner_set_log(sr, LOGDIR "/unit/server/c_object.out");
347  srunner_run_all(sr, CK_ENV); /*verbosity from env variable*/
348  nf = srunner_ntests_failed(sr);
349  srunner_free(sr);
350  return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
351 }
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:170
START_TEST
START_TEST(test_find_best_apply_object_match)
Definition: check_c_object.cpp:66
global.h
settings
struct Settings settings
Definition: init.cpp:139
AP_APPLY
#define AP_APPLY
Definition: define.h:574
llevError
@ llevError
Definition: logger.h:11
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.cpp:842
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
test_map
mapstruct * test_map
Definition: comet_perf.cpp:74
object::inv
object * inv
Definition: object.h:298
altar_valkyrie.obj
obj
Definition: altar_valkyrie.py:33
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
cctk_setdatadir
void cctk_setdatadir(const char *datadir)
Definition: toolkit_common.cpp:69
DO_DROP
#define DO_DROP
Definition: check_c_object.cpp:190
c_object_suite
static END_TEST Suite * c_object_suite(void)
Definition: check_c_object.cpp:318
give.top
def top
Definition: give.py:42
Ice.tmp
int tmp
Definition: Ice.py:207
setup
static void setup(void)
Definition: check_c_object.cpp:40
object::title
sstring title
Definition: object.h:325
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2857
object::above
object * above
Definition: object.h:296
FAIL_UNLESS
#define FAIL_UNLESS(expr,...)
Definition: toolkit_common.h:11
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
test_items
static const char * test_items[TEST_ITEMS_COUNT]
Definition: check_c_object.cpp:175
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
toolkit_common.h
disinfect.map
map
Definition: disinfect.py:4
do_test
static void do_test(const int do_what, const char *param,...)
Definition: check_c_object.cpp:203
Settings::debug
LogLevel debug
Definition: global.h:243
make_face_from_files.args
args
Definition: make_face_from_files.py:37
main
int main(void)
Definition: check_c_object.cpp:334
command_take
void command_take(object *op, const char *params)
Definition: c_object.cpp:845
object::weight_limit
int32_t weight_limit
Definition: object.h:376
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
teardown
static void teardown(void)
Definition: check_c_object.cpp:43
CONTAINER
@ CONTAINER
Definition: object.h:236
convert.action
action
Definition: convert.py:25
object::type
uint8_t type
Definition: object.h:348
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Definition: object.h:584
free_map
void free_map(mapstruct *m)
Definition: map.cpp:1650
archetype
Definition: object.h:483
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.cpp:4574
sproto.h
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2100
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2168
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
command_drop
void command_drop(object *op, const char *params)
Definition: c_object.cpp:1354
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
DO_TAKE
#define DO_TAKE
Definition: check_c_object.cpp:189
bigchest.check
check
Definition: bigchest.py:10
TEST_ITEMS_COUNT
#define TEST_ITEMS_COUNT
Definition: check_c_object.cpp:174
mapstruct
Definition: map.h:313
init
void init(int argc, char **argv)
Definition: init.cpp:1087
roll-o-matic.params
params
Definition: roll-o-matic.py:193
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
find_best_apply_object_match
static object * find_best_apply_object_match(object *start, object *pl, const char *params, int aflag)
Definition: check_c_object.cpp:47
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
loader.h
object::container
object * container
Definition: object.h:299
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
object::nrof
uint32_t nrof
Definition: object.h:342
AP_UNAPPLY
#define AP_UNAPPLY
Definition: define.h:575
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
put_object_in_sack
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.cpp:937