blob: 3567d2efce2366706537591bf56c799dba0e4c4e [file] [log] [blame]
Pascal Brandc639ac82015-07-02 08:53:34 +02001/*
2 * Copyright (c) 2014, STMicroelectronics International N.V.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14/*************************************************************************
15* 1. Includes
16*************************************************************************/
17#include "adbg_int.h"
18
19/*************************************************************************
20* 2. Definition of external constants and variables
21*************************************************************************/
22
23/*************************************************************************
24* 3. File scope types, constants and variables
25*************************************************************************/
26
27/*************************************************************************
28* 4. Declaration of file local functions
29*************************************************************************/
30
31/*
32 * Deletes a subcase. Don't call this function before the
33 * subcase is removed from list.
34 */
35static void ADBG_SubCase_Delete(ADBG_SubCase_t *SubCase);
36
37static ADBG_SubCase_t *ADBG_Case_CreateSubCase(ADBG_Case_t *Case_p,
38 const char *const Title_p);
39
40static ADBG_SubCase_t *ADBG_Case_GetParentSubCase(ADBG_Case_t *Case_p,
41 ADBG_SubCase_t *SubCase_p);
42
43static const char *ADBG_Case_GetTestID(ADBG_Case_t *Case_p);
44
45/*************************************************************************
46* 5. Definition of external functions
47*************************************************************************/
48ADBG_Case_t *ADBG_Case_New(
49 const ADBG_Case_SuiteEntry_t *SuiteEntry_p,
50 ADBG_SuiteData_t *SuiteData_p
51 )
52{
53 ADBG_Case_t *Case_p;
54
55 Case_p = HEAP_ALLOC(ADBG_Case_t);
56 if (Case_p == NULL)
57 return NULL;
58
59 memset(Case_p, 0, sizeof(ADBG_Case_t));
60 Case_p->SuiteEntry_p = SuiteEntry_p;
61 Case_p->SuiteData_p = SuiteData_p;
62 return Case_p;
63}
64
65void ADBG_Case_Delete(
66 ADBG_Case_t *Case_p
67 )
68{
69 ADBG_SubCase_Delete(Case_p->FirstSubCase_p);
70 HEAP_FREE(&Case_p);
71}
72
73bool ADBG_Case_SubCaseIsMain(
74 const ADBG_Case_t *const Case_p,
75 const ADBG_SubCase_t *const SubCase_p
76 )
77{
78 IDENTIFIER_NOT_USED(Case_p)
79 return SubCase_p->Parent_p == NULL;
80}
81
82
83void ADBG_Case_IterateSubCase(
84 ADBG_Case_t *Case_p,
85 ADBG_SubCase_Iterator_t *Iterator_p
86 )
87{
88 Iterator_p->Case_p = Case_p;
89 Iterator_p->CurrentSubCase_p = NULL;
90}
91
92ADBG_SubCase_t *ADBG_Case_NextSubCase(
93 ADBG_SubCase_Iterator_t *Iterator_p
94 )
95{
96 ADBG_Case_t *Case_p = Iterator_p->Case_p;
97 ADBG_SubCase_t *SubCase_p = Iterator_p->CurrentSubCase_p;
98
99
100 /*
101 * Traverse the subcases depth first, that is:
102 * 1.1.1.1
103 * 1.1.1.2
104 * 1.1.1
105 * 1.1.2.1
106 * 1.1.2
107 * 1.1
108 * 1.2.1
109 * 1.2
110 * 1
111 */
112 if (SubCase_p == NULL) {
113 /* Find the first leaf */
114 SubCase_p = Case_p->FirstSubCase_p;
115 if (SubCase_p == NULL)
116 goto CleanupReturn;
117
118 while (!TAILQ_EMPTY(&SubCase_p->SubCasesList))
119 SubCase_p = TAILQ_FIRST(&SubCase_p->SubCasesList);
120 goto CleanupReturn;
121 }
122
123 /*
124 * Look for the next leaf belonging to the parent
125 */
126
127 if (SubCase_p->Parent_p == NULL) {
128 /* If parent is NULL this is the top
129 subcase and we're done */
130 SubCase_p = NULL;
131 goto CleanupReturn;
132 }
133
134 if (TAILQ_NEXT(SubCase_p, Link) == NULL) {
135 /* If this is the last subcase of the
136 parent move up to parent */
137 SubCase_p = SubCase_p->Parent_p;
138 goto CleanupReturn;
139 }
140
141 /*
142 * Find next leaf
143 */
144 SubCase_p = TAILQ_NEXT(SubCase_p, Link);
145 while (!TAILQ_EMPTY(&SubCase_p->SubCasesList))
146 SubCase_p = TAILQ_FIRST(&SubCase_p->SubCasesList);
147
148CleanupReturn:
149 Iterator_p->CurrentSubCase_p = SubCase_p;
150 return SubCase_p;
151}
152
153void Do_ADBG_BeginSubCase(
154 ADBG_Case_t *const Case_p,
155 const char *const FormatTitle_p, ...
156 )
157{
158 ADBG_SubCase_t *SubCase_p = NULL;
159
160 if (Case_p == NULL) {
161 Do_ADBG_Log("Do_ADBG_BeginSubCase: NULL Case_p!");
162 return;
163 }
164
165 if (FormatTitle_p == NULL) {
166 Do_ADBG_Log("Do_ADBG_BeginSubCase: NULL FormatTitle_p!");
167 return;
168 }
169
170 va_list ArgList;
171 char Title[80];
172
173 /*lint -save -e718 -e746 -e530 lint doesn't seem to know of va_start */
174 va_start(ArgList, FormatTitle_p);
175 /*lint -restore */
176 (void)ADBG_vsnprintf(Title, sizeof(Title), FormatTitle_p, ArgList);
177 va_end(ArgList);
178
179 SubCase_p = ADBG_Case_CreateSubCase(Case_p, Title);
180
181 if (SubCase_p == NULL) {
182 Do_ADBG_Log("Do_ADBG_BeginSubCase: HEAP_ALLOC failed");
183 return;
184 }
185
186
187 if (ADBG_Case_SubCaseIsMain(Case_p, SubCase_p)) {
188 /* Main SubCase */
189 Do_ADBG_Log(" ");
190 Do_ADBG_Log("* %s %s", SubCase_p->TestID_p, SubCase_p->Title_p);
191 } else {
192 Do_ADBG_Log("o %s %s", SubCase_p->TestID_p, SubCase_p->Title_p);
193 }
194}
195
196void Do_ADBG_EndSubCase(
197 ADBG_Case_t *const Case_p,
198 const char *const FormatTitle_p, ...
199 )
200{
201 va_list ArgList;
202 char Title[80];
203 ADBG_SubCase_t *SubCase_p = NULL;
204
205 if (Case_p == NULL) {
206 Do_ADBG_Log("Do_ADBG_EndSubCase: NULL Case_p!");
207 return;
208 }
209
210 if (FormatTitle_p == NULL) {
211 strcpy(Title, "NULL");
212 } else {
213 /*lint -save -e718 -e746 -e530 lint doesn't
214 seem to know of va_start */
215 va_start(ArgList, FormatTitle_p);
216 /*lint -restore */
217 (void)ADBG_vsnprintf(Title, sizeof(Title), FormatTitle_p,
218 ArgList);
219 va_end(ArgList);
220 }
221
222
223 SubCase_p = Case_p->CurrentSubCase_p;
224
225 if (SubCase_p == NULL) {
226 Do_ADBG_Log("Do_ADBG_EndSubCase: "
227 "Have no active SubCase, bailing out for title \"%s\"",
228 Title);
229 return;
230 }
231
232 if (FormatTitle_p != NULL && strcmp(SubCase_p->Title_p, Title) != 0) {
233 Do_ADBG_Log("Do_ADBG_EndSubCase: "
234 "Active SubCase \"%s\" doesn't match supplied title \"%s\"",
235 SubCase_p->Title_p, Title);
236 return;
237 }
238
239 if (ADBG_Case_SubCaseIsMain(Case_p, SubCase_p)) {
240 if (FormatTitle_p == NULL) {
241 /* To end the main subcase we require
242 a matching title */
243 Do_ADBG_Log("Do_ADBG_EndSubCase: "
244 "The main SubCase \"%s\" doesn't match supplied title \"%s\"",
245 SubCase_p->Title_p, Title);
246 return;
247 }
248 /*
249 * Ending the main subcase
250 * make a complete copy of the aggregated result.
251 */
252 Case_p->Result = SubCase_p->Result;
253 } else {
254 /*
255 * Ending a subcase,
256 * Aggregate results to parent.
257 */
258 ADBG_SubCase_t *Parent_p = SubCase_p->Parent_p;
259
260 Parent_p->Result.NumSubTests += SubCase_p->Result.NumTests +
261 SubCase_p->Result.NumSubTests;
262 Parent_p->Result.NumFailedSubTests +=
263 SubCase_p->Result.NumFailedTests +
264 SubCase_p->Result.
265 NumFailedSubTests;
266 Parent_p->Result.AbortTestSuite =
267 SubCase_p->Result.AbortTestSuite;
268 if (SubCase_p->Result.NumTests > 0 ||
269 SubCase_p->Result.NumSubTests > 0)
270 Parent_p->Result.NumFailedSubCases++;
271 }
272
273 /* Print a summary of the subcase result */
274 if (SubCase_p->Result.NumFailedTests > 0 ||
275 SubCase_p->Result.NumFailedSubTests > 0) {
276 Do_ADBG_Log(" %s FAILED", SubCase_p->TestID_p);
277 } else {
278 Do_ADBG_Log(" %s OK", SubCase_p->TestID_p);
279 }
280
281 /* Update current subcase to be the parent of this subcase */
282 Case_p->CurrentSubCase_p =
283 ADBG_Case_GetParentSubCase(Case_p, SubCase_p);
284}
285
286void Do_ADBG_AbortSuite(
287 ADBG_Case_t *const Case_p
288 )
289{
290 Case_p->Result.AbortTestSuite = true;
291}
292
293ADBG_SuiteData_t *Do_ADBG_GetSuiteData(const ADBG_Case_t *const Case_p)
294{
295 return Case_p->SuiteData_p;
296}
297
298
299
300/*************************************************************************
301* 6. Definition of internal functions
302*************************************************************************/
303static ADBG_SubCase_t *ADBG_Case_CreateSubCase(
304 ADBG_Case_t *Case_p,
305 const char *const Title_p
306 )
307{
308 ADBG_SubCase_t *SubCase_p;
309
310 SubCase_p = HEAP_ALLOC(ADBG_SubCase_t);
311 if (SubCase_p == NULL)
312 goto ErrorReturn;
313
314 memset(SubCase_p, 0, sizeof(ADBG_SubCase_t));
315 TAILQ_INIT(&SubCase_p->SubCasesList);
316
317 SubCase_p->Title_p = SECUTIL_HEAP_STRDUP(Title_p);
318 if (SubCase_p->Title_p == NULL)
319 goto ErrorReturn;
320
321 /* Set parent pointer needed "early" below. */
322 SubCase_p->Parent_p = Case_p->CurrentSubCase_p;
323
324 if (SubCase_p->Parent_p == NULL) {
325 /* Main SubCase */
326 SubCase_p->TestID_p =
327 SECUTIL_HEAP_STRDUP(ADBG_Case_GetTestID(Case_p));
328 if (SubCase_p->TestID_p == NULL)
329 goto ErrorReturn;
330
331 Case_p->FirstSubCase_p = SubCase_p;
332 } else {
333 ADBG_SubCase_t *Parent_p = SubCase_p->Parent_p;
334 char PrefixTitle[80];
335
336 /* Update parent SubCase */
337 Parent_p->Result.NumSubCases++;
338 /*
339 * XXX 081112 EJENWIK
340 * bug in snprintf when passing more
341 * than one argument to snprintf.
342 */
343 (void)ADBG_snprintf(PrefixTitle, sizeof(PrefixTitle),
344 "%s",
345 Parent_p->TestID_p);
346 (void)ADBG_snprintf(PrefixTitle + strlen(PrefixTitle),
347 sizeof(PrefixTitle) - strlen(PrefixTitle),
348 ".%d",
349 Parent_p->Result.NumSubCases);
350 SubCase_p->TestID_p = SECUTIL_HEAP_STRDUP(PrefixTitle);
351 if (SubCase_p->TestID_p == NULL)
352 goto ErrorReturn;
353
354 TAILQ_INSERT_TAIL(&Parent_p->SubCasesList, SubCase_p, Link);
355 }
356
357 Case_p->CurrentSubCase_p = SubCase_p;
358 return SubCase_p;
359
360ErrorReturn:
361 ADBG_SubCase_Delete(SubCase_p);
362 return NULL;
363}
364
365static void ADBG_SubCase_Delete(
366 ADBG_SubCase_t *SubCase_p
367 )
368{
369 if (SubCase_p != NULL) {
370 /*
371 * Note that Util_ListDestroy() checks
372 * if SubCase_p->SubCasesList_p
373 * is NULL.
374 */
375 while (true) {
376 ADBG_SubCase_t *s =
377 TAILQ_FIRST(&SubCase_p->SubCasesList);
378
379 if (s == NULL)
380 break;
381
382 TAILQ_REMOVE(&SubCase_p->SubCasesList, s, Link);
383 ADBG_SubCase_Delete(s);
384 }
385 HEAP_FREE(&SubCase_p->TestID_p);
386 HEAP_FREE(&SubCase_p->Title_p);
387 HEAP_FREE(&SubCase_p);
388 }
389}
390
391ADBG_SubCase_t *ADBG_Case_GetParentSubCase(
392 ADBG_Case_t *Case_p,
393 ADBG_SubCase_t *SubCase_p
394 )
395{
396 IDENTIFIER_NOT_USED(Case_p)
397 IDENTIFIER_NOT_USED(SubCase_p)
398 return SubCase_p->Parent_p;
399}
400
401static const char *ADBG_Case_GetTestID(ADBG_Case_t *Case_p)
402{
403 IDENTIFIER_NOT_USED(Case_p)
404
405 return Case_p->SuiteEntry_p->CaseDefinition_p->TestID_p;
406}