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 (&current_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