1 /*-----------------------------------------------------------------------------
2 * Name: cv_report.c
3 * Purpose: Report statistics and layout implementation
4 *-----------------------------------------------------------------------------
5 * Copyright (c) 2017 - 2018 Arm Limited. All rights reserved.
6 *----------------------------------------------------------------------------*/
7 #include "CV_Report.h"
8 #include <stdio.h>
9 #include <string.h>
10
11 TEST_REPORT test_report;
12 static AS_STAT current_assertions; /* Current test case assertions statistics */
13 #define TAS (&test_report.assertions) /* Total assertions */
14 #define CAS (¤t_assertions) /* Current assertions */
15
16 #ifdef DISABLE_SEMIHOSTING
17 #if defined (__CC_ARM)
18 #pragma import __use_no_semihosting
19 #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
20 __ASM(".global __use_no_semihosting");
21 #endif
22 #define PRINT(x)
23 #define FLUSH()
_sys_exit(int return_code)24 void _sys_exit(int return_code) {}
25 #else
26 #define PRINT(x) MsgPrint x
27 #define FLUSH() MsgFlush()
28 #endif // DISABLE_SEMIHOSTING
29
30 static uint8_t Passed[] = "PASSED";
31 static uint8_t Warning[] = "WARNING";
32 static uint8_t Failed[] = "FAILED";
33 static uint8_t NotExe[] = "NOT EXECUTED";
34
35
36 /*-----------------------------------------------------------------------------
37 * Test report function prototypes
38 *----------------------------------------------------------------------------*/
39 static BOOL tr_Init (void);
40 static BOOL tc_Init (void);
41 static uint8_t *tr_Eval (void);
42 static uint8_t *tc_Eval (void);
43 static BOOL StatCount (TC_RES res);
44
45 /*-----------------------------------------------------------------------------
46 * Printer function prototypes
47 *----------------------------------------------------------------------------*/
48 static void MsgPrint (const char *msg, ...);
49 static void MsgFlush (void);
50
51
52 /*-----------------------------------------------------------------------------
53 * Assert interface function prototypes
54 *----------------------------------------------------------------------------*/
55 static BOOL As_File_Result (TC_RES res);
56 static BOOL As_File_Dbgi (TC_RES res, const char *fn, uint32_t ln, char *desc);
57
58 TC_ITF tcitf = {
59 As_File_Result,
60 As_File_Dbgi,
61 };
62
63
64 /*-----------------------------------------------------------------------------
65 * Test report interface function prototypes
66 *----------------------------------------------------------------------------*/
67 BOOL tr_File_Init (void);
68 BOOL tr_File_Open (const char *title, const char *date, const char *time, const char *fn);
69 BOOL tr_File_Close (void);
70 BOOL tc_File_Open (uint32_t num, const char *fn);
71 BOOL tc_File_Close (void);
72
73 REPORT_ITF ritf = {
74 tr_File_Init,
75 tr_File_Open,
76 tr_File_Close,
77 tc_File_Open,
78 tc_File_Close
79 };
80
81
82 /*-----------------------------------------------------------------------------
83 * Init test report
84 *----------------------------------------------------------------------------*/
tr_File_Init(void)85 BOOL tr_File_Init (void) {
86 return (tr_Init());
87 }
88
89
90 /*-----------------------------------------------------------------------------
91 * Open test report
92 *----------------------------------------------------------------------------*/
93 #if (PRINT_XML_REPORT==1)
tr_File_Open(const char * title,const char * date,const char * time,const char * fn)94 BOOL tr_File_Open (const char *title, const char *date, const char *time, const char *fn) {
95 PRINT(("<?xml version=\"1.0\"?>\n"));
96 PRINT(("<?xml-stylesheet href=\"TR_Style.xsl\" type=\"text/xsl\" ?>\n"));
97 PRINT(("<report>\n"));
98 PRINT(("<test>\n"));
99 PRINT(("<title>%s</title>\n", title));
100 PRINT(("<date>%s</date>\n", date));
101 PRINT(("<time>%s</time>\n", time));
102 PRINT(("<file>%s</file>\n", fn));
103 PRINT(("<test_cases>\n"));
104 #else
105 BOOL tr_File_Open (const char *title, const char *date, const char *time, const char __attribute__((unused)) *fn) {
106 PRINT(("%s %s %s \n\n", title, date, time));
107 #endif
108 return (__TRUE);
109 }
110
111
112 /*-----------------------------------------------------------------------------
113 * Open test case
114 *----------------------------------------------------------------------------*/
115 BOOL tc_File_Open (uint32_t num, const char *fn) {
116 (void)tc_Init ();
117 #if (PRINT_XML_REPORT==1)
118 PRINT(("<tc>\n"));
119 PRINT(("<no>%d</no>\n", num));
120 PRINT(("<func>%s</func>\n", fn));
121 PRINT(("<req></req>"));
122 PRINT(("<meth></meth>"));
123 PRINT(("<dbgi>\n"));
124 #else
125 PRINT(("TEST %02d: %-42s ", num, fn));
126 #endif
127 return (__TRUE);
128 }
129
130
131 /*-----------------------------------------------------------------------------
132 * Close test case
133 *----------------------------------------------------------------------------*/
134 BOOL tc_File_Close (void) {
135 uint8_t *res = tc_Eval();
136 #if (PRINT_XML_REPORT==1)
137 PRINT(("</dbgi>\n"));
138 PRINT(("<res>%s</res>\n", res));
139 PRINT(("</tc>\n"));
140 #else
141 if ((res==Passed)||(res==NotExe)) {
142 PRINT(("%s\n", res));
143 } else {
144 PRINT(("\n"));
145 }
146 #endif
147 FLUSH();
148 return (__TRUE);
149 }
150
151
152 /*-----------------------------------------------------------------------------
153 * Close test report
154 *----------------------------------------------------------------------------*/
155 BOOL tr_File_Close (void) {
156 #if (PRINT_XML_REPORT==1)
157 PRINT(("</test_cases>\n"));
158 PRINT(("<summary>\n"));
159 PRINT(("<tcnt>%d</tcnt>\n", test_report.tests));
160 PRINT(("<exec>%d</exec>\n", test_report.executed));
161 PRINT(("<pass>%d</pass>\n", test_report.passed));
162 PRINT(("<fail>%d</fail>\n", test_report.failed));
163 PRINT(("<warn>%d</warn>\n", test_report.warnings));
164 PRINT(("<tres>%s</tres>\n", tr_Eval()));
165 PRINT(("</summary>\n"));
166 PRINT(("</test>\n"));
167 PRINT(("</report>\n"));
168 #else
169 PRINT(("\nTest Summary: %d Tests, %d Executed, %d Passed, %d Failed, %d Warnings.\n",
170 test_report.tests,
171 test_report.executed,
172 test_report.passed,
173 test_report.failed,
174 test_report.warnings));
175 PRINT(("Test Result: %s\n", tr_Eval()));
176 #endif
177 FLUSH();
178 return (__TRUE);
179 }
180
181
182 /*-----------------------------------------------------------------------------
183 * Assertion result counter
184 *----------------------------------------------------------------------------*/
185 static BOOL As_File_Result (TC_RES res) {
186 return (StatCount (res));
187 }
188
189
190 /*-----------------------------------------------------------------------------
191 * Set debug information state
192 *----------------------------------------------------------------------------*/
193 #if (PRINT_XML_REPORT==1)
194 static BOOL As_File_Dbgi (TC_RES __attribute__((unused)) res, const char *fn, uint32_t ln, char *desc) {
195 PRINT(("<detail>\n"));
196 if (desc!=NULL) PRINT(("<desc>%s</desc>\n", desc));
197 PRINT(("<module>%s</module>\n", fn));
198 PRINT(("<line>%d</line>\n", ln));
199 PRINT(("</detail>\n"));
200 #else
201 static BOOL As_File_Dbgi (TC_RES res, const char *fn, uint32_t ln, char *desc) {
202 PRINT(("\n %s (%d)", fn, ln));
203 if (res==WARNING){ PRINT((" [WARNING]")); }
204 if (res==FAILED) { PRINT((" [FAILED]")); }
205 if (desc!=NULL) { PRINT((" %s", desc)); }
206 #endif
207 return (__TRUE);
208 }
209
210
211 /*-----------------------------------------------------------------------------
212 * Init test report
213 *----------------------------------------------------------------------------*/
214 static BOOL tr_Init (void) {
215 TAS->passed = 0;
216 TAS->failed = 0;
217 TAS->warnings = 0;
218 return (__TRUE);
219 }
220
221
222 /*-----------------------------------------------------------------------------
223 * Init test case
224 *----------------------------------------------------------------------------*/
225 static BOOL tc_Init (void) {
226 CAS->passed = 0;
227 CAS->failed = 0;
228 CAS->warnings = 0;
229 return (__TRUE);
230 }
231
232
233 /*-----------------------------------------------------------------------------
234 * Evaluate test report results
235 *----------------------------------------------------------------------------*/
236 static uint8_t *tr_Eval (void) {
237 if (test_report.failed > 0U) {
238 /* Test fails if any test case failed */
239 return (Failed);
240 }
241 else if (test_report.warnings > 0U) {
242 /* Test warns if any test case warnings */
243 return (Warning);
244 }
245 else if (test_report.passed > 0U) {
246 /* Test passes if at least one test case passed */
247 return (Passed);
248 }
249 else {
250 /* No test cases were executed */
251 return (NotExe);
252 }
253 }
254
255
256 /*-----------------------------------------------------------------------------
257 * Evaluate test case results
258 *----------------------------------------------------------------------------*/
259 static uint8_t *tc_Eval (void) {
260 test_report.tests++;
261 test_report.executed++;
262
263 if (CAS->failed > 0U) {
264 /* Test case fails if any failed assertion recorded */
265 test_report.failed++;
266 return Failed;
267 }
268 else if (CAS->warnings > 0U) {
269 /* Test case warns if any warnings assertion recorded */
270 test_report.warnings++;
271 return Warning;
272 }
273 else if (CAS->passed > 0U) {
274 /* Test case passes if at least one assertion passed */
275 test_report.passed++;
276 return Passed;
277 }
278 else {
279 /* Assert was not invoked - nothing to evaluate */
280 test_report.executed--;
281 return NotExe;
282 }
283 }
284
285
286 /*-----------------------------------------------------------------------------
287 * Statistics result counter
288 *----------------------------------------------------------------------------*/
289 static BOOL StatCount (TC_RES res) {
290 switch (res) {
291 case PASSED:
292 CAS->passed++;
293 TAS->passed++;
294 break;
295
296 case WARNING:
297 CAS->warnings++;
298 TAS->warnings++;
299 break;
300
301 case FAILED:
302 CAS->failed++;
303 TAS->failed++;
304 break;
305
306 case NOT_EXECUTED:
307 return (__FALSE);
308
309 default:
310 break;
311 }
312 return (__TRUE);
313 }
314
315
316 /*-----------------------------------------------------------------------------
317 * Set result
318 *----------------------------------------------------------------------------*/
319 TC_RES __set_result (const char *fn, uint32_t ln, TC_RES res, char* desc) {
320
321 // save assertion result
322 switch (res) {
323 case PASSED:
324 if (TAS->passed < BUFFER_ASSERTIONS) {
325 test_report.assertions.info.passed[TAS->passed].module = fn;
326 test_report.assertions.info.passed[TAS->passed].line = ln;
327 }
328 break;
329 case FAILED:
330 if (TAS->failed < BUFFER_ASSERTIONS) {
331 test_report.assertions.info.failed[TAS->failed].module = fn;
332 test_report.assertions.info.failed[TAS->failed].line = ln;
333 }
334 break;
335 case WARNING:
336 if (TAS->warnings < BUFFER_ASSERTIONS) {
337 test_report.assertions.info.warnings[TAS->warnings].module = fn;
338 test_report.assertions.info.warnings[TAS->warnings].line = ln;
339 }
340 break;
341 case NOT_EXECUTED:
342 break;
343
344 default:
345 break;
346 }
347
348 // set debug info (if the test case didn't pass)
349 if (res != PASSED) { (void)tcitf.Dbgi (res, fn, ln, desc); }
350 // set result
351 (void)tcitf.Result (res);
352 return (res);
353 }
354
355 /*-----------------------------------------------------------------------------
356 * Assert true
357 *----------------------------------------------------------------------------*/
358 TC_RES __assert_true (const char *fn, uint32_t ln, uint32_t cond) {
359 TC_RES res = FAILED;
360 if (cond != 0U) { res = PASSED; }
361 (void)__set_result(fn, ln, res, NULL);
362 return (res);
363 }
364
365 #ifndef DISABLE_SEMIHOSTING
366 /*-----------------------------------------------------------------------------
367 * MsgFlush: Flush the standard output
368 *----------------------------------------------------------------------------*/
369 static void MsgFlush(void) {
370 (void)fflush(stdout);
371 }
372
373 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
374 #pragma clang diagnostic push
375 #pragma clang diagnostic ignored "-Wformat-nonliteral"
376 #endif
377 /*-----------------------------------------------------------------------------
378 * MsgPrint: Print a message to the standard output
379 *----------------------------------------------------------------------------*/
380 static void MsgPrint (const char *msg, ...) {
381 va_list args;
382 va_start(args, msg);
383 vprintf(msg, args);
384 va_end(args);
385 }
386 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
387 #pragma clang diagnostic pop
388 #endif
389 #endif // DISABLE_SEMIHOSTING
390
391 /*-----------------------------------------------------------------------------
392 * End of file
393 *----------------------------------------------------------------------------*/
394