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);
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) {
242  } else {
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:171
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
Settings::debug
LogLevel debug
Definition: global.h:243
c_object_suite
static END_TEST Suite * c_object_suite(void)
Definition: check_c_object.cpp:318
Ice.tmp
int tmp
Definition: Ice.py:207
give.top
def top
Definition: give.py:42
monster
the faster the spell may be cast there are several other common only the caster may be affected by the spell The most common spell range is that of touch This denotes that the caster much touch the recipient of the spell in order to release the spell monster
Definition: spell-info.txt:45
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:2848
object::above
object * above
Definition: object.h:296
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:1555
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
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
init
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin it tries to load all available files in the SHARE plugins directory as plugin libraries It first displays the Initializing the plugin has the opportunity to signal itself by a message on the console Then the server displays an informative message containing both the plugin content and its keyword For the Python the standard load process thus GreenGoblin When a plugin has been it can request to be warned whenever a global event and are named freely by the developer If the directory doesn t nothing will happen< event name > can be init
Definition: plugins.txt:54
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Definition: object.h:575
free_map
void free_map(mapstruct *m)
Definition: map.cpp:1650
archetype
Definition: object.h:474
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.cpp:4565
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:2095
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2170
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:314
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:1828
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
object::nrof
uint32_t nrof
Definition: object.h:342
param
No space after the left no space before the right paren Comma right after the formal param
Definition: style-guide.txt:215
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