LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/test - pg_regress_ecpg.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 87.1 % 93 81
Test Date: 2026-07-27 02:17:12 Functions: 100.0 % 6 6
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 76.3 % 38 29

             Branch data     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-2026, 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                 :         135 : ecpg_filter_source(const char *sourcefile, const char *outfile)
      35                 :             : {
      36                 :             :     FILE       *s,
      37                 :             :                *t;
      38                 :             :     StringInfoData linebuf;
      39                 :             : 
      40                 :         135 :     s = fopen(sourcefile, "r");
      41         [ -  + ]:         135 :     if (!s)
      42                 :             :     {
      43                 :           0 :         fprintf(stderr, "Could not open file %s for reading\n", sourcefile);
      44                 :           0 :         exit(2);
      45                 :             :     }
      46                 :         135 :     t = fopen(outfile, "w");
      47         [ -  + ]:         135 :     if (!t)
      48                 :             :     {
      49                 :           0 :         fprintf(stderr, "Could not open file %s for writing\n", outfile);
      50                 :           0 :         exit(2);
      51                 :             :     }
      52                 :             : 
      53                 :         135 :     initStringInfo(&linebuf);
      54                 :             : 
      55         [ +  + ]:       35633 :     while (pg_get_line_buf(s, &linebuf))
      56                 :             :     {
      57                 :             :         /* check for "#line " in the beginning */
      58         [ +  + ]:       35498 :         if (strstr(linebuf.data, "#line ") == linebuf.data)
      59                 :             :         {
      60                 :        5915 :             char       *p = strchr(linebuf.data, '"');
      61                 :        5915 :             int         plen = 1;
      62                 :             : 
      63   [ +  -  +  +  :        7413 :             while (*p && (*(p + plen) == '.' || strchr(p + plen, '/') != NULL))
                   +  + ]
      64                 :             :             {
      65                 :        1498 :                 plen++;
      66                 :             :             }
      67                 :             :             /* plen is one more than the number of . and / characters */
      68         [ +  + ]:        5915 :             if (plen > 1)
      69                 :             :             {
      70                 :         210 :                 memmove(p + 1, p + plen, strlen(p + plen) + 1);
      71                 :             :                 /* we don't bother to fix up linebuf.len */
      72                 :             :             }
      73                 :             :         }
      74                 :       35498 :         fputs(linebuf.data, t);
      75                 :             :     }
      76                 :             : 
      77                 :         135 :     pfree(linebuf.data);
      78                 :         135 :     fclose(s);
      79                 :         135 :     fclose(t);
      80                 :         135 : }
      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                 :         135 : ecpg_filter_stderr(const char *resultfile, const char *tmpfile)
      94                 :             : {
      95                 :             :     FILE       *s,
      96                 :             :                *t;
      97                 :             :     StringInfoData linebuf;
      98                 :             : 
      99                 :         135 :     s = fopen(resultfile, "r");
     100         [ -  + ]:         135 :     if (!s)
     101                 :             :     {
     102                 :           0 :         fprintf(stderr, "Could not open file %s for reading\n", resultfile);
     103                 :           0 :         exit(2);
     104                 :             :     }
     105                 :         135 :     t = fopen(tmpfile, "w");
     106         [ -  + ]:         135 :     if (!t)
     107                 :             :     {
     108                 :           0 :         fprintf(stderr, "Could not open file %s for writing\n", tmpfile);
     109                 :           0 :         exit(2);
     110                 :             :     }
     111                 :             : 
     112                 :         135 :     initStringInfo(&linebuf);
     113                 :             : 
     114         [ +  + ]:       14106 :     while (pg_get_line_buf(s, &linebuf))
     115                 :             :     {
     116                 :       13971 :         char       *p1 = strstr(linebuf.data, "connection to server ");
     117                 :             : 
     118         [ +  + ]:       13971 :         if (p1)
     119                 :             :         {
     120                 :           6 :             char       *p2 = strstr(p1, "failed: ");
     121                 :             : 
     122         [ +  - ]:           6 :             if (p2)
     123                 :             :             {
     124                 :           6 :                 memmove(p1 + 21, p2, strlen(p2) + 1);
     125                 :             :                 /* we don't bother to fix up linebuf.len */
     126                 :             :             }
     127                 :             :         }
     128                 :       13971 :         fputs(linebuf.data, t);
     129                 :             :     }
     130                 :             : 
     131                 :         135 :     pfree(linebuf.data);
     132                 :         135 :     fclose(s);
     133                 :         135 :     fclose(t);
     134         [ -  + ]:         135 :     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                 :         135 : }
     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                 :         135 : 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                 :         135 :     snprintf(inprg, sizeof(inprg), "%s/%s", inputdir, testname);
     167                 :         135 :     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                 :         135 :     initStringInfo(&testname_dash);
     171                 :         135 :     appendStringInfoString(&testname_dash, testname);
     172         [ +  + ]:        2230 :     for (char *c = testname_dash.data; *c != '\0'; c++)
     173                 :             :     {
     174         [ +  + ]:        2095 :         if (*c == '/')
     175                 :         135 :             *c = '-';
     176                 :             :     }
     177                 :             : 
     178                 :         135 :     snprintf(expectfile_stdout, sizeof(expectfile_stdout),
     179                 :             :              "%s/expected/%s.stdout",
     180                 :             :              expecteddir, testname_dash.data);
     181                 :         135 :     snprintf(expectfile_stderr, sizeof(expectfile_stderr),
     182                 :             :              "%s/expected/%s.stderr",
     183                 :             :              expecteddir, testname_dash.data);
     184                 :         135 :     snprintf(expectfile_source, sizeof(expectfile_source),
     185                 :             :              "%s/expected/%s.c",
     186                 :             :              expecteddir, testname_dash.data);
     187                 :             : 
     188                 :         135 :     snprintf(outfile_stdout, sizeof(outfile_stdout),
     189                 :             :              "%s/results/%s.stdout",
     190                 :             :              outputdir, testname_dash.data);
     191                 :         135 :     snprintf(outfile_stderr, sizeof(outfile_stderr),
     192                 :             :              "%s/results/%s.stderr",
     193                 :             :              outputdir, testname_dash.data);
     194                 :         135 :     snprintf(outfile_source, sizeof(outfile_source),
     195                 :             :              "%s/results/%s.c",
     196                 :             :              outputdir, testname_dash.data);
     197                 :             : 
     198                 :         135 :     add_stringlist_item(resultfiles, outfile_stdout);
     199                 :         135 :     add_stringlist_item(expectfiles, expectfile_stdout);
     200                 :         135 :     add_stringlist_item(tags, "stdout");
     201                 :             : 
     202                 :         135 :     add_stringlist_item(resultfiles, outfile_stderr);
     203                 :         135 :     add_stringlist_item(expectfiles, expectfile_stderr);
     204                 :         135 :     add_stringlist_item(tags, "stderr");
     205                 :             : 
     206                 :         135 :     add_stringlist_item(resultfiles, outfile_source);
     207                 :         135 :     add_stringlist_item(expectfiles, expectfile_source);
     208                 :         135 :     add_stringlist_item(tags, "source");
     209                 :             : 
     210                 :         135 :     ecpg_filter_source(insource, outfile_source);
     211                 :             : 
     212                 :         135 :     snprintf(cmd, sizeof(cmd),
     213                 :             :              "\"%s\" >\"%s\" 2>\"%s\"",
     214                 :             :              inprg,
     215                 :             :              outfile_stdout,
     216                 :             :              outfile_stderr);
     217                 :             : 
     218                 :         135 :     appnameenv = psprintf("ecpg/%s", testname_dash.data);
     219                 :         135 :     setenv("PGAPPNAME", appnameenv, 1);
     220                 :         135 :     pfree(appnameenv);
     221                 :             : 
     222                 :         135 :     pid = spawn_process(cmd);
     223                 :             : 
     224         [ -  + ]:         135 :     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                 :         135 :     unsetenv("PGAPPNAME");
     232                 :             : 
     233                 :         135 :     free(testname_dash.data);
     234                 :             : 
     235                 :         135 :     return pid;
     236                 :             : }
     237                 :             : 
     238                 :             : static void
     239                 :         405 : ecpg_postprocess_result(const char *filename)
     240                 :             : {
     241                 :         405 :     int         nlen = strlen(filename);
     242                 :             : 
     243                 :             :     /* Only stderr files require filtering, at the moment */
     244   [ +  -  +  + ]:         405 :     if (nlen > 7 && strcmp(filename + nlen - 7, ".stderr") == 0)
     245                 :             :     {
     246                 :         135 :         char       *tmpfile = psprintf("%s.tmp", filename);
     247                 :             : 
     248                 :         135 :         ecpg_filter_stderr(filename, tmpfile);
     249                 :         135 :         pfree(tmpfile);
     250                 :             :     }
     251                 :         405 : }
     252                 :             : 
     253                 :             : static void
     254                 :           2 : ecpg_init(int argc, char *argv[])
     255                 :             : {
     256                 :             :     /* nothing to do here at the moment */
     257                 :           2 : }
     258                 :             : 
     259                 :             : int
     260                 :           2 : main(int argc, char *argv[])
     261                 :             : {
     262                 :           2 :     return regression_main(argc, argv,
     263                 :             :                            ecpg_init,
     264                 :             :                            ecpg_start_test,
     265                 :             :                            ecpg_postprocess_result);
     266                 :             : }
        

Generated by: LCOV version 2.0-1