1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5  * testutil.h
6  *
7  * Utility functions for handling test errors
8  *
9  */
10 
11 #ifndef _TESTUTIL_H
12 #define _TESTUTIL_H
13 
14 #include "pkix.h"
15 #include "plstr.h"
16 #include "prprf.h"
17 #include "prlong.h"
18 #include "pkix_pl_common.h"
19 #include "secutil.h"
20 #include <stdio.h>
21 #include <ctype.h>
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 /*
28  * In order to have a consistent format for displaying test information,
29  * all tests are REQUIRED to use the functions provided by this library
30  * (libtestutil.a) for displaying their information.
31  *
32  * A test using this library begins with a call to startTests with the test
33  * name as the arg (which is used only for formatting). Before the first
34  * subtest, a call to subTest should be made with the subtest name as the arg
35  * (again, for formatting). If the subTest is successful, then no action
36  * is needed. However, if the subTest is not successful, then a call
37  * to testError should be made with a descriptive error message as the arg.
38  * Note that a subTest MUST NOT call testError more than once.
39  * Finally, a call to endTests is made with the test name as the arg (for
40  * formatting). Note that most of these macros assume that a variable named
41  * "plContext" of type (void *) has been defined by the test. As such, it
42  * is essential that the test satisfy this condition.
43  */
44 
45 /*
46  * PKIX_TEST_STD_VARS should be called at the beginning of every function
47  * that uses PKIX_TEST_RETURN (e.g. subTests), but it should be called only
48  * AFTER declaring local variables (so we don't get compiler warnings about
49  * declarations after statements). PKIX_TEST_STD_VARS declares and initializes
50  * several variables needed by the other test macros.
51  */
52 #define PKIX_TEST_STD_VARS()                \
53     PKIX_Error *pkixTestErrorResult = NULL; \
54     char *pkixTestErrorMsg = NULL;
55 
56 /*
57  * PKIX_TEST_EXPECT_NO_ERROR should be used to wrap a standard PKIX function
58  * call (one which returns a pointer to PKIX_Error) that is expected to return
59  * NULL (i.e. to succeed). If "pkixTestErrorResult" is not NULL,
60  * "goto cleanup" is executed, where a testError call is made if there were
61  * unexpected results. This macro MUST NOT be called after the "cleanup" label.
62  *
63  * Example Usage: PKIX_TEST_EXPECT_NO_ERROR(pkixFunc_expected_to_succeed(...));
64  */
65 
66 #define PKIX_TEST_EXPECT_NO_ERROR(func) \
67     do {                                \
68         pkixTestErrorResult = (func);   \
69         if (pkixTestErrorResult) {      \
70             goto cleanup;               \
71         }                               \
72     } while (0)
73 
74 /*
75  * PKIX_TEST_EXPECT_ERROR should be used to wrap a standard PKIX function call
76  * (one which returns a pointer to PKIX_Error) that is expected to return
77  * a non-NULL value (i.e. to fail). If "pkixTestErrorResult" is NULL,
78  * "pkixTestErrorMsg" is set to a standard string and "goto cleanup"
79  * is executed, where a testError call is made if there were unexpected
80  * results. This macro MUST NOT be called after the "cleanup" label.
81  *
82  * Example Usage:  PKIX_TEST_EXPECT_ERROR(pkixFunc_expected_to_fail(...));
83  */
84 
85 #define PKIX_TEST_EXPECT_ERROR(func)                 \
86     do {                                             \
87         pkixTestErrorResult = (func);                \
88         if (!pkixTestErrorResult) {                  \
89             pkixTestErrorMsg =                       \
90                 "Should have thrown an error here."; \
91             goto cleanup;                            \
92         }                                            \
93         PKIX_TEST_DECREF_BC(pkixTestErrorResult);    \
94     } while (0)
95 
96 /*
97  * PKIX_TEST_DECREF_BC is a convenience macro which should only be called
98  * BEFORE the "cleanup" label ("BC"). If the input parameter is non-NULL, it
99  * DecRefs the input parameter and wraps the function with
100  * PKIX_TEST_EXPECT_NO_ERROR, which executes "goto cleanup" upon error.
101  * This macro MUST NOT be called after the "cleanup" label.
102  */
103 
104 #define PKIX_TEST_DECREF_BC(obj)                                                                  \
105     do {                                                                                          \
106         if (obj) {                                                                                \
107             PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_DecRef((PKIX_PL_Object *)(obj), plContext)); \
108             obj = NULL;                                                                           \
109         }                                                                                         \
110     } while (0)
111 
112 /*
113  * PKIX_TEST_DECREF_AC is a convenience macro which should only be called
114  * AFTER the "cleanup" label ("AC"). If the input parameter is non-NULL, it
115  * DecRefs the input parameter. A pkixTestTempResult variable is used to prevent
116  * incorrectly overwriting pkixTestErrorResult with NULL.
117  * In the case DecRef succeeds, pkixTestTempResult will be NULL, and we won't
118  * overwrite a previously set pkixTestErrorResult (if any). If DecRef fails,
119  * then we do want to overwrite a previously set pkixTestErrorResult since a
120  * DecRef failure is fatal and may be indicative of memory corruption.
121  */
122 
123 #define PKIX_TEST_DECREF_AC(obj)                                           \
124     do {                                                                   \
125         if (obj) {                                                         \
126             PKIX_Error *pkixTestTempResult = NULL;                         \
127             pkixTestTempResult =                                           \
128                 PKIX_PL_Object_DecRef((PKIX_PL_Object *)(obj), plContext); \
129             if (pkixTestTempResult)                                        \
130                 pkixTestErrorResult = pkixTestTempResult;                  \
131             obj = NULL;                                                    \
132         }                                                                  \
133     } while (0)
134 
135 /*
136  * PKIX_TEST_RETURN must always be AFTER the "cleanup" label. It does nothing
137  * if everything went as expected. However, if there were unexpected results,
138  * PKIX_TEST_RETURN calls testError, which displays a standard failure message
139  * and increments the number of subtests that have failed. In the case
140  * of an unexpected error, testError is called using the error's description
141  * as an input and the error is DecRef'd. In the case of unexpected success
142  * testError is called with a standard string.
143  */
144 #define PKIX_TEST_RETURN()                                                   \
145     {                                                                        \
146         if (pkixTestErrorMsg) {                                              \
147             testError(pkixTestErrorMsg);                                     \
148         } else if (pkixTestErrorResult) {                                    \
149             pkixTestErrorMsg =                                               \
150                 PKIX_Error2ASCII(pkixTestErrorResult, plContext);            \
151             if (pkixTestErrorMsg) {                                          \
152                 testError(pkixTestErrorMsg);                                 \
153                 PKIX_PL_Free((PKIX_PL_Object *)pkixTestErrorMsg,             \
154                              plContext);                                     \
155             } else {                                                         \
156                 testError("PKIX_Error2ASCII Failed");                        \
157             }                                                                \
158             if (pkixTestErrorResult != PKIX_ALLOC_ERROR()) {                 \
159                 PKIX_PL_Object_DecRef((PKIX_PL_Object *)pkixTestErrorResult, \
160                                       plContext);                            \
161                 pkixTestErrorResult = NULL;                                  \
162             }                                                                \
163         }                                                                    \
164     }
165 
166 /*
167  * PKIX_TEST_EQ_HASH_TOSTR_DUP is a convenience macro which executes the
168  * standard set of operations that test the Equals, Hashcode, ToString, and
169  * Duplicate functions of an object type. The goodObj, equalObj, and diffObj
170  * are as the names suggest. The expAscii parameter is the expected result of
171  * calling ToString on the goodObj. If expAscii is NULL, then ToString will
172  * not be called on the goodObj. The checkDuplicate parameter is treated as
173  * a Boolean to indicate whether the Duplicate function should be tested. If
174  * checkDuplicate is NULL, then Duplicate will not be called on the goodObj.
175  * The type is the name of the function's family. For example, if the type is
176  * Cert, this macro will call PKIX_PL_Cert_Equals, PKIX_PL_Cert_Hashcode, and
177  * PKIX_PL_Cert_ToString.
178  *
179  * Note: If goodObj uses the default Equals and Hashcode functions, then
180  * for goodObj and equalObj to be equal, they must have the same pointer value.
181  */
182 #define PKIX_TEST_EQ_HASH_TOSTR_DUP(goodObj, equalObj, diffObj,        \
183                                     expAscii, type, checkDuplicate)    \
184     do {                                                               \
185         subTest("PKIX_PL_" #type "_Equals   <match>");                 \
186         testEqualsHelper((PKIX_PL_Object *)(goodObj),                  \
187                          (PKIX_PL_Object *)(equalObj),                 \
188                          PKIX_TRUE,                                    \
189                          plContext);                                   \
190         subTest("PKIX_PL_" #type "_Hashcode <match>");                 \
191         testHashcodeHelper((PKIX_PL_Object *)(goodObj),                \
192                            (PKIX_PL_Object *)(equalObj),               \
193                            PKIX_TRUE,                                  \
194                            plContext);                                 \
195         subTest("PKIX_PL_" #type "_Equals   <non-match>");             \
196         testEqualsHelper((PKIX_PL_Object *)(goodObj),                  \
197                          (PKIX_PL_Object *)(diffObj),                  \
198                          PKIX_FALSE,                                   \
199                          plContext);                                   \
200         subTest("PKIX_PL_" #type "_Hashcode <non-match>");             \
201         testHashcodeHelper((PKIX_PL_Object *)(goodObj),                \
202                            (PKIX_PL_Object *)(diffObj),                \
203                            PKIX_FALSE,                                 \
204                            plContext);                                 \
205         if (expAscii) {                                                \
206             subTest("PKIX_PL_" #type "_ToString");                     \
207             testToStringHelper((PKIX_PL_Object *)(goodObj),            \
208                                (expAscii),                             \
209                                plContext);                             \
210         }                                                              \
211         if (checkDuplicate) {                                          \
212             subTest("PKIX_PL_" #type "_Duplicate");                    \
213             testDuplicateHelper((PKIX_PL_Object *)goodObj, plContext); \
214         }                                                              \
215     } while (0)
216 
217 /*
218  * PKIX_TEST_DECREF_BC is a convenience macro which should only be called
219  * BEFORE the "cleanup" label ("BC"). If the input parameter is non-NULL, it
220  * DecRefs the input parameter and wraps the function with
221  * PKIX_TEST_EXPECT_NO_ERROR, which executes "goto cleanup" upon error.
222  * This macro MUST NOT be called after the "cleanup" label.
223  */
224 
225 #define PKIX_TEST_ABORT_ON_NULL(obj) \
226     do {                             \
227         if (!obj) {                  \
228             goto cleanup;            \
229         }                            \
230     } while (0)
231 
232 #define PKIX_TEST_ARENAS_ARG(arena) \
233     (arena ? (PORT_Strcmp(arena, "arenas") ? PKIX_FALSE : (j++, PKIX_TRUE)) : PKIX_FALSE)
234 
235 #define PKIX_TEST_ERROR_RECEIVED (pkixTestErrorMsg || pkixTestErrorResult)
236 
237 /* see source file for function documentation */
238 
239 void startTests(char *testName);
240 
241 void endTests(char *testName);
242 
243 void subTest(char *subTestName);
244 
245 void testError(char *msg);
246 
247 extern PKIX_Error *
248 _ErrorCheck(PKIX_Error *errorResult);
249 
250 extern PKIX_Error *
251 _OutputError(PKIX_Error *errorResult);
252 
253 char *PKIX_String2ASCII(PKIX_PL_String *string, void *plContext);
254 
255 char *PKIX_Error2ASCII(PKIX_Error *error, void *plContext);
256 
257 char *PKIX_Object2ASCII(PKIX_PL_Object *object);
258 
259 char *PKIX_Cert2ASCII(PKIX_PL_Cert *cert);
260 
261 void
262 testHashcodeHelper(
263     PKIX_PL_Object *goodObject,
264     PKIX_PL_Object *otherObject,
265     PKIX_Boolean match,
266     void *plContext);
267 
268 void
269 testToStringHelper(
270     PKIX_PL_Object *goodObject,
271     char *expected,
272     void *plContext);
273 
274 void
275 testEqualsHelper(
276     PKIX_PL_Object *goodObject,
277     PKIX_PL_Object *otherObject,
278     PKIX_Boolean match,
279     void *plContext);
280 
281 void
282 testDuplicateHelper(
283     PKIX_PL_Object *object,
284     void *plContext);
285 void
286 testErrorUndo(char *msg);
287 
288 #ifdef __cplusplus
289 }
290 #endif
291 
292 #endif /* TESTUTIL_H */
293