1 /**
2 * @file
3 * @brief Test cases for checking the scripts for logic errors
4 */
5
6 /*
7 Copyright (C) 2002-2013 UFO: Alien Invasion.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18 See the GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 */
25
26 #include "test_shared.h"
27 #include "test_scripts.h"
28 #include "../client/client.h"
29 #include "../client/renderer/r_state.h" /* r_state */
30 #include "../client/ui/ui_main.h"
31 #include "../client/battlescape/cl_particle.h"
32 #include "../client/cgame/campaign/cp_campaign.h"
33
34 /**
35 * The suite initialization function.
36 * Returns zero on success, non-zero otherwise.
37 */
UFO_InitSuiteScripts(void)38 static int UFO_InitSuiteScripts (void)
39 {
40 TEST_Init();
41
42 cl_genericPool = Mem_CreatePool("Client: Generic");
43 vid_imagePool = Mem_CreatePool("Vid: Image system");
44
45 r_state.active_texunit = &r_state.texunits[0];
46 R_FontInit();
47 UI_Init();
48
49 OBJZERO(cls);
50 Com_ParseScripts(false);
51
52 return 0;
53 }
54
55 /**
56 * The suite cleanup function.
57 * Returns zero on success, non-zero otherwise.
58 */
UFO_CleanSuiteScripts(void)59 static int UFO_CleanSuiteScripts (void)
60 {
61 UI_Shutdown();
62 TEST_Shutdown();
63 return 0;
64 }
65
TEST_CheckImage(const char * path)66 static bool TEST_CheckImage (const char* path)
67 {
68 const char* extensions[] = {"png", "tga", "jpg", nullptr};
69 int i = 0;
70
71 if (Q_strnull(path))
72 return true;
73
74 while (extensions[i]) {
75 if (FS_CheckFile("pics/%s.%s", path, extensions[i]) != -1)
76 return true;
77 i++;
78 }
79
80 return false;
81 }
82
TEST_CheckModel(const char * path)83 static bool TEST_CheckModel (const char* path)
84 {
85 const char* extensions[] = {"md2", "md3", "obj", nullptr};
86 int i = 0;
87 if (Q_strnull(path))
88 return true;
89
90 while (extensions[i]) {
91 if (FS_CheckFile("models/%s.%s", path, extensions[i]) != -1)
92 return true;
93 i++;
94 }
95
96 return false;
97 }
98
TEST_CheckSound(const char * path)99 static bool TEST_CheckSound (const char* path)
100 {
101 const char* extensions[] = {"wav", "ogg", nullptr};
102 int i = 0;
103
104 if (Q_strnull(path))
105 return true;
106
107 while (extensions[i]) {
108 if (FS_CheckFile("sound/%s.%s", path, extensions[i]) != -1)
109 return true;
110 i++;
111 }
112
113 return false;
114 }
115
TEST_CheckParticle(const char * particleID)116 static bool TEST_CheckParticle (const char* particleID)
117 {
118 if (Q_strnull(particleID))
119 return true;
120
121 /* find the particle definition */
122 return CL_ParticleGet(particleID) != nullptr;
123 }
124
testTeamDefs(void)125 static void testTeamDefs (void)
126 {
127 int i;
128
129 for (i = 0; i < csi.numTeamDefs; i++) {
130 const teamDef_t* teamDef = &csi.teamDef[i];
131 int k;
132
133 UFO_CU_ASSERT_TRUE_MSG(teamDef->numTemplates > 0, va("%s has no character templates assigned", teamDef->id));
134
135 for (k = 0; k < SND_MAX; k++) {
136 int l;
137 for (l = 0; l < NAME_LAST; l++) {
138 LIST_Foreach(teamDef->sounds[k][l], char, soundFile) {
139 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckSound(soundFile), va("sound %s does not exist (team %s)", soundFile, teamDef->id));
140 }
141 }
142 }
143 }
144 }
145
testTeamDefsModelScriptData(void)146 static void testTeamDefsModelScriptData (void)
147 {
148 int i;
149 linkedList_t* armourPaths = nullptr;
150
151 for (i = 0; i < csi.numTeamDefs; i++) {
152 int j;
153 const teamDef_t* teamDef = &csi.teamDef[i];
154 if (!teamDef->armour)
155 continue;
156
157 for (j = 0; j < csi.numODs; j++) {
158 const objDef_t* od = INVSH_GetItemByIDX(j);
159 if (!od->isArmour())
160 continue;
161
162 /* not for this team */
163 if (!CHRSH_IsArmourUseableForTeam(od, teamDef))
164 continue;
165
166 if (!LIST_ContainsString(armourPaths, od->armourPath))
167 LIST_AddString(&armourPaths, od->armourPath);
168 }
169
170 UFO_CU_ASSERT_TRUE_MSG(!LIST_IsEmpty(armourPaths), va("no armour definitions found for team %s - but armour is set to true",
171 teamDef->id));
172
173 LIST_Foreach(armourPaths, char const, armourPath) {
174 int l;
175
176 for (l = NAME_NEUTRAL; l < NAME_LAST; l++) {
177 /* no models for this gender */
178 if (!teamDef->numModels[l])
179 continue;
180
181 CU_ASSERT_PTR_NOT_NULL_FATAL(teamDef->models[l]);
182
183 for (linkedList_t const* list = teamDef->models[l]; list; list = list->next) {
184 teamDef_t::model_t const& m = *static_cast<teamDef_t::model_t const*>(list->data);
185
186 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", m.path, m.body)), va("%s does not exist in models/%s (teamDef: %s)",
187 m.body, m.path, teamDef->id));
188 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.body)), va("%s does not exist in models/%s%s (teamDef: %s)",
189 m.body, m.path, armourPath, teamDef->id));
190
191 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", m.path, m.head)), va("%s does not exist in models/%s (teamDef: %s)",
192 m.head, m.path, teamDef->id));
193 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.head)), va("%s does not exist in models/%s%s (teamDef: %s)",
194 m.head, m.path, armourPath, teamDef->id));
195 }
196 }
197 }
198
199 LIST_Delete(&armourPaths);
200 }
201 }
202
testItems(void)203 static void testItems (void)
204 {
205 int j;
206
207 for (j = 0; j < csi.numODs; j++) {
208 const objDef_t* od = INVSH_GetItemByIDX(j);
209 int i;
210
211 if (od->isVirtual || od->isDummy)
212 continue;
213
214 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckSound(od->reloadSound), va("sound %s does not exist (item %s)", od->reloadSound, od->id));
215 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(od->model), va("model %s does not exist (item %s)", od->model, od->id));
216 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckImage(od->image), va("image %s does not exist (item %s)", od->image, od->id));
217
218 for (i = 0; i < od->numWeapons; i++) {
219 int k;
220
221 for (k = 0; k < od->numFiredefs[i]; k++) {
222 const fireDef_t* fd = &od->fd[i][k];
223 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckSound(fd->bounceSound), va("sound %s does not exist (firedef %s for item %s)", fd->bounceSound, fd->name, od->id));
224 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckSound(fd->fireSound), va("sound %s does not exist (firedef %s for item %s)", fd->fireSound, fd->name, od->id));
225 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckSound(fd->impactSound), va("sound %s does not exist (firedef %s for item %s)", fd->impactSound, fd->name, od->id));
226 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckSound(fd->hitBodySound), va("sound %s does not exist (firedef %s for item %s)", fd->hitBodySound, fd->name, od->id));
227 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckParticle(fd->hitBody), va("particle %s does not exist (firedef %s for item %s)", fd->hitBody, fd->name, od->id));
228 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckParticle(fd->impact), va("particle %s does not exist (firedef %s for item %s)", fd->impact, fd->name, od->id));
229 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckParticle(fd->projectile), va("particle %s does not exist (firedef %s for item %s)", fd->projectile, fd->name, od->id));
230 }
231 }
232 }
233 }
234
testNations(void)235 static void testNations (void)
236 {
237 int i;
238
239 for (i = 0; i < ccs.numNations; i++) {
240 const nation_t* nat = NAT_GetNationByIDX(i);
241 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckImage(va("nations/%s", nat->id)), va("nation %s has no image", nat->id));
242 CU_ASSERT_PTR_NOT_NULL(Com_GetTeamDefinitionByID(nat->id));
243 }
244 }
245
testAircraft(void)246 static void testAircraft (void)
247 {
248 AIR_Foreach(aircraft) {
249 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(aircraft->model), va("%s does not exist (aircraft: %s)", aircraft->model, aircraft->id));
250 UFO_CU_ASSERT_TRUE_MSG(TEST_CheckImage(aircraft->image), va("%s does not exist (aircraft: %s)", aircraft->image, aircraft->id));
251 }
252 }
253
testMapDef(void)254 static void testMapDef (void)
255 {
256 int i;
257 const mapDef_t* md;
258
259 i = 0;
260 MapDef_Foreach(md) {
261 if (md->civTeam != nullptr)
262 CU_ASSERT_PTR_NOT_NULL(Com_GetTeamDefinitionByID(md->civTeam));
263
264 CU_ASSERT_FALSE(md->maxAliens <= 0);
265 CU_ASSERT_PTR_NOT_NULL(md->map);
266 CU_ASSERT_PTR_NOT_NULL(md->description);
267 i++;
268 }
269
270 CU_ASSERT_PTR_NULL(md);
271 UFO_CU_ASSERT_EQUAL_INT_MSG_FATAL(i, csi.numMDs, va("only looped over %i mapdefs, but expected %i", i, csi.numMDs));
272
273 i = csi.numMDs;
274
275 MapDef_ForeachCondition(md, !md->singleplayer || !md->campaign) {
276 i--;
277 CU_ASSERT_PTR_NOT_NULL(md);
278 }
279
280 CU_ASSERT_PTR_NULL(md);
281 CU_ASSERT_NOT_EQUAL(i, csi.numMDs);
282
283 MapDef_ForeachSingleplayerCampaign(md) {
284 i--;
285 CU_ASSERT_PTR_NOT_NULL(md);
286 CU_ASSERT_STRING_NOT_EQUAL(md->id, "training_a");
287 CU_ASSERT_STRING_NOT_EQUAL(md->id, "training_b");
288 }
289
290 CU_ASSERT_PTR_NULL(md);
291 UFO_CU_ASSERT_EQUAL_INT_MSG_FATAL(i, 0, va("i: %i", i));
292 }
293
UFO_AddScriptsTests(void)294 int UFO_AddScriptsTests (void)
295 {
296 /* add a suite to the registry */
297 CU_pSuite ScriptsSuite = CU_add_suite("ScriptsTests", UFO_InitSuiteScripts, UFO_CleanSuiteScripts);
298
299 if (ScriptsSuite == nullptr)
300 return CU_get_error();
301
302 /* add the tests to the suite */
303 if (CU_ADD_TEST(ScriptsSuite, testTeamDefs) == nullptr)
304 return CU_get_error();
305
306 if (CU_ADD_TEST(ScriptsSuite, testTeamDefsModelScriptData) == nullptr)
307 return CU_get_error();
308
309 if (CU_ADD_TEST(ScriptsSuite, testItems) == nullptr)
310 return CU_get_error();
311
312 if (CU_ADD_TEST(ScriptsSuite, testNations) == nullptr)
313 return CU_get_error();
314
315 if (CU_ADD_TEST(ScriptsSuite, testAircraft) == nullptr)
316 return CU_get_error();
317
318 if (CU_ADD_TEST(ScriptsSuite, testMapDef) == nullptr)
319 return CU_get_error();
320
321 return CUE_SUCCESS;
322 }
323