* support/regression/fwk/lib/testfwk.c: printn is recursive and thus needs
[fw/sdcc] / support / regression / fwk / lib / testfwk.c
1 /** Test framework support functions.
2  */
3 #include <testfwk.h>
4 #include <stdarg.h>
5
6 #ifdef __ds390
7 #include <tinibios.h> /* main() must see the ISR declarations */
8 #endif
9
10 #if defined(PORT_HOST) || defined(SDCC_z80) || defined(SDCC_gbz80)
11 #define _REENTRANT
12 #else
13 #define _REENTRANT reentrant
14 #endif
15
16 /** Define this if the port's div or mod functions are broken.
17     A slow loop based method will be substituded.
18 */
19 //#define BROKEN_DIV_MOD                1
20
21 void _putchar(char c);
22 void _exitEmu(void);
23
24 #if BROKEN_DIV_MOD
25 int __div(int num, int denom)
26 {
27     int q = 0;
28     while (num >= denom) {
29         q++;
30         num -= denom;
31     }
32     return q;
33 }
34
35 int __mod(int num, int denom)
36 {
37     while (num >= denom) {
38         num -= denom;
39     }
40     return num;
41 }
42 #else
43 int __div(int num, int denom)
44 {
45     return num/denom;
46 }
47
48 int __mod(int num, int denom)
49 {
50     return num%denom;
51 }
52 #endif
53
54 static void _printn(int n) _REENTRANT
55 {
56     int rem;
57
58     if (n < 0) {
59         _putchar('-');
60         n = -n;
61     }
62
63     rem = __mod(n, 10);
64     if (rem != n) {
65         _printn(__div(n, 10));
66     }
67     _putchar('0' + rem);
68 }
69
70 void __printf(const char *szFormat, ...) REENTRANT
71 {
72     va_list ap;
73     va_start(ap, szFormat);
74
75     while (*szFormat) {
76         if (*szFormat == '%') {
77             switch (*++szFormat) {
78             case 's': {
79                 char *sz = va_arg(ap, char *);
80                 while (*sz) {
81                     _putchar(*sz++);
82                 }
83                 break;
84             }
85             case 'u': {
86                 int i = va_arg(ap, int);
87                 _printn(i);
88                 break;
89             }
90             case '%':
91                 _putchar('%');
92                 break;
93             default:
94                 break;
95             }
96         }
97         else {
98             _putchar(*szFormat);
99         }
100         szFormat++;
101     }
102     va_end(ap);
103 }
104
105 int __numTests;
106 int __numFailures;
107
108 void 
109 __fail(const char *szMsg, const char *szCond, const char *szFile, int line)
110 {
111     __printf("--- FAIL: \"%s\" on %s at %s:%u\n", szMsg, szCond, szFile, line);
112     __numFailures++;
113 }
114
115 int 
116 main(void)
117 {
118     TESTFUNP *cases;
119     int numCases = 0;
120
121     __printf("--- Running: %s\n", getSuiteName());
122
123     cases = suite();
124
125     while (*cases) {
126         __printf("Running %u\n", numCases);
127         (*cases)();
128         cases++;
129         numCases++;
130     }
131     
132     __printf("--- Summary: %u/%u/%u: %u failed of %u tests in %u cases.\n", 
133            __numFailures, __numTests, numCases,
134            __numFailures, __numTests, numCases
135            );
136
137     _exitEmu();
138
139     return 0;
140 }