1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
32 // main.cpp: main program for Glean
50 using namespace GLEAN
;
52 char* mandatoryArg(int argc
, char* argv
[], int i
);
53 void selectTests(Options
& o
, vector
<string
>& allTestNames
, int argc
,
55 void usage(char* command
);
56 void listTests(const Test
*tests
, bool verbose
);
59 main(int argc
, char* argv
[]) {
61 // Until someone gets around to writing a fancy GUI front-end,
62 // we'll set options the old-fashioned way.
64 bool visFilter
= false;
66 vector
<string
> allTestNames
;
67 for (Test
* t
= Test::testList
; t
; t
= t
->nextTest
)
68 allTestNames
.push_back(t
->name
);
69 sort(allTestNames
.begin(), allTestNames
.end());
70 o
.selectedTests
= allTestNames
;
72 for (int i
= 1; i
< argc
; ++i
) {
73 if (!strcmp(argv
[i
], "--help")) {
75 } else if (!strcmp(argv
[i
], "-v")
76 || !strcmp(argv
[i
], "--verbose")) {
78 } else if (!strcmp(argv
[i
], "-r")
79 || !strcmp(argv
[i
], "--run")) {
80 o
.mode
= Options::run
;
82 o
.db1Name
= mandatoryArg(argc
, argv
, i
);
83 } else if (!strcmp(argv
[i
], "-o")
84 || !strcmp(argv
[i
], "--overwrite")) {
86 } else if (!strcmp(argv
[i
], "--quick")) {
88 } else if (!strcmp(argv
[i
], "-c")
89 || !strcmp(argv
[i
], "--compare")) {
90 o
.mode
= Options::compare
;
92 o
.db1Name
= mandatoryArg(argc
, argv
, i
);
94 o
.db2Name
= mandatoryArg(argc
, argv
, i
);
95 } else if (!strcmp(argv
[i
], "--visuals")) {
98 o
.visFilter
= mandatoryArg(argc
, argv
, i
);
99 } else if (!strcmp(argv
[i
], "-t")
100 || !strcmp(argv
[i
], "--tests")) {
102 selectTests(o
, allTestNames
, argc
, argv
, i
);
103 } else if (!strcmp(argv
[i
], "--listtests")) {
104 o
.mode
= Options::listtests
;
105 # if defined(__X11__)
106 } else if (!strcmp(argv
[i
], "-display")
107 || !strcmp(argv
[i
], "--display")) {
109 o
.dpyName
= mandatoryArg(argc
, argv
, i
);
116 if (o
.mode
== Options::notSet
)
119 if (o
.mode
== Options::listtests
) {
120 listTests(Test::testList
, o
.verbosity
);
124 if (o
.quick
&& !visFilter
) {
125 // If we have --quick but not --visuals then limit testing to
126 // a single RGB, Z, Stencil visual.
127 o
.visFilter
= "rgb && z>0 && s>0 && conformant";
131 // Create the test environment, then invoke each test to generate
132 // results or compare two previous runs.
138 for (Test
* t
= Test::testList
; t
; t
= t
->nextTest
)
139 if (binary_search(o
.selectedTests
.begin(),
140 o
.selectedTests
.end(), t
->name
))
144 case Options::compare
:
146 for (Test
* t
= Test::testList
; t
; t
= t
->nextTest
)
147 if (binary_search(o
.selectedTests
.begin(),
148 o
.selectedTests
.end(), t
->name
))
152 catch (Test::CantOpenResultsFile e
) {
153 // For comparisons, we want to
154 // continue running even if a
155 // test result file can't be
156 // opened. We report the
157 // problem here, but don't exit
158 // as we would in the catch{}
160 cerr
<< "Can't open results file for test "
169 cerr
<< "Bad run mode in main()\n";
174 catch (WindowSystem::CantOpenDisplay
) {
175 cerr
<< "can't open display " << o
.dpyName
<< "\n";
179 catch (WindowSystem::NoOpenGL
) {
180 cerr
<< "display doesn't support OpenGL\n";
183 catch (DrawingSurfaceFilter::Syntax e
) {
184 cerr
<< "Syntax error in visual selection criteria:\n"
185 "'" << o
.visFilter
<< "'\n";
186 for (int i
= 0; i
< e
.position
; ++i
)
188 cerr
<< "^ " << e
.err
<< '\n';
191 catch (Environment::DBExists
) {
192 cerr
<< "Won't overwrite existing database " << o
.db1Name
196 catch (Environment::DBCantOpen e
) {
197 cerr
<< "Can't open database directory " << *e
.db
<< "\n";
200 catch (Test::CantOpenResultsFile e
) {
201 cerr
<< "Can't open results file for test " << e
.testName
202 << " in database " << e
.dbName
<< '\n';
206 cerr
<< "caught an unexpected error in main()\n";
215 mandatoryArg(int argc
, char* argv
[], int i
) {
216 if (i
< argc
&& argv
[i
][0] != '-')
225 selectTests(Options
& o
, vector
<string
>& allTestNames
, int argc
, char* argv
[],
230 // At present, we deal with the following syntax:
231 // [+] testname {(+|-) testname}
232 // Assume we're running none of the tests, then include
233 // those preceded by "+" and exclude those preceded by
235 // - testname {(+|-) testname}
236 // Assume we're running all of the tests, then exclude
237 // those preceded by "-" and include those preceded by
239 // XXX It would be nice to support the syntax "@filename" to mean
240 // "the list of tests given in the named file." This could be
241 // preceded by "+" or "-" just like an ordinary test name, or maybe
242 // the +/- should be required in the file itself.
246 SyntaxError(int pos
): position(pos
) { }
252 if (lex
.token
== Lex::MINUS
)
253 o
.selectedTests
= allTestNames
;
255 o
.selectedTests
.resize(0);
257 while (lex
.token
!= Lex::END
) {
258 bool inserting
= true;
259 if (lex
.token
== Lex::MINUS
) {
262 } else if (lex
.token
== Lex::PLUS
)
265 if (lex
.token
!= Lex::ID
)
266 throw SyntaxError(lex
.position());
268 if (!binary_search(allTestNames
.begin(),
269 allTestNames
.end(), lex
.id
))
270 cerr
<< "Warning: " << lex
.id
<< " ignored;"
271 " not a valid test name.\n";
273 vector
<string
>::iterator p
=
274 lower_bound(o
.selectedTests
.begin(),
275 o
.selectedTests
.end(), lex
.id
);
277 if (p
== o
.selectedTests
.end()
279 o
.selectedTests
.insert(p
,
283 if (p
!= o
.selectedTests
.end()
285 o
.selectedTests
.erase(p
);
291 catch (Lex::Lexical e
) {
292 cerr
<< "Lexical error in test inclusion/exclusion list:\n"
293 "'" << argv
[i
] << "'\n";
294 for (int i
= 0; i
< e
.position
; ++i
)
296 cerr
<< "^ " << e
.err
<< "\n\n";
299 catch (SyntaxError e
) {
300 cerr
<< "'" << argv
[i
] << "'\n";
301 for (int i
= 0; i
< e
.position
; ++i
)
303 cerr
<< "^ Syntax error in test inclusion/exclusion list\n\n";
310 listTests(const Test
*tests
, bool verbose
) {
311 for (const Test
*t
= tests
; t
; t
= t
->nextTest
) {
312 cout
<< t
->name
<< (verbose
? ":" : "") << "\n";
314 cout
<< t
->description
;
322 usage(char* command
) {
323 cerr
<< GLEAN::versionString
<< '\n';
324 cerr
<< "Usage: " << command
<< " mode [options]\n"
327 " (-r|--run) results-directory\n"
328 " or (-c|--compare) old-results-dir new-results-dir\n"
331 " (-v|--verbose) # each occurrence increases\n"
332 " # verbosity of output\n"
333 " (-o|--overwrite) # overwrite existing results database\n"
334 " --visuals 'filter-string' # select subset of visuals (FBConfigs,\n"
335 " # pixel formats) to test\n"
336 " (-t|--tests) {(+|-)test} # choose tests to include (+) or exclude (-)\n"
337 " --quick # run fewer tests to reduce test time\n"
338 " --listtests # list test names and exit\n"
339 " --help # display usage information\n"
341 " -display X11-display-name # select X11 display to use\n"
343 #elif defined(__WIN__)