UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
test_scripts.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 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 "../client/client.h"
28 #include "../client/cl_lua.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 class ScriptTest: public ::testing::Test {
35 protected:
36  static void SetUpTestCase() {
37  TEST_Init();
38 
39  cl_genericPool = Mem_CreatePool("Client: Generic");
40  vid_imagePool = Mem_CreatePool("Vid: Image system");
41 
43  R_FontInit();
44  CL_InitLua();
45  UI_Init();
46 
47  OBJZERO(cls);
48  Com_ParseScripts(false);
49  }
50 
51  static void TearDownTestCase() {
52  TEST_Shutdown();
53  }
54 };
55 
56 static bool TEST_CheckImage (const char* path)
57 {
58  const char* extensions[] = {"png", "tga", "jpg", nullptr};
59  int i = 0;
60 
61  if (Q_strnull(path))
62  return true;
63 
64  while (extensions[i]) {
65  if (FS_CheckFile("pics/%s.%s", path, extensions[i]) != -1)
66  return true;
67  i++;
68  }
69 
70  return false;
71 }
72 
73 static bool TEST_CheckModel (const char* path)
74 {
75  const char* extensions[] = {"md2", "md3", "obj", nullptr};
76  int i = 0;
77  if (Q_strnull(path))
78  return true;
79 
80  while (extensions[i]) {
81  if (FS_CheckFile("models/%s.%s", path, extensions[i]) != -1)
82  return true;
83  i++;
84  }
85 
86  return false;
87 }
88 
89 static bool TEST_CheckSound (const char* path)
90 {
91  const char* extensions[] = {"wav", "ogg", nullptr};
92  int i = 0;
93 
94  if (Q_strnull(path))
95  return true;
96 
97  while (extensions[i]) {
98  if (FS_CheckFile("sound/%s.%s", path, extensions[i]) != -1)
99  return true;
100  i++;
101  }
102 
103  return false;
104 }
105 
106 static bool TEST_CheckParticle (const char* particleID)
107 {
108  if (Q_strnull(particleID))
109  return true;
110 
111  /* find the particle definition */
112  return CL_ParticleGet(particleID) != nullptr;
113 }
114 
115 TEST_F(ScriptTest, TeamDefs)
116 {
117  for (int i = 0; i < csi.numTeamDefs; i++) {
118  const teamDef_t* teamDef = &csi.teamDef[i];
119 
120  ASSERT_TRUE(teamDef->numTemplates > 0) << teamDef->id << " has no character templates assigned";
121 
122  for (int k = 0; k < SND_MAX; k++) {
123  for (int l = 0; l < NAME_LAST; l++) {
124  LIST_Foreach(teamDef->sounds[k][l], char, soundFile) {
125  ASSERT_TRUE(TEST_CheckSound(soundFile)) << "sound " << soundFile << " does not exist (team " << teamDef->id << ")";
126  }
127  }
128  }
129  }
130 }
131 
132 TEST_F(ScriptTest, TeamDefsModelScriptData)
133 {
134  linkedList_t* armourPaths = nullptr;
135 
136  for (int i = 0; i < csi.numTeamDefs; i++) {
137  const teamDef_t* teamDef = &csi.teamDef[i];
138  if (!teamDef->armour)
139  continue;
140 
141  for (int j = 0; j < csi.numODs; j++) {
142  const objDef_t* od = INVSH_GetItemByIDX(j);
143  if (!od->isArmour())
144  continue;
145 
146  /* not for this team */
147  if (!CHRSH_IsArmourUseableForTeam(od, teamDef))
148  continue;
149 
150  if (!LIST_ContainsString(armourPaths, od->armourPath))
151  LIST_AddString(&armourPaths, od->armourPath);
152  }
153 
154  ASSERT_TRUE(!LIST_IsEmpty(armourPaths)) << "no armour definitions found for team " << teamDef->id << " - but armour is set to true";
155 
156  LIST_Foreach(armourPaths, char const, armourPath) {
157  for (int l = NAME_NEUTRAL; l < NAME_LAST; l++) {
158  /* no models for this gender */
159  if (!teamDef->numModels[l])
160  continue;
161 
162  ASSERT_TRUE(nullptr != teamDef->models[l]);
163 
164  for (linkedList_t const* list = teamDef->models[l]; list; list = list->next) {
165  teamDef_t::model_t const& m = *static_cast<teamDef_t::model_t const*>(list->data);
166 
167  ASSERT_TRUE(TEST_CheckModel(va("%s/%s", m.path, m.body))) << m.body << " does not exist in models/" << m.path << " (teamDef: " << teamDef->id << ")";
168  ASSERT_TRUE(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.body))) << m.body << " does not exist in models/" << m.path << armourPath << " (teamDef: " << teamDef->id << ")";
169 
170  ASSERT_TRUE(TEST_CheckModel(va("%s/%s", m.path, m.head))) << m.head << " does not exist in models/" << m.path << " (teamDef: " << teamDef->id << ")";
171  ASSERT_TRUE(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.head))) << m.head << " does not exist in models/" << m.path << armourPath << " (teamDef: " << teamDef->id << ")";
172  }
173  }
174  }
175 
176  LIST_Delete(&armourPaths);
177  }
178 }
179 
181 {
182  for (int j = 0; j < csi.numODs; j++) {
183  const objDef_t* od = INVSH_GetItemByIDX(j);
184  if (od->isVirtual || od->isDummy)
185  continue;
186 
187  ASSERT_TRUE(TEST_CheckSound(od->reloadSound)) << "sound " << od->reloadSound << " does not exist (item " << od->id << ")";
188  ASSERT_TRUE(TEST_CheckModel(od->model)) << "model " << od->model << " does not exist (item " << od->id << ")";
189  ASSERT_TRUE(TEST_CheckImage(od->image)) << "image " << od->image << " does not exist (item " << od->id << ")";
190 
191  for (int i = 0; i < od->numWeapons; i++) {
192  for (int k = 0; k < od->numFiredefs[i]; k++) {
193  const fireDef_t* fd = &od->fd[i][k];
194  ASSERT_TRUE(TEST_CheckSound(fd->bounceSound)) << "sound " << fd->bounceSound << " does not exist (firedef " << fd->name << " for item " << od->id << ")";
195  ASSERT_TRUE(TEST_CheckSound(fd->fireSound)) << "sound " << fd->fireSound << " does not exist (firedef " << fd->name << " for item " << od->id << ")";
196  ASSERT_TRUE(TEST_CheckSound(fd->impactSound)) << "sound " << fd->impactSound << " does not exist (firedef " << fd->name << " for item " << od->id << ")";
197  ASSERT_TRUE(TEST_CheckSound(fd->hitBodySound)) << "sound " << fd->hitBodySound << " does not exist (firedef " << fd->name << " for item " << od->id << ")";
198  ASSERT_TRUE(TEST_CheckParticle(fd->hitBody)) << "particle " << fd->hitBody << " does not exist (firedef " << fd->name << " for item " << od->id << ")";
199  ASSERT_TRUE(TEST_CheckParticle(fd->impact)) << "particle " << fd->impact << " does not exist (firedef " << fd->name << " for item " << od->id << ")";
200  ASSERT_TRUE(TEST_CheckParticle(fd->projectile)) << "particle " << fd->projectile << " does not exist (firedef " << fd->name << " for item " << od->id << ")";
201  }
202  }
203  }
204 }
205 
207 {
208  NAT_Foreach(nation) {
209  ASSERT_TRUE(TEST_CheckImage(va("nations/%s", nation->id))) << "nation " << nation->id << " has no image";
210  ASSERT_TRUE(nullptr != Com_GetTeamDefinitionByID(nation->id));
211  }
212 }
213 
214 TEST_F(ScriptTest, Aircraft)
215 {
216  AIR_Foreach(aircraft) {
217  ASSERT_TRUE(TEST_CheckModel(aircraft->model)) << aircraft->model << " does not exist (aircraft: " << aircraft->id << ")";
218  ASSERT_TRUE(TEST_CheckImage(aircraft->image)) << aircraft->image << " does not exist (aircraft: " << aircraft->id << ")";
219  }
220 }
221 
223 {
224  const mapDef_t* md;
225 
226  int i = 0;
227  MapDef_Foreach(md) {
228  if (md->civTeam != nullptr) {
229  ASSERT_TRUE(nullptr != Com_GetTeamDefinitionByID(md->civTeam));
230  }
231 
232  ASSERT_FALSE(md->maxAliens <= 0);
233  ASSERT_TRUE(nullptr != md->mapTheme);
234  ASSERT_TRUE(nullptr != md->description);
235  i++;
236  }
237 
238  ASSERT_TRUE(nullptr == md);
239  ASSERT_EQ(i, csi.numMDs) << "only looped over " << i << " mapdefs, but expected " << csi.numMDs;
240 
241  i = csi.numMDs;
242 
243  MapDef_ForeachCondition(md, !md->singleplayer || !md->campaign) {
244  i--;
245  ASSERT_TRUE(nullptr != md);
246  }
247 
248  ASSERT_TRUE(nullptr == md);
249  ASSERT_NE(i, csi.numMDs);
250 
252  i--;
253  ASSERT_TRUE(nullptr != md);
254  ASSERT_STRNE(md->id, "training_a");
255  ASSERT_STRNE(md->id, "training_b");
256  }
257 
258  ASSERT_TRUE(nullptr == md);
259  ASSERT_EQ(i, 0);
260 }
static void TearDownTestCase()
const char * bounceSound
Definition: inv_shared.h:118
bool Q_strnull(const char *string)
Definition: shared.h:138
const char * impact
Definition: inv_shared.h:113
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition: files.cpp:298
char id[MAX_VAR]
Definition: chr_shared.h:298
void UI_Init(void)
Definition: ui_main.cpp:278
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
char * id
Definition: q_shared.h:463
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
int numMDs
Definition: q_shared.h:572
csi_t csi
Definition: common.cpp:39
static bool TEST_CheckModel(const char *path)
void Com_ParseScripts(bool onlyServer)
Definition: scripts.cpp:3641
fireDef_t fd[MAX_WEAPONS_PER_OBJDEF][MAX_FIREDEFS_PER_WEAPON]
Definition: inv_shared.h:314
linkedList_t * models[NAME_LAST]
Definition: chr_shared.h:314
int numODs
Definition: q_shared.h:518
const char * hitBodySound
Definition: inv_shared.h:116
void LIST_Delete(linkedList_t **list)
Definition: list.cpp:195
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
gltexunit_t texunits[MAX_GL_TEXUNITS]
Definition: r_state.h:114
const char * impactSound
Definition: inv_shared.h:114
const teamDef_t * Com_GetTeamDefinitionByID(const char *team)
Returns the teamDef pointer for the searched team id - or nullptr if not found in the teamDef array...
Definition: scripts.cpp:2367
bool singleplayer
Definition: q_shared.h:481
memPool_t * cl_genericPool
Definition: cl_main.cpp:86
client_static_t cls
Definition: cl_main.cpp:83
const char * image
Definition: inv_shared.h:270
const char * hitBody
Definition: inv_shared.h:115
gltexunit_t * active_texunit
Definition: r_state.h:117
#define NAT_Foreach(var)
iterates trough nations
Definition: cp_nation.h:80
fireDefIndex_t numFiredefs[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:315
void LIST_AddString(linkedList_t **listDest, const char *data)
Adds an string to a new or to an already existing linked list. The string is copied here...
Definition: list.cpp:139
#define OBJZERO(obj)
Definition: shared.h:178
#define MapDef_ForeachCondition(var, condition)
Definition: q_shared.h:501
void TEST_Shutdown(void)
Definition: test_shared.cpp:34
void CL_InitLua(void)
Initializes the ui-lua interfacing environment.
Definition: cl_lua.cpp:126
const char * model
Definition: inv_shared.h:269
static void SetUpTestCase()
int numWeapons
Definition: inv_shared.h:317
static bool TEST_CheckParticle(const char *particleID)
static bool TEST_CheckSound(const char *path)
#define Mem_CreatePool(name)
Definition: mem.h:32
const char * fireSound
Definition: inv_shared.h:117
TEST_F(ScriptTest, TeamDefs)
ptlDef_t * CL_ParticleGet(const char *name)
teamDef_t teamDef[MAX_TEAMDEFS]
Definition: q_shared.h:548
const linkedList_t * LIST_ContainsString(const linkedList_t *list, const char *string)
Searches for the first occurrence of a given string.
Definition: list.cpp:73
#define MapDef_ForeachSingleplayerCampaign(var)
Definition: cl_shared.h:83
int numModels[NAME_LAST]
Definition: chr_shared.h:315
char * mapTheme
Definition: q_shared.h:464
linkedList_t * sounds[SND_MAX][NAME_LAST]
Definition: chr_shared.h:317
const char * armourPath
Definition: inv_shared.h:272
int numTeamDefs
Definition: q_shared.h:549
QGL_EXTERN GLint i
Definition: r_gl.h:113
void TEST_Init(void)
Definition: test_shared.cpp:72
const char * projectile
Definition: inv_shared.h:112
char * civTeam
Definition: q_shared.h:471
bool isDummy
Definition: inv_shared.h:290
bool isArmour() const
Definition: inv_shared.h:346
const char * name
Definition: inv_shared.h:111
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it's safe to delete the returned entry from the list while looping over ...
Definition: list.h:41
linkedList_t * next
Definition: list.h:32
bool armour
Definition: chr_shared.h:323
memPool_t * vid_imagePool
Definition: cl_main.cpp:88
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
rstate_t r_state
Definition: r_main.cpp:48
#define MapDef_Foreach(var)
Definition: q_shared.h:505
char * description
Definition: q_shared.h:466
#define AIR_Foreach(var)
iterates trough all aircraft
Definition: cp_aircraft.h:192
bool LIST_IsEmpty(const linkedList_t *list)
Checks whether the given list is empty.
Definition: list.cpp:335
int numTemplates
Definition: chr_shared.h:337
bool isVirtual
Definition: inv_shared.h:284
bool campaign
Definition: q_shared.h:480
static struct mdfour * m
Definition: md4.cpp:35
bool CHRSH_IsArmourUseableForTeam(const objDef_t *od, const teamDef_t *teamDef)
Definition: chr_shared.cpp:87
const char * reloadSound
Definition: inv_shared.h:297
const char * id
Definition: inv_shared.h:268
void R_FontInit(void)
Definition: r_font.cpp:722
int maxAliens
Definition: q_shared.h:483
static bool TEST_CheckImage(const char *path)