From f2f2792ec244a59a3773ad654d1478a1d48ac81c Mon Sep 17 00:00:00 2001 From: Mark Dilger Date: Sun, 26 Jan 2020 10:41:37 -0800 Subject: [PATCH 2/2] Adding frontend tests for json parser. Creating tests in new directory src/test/bin for testing that the json parser can be included and used from within a frontend standalone binary. --- src/Makefile | 4 +- src/test/Makefile | 7 ++-- src/test/bin/.gitignore | 1 + src/test/bin/Makefile | 41 ++++++++++++++++++++ src/test/bin/README | 15 ++++++++ src/test/bin/t/001_test_json.pl | 48 +++++++++++++++++++++++ src/test/bin/test_json.c | 67 +++++++++++++++++++++++++++++++++ 7 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 src/test/bin/.gitignore create mode 100644 src/test/bin/Makefile create mode 100644 src/test/bin/README create mode 100644 src/test/bin/t/001_test_json.pl create mode 100644 src/test/bin/test_json.c diff --git a/src/Makefile b/src/Makefile index bcdbd9588a..ccd4bab0de 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,8 @@ # # Makefile for src # -# Copyright (c) 1994, Regents of the University of California +# Portions Copyright (c) 1994, Regents of the University of California +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group # # src/Makefile # @@ -27,6 +28,7 @@ SUBDIRS = \ bin \ pl \ makefiles \ + test/bin \ test/regress \ test/isolation \ test/perl diff --git a/src/test/Makefile b/src/test/Makefile index efb206aa75..e24732f190 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -12,7 +12,7 @@ subdir = src/test top_builddir = ../.. include $(top_builddir)/src/Makefile.global -SUBDIRS = perl regress isolation modules authentication recovery subscription +SUBDIRS = bin perl regress isolation modules authentication recovery subscription # Test suites that are not safe by default but can be run if selected # by the user via the whitespace-separated list in variable @@ -40,10 +40,11 @@ endif ALWAYS_SUBDIRS = $(filter-out $(SUBDIRS),examples kerberos ldap locale thread ssl) # We want to recurse to all subdirs for all standard targets, except that -# installcheck and install should not recurse into the subdirectory "modules". +# installcheck and install should not recurse into the subdirectory "modules" +# nor "bin". recurse_alldirs_targets := $(filter-out installcheck install, $(standard_targets)) -installable_dirs := $(filter-out modules, $(SUBDIRS)) +installable_dirs := $(filter-out modules bin, $(SUBDIRS)) $(call recurse,$(recurse_alldirs_targets)) $(call recurse,installcheck, $(installable_dirs)) diff --git a/src/test/bin/.gitignore b/src/test/bin/.gitignore new file mode 100644 index 0000000000..6709c749d8 --- /dev/null +++ b/src/test/bin/.gitignore @@ -0,0 +1 @@ +test_json diff --git a/src/test/bin/Makefile b/src/test/bin/Makefile new file mode 100644 index 0000000000..3eee9091bc --- /dev/null +++ b/src/test/bin/Makefile @@ -0,0 +1,41 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/test/bin +# +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/bin/bin/Makefile +# +#------------------------------------------------------------------------- + +PGFILEDESC = "bin - the PostgreSQL standalone code binaries for testing" +PGAPPICON=win32 + +subdir = src/test/bin +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +# make this available to TAP test scripts +export with_readline + +REFDOCDIR= $(top_srcdir)/doc/src/sgml/ref + +override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS) +LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) + +OBJS = \ + $(WIN32RES) \ + test_json.o + +all: test_json + +test_json: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) + +check: + PATH="$(abs_top_builddir)/src/test/bin:$$PATH" $(prove_check) + +clean distclean maintainer-clean: + rm -f test_json$(X) $(OBJS) + rm -rf tmp_check diff --git a/src/test/bin/README b/src/test/bin/README new file mode 100644 index 0000000000..214671af88 --- /dev/null +++ b/src/test/bin/README @@ -0,0 +1,15 @@ +src/test/bin/README + +Binary executable tests +======================= + +This directory contains a set of programs that exercise functionality declared +in src/include/common and defined in src/common. The purpose of these programs +is to verify that code intended to work both from frontend and backend code do +indeed work when compiled and used in frontend code. The structure of this +directory makes no attempt to test that such code works in the backend, as the +backend has its own tests already, and presumably those tests sufficiently +exercide the code as used by it. + +These test programs are part of the tap-test suite. Configure with tap tests +enabled or these tests will be skipped. diff --git a/src/test/bin/t/001_test_json.pl b/src/test/bin/t/001_test_json.pl new file mode 100644 index 0000000000..08e15c956d --- /dev/null +++ b/src/test/bin/t/001_test_json.pl @@ -0,0 +1,48 @@ +# Basic logical replication test +use strict; +use warnings; +use TestLib (); +use Cwd; + +use Test::More tests => 83; + +# There doesn't seem to be any easy way to get TestLib to use the binaries from +# our directory, so we hack up a path to our binary and run that directly. This +# seems brittle enough that some other solution should be found, if possible. + +my $test_json = join('/', $ENV{TESTDIR}, 'test_json'); + +ok(-f $test_json, "test_json file exists"); +ok(-x $test_json, "test_json file is executable"); + +# Verify some valid JSON is accepted by our parser +TestLib::command_like( [$test_json, q/null/ ], qr{\bVALID\b}, "null"); +TestLib::command_like( [$test_json, q/{}/ ], qr{\bVALID\b}, "empty object"); +TestLib::command_like( [$test_json, q/[]/ ], qr{\bVALID\b}, "empty array"); +TestLib::command_like( [$test_json, q/-12345/ ], qr{\bVALID\b}, "negative integer"); +TestLib::command_like( [$test_json, q/-1/ ], qr{\bVALID\b}, "negative integer"); +TestLib::command_like( [$test_json, q/0/ ], qr{\bVALID\b}, "zero"); +TestLib::command_like( [$test_json, q/1/ ], qr{\bVALID\b}, "positive integer"); +TestLib::command_like( [$test_json, q/12345/ ], qr{\bVALID\b}, "positive integer"); +TestLib::command_like( [$test_json, q/-1.23456789/], qr{\bVALID\b}, "negative float"); +TestLib::command_like( [$test_json, q/1.23456789/ ], qr{\bVALID\b}, "positive float"); +TestLib::command_like( [$test_json, q/{"a": "b"}/ ], qr{\bVALID\b}, "object"); +TestLib::command_like( [$test_json, q/["a", "b"]/ ], qr{\bVALID\b}, "array"); +TestLib::command_like( [$test_json, q/"pigs feet"/], qr{\bVALID\b}, 'text string'); + +# Verify some invalid JSON is rejected by our parser +TestLib::command_like( [$test_json, q/{/ ], qr{\bINVALID\b}, 'unclosed object'); +TestLib::command_like( [$test_json, q/[/ ], qr{\bINVALID\b}, 'unclosed array'); +TestLib::command_like( [$test_json, q/(/ ], qr{\bINVALID\b}, 'unclosed parenthesis'); +TestLib::command_like( [$test_json, q/}/ ], qr{\bINVALID\b}, 'unopened object'); +TestLib::command_like( [$test_json, q/]/ ], qr{\bINVALID\b}, 'unopened array'); +TestLib::command_like( [$test_json, q/)/ ], qr{\bINVALID\b}, 'unopened parenthesis'); +TestLib::command_like( [$test_json, q/{{{}}/ ], qr{\bINVALID\b}, 'unbalanced object curlies'); +TestLib::command_like( [$test_json, q/{{}}}/ ], qr{\bINVALID\b}, 'unbalanced object curlies'); +TestLib::command_like( [$test_json, q/[[[]]/ ], qr{\bINVALID\b}, 'unbalanced array braces'); +TestLib::command_like( [$test_json, q/[[]]]/ ], qr{\bINVALID\b}, 'unbalanced array braces'); +TestLib::command_like( [$test_json, q/((())/ ], qr{\bINVALID\b}, 'unbalanced array braces'); +TestLib::command_like( [$test_json, q/(()))/ ], qr{\bINVALID\b}, 'unbalanced array braces'); +TestLib::command_like( [$test_json, q/1 7 13/ ], qr{\bINVALID\b}, 'integer sequence'); +TestLib::command_like( [$test_json, q/{"a", "b"}/ ], qr{\bINVALID\b}, 'mixed object and array syntax'); diff --git a/src/test/bin/test_json.c b/src/test/bin/test_json.c new file mode 100644 index 0000000000..567a35f3b0 --- /dev/null +++ b/src/test/bin/test_json.c @@ -0,0 +1,67 @@ +/* + * pg_test_json.c + * tests validity of json strings against parser implementation. + */ + +#include "postgres_fe.h" + +#include "common/jsonapi.h" +#include "libpq-fe.h" + +static const char *progname; + +static void parse_json(const char *str); + +int +main(int argc, char *argv[]) +{ + int argidx; + + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_json")); + progname = get_progname(argv[0]); + + /* + * Make stdout unbuffered to match stderr; and ensure stderr is unbuffered + * too, which it should already be everywhere except sometimes in Windows. + */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + if (argc > 1) + { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) + { + printf(_("Usage: %s jsonstr [, ...]\n"), progname); + exit(0); + } + if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) + { + puts("pg_test_json (PostgreSQL) " PG_VERSION); + exit(0); + } + } + + for (argidx = 1; argidx < argc; argidx++) + parse_json(argv[argidx]); + + return 0; +} + +static void +parse_json(const char *str) +{ + char *json; + unsigned int json_len; + JsonLexContext *lex; + int client_encoding; + JsonParseErrorType parse_result; + + json_len = (unsigned int) strlen(str); + client_encoding = PQenv2encoding(); + + json = strdup(str); + lex = makeJsonLexContextCstringLen(json, strlen(json), client_encoding, true /* need_escapes */); + parse_result = pg_parse_json(lex, &nullSemAction); + fprintf(stdout, _("%s\n"), (JSON_SUCCESS == parse_result ? "VALID" : "INVALID")); + return; +} -- 2.21.1 (Apple Git-122.3)