1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <libpq-fe.h>
4
+ #include <string.h>
5
+
6
+ typedef struct {
7
+ char * query ;
8
+ char * * expectedResults ;
9
+ int expectedRows ;
10
+ int expectedCols ;
11
+ } Test ;
12
+
13
+ typedef struct {
14
+ PGconn * conn ;
15
+ Test * tests ;
16
+ int testCount ;
17
+ } PGTest ;
18
+
19
+ void connectDB (PGTest * pgTest , const char * ip , int port , const char * user , const char * password ) {
20
+ char conninfo [256 ];
21
+ snprintf (conninfo , sizeof (conninfo ), "host=%s port=%d dbname=main user=%s password=%s" , ip , port , user , password );
22
+ pgTest -> conn = PQconnectdb (conninfo );
23
+ if (PQstatus (pgTest -> conn ) != CONNECTION_OK ) {
24
+ printf ("Connection to database failed: %s" , PQerrorMessage (pgTest -> conn ));
25
+ PQfinish (pgTest -> conn );
26
+ exit (1 );
27
+ }
28
+ }
29
+
30
+ void disconnectDB (PGTest * pgTest ) {
31
+ PQfinish (pgTest -> conn );
32
+ }
33
+
34
+ void addTest (PGTest * pgTest , const char * query , char * * expectedResults , int expectedRows , int expectedCols ) {
35
+ pgTest -> tests = realloc (pgTest -> tests , sizeof (Test ) * (pgTest -> testCount + 1 ));
36
+ pgTest -> tests [pgTest -> testCount ].query = strdup (query );
37
+ pgTest -> tests [pgTest -> testCount ].expectedResults = expectedResults ;
38
+ pgTest -> tests [pgTest -> testCount ].expectedRows = expectedRows ;
39
+ pgTest -> tests [pgTest -> testCount ].expectedCols = expectedCols ;
40
+ pgTest -> testCount ++ ;
41
+ }
42
+
43
+ int runTests (PGTest * pgTest ) {
44
+ for (int i = 0 ; i < pgTest -> testCount ; i ++ ) {
45
+ Test * test = & pgTest -> tests [i ];
46
+ printf ("Running test: %s\n" , test -> query );
47
+ PGresult * res = PQexec (pgTest -> conn , test -> query );
48
+ if (PQresultStatus (res ) != PGRES_TUPLES_OK && PQresultStatus (res ) != PGRES_COMMAND_OK ) {
49
+ printf ("Query failed: %s\n" , PQerrorMessage (pgTest -> conn ));
50
+ PQclear (res );
51
+ return 0 ;
52
+ }
53
+ if (PQresultStatus (res ) == PGRES_TUPLES_OK ) {
54
+ int rows = PQntuples (res );
55
+ int cols = PQnfields (res );
56
+ if (cols != test -> expectedCols ) {
57
+ printf ("Expected %d columns, got %d\n" , test -> expectedCols , cols );
58
+ PQclear (res );
59
+ return 0 ;
60
+ }
61
+ for (int r = 0 ; r < rows ; r ++ ) {
62
+ for (int c = 0 ; c < cols ; c ++ ) {
63
+ char * result = PQgetvalue (res , r , c );
64
+ if (strcmp (result , test -> expectedResults [r * cols + c ]) != 0 ) {
65
+ printf ("Expected: '%s', got: '%s'\n" , test -> expectedResults [r * cols + c ], result );
66
+ PQclear (res );
67
+ return 0 ;
68
+ }
69
+ }
70
+ }
71
+ if (rows != test -> expectedRows ) {
72
+ printf ("Expected %d rows, got %d\n" , test -> expectedRows , rows );
73
+ PQclear (res );
74
+ return 0 ;
75
+ }
76
+ }
77
+ PQclear (res );
78
+ }
79
+ return 1 ;
80
+ }
81
+
82
+ size_t removeNewline (char * line ) {
83
+ size_t len = strlen (line );
84
+ if (len > 0 && (line [len - 1 ] == '\n' || line [len - 1 ] == '\r' )) {
85
+ line [-- len ] = '\0' ;
86
+ }
87
+ if (len > 0 && line [len - 1 ] == '\r' ) {
88
+ line [-- len ] = '\0' ;
89
+ }
90
+ return len ;
91
+ }
92
+
93
+ void readTestsFromFile (PGTest * pgTest , const char * filename ) {
94
+ FILE * file = fopen (filename , "r" );
95
+ if (!file ) {
96
+ perror ("Failed to open test data file" );
97
+ exit (1 );
98
+ }
99
+
100
+ char line [1024 ];
101
+ while (fgets (line , sizeof (line ), file )) {
102
+ size_t len = removeNewline (line );
103
+ if (len == 0 ) continue ;
104
+
105
+ char * query = strdup (line );
106
+ char * * expectedResults = NULL ;
107
+ int expectedRows = 0 , expectedCols = 0 ;
108
+
109
+ while (fgets (line , sizeof (line ), file )) {
110
+ len = removeNewline (line );
111
+ if (len == 0 ) break ;
112
+
113
+ char * token = strtok (line , "," );
114
+ int col = 0 ;
115
+ while (token ) {
116
+ expectedResults = realloc (expectedResults , sizeof (char * ) * (expectedRows * expectedCols + col + 1 ));
117
+ expectedResults [expectedRows * expectedCols + col ] = strdup (token );
118
+ token = strtok (NULL , "," );
119
+ col ++ ;
120
+ }
121
+ expectedRows ++ ;
122
+ if (expectedCols == 0 ) expectedCols = col ;
123
+ }
124
+ addTest (pgTest , query , expectedResults , expectedRows , expectedCols );
125
+ }
126
+
127
+ fclose (file );
128
+ }
129
+
130
+ int main (int argc , char * argv []) {
131
+ if (argc != 6 ) {
132
+ printf ("Usage: %s <ip> <port> <user> <password> <testFile>\n" , argv [0 ]);
133
+ return 1 ;
134
+ }
135
+
136
+ PGTest pgTest = {0 };
137
+ connectDB (& pgTest , argv [1 ], atoi (argv [2 ]), argv [3 ], argv [4 ]);
138
+
139
+ readTestsFromFile (& pgTest , argv [5 ]);
140
+
141
+ int result = runTests (& pgTest );
142
+ disconnectDB (& pgTest );
143
+ free (pgTest .tests );
144
+ return result ? 0 : 1 ;
145
+ }
0 commit comments