LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/test - pg_regress_ecpg.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 81 93 87.1 %
Date: 2024-12-02 20:15:07 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_regress_ecpg --- regression test driver for ecpg
       4             :  *
       5             :  * This is a C implementation of the previous shell script for running
       6             :  * the regression tests, and should be mostly compatible with it.
       7             :  * Initial author of C translation: Magnus Hagander
       8             :  *
       9             :  * This code is released under the terms of the PostgreSQL License.
      10             :  *
      11             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
      12             :  * Portions Copyright (c) 1994, Regents of the University of California
      13             :  *
      14             :  * src/interfaces/ecpg/test/pg_regress_ecpg.c
      15             :  *
      16             :  *-------------------------------------------------------------------------
      17             :  */
      18             : 
      19             : #include "postgres_fe.h"
      20             : 
      21             : #include "common/string.h"
      22             : #include "lib/stringinfo.h"
      23             : #include "pg_regress.h"
      24             : 
      25             : 
      26             : /*
      27             :  * Create a filtered copy of sourcefile, removing any path
      28             :  * appearing in #line directives; for example, replace
      29             :  * #line x "./../bla/foo.h" with #line x "foo.h".
      30             :  * This is needed because the path part can vary depending
      31             :  * on compiler, platform, build options, etc.
      32             :  */
      33             : static void
      34         262 : ecpg_filter_source(const char *sourcefile, const char *outfile)
      35             : {
      36             :     FILE       *s,
      37             :                *t;
      38             :     StringInfoData linebuf;
      39             : 
      40         262 :     s = fopen(sourcefile, "r");
      41         262 :     if (!s)
      42             :     {
      43           0 :         fprintf(stderr, "Could not open file %s for reading\n", sourcefile);
      44           0 :         exit(2);
      45             :     }
      46         262 :     t = fopen(outfile, "w");
      47         262 :     if (!t)
      48             :     {
      49           0 :         fprintf(stderr, "Could not open file %s for writing\n", outfile);
      50           0 :         exit(2);
      51             :     }
      52             : 
      53         262 :     initStringInfo(&linebuf);
      54             : 
      55       69346 :     while (pg_get_line_buf(s, &linebuf))
      56             :     {
      57             :         /* check for "#line " in the beginning */
      58       69084 :         if (strstr(linebuf.data, "#line ") == linebuf.data)
      59             :         {
      60       11482 :             char       *p = strchr(linebuf.data, '"');
      61       11482 :             int         plen = 1;
      62             : 
      63       14430 :             while (*p && (*(p + plen) == '.' || strchr(p + plen, '/') != NULL))
      64             :             {
      65        2948 :                 plen++;
      66             :             }
      67             :             /* plen is one more than the number of . and / characters */
      68       11482 :             if (plen > 1)
      69             :             {
      70         408 :                 memmove(p + 1, p + plen, strlen(p + plen) + 1);
      71             :                 /* we don't bother to fix up linebuf.len */
      72             :             }
      73             :         }
      74       69084 :         fputs(linebuf.data, t);
      75             :     }
      76             : 
      77         262 :     pfree(linebuf.data);
      78         262 :     fclose(s);
      79         262 :     fclose(t);
      80         262 : }
      81             : 
      82             : /*
      83             :  * Remove the details of connection failure error messages
      84             :  * in a test result file, since the target host/pathname and/or port
      85             :  * can vary.  Rewrite the result file in-place.
      86             :  *
      87             :  * At some point it might be interesting to unify this with
      88             :  * ecpg_filter_source, but building a general pattern matcher
      89             :  * is no fun, nor does it seem desirable to introduce a
      90             :  * dependency on an external one.
      91             :  */
      92             : static void
      93         262 : ecpg_filter_stderr(const char *resultfile, const char *tmpfile)
      94             : {
      95             :     FILE       *s,
      96             :                *t;
      97             :     StringInfoData linebuf;
      98             : 
      99         262 :     s = fopen(resultfile, "r");
     100         262 :     if (!s)
     101             :     {
     102           0 :         fprintf(stderr, "Could not open file %s for reading\n", resultfile);
     103           0 :         exit(2);
     104             :     }
     105         262 :     t = fopen(tmpfile, "w");
     106         262 :     if (!t)
     107             :     {
     108           0 :         fprintf(stderr, "Could not open file %s for writing\n", tmpfile);
     109           0 :         exit(2);
     110             :     }
     111             : 
     112         262 :     initStringInfo(&linebuf);
     113             : 
     114       27384 :     while (pg_get_line_buf(s, &linebuf))
     115             :     {
     116       27122 :         char       *p1 = strstr(linebuf.data, "connection to server ");
     117             : 
     118       27122 :         if (p1)
     119             :         {
     120          12 :             char       *p2 = strstr(p1, "failed: ");
     121             : 
     122          12 :             if (p2)
     123             :             {
     124          12 :                 memmove(p1 + 21, p2, strlen(p2) + 1);
     125             :                 /* we don't bother to fix up linebuf.len */
     126             :             }
     127             :         }
     128       27122 :         fputs(linebuf.data, t);
     129             :     }
     130             : 
     131         262 :     pfree(linebuf.data);
     132         262 :     fclose(s);
     133         262 :     fclose(t);
     134         262 :     if (rename(tmpfile, resultfile) != 0)
     135             :     {
     136           0 :         fprintf(stderr, "Could not overwrite file %s with %s\n",
     137             :                 resultfile, tmpfile);
     138           0 :         exit(2);
     139             :     }
     140         262 : }
     141             : 
     142             : /*
     143             :  * start an ecpg test process for specified file (including redirection),
     144             :  * and return process ID
     145             :  */
     146             : 
     147             : static PID_TYPE
     148         262 : ecpg_start_test(const char *testname,
     149             :                 _stringlist **resultfiles,
     150             :                 _stringlist **expectfiles,
     151             :                 _stringlist **tags)
     152             : {
     153             :     PID_TYPE    pid;
     154             :     char        inprg[MAXPGPATH];
     155             :     char        insource[MAXPGPATH];
     156             :     StringInfoData testname_dash;
     157             :     char        outfile_stdout[MAXPGPATH],
     158             :                 expectfile_stdout[MAXPGPATH];
     159             :     char        outfile_stderr[MAXPGPATH],
     160             :                 expectfile_stderr[MAXPGPATH];
     161             :     char        outfile_source[MAXPGPATH],
     162             :                 expectfile_source[MAXPGPATH];
     163             :     char        cmd[MAXPGPATH * 3];
     164             :     char       *appnameenv;
     165             : 
     166         262 :     snprintf(inprg, sizeof(inprg), "%s/%s", inputdir, testname);
     167         262 :     snprintf(insource, sizeof(insource), "%s/%s.c", inputdir, testname);
     168             : 
     169             :     /* make a version of the test name that has dashes in place of slashes */
     170         262 :     initStringInfo(&testname_dash);
     171         262 :     appendStringInfoString(&testname_dash, testname);
     172        4360 :     for (char *c = testname_dash.data; *c != '\0'; c++)
     173             :     {
     174        4098 :         if (*c == '/')
     175         262 :             *c = '-';
     176             :     }
     177             : 
     178         262 :     snprintf(expectfile_stdout, sizeof(expectfile_stdout),
     179             :              "%s/expected/%s.stdout",
     180             :              expecteddir, testname_dash.data);
     181         262 :     snprintf(expectfile_stderr, sizeof(expectfile_stderr),
     182             :              "%s/expected/%s.stderr",
     183             :              expecteddir, testname_dash.data);
     184         262 :     snprintf(expectfile_source, sizeof(expectfile_source),
     185             :              "%s/expected/%s.c",
     186             :              expecteddir, testname_dash.data);
     187             : 
     188         262 :     snprintf(outfile_stdout, sizeof(outfile_stdout),
     189             :              "%s/results/%s.stdout",
     190             :              outputdir, testname_dash.data);
     191         262 :     snprintf(outfile_stderr, sizeof(outfile_stderr),
     192             :              "%s/results/%s.stderr",
     193             :              outputdir, testname_dash.data);
     194         262 :     snprintf(outfile_source, sizeof(outfile_source),
     195             :              "%s/results/%s.c",
     196             :              outputdir, testname_dash.data);
     197             : 
     198         262 :     add_stringlist_item(resultfiles, outfile_stdout);
     199         262 :     add_stringlist_item(expectfiles, expectfile_stdout);
     200         262 :     add_stringlist_item(tags, "stdout");
     201             : 
     202         262 :     add_stringlist_item(resultfiles, outfile_stderr);
     203         262 :     add_stringlist_item(expectfiles, expectfile_stderr);
     204         262 :     add_stringlist_item(tags, "stderr");
     205             : 
     206         262 :     add_stringlist_item(resultfiles, outfile_source);
     207         262 :     add_stringlist_item(expectfiles, expectfile_source);
     208         262 :     add_stringlist_item(tags, "source");
     209             : 
     210         262 :     ecpg_filter_source(insource, outfile_source);
     211             : 
     212         262 :     snprintf(cmd, sizeof(cmd),
     213             :              "\"%s\" >\"%s\" 2>\"%s\"",
     214             :              inprg,
     215             :              outfile_stdout,
     216             :              outfile_stderr);
     217             : 
     218         262 :     appnameenv = psprintf("ecpg/%s", testname_dash.data);
     219         262 :     setenv("PGAPPNAME", appnameenv, 1);
     220         262 :     free(appnameenv);
     221             : 
     222         262 :     pid = spawn_process(cmd);
     223             : 
     224         262 :     if (pid == INVALID_PID)
     225             :     {
     226           0 :         fprintf(stderr, _("could not start process for test %s\n"),
     227             :                 testname);
     228           0 :         exit(2);
     229             :     }
     230             : 
     231         262 :     unsetenv("PGAPPNAME");
     232             : 
     233         262 :     free(testname_dash.data);
     234             : 
     235         262 :     return pid;
     236             : }
     237             : 
     238             : static void
     239         786 : ecpg_postprocess_result(const char *filename)
     240             : {
     241         786 :     int         nlen = strlen(filename);
     242             : 
     243             :     /* Only stderr files require filtering, at the moment */
     244         786 :     if (nlen > 7 && strcmp(filename + nlen - 7, ".stderr") == 0)
     245             :     {
     246         262 :         char       *tmpfile = psprintf("%s.tmp", filename);
     247             : 
     248         262 :         ecpg_filter_stderr(filename, tmpfile);
     249         262 :         pfree(tmpfile);
     250             :     }
     251         786 : }
     252             : 
     253             : static void
     254           4 : ecpg_init(int argc, char *argv[])
     255             : {
     256             :     /* nothing to do here at the moment */
     257           4 : }
     258             : 
     259             : int
     260           4 : main(int argc, char *argv[])
     261             : {
     262           4 :     return regression_main(argc, argv,
     263             :                            ecpg_init,
     264             :                            ecpg_start_test,
     265             :                            ecpg_postprocess_result);
     266             : }

Generated by: LCOV version 1.14