blob: bc40ea8b04eb79db2724c2c4e5a541dc37a097ba [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
Pascal Brandc639ac82015-07-02 08:53:34 +0200282/*************************************************************************
283* 6. Definition of internal functions
284*************************************************************************/
285static ADBG_SubCase_t *ADBG_Case_CreateSubCase(
286 ADBG_Case_t *Case_p,
287 const char *const Title_p
288 )
289{
290 ADBG_SubCase_t *SubCase_p;
291
292 SubCase_p = HEAP_ALLOC(ADBG_SubCase_t);
293 if (SubCase_p == NULL)
294 goto ErrorReturn;
295
296 memset(SubCase_p, 0, sizeof(ADBG_SubCase_t));
297 TAILQ_INIT(&SubCase_p->SubCasesList);
298
299 SubCase_p->Title_p = SECUTIL_HEAP_STRDUP(Title_p);
300 if (SubCase_p->Title_p == NULL)
301 goto ErrorReturn;
302
303 /* Set parent pointer needed "early" below. */
304 SubCase_p->Parent_p = Case_p->CurrentSubCase_p;
305
306 if (SubCase_p->Parent_p == NULL) {
307 /* Main SubCase */
308 SubCase_p->TestID_p =
309 SECUTIL_HEAP_STRDUP(ADBG_Case_GetTestID(Case_p));
310 if (SubCase_p->TestID_p == NULL)
311 goto ErrorReturn;
312
313 Case_p->FirstSubCase_p = SubCase_p;
314 } else {
315 ADBG_SubCase_t *Parent_p = SubCase_p->Parent_p;
316 char PrefixTitle[80];
317
318 /* Update parent SubCase */
319 Parent_p->Result.NumSubCases++;
320 /*
321 * XXX 081112 EJENWIK
322 * bug in snprintf when passing more
323 * than one argument to snprintf.
324 */
325 (void)ADBG_snprintf(PrefixTitle, sizeof(PrefixTitle),
326 "%s",
327 Parent_p->TestID_p);
328 (void)ADBG_snprintf(PrefixTitle + strlen(PrefixTitle),
329 sizeof(PrefixTitle) - strlen(PrefixTitle),
330 ".%d",
331 Parent_p->Result.NumSubCases);
332 SubCase_p->TestID_p = SECUTIL_HEAP_STRDUP(PrefixTitle);
333 if (SubCase_p->TestID_p == NULL)
334 goto ErrorReturn;
335
336 TAILQ_INSERT_TAIL(&Parent_p->SubCasesList, SubCase_p, Link);
337 }
338
339 Case_p->CurrentSubCase_p = SubCase_p;
340 return SubCase_p;
341
342ErrorReturn:
343 ADBG_SubCase_Delete(SubCase_p);
344 return NULL;
345}
346
347static void ADBG_SubCase_Delete(
348 ADBG_SubCase_t *SubCase_p
349 )
350{
351 if (SubCase_p != NULL) {
352 /*
353 * Note that Util_ListDestroy() checks
354 * if SubCase_p->SubCasesList_p
355 * is NULL.
356 */
357 while (true) {
358 ADBG_SubCase_t *s =
359 TAILQ_FIRST(&SubCase_p->SubCasesList);
360
361 if (s == NULL)
362 break;
363
364 TAILQ_REMOVE(&SubCase_p->SubCasesList, s, Link);
365 ADBG_SubCase_Delete(s);
366 }
367 HEAP_FREE(&SubCase_p->TestID_p);
368 HEAP_FREE(&SubCase_p->Title_p);
369 HEAP_FREE(&SubCase_p);
370 }
371}
372
373ADBG_SubCase_t *ADBG_Case_GetParentSubCase(
374 ADBG_Case_t *Case_p,
375 ADBG_SubCase_t *SubCase_p
376 )
377{
378 IDENTIFIER_NOT_USED(Case_p)
379 IDENTIFIER_NOT_USED(SubCase_p)
380 return SubCase_p->Parent_p;
381}
382
383static const char *ADBG_Case_GetTestID(ADBG_Case_t *Case_p)
384{
385 IDENTIFIER_NOT_USED(Case_p)
386
387 return Case_p->SuiteEntry_p->CaseDefinition_p->TestID_p;
388}