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 <http://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 : \
67 : printf ("%d. Checking %s...", \
68 : tests, (description) ?: ""); \
69 : fflush (stdout); \
70 : \
71 : test_result = (test); \
72 : expected_result = (expected); \
73 : \
74 : if (test_result == expected_result) \
75 : { \
76 : printf (" ok.\n"); \
77 : } \
78 : else \
79 : { \
80 : printf (" failed.\n"); \
81 : printf (" %s == %s failed.\n", \
82 : STRINGIFY(test), \
83 : STRINGIFY(expected)); \
84 : tests_failed ++; \
85 : if (! current_test_group_failed) \
86 : { \
87 : current_test_group_failed = 1; \
88 : test_groups_failed ++; \
89 : } \
90 : } \
91 : } while (0)
92 :
93 : /* Test that a condition evaluates to true. */
94 : #define TEST_P(description, test) \
95 : TEST(description, !!(test), 1)
96 :
97 : /* Like CHECK, but if the test fails, abort the program. */
98 : #define ASSERT(description, test, expected) \
99 : do { \
100 : int tests_failed_pre = tests_failed; \
101 : CHECK(description, test, expected); \
102 : if (tests_failed_pre != tests_failed) \
103 : exit_tests (1); \
104 : } while (0)
105 :
106 : /* Call this if something went wrong. */
107 : #define ABORT(message) \
108 : do { \
109 : printf ("aborting..."); \
110 : if (message) \
111 : printf (" %s\n", (message)); \
112 : \
113 : exit_tests (1); \
114 : } while (0)
115 :
116 : /* You need to fill this function in. */
117 : static void do_test (int argc, char *argv[]);
118 :
119 :
120 : /* Print stats and call the real exit. If FORCE is set use
121 : EXIT_FAILURE even if no test has failed. */
122 : static void
123 1 : exit_tests (int force)
124 : {
125 1 : if (tests_failed == 0)
126 : {
127 1 : printf ("All %d tests passed.\n", tests);
128 1 : exit (!!force);
129 : }
130 : else
131 : {
132 0 : printf ("%d of %d tests failed",
133 : tests_failed, tests);
134 0 : if (test_groups > 1)
135 0 : printf (" (%d of %d groups)",
136 : test_groups_failed, test_groups);
137 0 : printf ("\n");
138 0 : exit (1);
139 : }
140 : }
141 :
142 :
143 : /* Prepend FNAME with the srcdir environment variable's value and
144 : return a malloced filename. Caller must release the returned
145 : string using test_free. */
146 : char *
147 1 : prepend_srcdir (const char *fname)
148 : {
149 : static const char *srcdir;
150 : char *result;
151 :
152 1 : if (!srcdir && !(srcdir = getenv ("srcdir")))
153 0 : srcdir = ".";
154 :
155 1 : result = malloc (strlen (srcdir) + 1 + strlen (fname) + 1);
156 1 : strcpy (result, srcdir);
157 1 : strcat (result, "/");
158 1 : strcat (result, fname);
159 1 : return result;
160 : }
161 :
162 :
163 : void
164 1 : test_free (void *a)
165 : {
166 1 : if (a)
167 1 : free (a);
168 1 : }
169 :
170 :
171 : int
172 1 : main (int argc, char *argv[])
173 : {
174 : const char *s;
175 :
176 : (void) test_group;
177 :
178 1 : s = getenv ("verbose");
179 1 : if (s && *s)
180 0 : verbose = 1;
181 :
182 1 : do_test (argc, argv);
183 1 : exit_tests (0);
184 :
185 0 : return !!tests_failed;
186 : }
|