tests: Add json testrunner
* configure.ac: Configure makefile. * tests/Makefile.am: Run json tests if gpg tests are run. * tests/json/t-json.c: New testrunner for json tests. * tests/json/t-config.in, tests/json/t-config.out: First test. -- The idea of this test runner is that it only looks for parts in the output. This should allow it to write robust tests that check for the basics in the output but don't fail when the output is extended or slightly changed.
This commit is contained in:
parent
c4aa4af50f
commit
0c31837766
@ -853,6 +853,7 @@ AC_CONFIG_FILES(Makefile src/Makefile
|
||||
tests/gpg/Makefile
|
||||
tests/gpgsm/Makefile
|
||||
tests/opassuan/Makefile
|
||||
tests/json/Makefile
|
||||
doc/Makefile
|
||||
src/versioninfo.rc
|
||||
src/gpgme.pc
|
||||
|
@ -38,7 +38,7 @@ noinst_PROGRAMS = $(TESTS) run-keylist run-export run-import run-sign \
|
||||
|
||||
|
||||
if RUN_GPG_TESTS
|
||||
gpgtests = gpg
|
||||
gpgtests = gpg json
|
||||
else
|
||||
gpgtests =
|
||||
endif
|
||||
|
4
tests/json/t-config.in
Normal file
4
tests/json/t-config.in
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"op": "config",
|
||||
"component": "gpg"
|
||||
}
|
19
tests/json/t-config.out
Normal file
19
tests/json/t-config.out
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"components": [{
|
||||
"name": "gpg",
|
||||
"description": "OpenPGP",
|
||||
"options": [{
|
||||
"name": "Monitor",
|
||||
"flags": 1,
|
||||
"level": 0,
|
||||
"type": 0,
|
||||
"alt_type": 0
|
||||
}, {
|
||||
"name": "verbose",
|
||||
"description": "verbose",
|
||||
"level": 0,
|
||||
"type": 0,
|
||||
"alt_type": 0
|
||||
}]
|
||||
}]
|
||||
}
|
344
tests/json/t-json.c
Normal file
344
tests/json/t-json.c
Normal file
@ -0,0 +1,344 @@
|
||||
/* t-json.c - Regression test.
|
||||
Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik
|
||||
Software engineering by Intevation GmbH
|
||||
|
||||
This file is part of GPGME.
|
||||
|
||||
GPGME is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
GPGME is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <gpgme.h>
|
||||
#include <gpg-error.h>
|
||||
|
||||
#include "../gpg/t-support.h"
|
||||
#include "../../src/cJSON.h"
|
||||
|
||||
/* Register tests here */
|
||||
static const char*tests[] = { "t-config", NULL };
|
||||
|
||||
static int verbose = 0;
|
||||
|
||||
static char *
|
||||
get_file (const char *fname)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gpgrt_stream_t fp;
|
||||
struct stat st;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
|
||||
fp = gpgrt_fopen (fname, "r");
|
||||
if (!fp)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
fprintf (stderr, "Error: can't open '%s': %s\n", fname,
|
||||
gpg_strerror (err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat (gpgrt_fileno(fp), &st))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
fprintf (stderr, "Error: can't stat '%s': %s\n", fname,
|
||||
gpg_strerror (err));
|
||||
gpgrt_fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buflen = st.st_size;
|
||||
buf = malloc (buflen+1);
|
||||
if (!buf)
|
||||
{
|
||||
fprintf (stderr, "Error: no mem\n");
|
||||
gpgrt_fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (gpgrt_fread (buf, buflen, 1, fp) != 1)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
fprintf (stderr, "error reading '%s': %s\n", fname, gpg_strerror (err));
|
||||
gpgrt_fclose (fp);
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
buf[buflen] = 0;
|
||||
gpgrt_fclose (fp);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Check that the element needle exists in hay. Returns 0 if
|
||||
the needle was found. */
|
||||
int
|
||||
test_contains (cjson_t needle, cjson_t hay)
|
||||
{
|
||||
/*fprintf (stderr, "checking \n%s\n -------against-------- \n%s\n",
|
||||
cJSON_Print (needle), cJSON_Print (hay)); */
|
||||
|
||||
/* Type check. This automatically checks bool vals and NULL */
|
||||
if (needle->type != hay->type)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf (stderr, "type mismatch expected %i got %i\n", needle->type,
|
||||
hay->type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* First the simple types */
|
||||
if (cjson_is_number (needle))
|
||||
{
|
||||
if (needle->valueint != hay->valueint)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf (stderr, "Value mismatch. Expected %i got %i\n",
|
||||
needle->valueint, hay->valueint);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (cjson_is_string (needle))
|
||||
{
|
||||
if (strcmp (needle->valuestring, hay->valuestring))
|
||||
{
|
||||
if (verbose)
|
||||
fprintf (stderr, "String mismatch Expected '%s' got '%s'\n",
|
||||
needle->valuestring, hay->valuestring);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the complex types */
|
||||
if (needle->child)
|
||||
{
|
||||
if (!hay->child)
|
||||
{
|
||||
fprintf (stderr, "Depth mismatch. Expected child for %s\n",
|
||||
nonnull (needle->string));
|
||||
}
|
||||
if (test_contains (needle->child, hay->child))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (needle->prev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Walk elements of an array */
|
||||
for (cjson_t it = needle->next; it; it = it->next)
|
||||
{
|
||||
int found = 0;
|
||||
if (!it->string && it->child)
|
||||
{
|
||||
/* Try out all other anonymous children on the same level */
|
||||
cjson_t hit = hay;
|
||||
/* Return to the beginning */
|
||||
while (hit->prev)
|
||||
{
|
||||
hit = hit->prev;
|
||||
}
|
||||
for (; hit && hit->child; hit = hit->next)
|
||||
{
|
||||
found |= !test_contains (it->child, hit->child);
|
||||
if (found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try the children in the haystack */
|
||||
for (cjson_t hit = hay; hit; hit = hit->next)
|
||||
{
|
||||
if (hit->string && it->string &&
|
||||
!strcmp (hit->string, it->string))
|
||||
{
|
||||
found = 1;
|
||||
if (test_contains (it, hit))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf (stderr, "Failed to find '%s' in list\n",
|
||||
nonnull (it->string));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
check_response (const char *response, const char *expected)
|
||||
{
|
||||
cjson_t hay;
|
||||
cjson_t needle;
|
||||
int rc;
|
||||
size_t erroff;
|
||||
|
||||
hay = cJSON_Parse (response, &erroff);
|
||||
|
||||
if (!hay)
|
||||
{
|
||||
fprintf (stderr, "Failed to parse json at %i:\n%s\n", (int) erroff,
|
||||
response);
|
||||
return 1;
|
||||
}
|
||||
needle = cJSON_Parse (expected, &erroff);
|
||||
if (!needle)
|
||||
{
|
||||
fprintf (stderr, "Failed to parse json at %i:\n%s\n", (int) erroff,
|
||||
expected);
|
||||
cJSON_Delete (hay);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = test_contains (needle, hay);
|
||||
|
||||
cJSON_Delete (needle);
|
||||
cJSON_Delete (hay);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
run_test (const char *test, const char *gpgme_json)
|
||||
{
|
||||
gpgme_ctx_t ctx;
|
||||
gpgme_data_t json_stdin = NULL;
|
||||
gpgme_data_t json_stdout = NULL;
|
||||
gpgme_data_t json_stderr = NULL;
|
||||
char *test_in;
|
||||
char *test_out;
|
||||
const char *argv[2];
|
||||
char *response;
|
||||
char *expected;
|
||||
size_t response_size;
|
||||
int rc = 0;
|
||||
const char *top_srcdir = getenv ("top_srcdir");
|
||||
|
||||
if (!top_srcdir)
|
||||
{
|
||||
fprintf (stderr, "Error top_srcdir environment variable not set\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gpgrt_asprintf (&test_in, "%s//tests//json//%s.in",
|
||||
top_srcdir, test);
|
||||
gpgrt_asprintf (&test_out, "%s//tests//json//%s.out",
|
||||
top_srcdir, test);
|
||||
|
||||
printf ("Running %s...\n", test);
|
||||
|
||||
fail_if_err (gpgme_new (&ctx));
|
||||
|
||||
gpgme_set_protocol (ctx, GPGME_PROTOCOL_SPAWN);
|
||||
|
||||
fail_if_err (gpgme_data_new_from_file (&json_stdin, test_in, 1));
|
||||
fail_if_err (gpgme_data_new (&json_stdout));
|
||||
fail_if_err (gpgme_data_new (&json_stderr));
|
||||
|
||||
argv[0] = gpgme_json;
|
||||
argv[1] = "-s";
|
||||
|
||||
fail_if_err (gpgme_op_spawn (ctx, gpgme_json, argv,
|
||||
json_stdin,
|
||||
json_stdout,
|
||||
json_stderr,
|
||||
0));
|
||||
response = gpgme_data_release_and_get_mem (json_stdout,
|
||||
&response_size);
|
||||
test (response_size);
|
||||
|
||||
expected = get_file (test_out);
|
||||
|
||||
test (expected);
|
||||
|
||||
rc = check_response (response, expected);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
printf (" success\n");
|
||||
gpgme_data_release (json_stderr);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *buf;
|
||||
size_t size;
|
||||
|
||||
buf = gpgme_data_release_and_get_mem (json_stderr, &size);
|
||||
printf (" failed\n");
|
||||
if (size)
|
||||
{
|
||||
printf ("gpgme-json stderr:\n%.*s\n", (int)size, buf);
|
||||
}
|
||||
free (buf);
|
||||
}
|
||||
|
||||
free (test_out);
|
||||
free (test_in);
|
||||
free (response);
|
||||
free (expected);
|
||||
gpgme_data_release (json_stdin);
|
||||
gpgme_release (ctx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
const char *gpgme_json = getenv ("gpgme_json");
|
||||
|
||||
if (argc == 2 && !strcmp (argv[1], "--verbose"))
|
||||
{
|
||||
/* Note that verbose will print out lots of mismatchs
|
||||
because we have to try trough anonymous objects */
|
||||
verbose = 1;
|
||||
}
|
||||
|
||||
|
||||
init_gpgme (GPGME_PROTOCOL_SPAWN);
|
||||
|
||||
for (const char **test = tests; *test; test++)
|
||||
{
|
||||
if (run_test (*test, gpgme_json))
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user