Line data Source code
1 : /* test.c - Infrastructure for unit tests.
2 : * Copyright (C) 2015 g10 Code GmbH
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 : #include <string.h>
24 :
25 : #include "gpg.h"
26 :
27 : /* A unit test consists of one or more tests. Tests can be broken
28 : into groups and each group can consist of one or more tests. */
29 :
30 : /* The number of test groups. */
31 : static int test_groups;
32 : /* The current test group. */
33 : static char *test_group;
34 :
35 : /* Whether there was already a failure in the current test group. */
36 : static int current_test_group_failed;
37 : /* The number of test groups with a failure. */
38 : static int test_groups_failed;
39 :
40 : /* The total number of tests. */
41 : static int tests;
42 : /* The total number of tests that failed. */
43 : static int tests_failed;
44 :
45 : /* Flag to request verbose diagnostics. This is set if the envvar
46 : "verbose" exists and is not the empty string. */
47 : static int verbose;
48 :
49 : #define TEST_GROUP(description) \
50 : do { \
51 : test_group = (description); \
52 : test_groups ++; \
53 : current_test_group_failed = 0; \
54 : } while (0)
55 :
56 : #define STRINGIFY2(x) #x
57 : #define STRINGIFY(x) STRINGIFY2(x)
58 :
59 : /* Execute a test. */
60 : #define TEST(description, test, expected) \
61 : do { \
62 : int test_result; \
63 : int expected_result; \
64 : \
65 : tests ++; \
66 : if (verbose) \
67 : { \
68 : printf ("%d. Checking %s...", \
69 : tests, (description) ?: ""); \
70 : fflush (stdout); \
71 : } \
72 : test_result = (test); \
73 : expected_result = (expected); \
74 : \
75 : if (test_result == expected_result) \
76 : { \
77 : if (verbose) printf (" ok.\n"); \
78 : } \
79 : else \
80 : { \
81 : if (!verbose) \
82 : printf ("%d. Checking %s...", \
83 : tests, (description) ?: ""); \
84 : printf (" failed.\n"); \
85 : printf (" %s == %s failed.\n", \
86 : STRINGIFY(test), \
87 : STRINGIFY(expected)); \
88 : tests_failed ++; \
89 : if (! current_test_group_failed) \
90 : { \
91 : current_test_group_failed = 1; \
92 : test_groups_failed ++; \
93 : } \
94 : } \
95 : } while (0)
96 :
97 : /* Test that a condition evaluates to true. */
98 : #define TEST_P(description, test) \
99 : TEST(description, !!(test), 1)
100 :
101 : /* Like CHECK, but if the test fails, abort the program. */
102 : #define ASSERT(description, test, expected) \
103 : do { \
104 : int tests_failed_pre = tests_failed; \
105 : CHECK(description, test, expected); \
106 : if (tests_failed_pre != tests_failed) \
107 : exit_tests (1); \
108 : } while (0)
109 :
110 : /* Call this if something went wrong. */
111 : #define ABORT(message) \
112 : do { \
113 : printf ("aborting..."); \
114 : if (message) \
115 : printf (" %s\n", (message)); \
116 : \
117 : exit_tests (1); \
118 : } while (0)
119 :
120 : /* You need to fill this function in. */
121 : static void do_test (int argc, char *argv[]);
122 :
123 :
124 : /* Print stats and call the real exit. If FORCE is set use
125 : EXIT_FAILURE even if no test has failed. */
126 : static void
127 2 : exit_tests (int force)
128 : {
129 2 : if (tests_failed == 0)
130 : {
131 2 : if (verbose)
132 0 : printf ("All %d tests passed.\n", tests);
133 2 : exit (!!force);
134 : }
135 : else
136 : {
137 0 : printf ("%d of %d tests failed",
138 : tests_failed, tests);
139 0 : if (test_groups > 1)
140 0 : printf (" (%d of %d groups)",
141 : test_groups_failed, test_groups);
142 0 : printf ("\n");
143 0 : exit (1);
144 : }
145 : }
146 :
147 :
148 : /* Prepend FNAME with the srcdir environment variable's value and
149 : return a malloced filename. Caller must release the returned
150 : string using test_free. */
151 : char *
152 2 : prepend_srcdir (const char *fname)
153 : {
154 : static const char *srcdir;
155 : char *result;
156 :
157 2 : if (!srcdir && !(srcdir = getenv ("srcdir")))
158 0 : srcdir = ".";
159 :
160 2 : result = malloc (strlen (srcdir) + 1 + strlen (fname) + 1);
161 2 : strcpy (result, srcdir);
162 2 : strcat (result, "/");
163 2 : strcat (result, fname);
164 2 : return result;
165 : }
166 :
167 :
168 : void
169 2 : test_free (void *a)
170 : {
171 2 : if (a)
172 2 : free (a);
173 2 : }
174 :
175 :
176 : int
177 2 : main (int argc, char *argv[])
178 : {
179 : const char *s;
180 :
181 : (void) test_group;
182 :
183 2 : s = getenv ("verbose");
184 2 : if (s && *s)
185 0 : verbose = 1;
186 :
187 2 : do_test (argc, argv);
188 2 : exit_tests (0);
189 :
190 0 : return !!tests_failed;
191 : }
|