Line data Source code
1 : /* t-json.c - Regression test.
2 : Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
3 : Software engineering by Intevation GmbH
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, write to the Free Software
19 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : 02111-1307, USA. */
21 :
22 : #ifdef HAVE_CONFIG_H
23 : # include <config.h>
24 : #endif
25 :
26 : #include <stdlib.h>
27 : #include <stdio.h>
28 : #include <string.h>
29 : #include <errno.h>
30 : #include <sys/stat.h>
31 :
32 : #include <gpgme.h>
33 : #include <gpg-error.h>
34 :
35 : #include "../gpg/t-support.h"
36 : #include "../../src/cJSON.h"
37 :
38 : /* Register tests here */
39 : static const char*tests[] = { "t-config", "t-version",
40 : "t-keylist", "t-keylist-secret", "t-decrypt", "t-config-opt",
41 : "t-encrypt", "t-encrypt-sign", "t-sign", "t-verify",
42 : "t-decrypt-verify", "t-export", "t-createkey",
43 : "t-export-secret-info", "t-chunking", "t-sig-notations",
44 : /* For these two the order is important
45 : * as t-import imports the deleted key from t-delete */
46 : "t-delete", "t-import",
47 : NULL };
48 :
49 : static int verbose = 0;
50 :
51 : static char *
52 18 : get_file (const char *fname)
53 : {
54 : gpg_error_t err;
55 : gpgrt_stream_t fp;
56 : struct stat st;
57 : char *buf;
58 : size_t buflen;
59 :
60 18 : fp = gpgrt_fopen (fname, "r");
61 18 : if (!fp)
62 : {
63 0 : err = gpg_error_from_syserror ();
64 0 : fprintf (stderr, "Error: can't open '%s': %s\n", fname,
65 : gpg_strerror (err));
66 0 : return NULL;
67 : }
68 :
69 18 : if (fstat (gpgrt_fileno(fp), &st))
70 : {
71 0 : err = gpg_error_from_syserror ();
72 0 : fprintf (stderr, "Error: can't stat '%s': %s\n", fname,
73 : gpg_strerror (err));
74 0 : gpgrt_fclose (fp);
75 0 : return NULL;
76 : }
77 :
78 18 : buflen = st.st_size;
79 18 : buf = malloc (buflen+1);
80 18 : if (!buf)
81 : {
82 0 : fprintf (stderr, "Error: no mem\n");
83 0 : gpgrt_fclose (fp);
84 0 : return NULL;
85 : }
86 :
87 18 : if (gpgrt_fread (buf, buflen, 1, fp) != 1)
88 : {
89 0 : err = gpg_error_from_syserror ();
90 0 : fprintf (stderr, "error reading '%s': %s\n", fname, gpg_strerror (err));
91 0 : gpgrt_fclose (fp);
92 0 : free (buf);
93 0 : return NULL;
94 : }
95 18 : buf[buflen] = 0;
96 18 : gpgrt_fclose (fp);
97 :
98 18 : return buf;
99 : }
100 :
101 : /* Check that the element needle exists in hay. Returns 0 if
102 : the needle was found. */
103 : int
104 504 : test_contains (cjson_t needle, cjson_t hay)
105 : {
106 504 : if (verbose == 2)
107 0 : fprintf (stderr, "%s: -------checking-------- "
108 : "\n%s\n -------against-------- \n%s\n",
109 0 : nonnull (needle->string), cJSON_Print (needle),
110 : cJSON_Print (hay));
111 :
112 : /* Type check. This automatically checks bool vals and NULL */
113 504 : if (needle->type != hay->type)
114 : {
115 10 : if (verbose)
116 0 : fprintf (stderr, "%s: type mismatch expected %i got %i\n",
117 0 : nonnull (needle->string), needle->type,
118 : hay->type);
119 10 : return 1;
120 : }
121 :
122 : /* First the simple types */
123 494 : if (cjson_is_number (needle))
124 : {
125 73 : if (needle->valueint != hay->valueint)
126 : {
127 0 : if (verbose)
128 0 : fprintf (stderr, "%s: value mismatch. Expected %i got %i\n",
129 0 : nonnull (needle->string), needle->valueint,
130 : hay->valueint);
131 0 : return 1;
132 : }
133 : }
134 494 : if (cjson_is_string (needle))
135 : {
136 157 : if (strcmp (needle->valuestring, hay->valuestring) &&
137 : /* Use * as a general don't care placeholder */
138 17 : strcmp (needle->valuestring, "*"))
139 : {
140 14 : if (verbose)
141 0 : fprintf (stderr, "%s: string mismatch Expected '%s' got '%s'\n",
142 : needle->string, needle->valuestring, hay->valuestring);
143 14 : return 1;
144 : }
145 : }
146 :
147 : /* Now the complex types */
148 480 : if (needle->child)
149 : {
150 65 : if (!hay->child)
151 : {
152 0 : fprintf (stderr, "Depth mismatch. Expected child for %s\n",
153 0 : nonnull (needle->string));
154 : }
155 65 : if (test_contains (needle->child, hay->child))
156 : {
157 3 : int found = 0;
158 6 : for (cjson_t hit = hay->child; hit; hit = hit->next)
159 : {
160 6 : found |= !test_contains (needle->child, hit);
161 6 : if (found)
162 : {
163 3 : break;
164 : }
165 : }
166 3 : if (!found)
167 : {
168 0 : return 1;
169 : }
170 : }
171 : }
172 :
173 480 : if (needle->prev)
174 : {
175 376 : return 0;
176 : }
177 :
178 : /* Walk elements of an array */
179 492 : for (cjson_t it = needle->next; it; it = it->next)
180 : {
181 397 : int found = 0;
182 397 : if (!it->string && it->child)
183 : {
184 : /* Try out all other anonymous children on the same level */
185 12 : cjson_t hit = hay;
186 : /* Return to the beginning */
187 24 : while (hit->prev)
188 : {
189 0 : hit = hit->prev;
190 : }
191 30 : for (; hit && hit->child; hit = hit->next)
192 : {
193 30 : found |= !test_contains (it->child, hit->child);
194 30 : if (found)
195 : {
196 12 : break;
197 : }
198 : }
199 12 : if (!found)
200 : {
201 0 : return 1;
202 : }
203 12 : continue;
204 : }
205 :
206 : /* Try the children in the haystack */
207 5658 : for (cjson_t hit = hay; hit; hit = hit->next)
208 : {
209 10564 : if (hit->string && it->string &&
210 5282 : !strcmp (hit->string, it->string))
211 : {
212 385 : found = 1;
213 385 : if (test_contains (it, hit))
214 : {
215 9 : return 1;
216 : }
217 : }
218 : }
219 376 : if (!found)
220 : {
221 0 : if (verbose)
222 0 : fprintf (stderr, "Failed to find '%s' in list\n",
223 0 : nonnull (it->string));
224 0 : return 1;
225 : }
226 : }
227 95 : return 0;
228 : }
229 :
230 :
231 : int
232 18 : check_response (const char *response, const char *expected)
233 : {
234 : cjson_t hay;
235 : cjson_t needle;
236 : int rc;
237 : size_t erroff;
238 :
239 18 : hay = cJSON_Parse (response, &erroff);
240 :
241 18 : if (!hay)
242 : {
243 0 : fprintf (stderr, "Failed to parse json at %i:\n%s\n", (int) erroff,
244 : response);
245 0 : return 1;
246 : }
247 18 : needle = cJSON_Parse (expected, &erroff);
248 18 : if (!needle)
249 : {
250 0 : fprintf (stderr, "Failed to parse json at %i:\n%s\n", (int) erroff,
251 : expected);
252 0 : cJSON_Delete (hay);
253 0 : return 1;
254 : }
255 :
256 18 : rc = test_contains (needle, hay);
257 :
258 18 : cJSON_Delete (needle);
259 18 : cJSON_Delete (hay);
260 18 : return rc;
261 : }
262 :
263 :
264 : int
265 18 : run_test (const char *test, const char *gpgme_json)
266 : {
267 : gpgme_ctx_t ctx;
268 18 : gpgme_data_t json_stdin = NULL;
269 18 : gpgme_data_t json_stdout = NULL;
270 18 : gpgme_data_t json_stderr = NULL;
271 : char *test_in;
272 : char *test_out;
273 : const char *argv[3];
274 : char *response;
275 18 : char *expected = NULL;
276 : size_t response_size;
277 18 : int rc = 0;
278 18 : const char *top_srcdir = getenv ("top_srcdir");
279 :
280 18 : if (!top_srcdir)
281 : {
282 0 : fprintf (stderr, "Error top_srcdir environment variable not set\n");
283 0 : exit(1);
284 : }
285 :
286 18 : gpgrt_asprintf (&test_in, "%s/tests/json/%s.in.json",
287 : top_srcdir, test);
288 18 : gpgrt_asprintf (&test_out, "%s/tests/json/%s.out.json",
289 : top_srcdir, test);
290 :
291 18 : printf ("Running %s...\n", test);
292 :
293 18 : fail_if_err (gpgme_new (&ctx));
294 :
295 18 : gpgme_set_protocol (ctx, GPGME_PROTOCOL_SPAWN);
296 :
297 18 : fail_if_err (gpgme_data_new_from_file (&json_stdin, test_in, 1));
298 18 : fail_if_err (gpgme_data_new (&json_stdout));
299 18 : fail_if_err (gpgme_data_new (&json_stderr));
300 :
301 18 : argv[0] = gpgme_json;
302 18 : argv[1] = "-s";
303 18 : argv[2] = NULL;
304 :
305 18 : fail_if_err (gpgme_op_spawn (ctx, gpgme_json, argv,
306 : json_stdin,
307 : json_stdout,
308 : json_stderr,
309 : 0));
310 18 : response = gpgme_data_release_and_get_mem (json_stdout,
311 : &response_size);
312 18 : if (response_size)
313 : {
314 18 : expected = get_file (test_out);
315 :
316 18 : test (expected);
317 :
318 18 : rc = check_response (response, expected);
319 : }
320 : else
321 : {
322 0 : rc = 1;
323 : }
324 :
325 18 : if (!rc)
326 : {
327 18 : printf (" success\n");
328 18 : gpgme_data_release (json_stderr);
329 : }
330 : else
331 : {
332 : char *buf;
333 : size_t size;
334 :
335 0 : buf = gpgme_data_release_and_get_mem (json_stderr, &size);
336 0 : printf (" failed%s\n", response_size ? "" :
337 : ", no response from gpgme-json");
338 0 : if (size)
339 : {
340 0 : printf ("gpgme-json stderr:\n%.*s\n", (int)size, buf);
341 : }
342 0 : free (buf);
343 : }
344 :
345 18 : free (test_out);
346 18 : free (test_in);
347 18 : free (response);
348 18 : free (expected);
349 18 : gpgme_data_release (json_stdin);
350 18 : gpgme_release (ctx);
351 :
352 18 : return rc;
353 : }
354 :
355 : int
356 1 : main (int argc, char *argv[])
357 : {
358 1 : const char *gpgme_json = getenv ("gpgme_json");
359 1 : int last_argc = -1;
360 :
361 1 : if (argc)
362 1 : { argc--; argv++; }
363 :
364 :
365 2 : while (argc && last_argc != argc )
366 : {
367 0 : last_argc = argc;
368 0 : if (!strcmp (*argv, "--verbose"))
369 : {
370 0 : verbose++;
371 0 : argc--; argv++;
372 : }
373 : }
374 :
375 1 : if (!check_gpg_version ("2.2.0"))
376 : {
377 : /* Lets not break too much or have to test all combinations */
378 0 : printf ("Testsuite skipped. Minimum GnuPG version (2.2.0) "
379 : "not found.\n");
380 0 : exit(0);
381 : }
382 :
383 1 : init_gpgme (GPGME_PROTOCOL_SPAWN);
384 :
385 19 : for (const char **test = tests; *test; test++)
386 : {
387 18 : if (run_test (*test, gpgme_json))
388 : {
389 0 : exit(1);
390 : }
391 : }
392 1 : return 0;
393 : }
|