TPCCLIB
Loading...
Searching...
No Matches
resmatch.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpccurveio.h"
19/*****************************************************************************/
20
21/******************************************************************************/
22double ROUGH_TEST_LIMIT=0.01;
23double AROUND_TEST_LIMIT=0.05;
24/******************************************************************************/
25
26/******************************************************************************/
27static char *info[] = {
28 "Verify that two result files do have matching contents;",
29 "this can be used for automating software and analysis tool testing.",
30 "Programs return code is 0, if files were matching, 10, if the files did",
31 "not match, and 1-9 in case of error.",
32 " ",
33 "Usage: @P [Options] file1 file2",
34 " ",
35 "Options:",
36 " -header=<y|N>",
37 " Header fields are verified (y) or not verified (n, default)",
38 " -param[eters]=<y|N>",
39 " Parameter names are verified (y) or not verified (n, default)",
40 " -regions=<y|N>",
41 " Region names are verified (y) or not verified (n, default)",
42 " -res[ults]=<List of result column numbers (e.g. -res=1-2 or -res=1,3)>",
43 " By default all result values are verified. With this option,",
44 " only selected columns (or none with -res=0) are verified.",
45 " -roughly",
46 " Result values are required to match roughly (<2% difference allowed).",
47 " -around",
48 " Results are required to be around the same (<10% difference allowed).",
49 " -abs=<value>",
50 " Absolute result differences must not exceed the specified limit value",
51 " -errors=<Y|n>",
52 " Result errors (SD, CL) are verified (y, default) or not verified (n)",
53 " -stdoptions", // List standard options like --help, -v, etc
54 " ",
55 "See also: reslist, res2html, resdel, pardiff, fit2res, tacmatch, imgmatch",
56 " ",
57 "Keywords: results, tool, software testing",
58 0};
59/*****************************************************************************/
60
61/*****************************************************************************/
62/* Turn on the globbing of the command line, since it is disabled by default in
63 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
64 In Unix&Linux wildcard command line processing is enabled by default. */
65/*
66#undef _CRT_glob
67#define _CRT_glob -1
68*/
69int _dowildcard = -1;
70/*****************************************************************************/
71
72/*****************************************************************************/
76int main(int argc, char **argv)
77{
78 int ai, help=0, version=0, verbose=1;
79 int pi, ri, n, test_nr=0, ret, ok=0;
80 char *cptr, resfile1[FILENAME_MAX], resfile2[FILENAME_MAX];
81 RES res1, res2;
82 INT_list parlist;
83 /* Optional tests */
84 int header=0;
85 int parameters=0;
86 int regions=0;
87 int rough_test=0;
88 int test_errors=1;
89 double test_limit=1.0E-15;
90 double test_abs=-1.0;
91
92
93 /*
94 * Get arguments
95 */
96 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
97 resfile1[0]=resfile2[0]=(char)0;
98 resInit(&res1); resInit(&res2);
99 parlist.nr=0;
100 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* option */
101 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
102 cptr=argv[ai]+1;
103 if(strncasecmp(cptr, "HEADER=", 7)==0) {
104 cptr+=7;
105 if(strncasecmp(cptr, "YES", 1)==0) {header=1; continue;}
106 else if(strncasecmp(cptr, "NO", 1)==0) {header=0; continue;}
107 } else if(strncasecmp(cptr, "PARAMETERS=", 11)==0) {
108 cptr+=11;
109 if(strncasecmp(cptr, "YES", 1)==0) {parameters=1; continue;}
110 else if(strncasecmp(cptr, "NO", 1)==0) {parameters=0; continue;}
111 } else if(strncasecmp(cptr, "PARAM=", 6)==0) {
112 cptr+=6;
113 if(strncasecmp(cptr, "YES", 1)==0) {parameters=1; continue;}
114 else if(strncasecmp(cptr, "NO", 1)==0) {parameters=0; continue;}
115 } else if(strncasecmp(cptr, "REGIONS=", 8)==0) {
116 cptr+=8;
117 if(strncasecmp(cptr, "YES", 1)==0) {regions=1; continue;}
118 else if(strncasecmp(cptr, "NO", 1)==0) {regions=0; continue;}
119 } else if(strncasecmp(cptr, "ROUGHLY", 5)==0) {
120 rough_test=1; test_limit=ROUGH_TEST_LIMIT;
121 if(test_abs<0.0) continue;
122 } else if(strncasecmp(cptr, "AROUND", 5)==0) {
123 rough_test=2; test_limit=AROUND_TEST_LIMIT; continue;
124 } else if(strncasecmp(cptr, "RESULTS=", 8)==0) {
125 if(parlist.nr==0) {
126 ret=intExpand(cptr+8, &parlist);
127 if(ret==0 && parlist.nr>0 && parlist.i[0]>=0) continue;
128 }
129 } else if(strncasecmp(cptr, "RES=", 4)==0) {
130 if(parlist.nr==0) {
131 ret=intExpand(cptr+4, &parlist);
132 if(ret==0 && parlist.nr>0 && parlist.i[0]>=0) continue;
133 }
134 } else if(strncasecmp(cptr, "ABS=", 4)==0) {
135 cptr+=4; test_abs=atof_dpi(cptr);
136 if(test_abs>=0.0 && rough_test==0) continue;
137 } else if(strncasecmp(cptr, "ERRORS=", 7)==0) {
138 cptr+=7;
139 if(strncasecmp(cptr, "YES", 1)==0) {test_errors=1; continue;}
140 else if(strncasecmp(cptr, "NO", 1)==0) {test_errors=0; continue;}
141 }
142 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
143 if(parlist.nr>0) free(parlist.i);
144 return(1);
145 } else break;
146
147 /* Print help or version? */
148 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
149 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
150 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
151
152 /* Process other arguments, starting from the first non-option */
153 for(; ai<argc; ai++) {
154 if(!resfile1[0]) {
155 strlcpy(resfile1, argv[ai], FILENAME_MAX); continue;
156 } else if(!resfile2[0]) {
157 strlcpy(resfile2, argv[ai], FILENAME_MAX); continue;
158 }
159 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
160 if(parlist.nr>0) free(parlist.i);
161 return(1);
162 }
163
164 /* Is something missing? */
165 if(!resfile2[0]) {
166 fprintf(stderr, "Error: missing result file name.\n");
167 if(parlist.nr>0) free(parlist.i);
168 return(1);
169 }
170
171 /* In verbose mode print arguments and options */
172 if(verbose>0) {
173 printf("resfile1 := %s\n", resfile1);
174 printf("resfile2 := %s\n", resfile2);
175 printf("header := %d\n", header);
176 printf("parameters := %d\n", parameters);
177 printf("regions := %d\n", regions);
178 printf("rough_test := %d\n", rough_test);
179 printf("test_limit := %g\n", test_limit);
180 printf("test_abs := %g\n", test_abs);
181 printf("test_errors := %d\n", test_errors);
182 printf("results :=");
183 for(pi=0; pi<parlist.nr; pi++) printf(" %d", parlist.i[pi]);
184 printf("\n");
185 }
186 if(verbose>10) RESULT_TEST=verbose-10;
187
188
189 /*
190 * Read result files
191 */
192 if(verbose>0) printf("reading results\n");
193 if(resRead(resfile1, &res1, verbose-2)) {
194 fprintf(stderr, "Error in reading '%s': %s\n", resfile1, reserrmsg);
195 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
196 return(2);
197 }
198 if(resRead(resfile2, &res2, verbose-2)) {
199 fprintf(stderr, "Error in reading '%s': %s\n", resfile2, reserrmsg);
200 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
201 return(2);
202 }
203 /* Check that selected columns exist in results */
204 if(parlist.nr>0 && parlist.i[0]>0) {
205 for(pi=0; pi<parlist.nr; pi++) if(parlist.i[pi]>res1.parNr) {
206 fprintf(stderr, "Error: results do not contain required column %d\n",
207 parlist.i[pi]);
208 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
209 return(1);
210 }
211 }
212 /* Report the file names */
213 if(verbose>=0) {
214 printf("file1 := %s\n", resfile1);
215 printf("file2 := %s\n", resfile2);
216 }
217
218 /*
219 * Test the number of regions
220 */
221 if(verbose>0) printf("testing number of regions\n");
222 if(res1.voiNr!=res2.voiNr) {
223 if(verbose>=0) fprintf(stdout, "result := no match\n");
224 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
225 return(10);
226 }
227 test_nr++;
228
229 /*
230 * Test the number of parameters
231 */
232 if(verbose>0) printf("testing number of parameters\n");
233 if(res1.parNr!=res2.parNr) {
234 /* That is not a problem if the last parameters are not to be compared */
235 if(parlist.nr<=0) ok=0;
236 else if(parlist.nr==1 && parlist.i[0]==0) ok=1;
237 else for(pi=0, ok=1; pi<parlist.nr; pi++)
238 if(parlist.i[pi]>res1.parNr || parlist.i[pi]>res2.parNr) {ok=0; break;}
239 if(ok!=1) {
240 if(verbose>=0) fprintf(stdout, "result := no match\n");
241 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
242 return(10);
243 }
244 }
245 test_nr++;
246
247 /*
248 * Check header fields
249 */
250 if(header) {
251 if(verbose>0) printf("testing header\n");
252 if((ret=resMatchHeader(&res1, &res2))!=0) {
253 if(verbose>=0)
254 fprintf(stdout, "result := no match in header field (%d)\n", ret);
255 if(ret!=5) { // other missmatches than studynr are considered important
256 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
257 return(10);
258 }
259 }
260 test_nr++;
261 }
262
263 /*
264 * Check region names
265 */
266 if(regions) {
267 if(verbose>0) printf("testing regions\n");
268 if(resMatchRegions(&res1, &res2)) {
269 if(verbose>=0) fprintf(stdout, "result := no match in regions\n");
270 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
271 return(10);
272 }
273 test_nr++;
274 }
275
276 /*
277 * Check result parameter names
278 */
279 if(parameters) {
280 if(verbose>0) printf("testing regions\n");
281 if(resMatchParameternames(&res1, &res2)) {
282 if(verbose>=0) fprintf(stdout, "result := no match in parameter names\n");
283 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
284 return(10);
285 }
286 test_nr++;
287 }
288
289 /*
290 * Check result parameter values
291 */
292 if(parlist.nr==1 && parlist.i[0]==0) {
293 if(verbose>0) printf("parameter values are NOT tested\n");
294 } else {
295 if(verbose>0) printf("testing parameter values\n");
296 for(ri=0, n=0; ri<res1.parNr; ri++) {
297 if(parlist.nr>0) { /* should this column be verified? */
298 for(pi=ok=0; pi<parlist.nr; pi++) if(ri==parlist.i[pi]-1) {ok=1; break;}
299 if(ok==0) continue;
300 }
301 n++;
302 if(verbose>2) printf(" test parameter values for col %d\n", ri+1);
303 if(test_abs<0.0)
304 ret=resMatchParameters(&res1, &res2, ri, test_limit, test_errors);
305 else
306 ret=resMatchParametersAbs(&res1, &res2, ri, test_abs, test_errors);
307 if(ret!=0) {
308 if(verbose>1) printf(" ret:=%d\n", ret);
309 if(verbose>=0) fprintf(stdout, "result := no match in parameter values (column %d)\n", ri+1);
310 if(verbose>2) {
311 for(int i=0; i<res1.voiNr; i++)
312 printf(" %g vs %g\n", res1.voi[i].parameter[ri], res2.voi[i].parameter[ri]);
313 }
314 resEmpty(&res1); resEmpty(&res2); if(parlist.nr>0) free(parlist.i);
315 return(10);
316 }
317 }
318 if(n>0) test_nr++;
319 }
320
321 /* Report the success */
322 if(verbose>=0) {
323 fprintf(stdout, "result := match was found\n");
324 fprintf(stdout, "nr_of_tests := %d\n", test_nr);
325 }
326
327 resEmpty(&res1); resEmpty(&res2);
328 if(parlist.nr>0) free(parlist.i);
329 return(0);
330}
331/******************************************************************************/
332
333/******************************************************************************/
335
double atof_dpi(char *str)
Definition decpoint.c:59
int intExpand(char *text, INT_list *list)
Definition intex.c:43
Header file for libtpccurveio.
char reserrmsg[64]
Definition result.c:6
void resInit(RES *res)
Definition result.c:52
int resMatchRegions(RES *res1, RES *res2)
Definition result.c:1531
int resMatchParameternames(RES *res1, RES *res2)
Definition result.c:1564
int resRead(char *filename, RES *res, int verbose)
Definition result.c:199
int resMatchParameters(RES *res1, RES *res2, int test_par, double test_limit, int test_sd)
Definition result.c:1600
int resMatchHeader(RES *res1, RES *res2)
Definition result.c:1494
int resMatchParametersAbs(RES *res1, RES *res2, int test_par, double test_limit, int test_sd)
Definition result.c:1694
void resEmpty(RES *res)
Definition result.c:22
int RESULT_TEST
Definition result.c:5
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
int * i
Definition libtpcmisc.h:322
int parNr
int voiNr
ResVOI * voi
double parameter[MAX_RESPARAMS]