summaryrefslogtreecommitdiffstats
path: root/src/interfaces/ecpg/test/pg_regress_ecpg.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
commit5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch)
tree739caf8c461053357daa9f162bef34516c7bf452 /src/interfaces/ecpg/test/pg_regress_ecpg.c
parentInitial commit. (diff)
downloadpostgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz
postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/interfaces/ecpg/test/pg_regress_ecpg.c')
-rw-r--r--src/interfaces/ecpg/test/pg_regress_ecpg.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c b/src/interfaces/ecpg/test/pg_regress_ecpg.c
new file mode 100644
index 0000000..f920af4
--- /dev/null
+++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c
@@ -0,0 +1,266 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_regress_ecpg --- regression test driver for ecpg
+ *
+ * This is a C implementation of the previous shell script for running
+ * the regression tests, and should be mostly compatible with it.
+ * Initial author of C translation: Magnus Hagander
+ *
+ * This code is released under the terms of the PostgreSQL License.
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/interfaces/ecpg/test/pg_regress_ecpg.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include "pg_regress.h"
+#include "common/string.h"
+#include "lib/stringinfo.h"
+
+
+/*
+ * Create a filtered copy of sourcefile, removing any path
+ * appearing in #line directives; for example, replace
+ * #line x "./../bla/foo.h" with #line x "foo.h".
+ * This is needed because the path part can vary depending
+ * on compiler, platform, build options, etc.
+ */
+static void
+ecpg_filter_source(const char *sourcefile, const char *outfile)
+{
+ FILE *s,
+ *t;
+ StringInfoData linebuf;
+
+ s = fopen(sourcefile, "r");
+ if (!s)
+ {
+ fprintf(stderr, "Could not open file %s for reading\n", sourcefile);
+ exit(2);
+ }
+ t = fopen(outfile, "w");
+ if (!t)
+ {
+ fprintf(stderr, "Could not open file %s for writing\n", outfile);
+ exit(2);
+ }
+
+ initStringInfo(&linebuf);
+
+ while (pg_get_line_buf(s, &linebuf))
+ {
+ /* check for "#line " in the beginning */
+ if (strstr(linebuf.data, "#line ") == linebuf.data)
+ {
+ char *p = strchr(linebuf.data, '"');
+ int plen = 1;
+
+ while (*p && (*(p + plen) == '.' || strchr(p + plen, '/') != NULL))
+ {
+ plen++;
+ }
+ /* plen is one more than the number of . and / characters */
+ if (plen > 1)
+ {
+ memmove(p + 1, p + plen, strlen(p + plen) + 1);
+ /* we don't bother to fix up linebuf.len */
+ }
+ }
+ fputs(linebuf.data, t);
+ }
+
+ pfree(linebuf.data);
+ fclose(s);
+ fclose(t);
+}
+
+/*
+ * Remove the details of connection failure error messages
+ * in a test result file, since the target host/pathname and/or port
+ * can vary. Rewrite the result file in-place.
+ *
+ * At some point it might be interesting to unify this with
+ * ecpg_filter_source, but building a general pattern matcher
+ * is no fun, nor does it seem desirable to introduce a
+ * dependency on an external one.
+ */
+static void
+ecpg_filter_stderr(const char *resultfile, const char *tmpfile)
+{
+ FILE *s,
+ *t;
+ StringInfoData linebuf;
+
+ s = fopen(resultfile, "r");
+ if (!s)
+ {
+ fprintf(stderr, "Could not open file %s for reading\n", resultfile);
+ exit(2);
+ }
+ t = fopen(tmpfile, "w");
+ if (!t)
+ {
+ fprintf(stderr, "Could not open file %s for writing\n", tmpfile);
+ exit(2);
+ }
+
+ initStringInfo(&linebuf);
+
+ while (pg_get_line_buf(s, &linebuf))
+ {
+ char *p1 = strstr(linebuf.data, "connection to server ");
+
+ if (p1)
+ {
+ char *p2 = strstr(p1, "failed: ");
+
+ if (p2)
+ {
+ memmove(p1 + 21, p2, strlen(p2) + 1);
+ /* we don't bother to fix up linebuf.len */
+ }
+ }
+ fputs(linebuf.data, t);
+ }
+
+ pfree(linebuf.data);
+ fclose(s);
+ fclose(t);
+ if (rename(tmpfile, resultfile) != 0)
+ {
+ fprintf(stderr, "Could not overwrite file %s with %s\n",
+ resultfile, tmpfile);
+ exit(2);
+ }
+}
+
+/*
+ * start an ecpg test process for specified file (including redirection),
+ * and return process ID
+ */
+
+static PID_TYPE
+ecpg_start_test(const char *testname,
+ _stringlist **resultfiles,
+ _stringlist **expectfiles,
+ _stringlist **tags)
+{
+ PID_TYPE pid;
+ char inprg[MAXPGPATH];
+ char insource[MAXPGPATH];
+ StringInfoData testname_dash;
+ char outfile_stdout[MAXPGPATH],
+ expectfile_stdout[MAXPGPATH];
+ char outfile_stderr[MAXPGPATH],
+ expectfile_stderr[MAXPGPATH];
+ char outfile_source[MAXPGPATH],
+ expectfile_source[MAXPGPATH];
+ char cmd[MAXPGPATH * 3];
+ char *appnameenv;
+
+ snprintf(inprg, sizeof(inprg), "%s/%s", inputdir, testname);
+ snprintf(insource, sizeof(insource), "%s.c", testname);
+
+ /* make a version of the test name that has dashes in place of slashes */
+ initStringInfo(&testname_dash);
+ appendStringInfoString(&testname_dash, testname);
+ for (char *c = testname_dash.data; *c != '\0'; c++)
+ {
+ if (*c == '/')
+ *c = '-';
+ }
+
+ snprintf(expectfile_stdout, sizeof(expectfile_stdout),
+ "%s/expected/%s.stdout",
+ outputdir, testname_dash.data);
+ snprintf(expectfile_stderr, sizeof(expectfile_stderr),
+ "%s/expected/%s.stderr",
+ outputdir, testname_dash.data);
+ snprintf(expectfile_source, sizeof(expectfile_source),
+ "%s/expected/%s.c",
+ outputdir, testname_dash.data);
+
+ snprintf(outfile_stdout, sizeof(outfile_stdout),
+ "%s/results/%s.stdout",
+ outputdir, testname_dash.data);
+ snprintf(outfile_stderr, sizeof(outfile_stderr),
+ "%s/results/%s.stderr",
+ outputdir, testname_dash.data);
+ snprintf(outfile_source, sizeof(outfile_source),
+ "%s/results/%s.c",
+ outputdir, testname_dash.data);
+
+ add_stringlist_item(resultfiles, outfile_stdout);
+ add_stringlist_item(expectfiles, expectfile_stdout);
+ add_stringlist_item(tags, "stdout");
+
+ add_stringlist_item(resultfiles, outfile_stderr);
+ add_stringlist_item(expectfiles, expectfile_stderr);
+ add_stringlist_item(tags, "stderr");
+
+ add_stringlist_item(resultfiles, outfile_source);
+ add_stringlist_item(expectfiles, expectfile_source);
+ add_stringlist_item(tags, "source");
+
+ ecpg_filter_source(insource, outfile_source);
+
+ snprintf(cmd, sizeof(cmd),
+ "\"%s\" >\"%s\" 2>\"%s\"",
+ inprg,
+ outfile_stdout,
+ outfile_stderr);
+
+ appnameenv = psprintf("ecpg/%s", testname_dash.data);
+ setenv("PGAPPNAME", appnameenv, 1);
+ free(appnameenv);
+
+ pid = spawn_process(cmd);
+
+ if (pid == INVALID_PID)
+ {
+ fprintf(stderr, _("could not start process for test %s\n"),
+ testname);
+ exit(2);
+ }
+
+ unsetenv("PGAPPNAME");
+
+ free(testname_dash.data);
+
+ return pid;
+}
+
+static void
+ecpg_postprocess_result(const char *filename)
+{
+ int nlen = strlen(filename);
+
+ /* Only stderr files require filtering, at the moment */
+ if (nlen > 7 && strcmp(filename + nlen - 7, ".stderr") == 0)
+ {
+ char *tmpfile = psprintf("%s.tmp", filename);
+
+ ecpg_filter_stderr(filename, tmpfile);
+ pfree(tmpfile);
+ }
+}
+
+static void
+ecpg_init(int argc, char *argv[])
+{
+ /* nothing to do here at the moment */
+}
+
+int
+main(int argc, char *argv[])
+{
+ return regression_main(argc, argv,
+ ecpg_init,
+ ecpg_start_test,
+ ecpg_postprocess_result);
+}