Imported Upstream version 3.5.1
[platform/upstream/ccache.git] / unittest / framework.c
1 // Copyright (C) 2010-2018 Joel Rosdahl
2 //
3 // This program is free software; you can redistribute it and/or modify it
4 // under the terms of the GNU General Public License as published by the Free
5 // Software Foundation; either version 3 of the License, or (at your option)
6 // any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but WITHOUT
9 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 // more details.
12 //
13 // You should have received a copy of the GNU General Public License along with
14 // this program; if not, write to the Free Software Foundation, Inc., 51
15 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17 #include "framework.h"
18 #include "util.h"
19
20 #include <float.h>
21 #include <math.h>
22 #if defined(HAVE_TERMIOS_H)
23 #define USE_COLOR
24 #include <termios.h>
25 #endif
26
27 static unsigned total_asserts;
28 static unsigned total_tests;
29 static unsigned total_suites;
30 static unsigned failed_tests;
31 static const char *current_suite;
32 static const char *current_test;
33 static char *dir_before_suite;
34 static char *dir_before_test;
35 static int verbose;
36
37 static const char COLOR_END[] = "\x1b[m";
38 static const char COLOR_GREEN[] = "\x1b[1;32m";
39 static const char COLOR_RED[] = "\x1b[1;31m";
40
41 #define COLOR(tty, color) ((tty) ? COLOR_ ## color : "")
42
43 static int
44 is_tty(int fd)
45 {
46 #ifdef USE_COLOR
47         struct termios t;
48         return tcgetattr(fd, &t) == 0;
49 #else
50         (void)fd;
51         return 0;
52 #endif
53 }
54
55 static const char *
56 plural_s(unsigned n)
57 {
58         return n == 1 ? "" : "s";
59 }
60
61 int
62 cct_run(suite_fn *suites, int verbose_output)
63 {
64         suite_fn *suite;
65         int tty = is_tty(1);
66
67         x_unsetenv("GCC_COLORS"); // Avoid confusing argument processing tests.
68         verbose = verbose_output;
69
70         for (suite = suites; *suite; suite++) {
71                 unsigned test_index = 0;
72                 while (true) {
73                         test_index = (*suite)(test_index + 1);
74                         if (test_index == 0) {
75                                 // We have reached the end of the suite.
76                                 break;
77                         }
78                 }
79         }
80
81         if (failed_tests == 0) {
82                 printf("%sPASSED%s: %u assertion%s, %u test%s, %u suite%s\n",
83                        COLOR(tty, GREEN), COLOR(tty, END),
84                        total_asserts, plural_s(total_asserts),
85                        total_tests, plural_s(total_tests),
86                        total_suites, plural_s(total_suites));
87         } else {
88                 printf("%sFAILED%s: %u test%s\n",
89                        COLOR(tty, RED), COLOR(tty, END),
90                        failed_tests, plural_s(failed_tests));
91         }
92         return failed_tests > 0 ? 1 : 0;
93 }
94
95 void
96 cct_suite_begin(const char *name)
97 {
98         ++total_suites;
99         if (verbose) {
100                 printf("=== SUITE: %s ===\n", name);
101         }
102         dir_before_suite = gnu_getcwd();
103         create_dir(name);
104         cct_chdir(name);
105         current_suite = name;
106 }
107
108 void
109 cct_suite_end()
110 {
111         cct_chdir(dir_before_suite);
112         free(dir_before_suite);
113         dir_before_suite = NULL;
114 }
115
116 void
117 cct_test_begin(const char *name)
118 {
119         ++total_tests;
120         if (verbose) {
121                 printf("--- TEST: %s ---\n", name);
122         }
123         dir_before_test = gnu_getcwd();
124         create_dir(name);
125         cct_chdir(name);
126         current_test = name;
127
128         putenv("CCACHE_CONFIG_PATH=/dev/null");
129         cc_reset();
130 }
131
132 void
133 cct_test_end()
134 {
135         if (dir_before_test) {
136                 cct_chdir(dir_before_test);
137                 free(dir_before_test);
138                 dir_before_test = NULL;
139         }
140 }
141
142 void
143 cct_check_passed(const char *file, int line, const char *what)
144 {
145         ++total_asserts;
146         if (verbose) {
147                 printf("%s:%d: Passed assertion: %s\n", file, line, what);
148         }
149 }
150
151 void
152 cct_check_failed(const char *file, int line, const char *what,
153                  const char *expected, const char *actual)
154 {
155         ++total_asserts;
156         ++failed_tests;
157         fprintf(stderr, "%s:%d: Failed assertion:\n", file, line);
158         fprintf(stderr, "  Suite:      %s\n", current_suite);
159         fprintf(stderr, "  Test:       %s\n", current_test);
160         if (expected) {
161                 fprintf(stderr, "  Expression: %s\n", what);
162                 if (actual) {
163                         fprintf(stderr, "  Expected:   %s\n", expected);
164                         fprintf(stderr, "  Actual:     %s\n", actual);
165                 } else {
166                         fprintf(stderr, "  Message:    %s\n", expected);
167                 }
168         } else {
169                 fprintf(stderr, "  Assertion:  %s\n", what);
170         }
171         fprintf(stderr, "\n");
172 }
173
174 bool
175 cct_check_double_eq(const char *file, int line, const char *expression,
176                     double expected, double actual)
177 {
178         if (fabs(expected -  actual) < DBL_EPSILON) {
179                 cct_check_passed(file, line, expression);
180                 return true;
181         } else {
182                 char *exp_str = format("%.1f", expected);
183                 char *act_str = format("%.1f", actual);
184                 cct_check_failed(file, line, expression, exp_str, act_str);
185                 free(exp_str);
186                 free(act_str);
187                 return false;
188         }
189 }
190 bool
191 cct_check_int_eq(const char *file, int line, const char *expression,
192                  int64_t expected, int64_t actual)
193 {
194         if (expected == actual) {
195                 cct_check_passed(file, line, expression);
196                 return true;
197         } else {
198 #if defined(HAVE_LONG_LONG) && !defined(__MINGW32__)
199                 char *exp_str = format("%lld", (long long)expected);
200                 char *act_str = format("%lld", (long long)actual);
201 #else
202                 char *exp_str = format("%ld", (long)expected);
203                 char *act_str = format("%ld", (long)actual);
204 #endif
205                 cct_check_failed(file, line, expression, exp_str, act_str);
206                 free(exp_str);
207                 free(act_str);
208                 return false;
209         }
210 }
211
212 bool
213 cct_check_str_eq(const char *file, int line, const char *expression,
214                  char *expected, char *actual,
215                  bool free1, bool free2)
216 {
217         bool result;
218
219         if (expected && actual && str_eq(actual, expected)) {
220                 cct_check_passed(file, line, expression);
221                 result = true;
222         } else {
223                 char *exp_str = expected ? format("\"%s\"", expected) : x_strdup("(null)");
224                 char *act_str = actual ? format("\"%s\"", actual) : x_strdup("(null)");
225                 cct_check_failed(file, line, expression, exp_str, act_str);
226                 free(exp_str);
227                 free(act_str);
228                 result = false;
229         }
230
231         if (free1) {
232                 free(expected);
233         }
234         if (free2) {
235                 free(actual);
236         }
237         return result;
238 }
239
240 bool
241 cct_check_args_eq(const char *file, int line, const char *expression,
242                   struct args *expected, struct args *actual,
243                   bool free1, bool free2)
244 {
245         bool result;
246
247         if (expected && actual && args_equal(actual, expected)) {
248                 cct_check_passed(file, line, expression);
249                 result = true;
250         } else {
251                 char *exp_str = expected ? args_to_string(expected) : x_strdup("(null)");
252                 char *act_str = actual ? args_to_string(actual) : x_strdup("(null)");
253                 cct_check_failed(file, line, expression, exp_str, act_str);
254                 free(exp_str);
255                 free(act_str);
256                 result = false;
257         }
258
259         if (free1) {
260                 args_free(expected);
261         }
262         if (free2) {
263                 args_free(actual);
264         }
265         return result;
266 }
267
268 void
269 cct_chdir(const char *path)
270 {
271         if (chdir(path) != 0) {
272                 fprintf(stderr, "chdir: %s: %s", path, strerror(errno));
273                 abort();
274         }
275 }
276
277 void
278 cct_wipe(const char *path)
279 {
280         // TODO: rewrite using traverse().
281 #ifndef __MINGW32__
282         char *command = format("rm -rf %s", path);
283 #else
284         char *command = format("rd /s /q %s", path);
285 #endif
286         if (system(command) != 0) {
287                 perror(command);
288         }
289         free(command);
290 }
291
292 void
293 cct_create_fresh_dir(const char *path)
294 {
295         cct_wipe(path);
296         if (mkdir(path, 0777) != 0) {
297                 fprintf(stderr, "mkdir: %s: %s", path, strerror(errno));;
298                 abort();
299         }
300 }