Crossfire Server, Trunk  R20993
check_monster_change.c
Go to the documentation of this file.
1 /*
2  * CrossFire, A Multiplayer game for X-windows
3  *
4  * Copyright (C) 2002-2018 Mark Wedel & Crossfire Development Team
5  * Copyright (C) 1992 Frank Tore Johansen
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * The authors can be reached via e-mail at crossfire-devel@real-time.com
22  */
23 
24 /*
25  * Test case for monster changing.
26  *
27  * TODO:
28  * Given where change_object is (time.c),
29  * this should be merged into check_time.c
30  */
31 
32 #include <global.h>
33 #include <stdlib.h>
34 #include <check.h>
35 #include <loader.h>
36 #include <toolkit_common.h>
37 #include <sproto.h>
38 
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 *do_monster_change(object *op, mapstruct *map, short expect, const char *new_name);
48 
49 START_TEST(test_monster_change) {
50  object *monster = NULL, *tmp = NULL;
51  object *floor = NULL;
52  mapstruct *map = NULL;
53  int x, y;
54 
55  map = get_empty_map(5, 5);
56  // Fill the floor
57  for (x = 0; x < 5; ++x)
58  {
59  for (y = 0; y < 5; ++y)
60  {
61  floor = create_archetype("battleground");
62  fail_unless(floor != NULL, "cannot find arch battleground");
63  object_insert_in_map_at(floor, map, NULL, 0, x, y);
64  }
65  }
66  // Add a monster.
67  monster = create_archetype("kobold");
68  fail_unless(monster != NULL, "failed to find arch kobold");
69  // First test: 1-tile to 1-tile conversion.
70  monster->other_arch = find_archetype("ogre");
71  // Ensure we got other_arch
72  fail_unless(monster->other_arch != NULL, "Could not find other_arch to transform object %s.", monster->name);
73  monster->map = map;
74  monster->stats.food = 1; // Tell it to make one of the next unit
75  object_insert_in_map_at(monster, map, NULL, 0 , 0 , 0);
76  tmp = do_monster_change(monster, map, 1, "ogre");
77  fail_unless(monster != tmp, "We got the same object back when we should have gotten a new one!");
78  // Now we do a change to a larger monster as the next test.
79  monster = tmp;
80  monster->other_arch = find_archetype("angel_knight");
81  // Ensure we got other_arch
82  fail_unless(monster->other_arch != NULL, "Could not find other_arch to transform object %s.", monster->name);
83  monster->stats.food = 1; // Tell it to make one of the next unit
84  tmp = do_monster_change(monster, map, 1, "angel_knight");
85  fail_unless(monster != tmp, "We got the same object back when we should have gotten a new one!");
86  // Change from multipart to multipart as the next test.
87  monster = tmp;
88  monster->other_arch = find_archetype("bear");
89  // Ensure we got other_arch
90  fail_unless(monster->other_arch != NULL, "Could not find other_arch to transform object %s.", monster->name);
91  monster->stats.food = 1; // Tell it to make one of the next unit
92  tmp = do_monster_change(monster, map, 1, "bear");
93  fail_unless(monster != tmp, "We got the same object back when we should have gotten a new one!");
94  // Change from multipart back down to one.
95  monster = tmp;
96  monster->other_arch = find_archetype("bee");
97  // Ensure we got other_arch
98  fail_unless(monster->other_arch != NULL, "Could not find other_arch to transform object %s.", monster->name);
99  monster->stats.food = 1; // Tell it to make one of the next unit
100  tmp = do_monster_change(monster, map, 1, "bee");
101  fail_unless(monster != tmp, "We got the same object back when we should have gotten a new one!");
102  // Last test -- Try to change to something way too big for the map.
103  monster = tmp;
104  monster->other_arch = find_archetype("Greater_Demon");
105  // Ensure we got other_arch
106  fail_unless(monster->other_arch != NULL, "Could not find other_arch to transform object %s.", monster->name);
107  monster->stats.food = 1; // Tell it to make one of the next unit
108  tmp = do_monster_change(monster, map, 0, "Greater_Demon");
109  fail_unless(monster == tmp, "We expected to get the same monster, but got a different one.");
110 }
111 END_TEST
112 
128 static object *do_monster_change(object *op, mapstruct *map, short expect, const char *new_name)
129 {
130  change_object(op);
131  if (expect)
132  // Now we make sure our monster is freed or removed.
133  fail_unless(QUERY_FLAG(op, FLAG_FREED) || QUERY_FLAG(op, FLAG_REMOVED), "original object not removed on expected success!");
134  else
135  {
136  // Expect failure and reinsertion of original
137  fail_unless(!QUERY_FLAG(op, FLAG_FREED) && !QUERY_FLAG(op, FLAG_FREED), "Expected failure, was successful in change!");
138  return op;
139  }
140  // And now we have the glorious task of finding the new object. It will not be where the other one was.
141  for (int x = 0; x < 5; ++x)
142  for (int y = 0; y < 5; ++y)
143  {
144  // There should be only one thing on the map.
145  op = map_find_by_flag(map, x, y, FLAG_MONSTER);
146  if (op != NULL)
147  {
148  // Found the object! Break from the loops.
149  // Using a goto to break out of two loops. So sue me. :P
150  goto no_more_looping;
151  }
152  }
153 no_more_looping:
154  // Make sure we found the next object
155  fail_unless(op != NULL, "Could not find new object %s in the map.", new_name);
156  return op;
157 }
158 
159 static Suite *change_suite(void) {
160  Suite *s = suite_create("change_monster");
161  TCase *tc_core = tcase_create("Core");
162 
163  /*setup and teardown will be called before each test in testcase 'tc_core' */
164  tcase_add_checked_fixture(tc_core, setup, teardown);
165 
166  suite_add_tcase(s, tc_core);
167  tcase_add_test(tc_core, test_monster_change);
168 
169  return s;
170 }
171 
172 int main(void) {
173  int nf;
174  Suite *s = change_suite();
175  SRunner *sr= srunner_create(s);
176 
177  /* If you wish to debug the program, uncomment this line. */
178  srunner_set_fork_status (sr, CK_NOFORK);
179 
180  settings.debug = 0;
181  init(0, NULL);
182 
183  srunner_set_xml(sr, LOGDIR "/unit/server/monster_change.xml");
184  srunner_set_log(sr, LOGDIR "/unit/server/monster_change.out");
185  srunner_run_all(sr, CK_ENV); /*verbosity from env variable*/
186  nf = srunner_ntests_failed(sr);
187  srunner_free(sr);
188  return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
189 }
archetype * find_archetype(const char *name)
Definition: arch.c:692
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.c:872
static void setup(void)
static object * do_monster_change(object *op, mapstruct *map, short expect, const char *new_name)
START_TEST(test_monster_change)
LogLevel debug
Definition: global.h:238
struct archt * other_arch
Definition: object.h:413
#define FLAG_REMOVED
Definition: define.h:232
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1936
static Suite * change_suite(void)
object * create_archetype(const char *name)
Definition: arch.c:617
int main(void)
struct mapdef * map
Definition: object.h:297
const char * name
Definition: object.h:311
void init(int argc, char **argv)
Definition: init.c:995
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
object * map_find_by_flag(mapstruct *map, int x, int y, int flag)
Definition: map.c:2673
static void teardown(void)
living stats
Definition: object.h:368
struct Settings settings
Definition: init.c:40
#define FLAG_MONSTER
Definition: define.h:245
Definition: map.h:325
void change_object(object *op)
Definition: time.c:587
int32_t food
Definition: living.h:48
#define FLAG_FREED
Definition: define.h:233