blob: a97c1b0a244962771edb05e62fe615a9e44db138 [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*************************************************************************/
Jens Wiklander47d9a0b2016-12-26 21:39:09 +010048ADBG_Case_t *ADBG_Case_New(const ADBG_Case_SuiteEntry_t *SuiteEntry_p)
Pascal Brandc639ac82015-07-02 08:53:34 +020049{
50 ADBG_Case_t *Case_p;
51
52 Case_p = HEAP_ALLOC(ADBG_Case_t);
53 if (Case_p == NULL)
54 return NULL;
55
56 memset(Case_p, 0, sizeof(ADBG_Case_t));
57 Case_p->SuiteEntry_p = SuiteEntry_p;
Pascal Brandc639ac82015-07-02 08:53:34 +020058 return Case_p;
59}
60
61void ADBG_Case_Delete(
62 ADBG_Case_t *Case_p
63 )
64{
65 ADBG_SubCase_Delete(Case_p->FirstSubCase_p);
66 HEAP_FREE(&Case_p);
67}
68
69bool ADBG_Case_SubCaseIsMain(
70 const ADBG_Case_t *const Case_p,
71 const ADBG_SubCase_t *const SubCase_p
72 )
73{
74 IDENTIFIER_NOT_USED(Case_p)
75 return SubCase_p->Parent_p == NULL;
76}
77
78
79void ADBG_Case_IterateSubCase(
80 ADBG_Case_t *Case_p,
81 ADBG_SubCase_Iterator_t *Iterator_p
82 )
83{
84 Iterator_p->Case_p = Case_p;
85 Iterator_p->CurrentSubCase_p = NULL;
86}
87
88ADBG_SubCase_t *ADBG_Case_NextSubCase(
89 ADBG_SubCase_Iterator_t *Iterator_p
90 )
91{
92 ADBG_Case_t *Case_p = Iterator_p->Case_p;
93 ADBG_SubCase_t *SubCase_p = Iterator_p->CurrentSubCase_p;
94
95
96 /*
97 * Traverse the subcases depth first, that is:
98 * 1.1.1.1
99 * 1.1.1.2
100 * 1.1.1
101 * 1.1.2.1
102 * 1.1.2
103 * 1.1
104 * 1.2.1
105 * 1.2
106 * 1
107 */
108 if (SubCase_p == NULL) {
109 /* Find the first leaf */
110 SubCase_p = Case_p->FirstSubCase_p;
111 if (SubCase_p == NULL)
112 goto CleanupReturn;
113
114 while (!TAILQ_EMPTY(&SubCase_p->SubCasesList))
115 SubCase_p = TAILQ_FIRST(&SubCase_p->SubCasesList);
116 goto CleanupReturn;
117 }
118
119 /*
120 * Look for the next leaf belonging to the parent
121 */
122
123 if (SubCase_p->Parent_p == NULL) {
124 /* If parent is NULL this is the top
125 subcase and we're done */
126 SubCase_p = NULL;
127 goto CleanupReturn;
128 }
129
130 if (TAILQ_NEXT(SubCase_p, Link) == NULL) {
131 /* If this is the last subcase of the
132 parent move up to parent */
133 SubCase_p = SubCase_p->Parent_p;
134 goto CleanupReturn;
135 }
136
137 /*
138 * Find next leaf
139 */
140 SubCase_p = TAILQ_NEXT(SubCase_p, Link);
141 while (!TAILQ_EMPTY(&SubCase_p->SubCasesList))
142 SubCase_p = TAILQ_FIRST(&SubCase_p->SubCasesList);
143
144CleanupReturn:
145 Iterator_p->CurrentSubCase_p = SubCase_p;
146 return SubCase_p;
147}
148
149void Do_ADBG_BeginSubCase(
150 ADBG_Case_t *const Case_p,
151 const char *const FormatTitle_p, ...
152 )
153{
154 ADBG_SubCase_t *SubCase_p = NULL;
155
156 if (Case_p == NULL) {
157 Do_ADBG_Log("Do_ADBG_BeginSubCase: NULL Case_p!");
158 return;
159 }
160
161 if (FormatTitle_p == NULL) {
162 Do_ADBG_Log("Do_ADBG_BeginSubCase: NULL FormatTitle_p!");
163 return;
164 }
165
166 va_list ArgList;
167 char Title[80];
168
169 /*lint -save -e718 -e746 -e530 lint doesn't seem to know of va_start */
170 va_start(ArgList, FormatTitle_p);
171 /*lint -restore */
172 (void)ADBG_vsnprintf(Title, sizeof(Title), FormatTitle_p, ArgList);
173 va_end(ArgList);
174
175 SubCase_p = ADBG_Case_CreateSubCase(Case_p, Title);
176
177 if (SubCase_p == NULL) {
178 Do_ADBG_Log("Do_ADBG_BeginSubCase: HEAP_ALLOC failed");
179 return;
180 }
181
182
183 if (ADBG_Case_SubCaseIsMain(Case_p, SubCase_p)) {
184 /* Main SubCase */
185 Do_ADBG_Log(" ");
186 Do_ADBG_Log("* %s %s", SubCase_p->TestID_p, SubCase_p->Title_p);
187 } else {
188 Do_ADBG_Log("o %s %s", SubCase_p->TestID_p, SubCase_p->Title_p);
189 }
190}
191
192void Do_ADBG_EndSubCase(
193 ADBG_Case_t *const Case_p,
194 const char *const FormatTitle_p, ...
195 )
196{
197 va_list ArgList;
198 char Title[80];
199 ADBG_SubCase_t *SubCase_p = NULL;
200
201 if (Case_p == NULL) {
202 Do_ADBG_Log("Do_ADBG_EndSubCase: NULL Case_p!");
203 return;
204 }
205
206 if (FormatTitle_p == NULL) {
207 strcpy(Title, "NULL");
208 } else {
209 /*lint -save -e718 -e746 -e530 lint doesn't
210 seem to know of va_start */
211 va_start(ArgList, FormatTitle_p);
212 /*lint -restore */
213 (void)ADBG_vsnprintf(Title, sizeof(Title), FormatTitle_p,
214 ArgList);
215 va_end(ArgList);
216 }
217
218
219 SubCase_p = Case_p->CurrentSubCase_p;
220
221 if (SubCase_p == NULL) {
222 Do_ADBG_Log("Do_ADBG_EndSubCase: "
223 "Have no active SubCase, bailing out for title \"%s\"",
224 Title);
225 return;
226 }
227
228 if (FormatTitle_p != NULL && strcmp(SubCase_p->Title_p, Title) != 0) {
229 Do_ADBG_Log("Do_ADBG_EndSubCase: "
230 "Active SubCase \"%s\" doesn't match supplied title \"%s\"",
231 SubCase_p->Title_p, Title);
232 return;
233 }
234
235 if (ADBG_Case_SubCaseIsMain(Case_p, SubCase_p)) {
236 if (FormatTitle_p == NULL) {
237 /* To end the main subcase we require
238 a matching title */
239 Do_ADBG_Log("Do_ADBG_EndSubCase: "
240 "The main SubCase \"%s\" doesn't match supplied title \"%s\"",
241 SubCase_p->Title_p, Title);
242 return;
243 }
244 /*
245 * Ending the main subcase
246 * make a complete copy of the aggregated result.
247 */
248 Case_p->Result = SubCase_p->Result;
249 } else {
250 /*
251 * Ending a subcase,
252 * Aggregate results to parent.
253 */
254 ADBG_SubCase_t *Parent_p = SubCase_p->Parent_p;
255
256 Parent_p->Result.NumSubTests += SubCase_p->Result.NumTests +
257 SubCase_p->Result.NumSubTests;
258 Parent_p->Result.NumFailedSubTests +=
259 SubCase_p->Result.NumFailedTests +
260 SubCase_p->Result.
261 NumFailedSubTests;
262 Parent_p->Result.AbortTestSuite =
263 SubCase_p->Result.AbortTestSuite;
264 if (SubCase_p->Result.NumTests > 0 ||
265 SubCase_p->Result.NumSubTests > 0)
266 Parent_p->Result.NumFailedSubCases++;
267 }
268
269 /* Print a summary of the subcase result */
270 if (SubCase_p->Result.NumFailedTests > 0 ||
271 SubCase_p->Result.NumFailedSubTests > 0) {
272 Do_ADBG_Log(" %s FAILED", SubCase_p->TestID_p);
273 } else {
274 Do_ADBG_Log(" %s OK", SubCase_p->TestID_p);
275 }
276
277 /* Update current subcase to be the parent of this subcase */
278 Case_p->CurrentSubCase_p =
279 ADBG_Case_GetParentSubCase(Case_p, SubCase_p);
280}
281
282void Do_ADBG_AbortSuite(
283 ADBG_Case_t *const Case_p
284 )
285{
286 Case_p->Result.AbortTestSuite = true;
287}
288
Pascal Brandc639ac82015-07-02 08:53:34 +0200289/*************************************************************************
290* 6. Definition of internal functions
291*************************************************************************/
292static ADBG_SubCase_t *ADBG_Case_CreateSubCase(
293 ADBG_Case_t *Case_p,
294 const char *const Title_p
295 )
296{
297 ADBG_SubCase_t *SubCase_p;
298
299 SubCase_p = HEAP_ALLOC(ADBG_SubCase_t);
300 if (SubCase_p == NULL)
301 goto ErrorReturn;
302
303 memset(SubCase_p, 0, sizeof(ADBG_SubCase_t));
304 TAILQ_INIT(&SubCase_p->SubCasesList);
305
306 SubCase_p->Title_p = SECUTIL_HEAP_STRDUP(Title_p);
307 if (SubCase_p->Title_p == NULL)
308 goto ErrorReturn;
309
310 /* Set parent pointer needed "early" below. */
311 SubCase_p->Parent_p = Case_p->CurrentSubCase_p;
312
313 if (SubCase_p->Parent_p == NULL) {
314 /* Main SubCase */
315 SubCase_p->TestID_p =
316 SECUTIL_HEAP_STRDUP(ADBG_Case_GetTestID(Case_p));
317 if (SubCase_p->TestID_p == NULL)
318 goto ErrorReturn;
319
320 Case_p->FirstSubCase_p = SubCase_p;
321 } else {
322 ADBG_SubCase_t *Parent_p = SubCase_p->Parent_p;
323 char PrefixTitle[80];
324
325 /* Update parent SubCase */
326 Parent_p->Result.NumSubCases++;
327 /*
328 * XXX 081112 EJENWIK
329 * bug in snprintf when passing more
330 * than one argument to snprintf.
331 */
332 (void)ADBG_snprintf(PrefixTitle, sizeof(PrefixTitle),
333 "%s",
334 Parent_p->TestID_p);
335 (void)ADBG_snprintf(PrefixTitle + strlen(PrefixTitle),
336 sizeof(PrefixTitle) - strlen(PrefixTitle),
337 ".%d",
338 Parent_p->Result.NumSubCases);
339 SubCase_p->TestID_p = SECUTIL_HEAP_STRDUP(PrefixTitle);
340 if (SubCase_p->TestID_p == NULL)
341 goto ErrorReturn;
342
343 TAILQ_INSERT_TAIL(&Parent_p->SubCasesList, SubCase_p, Link);
344 }
345
346 Case_p->CurrentSubCase_p = SubCase_p;
347 return SubCase_p;
348
349ErrorReturn:
350 ADBG_SubCase_Delete(SubCase_p);
351 return NULL;
352}
353
354static void ADBG_SubCase_Delete(
355 ADBG_SubCase_t *SubCase_p
356 )
357{
358 if (SubCase_p != NULL) {
359 /*
360 * Note that Util_ListDestroy() checks
361 * if SubCase_p->SubCasesList_p
362 * is NULL.
363 */
364 while (true) {
365 ADBG_SubCase_t *s =
366 TAILQ_FIRST(&SubCase_p->SubCasesList);
367
368 if (s == NULL)
369 break;
370
371 TAILQ_REMOVE(&SubCase_p->SubCasesList, s, Link);
372 ADBG_SubCase_Delete(s);
373 }
374 HEAP_FREE(&SubCase_p->TestID_p);
375 HEAP_FREE(&SubCase_p->Title_p);
376 HEAP_FREE(&SubCase_p);
377 }
378}
379
380ADBG_SubCase_t *ADBG_Case_GetParentSubCase(
381 ADBG_Case_t *Case_p,
382 ADBG_SubCase_t *SubCase_p
383 )
384{
385 IDENTIFIER_NOT_USED(Case_p)
386 IDENTIFIER_NOT_USED(SubCase_p)
387 return SubCase_p->Parent_p;
388}
389
390static const char *ADBG_Case_GetTestID(ADBG_Case_t *Case_p)
391{
392 IDENTIFIER_NOT_USED(Case_p)
393
394 return Case_p->SuiteEntry_p->CaseDefinition_p->TestID_p;
395}