blob: baadb419ef8700ff1732b2aecf84e933b8b9adcf [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 Wiklander74abfe32017-01-03 14:17:47 +010048ADBG_Case_t *ADBG_Case_New(const struct adbg_case_def *case_def)
Pascal Brandc639ac82015-07-02 08:53:34 +020049{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010050 ADBG_Case_t *Case_p = NULL;
Pascal Brandc639ac82015-07-02 08:53:34 +020051
Jens Wiklander7c30dfd2016-12-27 21:59:36 +010052 Case_p = calloc(1, sizeof(*Case_p));
53 if (Case_p)
Jens Wiklander74abfe32017-01-03 14:17:47 +010054 Case_p->case_def = case_def;
Pascal Brandc639ac82015-07-02 08:53:34 +020055
Pascal Brandc639ac82015-07-02 08:53:34 +020056 return Case_p;
57}
58
Jens Wiklander7c30dfd2016-12-27 21:59:36 +010059void ADBG_Case_Delete(ADBG_Case_t *Case_p)
Pascal Brandc639ac82015-07-02 08:53:34 +020060{
61 ADBG_SubCase_Delete(Case_p->FirstSubCase_p);
Jens Wiklander7c30dfd2016-12-27 21:59:36 +010062 free(Case_p);
Pascal Brandc639ac82015-07-02 08:53:34 +020063}
64
65bool ADBG_Case_SubCaseIsMain(
66 const ADBG_Case_t *const Case_p,
67 const ADBG_SubCase_t *const SubCase_p
68 )
69{
70 IDENTIFIER_NOT_USED(Case_p)
71 return SubCase_p->Parent_p == NULL;
72}
73
74
75void ADBG_Case_IterateSubCase(
76 ADBG_Case_t *Case_p,
77 ADBG_SubCase_Iterator_t *Iterator_p
78 )
79{
80 Iterator_p->Case_p = Case_p;
81 Iterator_p->CurrentSubCase_p = NULL;
82}
83
84ADBG_SubCase_t *ADBG_Case_NextSubCase(
85 ADBG_SubCase_Iterator_t *Iterator_p
86 )
87{
88 ADBG_Case_t *Case_p = Iterator_p->Case_p;
89 ADBG_SubCase_t *SubCase_p = Iterator_p->CurrentSubCase_p;
90
91
92 /*
93 * Traverse the subcases depth first, that is:
94 * 1.1.1.1
95 * 1.1.1.2
96 * 1.1.1
97 * 1.1.2.1
98 * 1.1.2
99 * 1.1
100 * 1.2.1
101 * 1.2
102 * 1
103 */
104 if (SubCase_p == NULL) {
105 /* Find the first leaf */
106 SubCase_p = Case_p->FirstSubCase_p;
107 if (SubCase_p == NULL)
108 goto CleanupReturn;
109
110 while (!TAILQ_EMPTY(&SubCase_p->SubCasesList))
111 SubCase_p = TAILQ_FIRST(&SubCase_p->SubCasesList);
112 goto CleanupReturn;
113 }
114
115 /*
116 * Look for the next leaf belonging to the parent
117 */
118
119 if (SubCase_p->Parent_p == NULL) {
120 /* If parent is NULL this is the top
121 subcase and we're done */
122 SubCase_p = NULL;
123 goto CleanupReturn;
124 }
125
126 if (TAILQ_NEXT(SubCase_p, Link) == NULL) {
127 /* If this is the last subcase of the
128 parent move up to parent */
129 SubCase_p = SubCase_p->Parent_p;
130 goto CleanupReturn;
131 }
132
133 /*
134 * Find next leaf
135 */
136 SubCase_p = TAILQ_NEXT(SubCase_p, Link);
137 while (!TAILQ_EMPTY(&SubCase_p->SubCasesList))
138 SubCase_p = TAILQ_FIRST(&SubCase_p->SubCasesList);
139
140CleanupReturn:
141 Iterator_p->CurrentSubCase_p = SubCase_p;
142 return SubCase_p;
143}
144
145void Do_ADBG_BeginSubCase(
146 ADBG_Case_t *const Case_p,
147 const char *const FormatTitle_p, ...
148 )
149{
150 ADBG_SubCase_t *SubCase_p = NULL;
151
152 if (Case_p == NULL) {
153 Do_ADBG_Log("Do_ADBG_BeginSubCase: NULL Case_p!");
154 return;
155 }
156
157 if (FormatTitle_p == NULL) {
158 Do_ADBG_Log("Do_ADBG_BeginSubCase: NULL FormatTitle_p!");
159 return;
160 }
161
162 va_list ArgList;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100163 char Title[80] = { };
Pascal Brandc639ac82015-07-02 08:53:34 +0200164
Pascal Brandc639ac82015-07-02 08:53:34 +0200165 va_start(ArgList, FormatTitle_p);
Jens Wiklander7e7c9c52016-12-27 17:57:46 +0100166 vsnprintf(Title, sizeof(Title), FormatTitle_p, ArgList);
Pascal Brandc639ac82015-07-02 08:53:34 +0200167 va_end(ArgList);
168
169 SubCase_p = ADBG_Case_CreateSubCase(Case_p, Title);
170
171 if (SubCase_p == NULL) {
172 Do_ADBG_Log("Do_ADBG_BeginSubCase: HEAP_ALLOC failed");
173 return;
174 }
175
176
177 if (ADBG_Case_SubCaseIsMain(Case_p, SubCase_p)) {
178 /* Main SubCase */
179 Do_ADBG_Log(" ");
180 Do_ADBG_Log("* %s %s", SubCase_p->TestID_p, SubCase_p->Title_p);
181 } else {
182 Do_ADBG_Log("o %s %s", SubCase_p->TestID_p, SubCase_p->Title_p);
183 }
184}
185
186void Do_ADBG_EndSubCase(
187 ADBG_Case_t *const Case_p,
188 const char *const FormatTitle_p, ...
189 )
190{
191 va_list ArgList;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100192 char Title[80] = { };
Pascal Brandc639ac82015-07-02 08:53:34 +0200193 ADBG_SubCase_t *SubCase_p = NULL;
194
195 if (Case_p == NULL) {
196 Do_ADBG_Log("Do_ADBG_EndSubCase: NULL Case_p!");
197 return;
198 }
199
200 if (FormatTitle_p == NULL) {
201 strcpy(Title, "NULL");
202 } else {
Pascal Brandc639ac82015-07-02 08:53:34 +0200203 va_start(ArgList, FormatTitle_p);
Jens Wiklander7e7c9c52016-12-27 17:57:46 +0100204 vsnprintf(Title, sizeof(Title), FormatTitle_p, ArgList);
Pascal Brandc639ac82015-07-02 08:53:34 +0200205 va_end(ArgList);
206 }
207
208
209 SubCase_p = Case_p->CurrentSubCase_p;
210
211 if (SubCase_p == NULL) {
212 Do_ADBG_Log("Do_ADBG_EndSubCase: "
213 "Have no active SubCase, bailing out for title \"%s\"",
214 Title);
215 return;
216 }
217
218 if (FormatTitle_p != NULL && strcmp(SubCase_p->Title_p, Title) != 0) {
219 Do_ADBG_Log("Do_ADBG_EndSubCase: "
220 "Active SubCase \"%s\" doesn't match supplied title \"%s\"",
221 SubCase_p->Title_p, Title);
222 return;
223 }
224
225 if (ADBG_Case_SubCaseIsMain(Case_p, SubCase_p)) {
226 if (FormatTitle_p == NULL) {
227 /* To end the main subcase we require
228 a matching title */
229 Do_ADBG_Log("Do_ADBG_EndSubCase: "
230 "The main SubCase \"%s\" doesn't match supplied title \"%s\"",
231 SubCase_p->Title_p, Title);
232 return;
233 }
234 /*
235 * Ending the main subcase
236 * make a complete copy of the aggregated result.
237 */
238 Case_p->Result = SubCase_p->Result;
239 } else {
240 /*
241 * Ending a subcase,
242 * Aggregate results to parent.
243 */
244 ADBG_SubCase_t *Parent_p = SubCase_p->Parent_p;
245
246 Parent_p->Result.NumSubTests += SubCase_p->Result.NumTests +
247 SubCase_p->Result.NumSubTests;
248 Parent_p->Result.NumFailedSubTests +=
249 SubCase_p->Result.NumFailedTests +
250 SubCase_p->Result.
251 NumFailedSubTests;
252 Parent_p->Result.AbortTestSuite =
253 SubCase_p->Result.AbortTestSuite;
254 if (SubCase_p->Result.NumTests > 0 ||
255 SubCase_p->Result.NumSubTests > 0)
256 Parent_p->Result.NumFailedSubCases++;
257 }
258
259 /* Print a summary of the subcase result */
260 if (SubCase_p->Result.NumFailedTests > 0 ||
261 SubCase_p->Result.NumFailedSubTests > 0) {
262 Do_ADBG_Log(" %s FAILED", SubCase_p->TestID_p);
263 } else {
264 Do_ADBG_Log(" %s OK", SubCase_p->TestID_p);
265 }
266
267 /* Update current subcase to be the parent of this subcase */
268 Case_p->CurrentSubCase_p =
269 ADBG_Case_GetParentSubCase(Case_p, SubCase_p);
270}
271
Pascal Brandc639ac82015-07-02 08:53:34 +0200272/*************************************************************************
273* 6. Definition of internal functions
274*************************************************************************/
275static ADBG_SubCase_t *ADBG_Case_CreateSubCase(
276 ADBG_Case_t *Case_p,
277 const char *const Title_p
278 )
279{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100280 ADBG_SubCase_t *SubCase_p = NULL;
Pascal Brandc639ac82015-07-02 08:53:34 +0200281
Jens Wiklander7c30dfd2016-12-27 21:59:36 +0100282 SubCase_p = calloc(1, sizeof(*SubCase_p));
Pascal Brandc639ac82015-07-02 08:53:34 +0200283 if (SubCase_p == NULL)
284 goto ErrorReturn;
285
Pascal Brandc639ac82015-07-02 08:53:34 +0200286 TAILQ_INIT(&SubCase_p->SubCasesList);
287
Jens Wiklander7c30dfd2016-12-27 21:59:36 +0100288 SubCase_p->Title_p = strdup(Title_p);
Pascal Brandc639ac82015-07-02 08:53:34 +0200289 if (SubCase_p->Title_p == NULL)
290 goto ErrorReturn;
291
292 /* Set parent pointer needed "early" below. */
293 SubCase_p->Parent_p = Case_p->CurrentSubCase_p;
294
295 if (SubCase_p->Parent_p == NULL) {
296 /* Main SubCase */
Jens Wiklander7c30dfd2016-12-27 21:59:36 +0100297 SubCase_p->TestID_p = strdup(ADBG_Case_GetTestID(Case_p));
Pascal Brandc639ac82015-07-02 08:53:34 +0200298 if (SubCase_p->TestID_p == NULL)
299 goto ErrorReturn;
300
301 Case_p->FirstSubCase_p = SubCase_p;
302 } else {
303 ADBG_SubCase_t *Parent_p = SubCase_p->Parent_p;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100304 char PrefixTitle[80] = { };
Pascal Brandc639ac82015-07-02 08:53:34 +0200305
306 /* Update parent SubCase */
307 Parent_p->Result.NumSubCases++;
Jens Wiklander7e7c9c52016-12-27 17:57:46 +0100308 snprintf(PrefixTitle, sizeof(PrefixTitle), "%s.%d",
309 Parent_p->TestID_p, Parent_p->Result.NumSubCases);
Jens Wiklander7c30dfd2016-12-27 21:59:36 +0100310 SubCase_p->TestID_p = strdup(PrefixTitle);
Pascal Brandc639ac82015-07-02 08:53:34 +0200311 if (SubCase_p->TestID_p == NULL)
312 goto ErrorReturn;
313
314 TAILQ_INSERT_TAIL(&Parent_p->SubCasesList, SubCase_p, Link);
315 }
316
317 Case_p->CurrentSubCase_p = SubCase_p;
318 return SubCase_p;
319
320ErrorReturn:
321 ADBG_SubCase_Delete(SubCase_p);
322 return NULL;
323}
324
325static void ADBG_SubCase_Delete(
326 ADBG_SubCase_t *SubCase_p
327 )
328{
329 if (SubCase_p != NULL) {
330 /*
331 * Note that Util_ListDestroy() checks
332 * if SubCase_p->SubCasesList_p
333 * is NULL.
334 */
335 while (true) {
336 ADBG_SubCase_t *s =
337 TAILQ_FIRST(&SubCase_p->SubCasesList);
338
339 if (s == NULL)
340 break;
341
342 TAILQ_REMOVE(&SubCase_p->SubCasesList, s, Link);
343 ADBG_SubCase_Delete(s);
344 }
Jens Wiklander7c30dfd2016-12-27 21:59:36 +0100345 free(SubCase_p->TestID_p);
346 free(SubCase_p->Title_p);
347 free(SubCase_p);
Pascal Brandc639ac82015-07-02 08:53:34 +0200348 }
349}
350
351ADBG_SubCase_t *ADBG_Case_GetParentSubCase(
352 ADBG_Case_t *Case_p,
353 ADBG_SubCase_t *SubCase_p
354 )
355{
356 IDENTIFIER_NOT_USED(Case_p)
357 IDENTIFIER_NOT_USED(SubCase_p)
358 return SubCase_p->Parent_p;
359}
360
361static const char *ADBG_Case_GetTestID(ADBG_Case_t *Case_p)
362{
363 IDENTIFIER_NOT_USED(Case_p)
364
Jens Wiklander74abfe32017-01-03 14:17:47 +0100365 return Case_p->case_def->TestID_p;
Pascal Brandc639ac82015-07-02 08:53:34 +0200366}