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