Merge "Properly clean up data in buffer upload test deinit()."
[platform/upstream/VK-GL-CTS.git] / framework / common / tcuCommandLine.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Command line parsing.
22  *//*--------------------------------------------------------------------*/
23
24 #include "tcuCommandLine.hpp"
25 #include "tcuPlatform.hpp"
26 #include "tcuTestCase.hpp"
27 #include "deFilePath.hpp"
28 #include "deStringUtil.hpp"
29 #include "deString.h"
30 #include "deInt32.h"
31 #include "deCommandLine.h"
32 #include "qpTestLog.h"
33 #include "qpDebugOut.h"
34
35 #include <string>
36 #include <vector>
37 #include <sstream>
38 #include <fstream>
39 #include <iostream>
40
41 using std::string;
42 using std::vector;
43
44 // OOM tests are enabled by default only on platforms that don't do memory overcommit (Win32)
45 #if (DE_OS == DE_OS_WIN32)
46 #       define TEST_OOM_DEFAULT         "enable"
47 #else
48 #       define TEST_OOM_DEFAULT         "disable"
49 #endif
50
51 namespace tcu
52 {
53
54 namespace opt
55 {
56
57 DE_DECLARE_COMMAND_LINE_OPT(CasePath,                                   std::string);
58 DE_DECLARE_COMMAND_LINE_OPT(CaseList,                                   std::string);
59 DE_DECLARE_COMMAND_LINE_OPT(CaseListFile,                               std::string);
60 DE_DECLARE_COMMAND_LINE_OPT(StdinCaseList,                              bool);
61 DE_DECLARE_COMMAND_LINE_OPT(LogFilename,                                std::string);
62 DE_DECLARE_COMMAND_LINE_OPT(RunMode,                                    tcu::RunMode);
63 DE_DECLARE_COMMAND_LINE_OPT(ExportFilenamePattern,              std::string);
64 DE_DECLARE_COMMAND_LINE_OPT(WatchDog,                                   bool);
65 DE_DECLARE_COMMAND_LINE_OPT(CrashHandler,                               bool);
66 DE_DECLARE_COMMAND_LINE_OPT(BaseSeed,                                   int);
67 DE_DECLARE_COMMAND_LINE_OPT(TestIterationCount,                 int);
68 DE_DECLARE_COMMAND_LINE_OPT(Visibility,                                 WindowVisibility);
69 DE_DECLARE_COMMAND_LINE_OPT(SurfaceWidth,                               int);
70 DE_DECLARE_COMMAND_LINE_OPT(SurfaceHeight,                              int);
71 DE_DECLARE_COMMAND_LINE_OPT(SurfaceType,                                tcu::SurfaceType);
72 DE_DECLARE_COMMAND_LINE_OPT(ScreenRotation,                             tcu::ScreenRotation);
73 DE_DECLARE_COMMAND_LINE_OPT(GLContextType,                              std::string);
74 DE_DECLARE_COMMAND_LINE_OPT(GLConfigID,                                 int);
75 DE_DECLARE_COMMAND_LINE_OPT(GLConfigName,                               std::string);
76 DE_DECLARE_COMMAND_LINE_OPT(GLContextFlags,                             std::string);
77 DE_DECLARE_COMMAND_LINE_OPT(CLPlatformID,                               int);
78 DE_DECLARE_COMMAND_LINE_OPT(CLDeviceIDs,                                std::vector<int>);
79 DE_DECLARE_COMMAND_LINE_OPT(CLBuildOptions,                             std::string);
80 DE_DECLARE_COMMAND_LINE_OPT(EGLDisplayType,                             std::string);
81 DE_DECLARE_COMMAND_LINE_OPT(EGLWindowType,                              std::string);
82 DE_DECLARE_COMMAND_LINE_OPT(EGLPixmapType,                              std::string);
83 DE_DECLARE_COMMAND_LINE_OPT(LogImages,                                  bool);
84 DE_DECLARE_COMMAND_LINE_OPT(LogShaderSources,                   bool);
85 DE_DECLARE_COMMAND_LINE_OPT(TestOOM,                                    bool);
86 DE_DECLARE_COMMAND_LINE_OPT(VKDeviceID,                                 int);
87
88 static void parseIntList (const char* src, std::vector<int>* dst)
89 {
90         std::istringstream      str     (src);
91         std::string                     val;
92
93         while (std::getline(str, val, ','))
94         {
95                 int intVal = 0;
96                 de::cmdline::parseType(val.c_str(), &intVal);
97                 dst->push_back(intVal);
98         }
99 }
100
101 void registerOptions (de::cmdline::Parser& parser)
102 {
103         using de::cmdline::Option;
104         using de::cmdline::NamedValue;
105
106         static const NamedValue<bool> s_enableNames[] =
107         {
108                 { "enable",             true    },
109                 { "disable",    false   }
110         };
111         static const NamedValue<tcu::RunMode> s_runModes[] =
112         {
113                 { "execute",            RUNMODE_EXECUTE                         },
114                 { "xml-caselist",       RUNMODE_DUMP_XML_CASELIST       },
115                 { "txt-caselist",       RUNMODE_DUMP_TEXT_CASELIST      },
116                 { "stdout-caselist",RUNMODE_DUMP_STDOUT_CASELIST}
117         };
118         static const NamedValue<WindowVisibility> s_visibilites[] =
119         {
120                 { "windowed",           WINDOWVISIBILITY_WINDOWED       },
121                 { "fullscreen",         WINDOWVISIBILITY_FULLSCREEN     },
122                 { "hidden",                     WINDOWVISIBILITY_HIDDEN         }
123         };
124         static const NamedValue<tcu::SurfaceType> s_surfaceTypes[] =
125         {
126                 { "window",                     SURFACETYPE_WINDOW                              },
127                 { "pixmap",                     SURFACETYPE_OFFSCREEN_NATIVE    },
128                 { "pbuffer",            SURFACETYPE_OFFSCREEN_GENERIC   },
129                 { "fbo",                        SURFACETYPE_FBO                                 }
130         };
131         static const NamedValue<tcu::ScreenRotation> s_screenRotations[] =
132         {
133                 { "unspecified",        SCREENROTATION_UNSPECIFIED      },
134                 { "0",                          SCREENROTATION_0                        },
135                 { "90",                         SCREENROTATION_90                       },
136                 { "180",                        SCREENROTATION_180                      },
137                 { "270",                        SCREENROTATION_270                      }
138         };
139
140         parser
141                 << Option<CasePath>                             ("n",           "deqp-case",                                    "Test case(s) to run, supports wildcards (e.g. dEQP-GLES2.info.*)")
142                 << Option<CaseList>                             (DE_NULL,       "deqp-caselist",                                "Case list to run in trie format (e.g. {dEQP-GLES2{info{version,renderer}}})")
143                 << Option<CaseListFile>                 (DE_NULL,       "deqp-caselist-file",                   "Read case list (in trie format) from given file")
144                 << Option<StdinCaseList>                (DE_NULL,       "deqp-stdin-caselist",                  "Read case list (in trie format) from stdin")
145                 << Option<LogFilename>                  (DE_NULL,       "deqp-log-filename",                    "Write test results to given file",                                     "TestResults.qpa")
146                 << Option<RunMode>                              (DE_NULL,       "deqp-runmode",                                 "Execute tests, or write list of test cases into a file",
147                                                                                                                                                                                                                                                                                 s_runModes,                     "execute")
148                 << Option<ExportFilenamePattern>(DE_NULL,       "deqp-caselist-export-file",    "Set the target file name pattern for caselist export",                                 "${packageName}-cases.${typeExtension}")
149                 << Option<WatchDog>                             (DE_NULL,       "deqp-watchdog",                                "Enable test watchdog",                                                         s_enableNames,          "disable")
150                 << Option<CrashHandler>                 (DE_NULL,       "deqp-crashhandler",                    "Enable crash handling",                                                        s_enableNames,          "disable")
151                 << Option<BaseSeed>                             (DE_NULL,       "deqp-base-seed",                               "Base seed for test cases that use randomization",                                              "0")
152                 << Option<TestIterationCount>   (DE_NULL,       "deqp-test-iteration-count",    "Iteration count for cases that support variable number of iterations", "0")
153                 << Option<Visibility>                   (DE_NULL,       "deqp-visibility",                              "Default test window visibility",                                       s_visibilites,          "windowed")
154                 << Option<SurfaceWidth>                 (DE_NULL,       "deqp-surface-width",                   "Use given surface width if possible",                                                                  "-1")
155                 << Option<SurfaceHeight>                (DE_NULL,       "deqp-surface-height",                  "Use given surface height if possible",                                                                 "-1")
156                 << Option<SurfaceType>                  (DE_NULL,       "deqp-surface-type",                    "Use given surface type",                                                       s_surfaceTypes,         "window")
157                 << Option<ScreenRotation>               (DE_NULL,       "deqp-screen-rotation",                 "Screen rotation for platforms that support it",        s_screenRotations,      "0")
158                 << Option<GLContextType>                (DE_NULL,       "deqp-gl-context-type",                 "OpenGL context type for platforms that support multiple")
159                 << Option<GLConfigID>                   (DE_NULL,       "deqp-gl-config-id",                    "OpenGL (ES) render config ID (EGL config id on EGL platforms)",                "-1")
160                 << Option<GLConfigName>                 (DE_NULL,       "deqp-gl-config-name",                  "Symbolic OpenGL (ES) render config name")
161                 << Option<GLContextFlags>               (DE_NULL,       "deqp-gl-context-flags",                "OpenGL context flags (comma-separated, supports debug and robust)")
162                 << Option<CLPlatformID>                 (DE_NULL,       "deqp-cl-platform-id",                  "Execute tests on given OpenCL platform (IDs start from 1)",                    "1")
163                 << Option<CLDeviceIDs>                  (DE_NULL,       "deqp-cl-device-ids",                   "Execute tests on given CL devices (comma-separated, IDs start from 1)",        parseIntList,   "")
164                 << Option<CLBuildOptions>               (DE_NULL,       "deqp-cl-build-options",                "Extra build options for OpenCL compiler")
165                 << Option<EGLDisplayType>               (DE_NULL,       "deqp-egl-display-type",                "EGL native display type")
166                 << Option<EGLWindowType>                (DE_NULL,       "deqp-egl-window-type",                 "EGL native window type")
167                 << Option<EGLPixmapType>                (DE_NULL,       "deqp-egl-pixmap-type",                 "EGL native pixmap type")
168                 << Option<VKDeviceID>                   (DE_NULL,       "deqp-vk-device-id",                    "Vulkan device ID (IDs start from 1)",                                                                  "1")
169                 << Option<LogImages>                    (DE_NULL,       "deqp-log-images",                              "Enable or disable logging of result images",           s_enableNames,          "enable")
170                 << Option<LogShaderSources>             (DE_NULL,       "deqp-log-shader-sources",              "Enable or disable logging of shader sources",          s_enableNames,          "enable")
171                 << Option<TestOOM>                              (DE_NULL,       "deqp-test-oom",                                "Run tests that exhaust memory on purpose",                     s_enableNames,          TEST_OOM_DEFAULT);
172 }
173
174 void registerLegacyOptions (de::cmdline::Parser& parser)
175 {
176         using de::cmdline::Option;
177
178         parser
179                 << Option<GLConfigID>                   (DE_NULL,       "deqp-egl-config-id",                   "Legacy name for --deqp-gl-config-id",  "-1")
180                 << Option<GLConfigName>                 (DE_NULL,       "deqp-egl-config-name",                 "Legacy name for --deqp-gl-config-name");
181 }
182
183 } // opt
184
185 // \todo [2014-02-13 pyry] This could be useful elsewhere as well.
186 class DebugOutStreambuf : public std::streambuf
187 {
188 public:
189                                                 DebugOutStreambuf       (void);
190                                                 ~DebugOutStreambuf      (void);
191
192 protected:
193         std::streamsize         xsputn                          (const char* s, std::streamsize count);
194         int                                     overflow                        (int ch = -1);
195
196 private:
197         void                            flushLine                       (void);
198
199         std::ostringstream      m_curLine;
200 };
201
202 DebugOutStreambuf::DebugOutStreambuf (void)
203 {
204 }
205
206 DebugOutStreambuf::~DebugOutStreambuf (void)
207 {
208         if (m_curLine.tellp() != std::streampos(0))
209                 flushLine();
210 }
211
212 std::streamsize DebugOutStreambuf::xsputn (const char* s, std::streamsize count)
213 {
214         for (std::streamsize pos = 0; pos < count; pos++)
215         {
216                 m_curLine.put(s[pos]);
217
218                 if (s[pos] == '\n')
219                         flushLine();
220         }
221
222         return count;
223 }
224
225 int DebugOutStreambuf::overflow (int ch)
226 {
227         if (ch == -1)
228                 return -1;
229         else
230         {
231                 DE_ASSERT((ch & 0xff) == ch);
232                 const char chVal = (char)(deUint8)(ch & 0xff);
233                 return xsputn(&chVal, 1) == 1 ? ch : -1;
234         }
235 }
236
237 void DebugOutStreambuf::flushLine (void)
238 {
239         qpPrint(m_curLine.str().c_str());
240         m_curLine.str("");
241 }
242
243 class CaseTreeNode
244 {
245 public:
246                                                                                 CaseTreeNode            (const std::string& name) : m_name(name) {}
247                                                                                 ~CaseTreeNode           (void);
248
249         const std::string&                                      getName                         (void) const { return m_name;                           }
250         bool                                                            hasChildren                     (void) const { return !m_children.empty();      }
251
252         bool                                                            hasChild                        (const std::string& name) const;
253         const CaseTreeNode*                                     getChild                        (const std::string& name) const;
254         CaseTreeNode*                                           getChild                        (const std::string& name);
255
256         void                                                            addChild                        (CaseTreeNode* child) { m_children.push_back(child); }
257
258 private:
259                                                                                 CaseTreeNode            (const CaseTreeNode&);
260         CaseTreeNode&                                           operator=                       (const CaseTreeNode&);
261
262         enum { NOT_FOUND = -1 };
263
264         // \todo [2014-10-30 pyry] Speed up with hash / sorting
265         int                                                                     findChildNdx            (const std::string& name) const;
266
267         std::string                                                     m_name;
268         std::vector<CaseTreeNode*>                      m_children;
269 };
270
271 CaseTreeNode::~CaseTreeNode (void)
272 {
273         for (vector<CaseTreeNode*>::const_iterator i = m_children.begin(); i != m_children.end(); ++i)
274                 delete *i;
275 }
276
277 int CaseTreeNode::findChildNdx (const std::string& name) const
278 {
279         for (int ndx = 0; ndx < (int)m_children.size(); ++ndx)
280         {
281                 if (m_children[ndx]->getName() == name)
282                         return ndx;
283         }
284         return NOT_FOUND;
285 }
286
287 inline bool CaseTreeNode::hasChild (const std::string& name) const
288 {
289         return findChildNdx(name) != NOT_FOUND;
290 }
291
292 inline const CaseTreeNode* CaseTreeNode::getChild (const std::string& name) const
293 {
294         const int ndx = findChildNdx(name);
295         return ndx == NOT_FOUND ? DE_NULL : m_children[ndx];
296 }
297
298 inline CaseTreeNode* CaseTreeNode::getChild (const std::string& name)
299 {
300         const int ndx = findChildNdx(name);
301         return ndx == NOT_FOUND ? DE_NULL : m_children[ndx];
302 }
303
304 static int getCurrentComponentLen (const char* path)
305 {
306         int ndx = 0;
307         for (; path[ndx] != 0 && path[ndx] != '.'; ++ndx);
308         return ndx;
309 }
310
311 static const CaseTreeNode* findNode (const CaseTreeNode* root, const char* path)
312 {
313         const CaseTreeNode*     curNode         = root;
314         const char*                     curPath         = path;
315         int                                     curLen          = getCurrentComponentLen(curPath);
316
317         for (;;)
318         {
319                 curNode = curNode->getChild(std::string(curPath, curPath+curLen));
320
321                 if (!curNode)
322                         break;
323
324                 curPath += curLen;
325
326                 if (curPath[0] == 0)
327                         break;
328                 else
329                 {
330                         DE_ASSERT(curPath[0] == '.');
331                         curPath         += 1;
332                         curLen           = getCurrentComponentLen(curPath);
333                 }
334         }
335
336         return curNode;
337 }
338
339 static void parseCaseTrie (CaseTreeNode* root, std::istream& in)
340 {
341         vector<CaseTreeNode*>   nodeStack;
342         string                                  curName;
343         bool                                    expectNode              = true;
344
345         if (in.get() != '{')
346                 throw std::invalid_argument("Malformed case trie");
347
348         nodeStack.push_back(root);
349
350         while (!nodeStack.empty())
351         {
352                 const int       curChr  = in.get();
353
354                 if (curChr == std::char_traits<char>::eof() || curChr == 0)
355                         throw std::invalid_argument("Unterminated case tree");
356
357                 if (curChr == '{' || curChr == ',' || curChr == '}')
358                 {
359                         if (!curName.empty() && expectNode)
360                         {
361                                 CaseTreeNode* const newChild = new CaseTreeNode(curName);
362
363                                 try
364                                 {
365                                         nodeStack.back()->addChild(newChild);
366                                 }
367                                 catch (...)
368                                 {
369                                         delete newChild;
370                                         throw;
371                                 }
372
373                                 if (curChr == '{')
374                                         nodeStack.push_back(newChild);
375
376                                 curName.clear();
377                         }
378                         else if (curName.empty() == expectNode)
379                                 throw std::invalid_argument(expectNode ? "Empty node name" : "Missing node separator");
380
381                         if (curChr == '}')
382                         {
383                                 expectNode = false;
384                                 nodeStack.pop_back();
385
386                                 // consume trailing new line
387                                 if (nodeStack.empty())
388                                 {
389                                         if (in.peek() == '\r')
390                                           in.get();
391                                         if (in.peek() == '\n')
392                                           in.get();
393                                 }
394                         }
395                         else
396                                 expectNode = true;
397                 }
398                 else if (isValidTestCaseNameChar((char)curChr))
399                         curName += (char)curChr;
400                 else
401                         throw std::invalid_argument("Illegal character in node name");
402         }
403 }
404
405 static void parseCaseList (CaseTreeNode* root, std::istream& in)
406 {
407         // \note Algorithm assumes that cases are sorted by groups, but will
408         //               function fine, albeit more slowly, if that is not the case.
409         vector<CaseTreeNode*>   nodeStack;
410         int                                             stackPos        = 0;
411         string                                  curName;
412
413         nodeStack.resize(8, DE_NULL);
414
415         nodeStack[0] = root;
416
417         for (;;)
418         {
419                 const int       curChr  = in.get();
420
421                 if (curChr == std::char_traits<char>::eof() || curChr == 0 || curChr == '\n' || curChr == '\r')
422                 {
423                         if (curName.empty())
424                                 throw std::invalid_argument("Empty test case name");
425
426                         if (nodeStack[stackPos]->hasChild(curName))
427                                 throw std::invalid_argument("Duplicate test case");
428
429                         CaseTreeNode* const newChild = new CaseTreeNode(curName);
430
431                         try
432                         {
433                                 nodeStack[stackPos]->addChild(newChild);
434                         }
435                         catch (...)
436                         {
437                                 delete newChild;
438                                 throw;
439                         }
440
441                         curName.clear();
442                         stackPos = 0;
443
444                         if (curChr == '\r' && in.peek() == '\n')
445                                 in.get();
446
447                         {
448                                 const int nextChr = in.peek();
449
450                                 if (nextChr == std::char_traits<char>::eof() || nextChr == 0)
451                                         break;
452                         }
453                 }
454                 else if (curChr == '.')
455                 {
456                         if (curName.empty())
457                                 throw std::invalid_argument("Empty test group name");
458
459                         if ((int)nodeStack.size() <= stackPos+1)
460                                 nodeStack.resize(nodeStack.size()*2, DE_NULL);
461
462                         if (!nodeStack[stackPos+1] || nodeStack[stackPos+1]->getName() != curName)
463                         {
464                                 CaseTreeNode* curGroup = nodeStack[stackPos]->getChild(curName);
465
466                                 if (!curGroup)
467                                 {
468                                         curGroup = new CaseTreeNode(curName);
469
470                                         try
471                                         {
472                                                 nodeStack[stackPos]->addChild(curGroup);
473                                         }
474                                         catch (...)
475                                         {
476                                                 delete curGroup;
477                                                 throw;
478                                         }
479                                 }
480
481                                 nodeStack[stackPos+1] = curGroup;
482
483                                 if ((int)nodeStack.size() > stackPos+2)
484                                         nodeStack[stackPos+2] = DE_NULL; // Invalidate rest of entries
485                         }
486
487                         DE_ASSERT(nodeStack[stackPos+1]->getName() == curName);
488
489                         curName.clear();
490                         stackPos += 1;
491                 }
492                 else if (isValidTestCaseNameChar((char)curChr))
493                         curName += (char)curChr;
494                 else
495                         throw std::invalid_argument("Illegal character in test case name");
496         }
497 }
498
499 static CaseTreeNode* parseCaseList (std::istream& in)
500 {
501         CaseTreeNode* const root = new CaseTreeNode("");
502         try
503         {
504                 if (in.peek() == '{')
505                         parseCaseTrie(root, in);
506                 else
507                         parseCaseList(root, in);
508
509                 {
510                         const int curChr = in.get();
511                         if (curChr != std::char_traits<char>::eof() && curChr != 0)
512                                 throw std::invalid_argument("Trailing characters at end of case list");
513                 }
514
515                 return root;
516         }
517         catch (...)
518         {
519                 delete root;
520                 throw;
521         }
522 }
523
524 class CasePaths
525 {
526 public:
527                                                         CasePaths       (const string& pathList);
528         bool                                    matches         (const string& caseName, bool allowPrefix=false) const;
529
530 private:
531         const vector<string>    m_casePatterns;
532 };
533
534 CasePaths::CasePaths (const string& pathList)
535         : m_casePatterns(de::splitString(pathList, ','))
536 {
537 }
538
539 // Match a single path component against a pattern component that may contain *-wildcards.
540 static bool matchWildcards(string::const_iterator       patternStart,
541                                                    string::const_iterator       patternEnd,
542                                                    string::const_iterator       pathStart,
543                                                    string::const_iterator       pathEnd,
544                                                    bool                                         allowPrefix)
545 {
546         string::const_iterator  pattern = patternStart;
547         string::const_iterator  path    = pathStart;
548
549         while (pattern != patternEnd && path != pathEnd && *pattern == *path)
550         {
551                 ++pattern;
552                 ++path;
553         }
554
555         if (pattern == patternEnd)
556                 return (path == pathEnd);
557         else if (*pattern == '*')
558         {
559                 for (; path != pathEnd; ++path)
560                 {
561                         if (matchWildcards(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
562                                 return true;
563                 }
564
565                 if (matchWildcards(pattern + 1, patternEnd, pathEnd, pathEnd, allowPrefix))
566                         return true;
567         }
568         else if (path == pathEnd && allowPrefix)
569                 return true;
570
571         return false;
572 }
573
574 #if defined(TCU_HIERARCHICAL_CASEPATHS)
575 // Match a list of pattern components to a list of path components. A pattern
576 // component may contain *-wildcards. A pattern component "**" matches zero or
577 // more whole path components.
578 static bool patternMatches(vector<string>::const_iterator       patternStart,
579                                                    vector<string>::const_iterator       patternEnd,
580                                                    vector<string>::const_iterator       pathStart,
581                                                    vector<string>::const_iterator       pathEnd,
582                                                    bool                                                         allowPrefix)
583 {
584         vector<string>::const_iterator  pattern = patternStart;
585         vector<string>::const_iterator  path    = pathStart;
586
587         while (pattern != patternEnd && path != pathEnd && *pattern != "**" &&
588                    (*pattern == *path || matchWildcards(pattern->begin(), pattern->end(),
589                                                                                                 path->begin(), path->end(), false)))
590         {
591                 ++pattern;
592                 ++path;
593         }
594
595         if (path == pathEnd && (allowPrefix || pattern == patternEnd))
596                 return true;
597         else if (pattern != patternEnd && *pattern == "**")
598         {
599                 for (; path != pathEnd; ++path)
600                         if (patternMatches(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
601                                 return true;
602                 if (patternMatches(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
603                         return true;
604         }
605
606         return false;
607 }
608 #endif
609
610 bool CasePaths::matches (const string& caseName, bool allowPrefix) const
611 {
612         const vector<string> components = de::splitString(caseName, '.');
613
614         for (size_t ndx = 0; ndx < m_casePatterns.size(); ++ndx)
615         {
616 #if defined(TCU_HIERARCHICAL_CASEPATHS)
617                 const vector<string> patternComponents = de::splitString(m_casePatterns[ndx], '.');
618
619                 if (patternMatches(patternComponents.begin(), patternComponents.end(),
620                                                    components.begin(), components.end(), allowPrefix))
621                         return true;
622 #else
623                 if (matchWildcards(m_casePatterns[ndx].begin(), m_casePatterns[ndx].end(),
624                                                    caseName.begin(), caseName.end(), allowPrefix))
625                         return true;
626 #endif
627         }
628
629         return false;
630 }
631
632 /*--------------------------------------------------------------------*//*!
633  * \brief Construct command line
634  * \note CommandLine is not fully initialized until parse() has been called.
635  *//*--------------------------------------------------------------------*/
636 CommandLine::CommandLine (void)
637         : m_logFlags    (0)
638         , m_caseTree    (DE_NULL)
639 {
640 }
641
642 /*--------------------------------------------------------------------*//*!
643  * \brief Construct command line from standard argc, argv pair.
644  *
645  * Calls parse() with given arguments
646  * \param argc Number of arguments
647  * \param argv Command line arguments
648  *//*--------------------------------------------------------------------*/
649 CommandLine::CommandLine (int argc, const char* const* argv)
650         : m_logFlags    (0)
651         , m_caseTree    (DE_NULL)
652 {
653         if (!parse(argc, argv))
654                 throw Exception("Failed to parse command line");
655 }
656
657 /*--------------------------------------------------------------------*//*!
658  * \brief Construct command line from string.
659  *
660  * Calls parse() with given argument.
661  * \param cmdLine Full command line string.
662  *//*--------------------------------------------------------------------*/
663 CommandLine::CommandLine (const std::string& cmdLine)
664         : m_logFlags    (0)
665         , m_caseTree    (DE_NULL)
666 {
667         if (!parse(cmdLine))
668                 throw Exception("Failed to parse command line");
669 }
670
671 CommandLine::~CommandLine (void)
672 {
673         delete m_caseTree;
674 }
675
676 void CommandLine::clear (void)
677 {
678         m_cmdLine.clear();
679         m_logFlags = 0;
680
681         delete m_caseTree;
682         m_caseTree = DE_NULL;
683 }
684
685 const de::cmdline::CommandLine& CommandLine::getCommandLine (void) const
686 {
687         return m_cmdLine;
688 }
689
690 void CommandLine::registerExtendedOptions (de::cmdline::Parser& parser)
691 {
692         DE_UNREF(parser);
693 }
694
695 /*--------------------------------------------------------------------*//*!
696  * \brief Parse command line from standard argc, argv pair.
697  * \note parse() must be called exactly once.
698  * \param argc Number of arguments
699  * \param argv Command line arguments
700  *//*--------------------------------------------------------------------*/
701 bool CommandLine::parse (int argc, const char* const* argv)
702 {
703         DebugOutStreambuf       sbuf;
704         std::ostream            debugOut        (&sbuf);
705         de::cmdline::Parser     parser;
706
707         opt::registerOptions(parser);
708         opt::registerLegacyOptions(parser);
709         registerExtendedOptions(parser);
710
711         clear();
712
713         if (!parser.parse(argc-1, argv+1, &m_cmdLine, std::cerr))
714         {
715                 debugOut << "\n" << de::FilePath(argv[0]).getBaseName() << " [options]\n\n";
716                 parser.help(debugOut);
717
718                 clear();
719                 return false;
720         }
721
722         if (!m_cmdLine.getOption<opt::LogImages>())
723                 m_logFlags |= QP_TEST_LOG_EXCLUDE_IMAGES;
724
725         if (!m_cmdLine.getOption<opt::LogShaderSources>())
726                 m_logFlags |= QP_TEST_LOG_EXCLUDE_SHADER_SOURCES;
727
728         if ((m_cmdLine.hasOption<opt::CasePath>()?1:0) +
729                 (m_cmdLine.hasOption<opt::CaseList>()?1:0) +
730                 (m_cmdLine.hasOption<opt::CaseListFile>()?1:0) +
731                 (m_cmdLine.getOption<opt::StdinCaseList>()?1:0) > 1)
732         {
733                 debugOut << "ERROR: multiple test case list options given!\n" << std::endl;
734                 clear();
735                 return false;
736         }
737
738         try
739         {
740                 if (m_cmdLine.hasOption<opt::CaseList>())
741                 {
742                         std::istringstream str(m_cmdLine.getOption<opt::CaseList>());
743
744                         m_caseTree = parseCaseList(str);
745                 }
746                 else if (m_cmdLine.hasOption<opt::CaseListFile>())
747                 {
748                         std::ifstream in(m_cmdLine.getOption<opt::CaseListFile>().c_str(), std::ios_base::binary);
749
750                         if (!in.is_open() || !in.good())
751                                 throw Exception("Failed to open case list file '" + m_cmdLine.getOption<opt::CaseListFile>() + "'");
752
753                         m_caseTree = parseCaseList(in);
754                 }
755                 else if (m_cmdLine.getOption<opt::StdinCaseList>())
756                 {
757                         m_caseTree = parseCaseList(std::cin);
758                 }
759                 else if (m_cmdLine.hasOption<opt::CasePath>())
760                         m_casePaths = de::MovePtr<const CasePaths>(new CasePaths(m_cmdLine.getOption<opt::CasePath>()));
761         }
762         catch (const std::exception& e)
763         {
764                 debugOut << "ERROR: Failed to parse test case list: " << e.what() << "\n";
765                 clear();
766                 return false;
767         }
768
769         return true;
770 }
771
772 /*--------------------------------------------------------------------*//*!
773  * \brief Parse command line from string.
774  * \note parse() must be called exactly once.
775  * \param cmdLine Full command line string.
776  *//*--------------------------------------------------------------------*/
777 bool CommandLine::parse (const std::string& cmdLine)
778 {
779         deCommandLine* parsedCmdLine = deCommandLine_parse(cmdLine.c_str());
780         if (!parsedCmdLine)
781                 throw std::bad_alloc();
782
783         bool isOk = false;
784         try
785         {
786                 isOk = parse(parsedCmdLine->numArgs, parsedCmdLine->args);
787         }
788         catch (...)
789         {
790                 deCommandLine_destroy(parsedCmdLine);
791                 throw;
792         }
793
794         deCommandLine_destroy(parsedCmdLine);
795         return isOk;
796 }
797
798 const char*                             CommandLine::getLogFileName                             (void) const    { return m_cmdLine.getOption<opt::LogFilename>().c_str();                       }
799 deUint32                                CommandLine::getLogFlags                                (void) const    { return m_logFlags;                                                                                            }
800 RunMode                                 CommandLine::getRunMode                                 (void) const    { return m_cmdLine.getOption<opt::RunMode>();                                           }
801 const char*                             CommandLine::getCaseListExportFile              (void) const    { return m_cmdLine.getOption<opt::ExportFilenamePattern>().c_str();     }
802 WindowVisibility                CommandLine::getVisibility                              (void) const    { return m_cmdLine.getOption<opt::Visibility>();                                        }
803 bool                                    CommandLine::isWatchDogEnabled                  (void) const    { return m_cmdLine.getOption<opt::WatchDog>();                                          }
804 bool                                    CommandLine::isCrashHandlingEnabled             (void) const    { return m_cmdLine.getOption<opt::CrashHandler>();                                      }
805 int                                             CommandLine::getBaseSeed                                (void) const    { return m_cmdLine.getOption<opt::BaseSeed>();                                          }
806 int                                             CommandLine::getTestIterationCount              (void) const    { return m_cmdLine.getOption<opt::TestIterationCount>();                        }
807 int                                             CommandLine::getSurfaceWidth                    (void) const    { return m_cmdLine.getOption<opt::SurfaceWidth>();                                      }
808 int                                             CommandLine::getSurfaceHeight                   (void) const    { return m_cmdLine.getOption<opt::SurfaceHeight>();                                     }
809 SurfaceType                             CommandLine::getSurfaceType                             (void) const    { return m_cmdLine.getOption<opt::SurfaceType>();                                       }
810 ScreenRotation                  CommandLine::getScreenRotation                  (void) const    { return m_cmdLine.getOption<opt::ScreenRotation>();                            }
811 int                                             CommandLine::getGLConfigId                              (void) const    { return m_cmdLine.getOption<opt::GLConfigID>();                                        }
812 int                                             CommandLine::getCLPlatformId                    (void) const    { return m_cmdLine.getOption<opt::CLPlatformID>();                                      }
813 const std::vector<int>& CommandLine::getCLDeviceIds                             (void) const    { return m_cmdLine.getOption<opt::CLDeviceIDs>();                                       }
814 int                                             CommandLine::getVKDeviceId                              (void) const    { return m_cmdLine.getOption<opt::VKDeviceID>();                                        }
815 bool                                    CommandLine::isOutOfMemoryTestEnabled   (void) const    { return m_cmdLine.getOption<opt::TestOOM>();                                           }
816
817 const char* CommandLine::getGLContextType (void) const
818 {
819         if (m_cmdLine.hasOption<opt::GLContextType>())
820                 return m_cmdLine.getOption<opt::GLContextType>().c_str();
821         else
822                 return DE_NULL;
823 }
824 const char* CommandLine::getGLConfigName (void) const
825 {
826         if (m_cmdLine.hasOption<opt::GLConfigName>())
827                 return m_cmdLine.getOption<opt::GLConfigName>().c_str();
828         else
829                 return DE_NULL;
830 }
831
832 const char* CommandLine::getGLContextFlags (void) const
833 {
834         if (m_cmdLine.hasOption<opt::GLContextFlags>())
835                 return m_cmdLine.getOption<opt::GLContextFlags>().c_str();
836         else
837                 return DE_NULL;
838 }
839
840 const char* CommandLine::getCLBuildOptions (void) const
841 {
842         if (m_cmdLine.hasOption<opt::CLBuildOptions>())
843                 return m_cmdLine.getOption<opt::CLBuildOptions>().c_str();
844         else
845                 return DE_NULL;
846 }
847
848 const char* CommandLine::getEGLDisplayType (void) const
849 {
850         if (m_cmdLine.hasOption<opt::EGLDisplayType>())
851                 return m_cmdLine.getOption<opt::EGLDisplayType>().c_str();
852         else
853                 return DE_NULL;
854 }
855
856 const char* CommandLine::getEGLWindowType (void) const
857 {
858         if (m_cmdLine.hasOption<opt::EGLWindowType>())
859                 return m_cmdLine.getOption<opt::EGLWindowType>().c_str();
860         else
861                 return DE_NULL;
862 }
863
864 const char* CommandLine::getEGLPixmapType (void) const
865 {
866         if (m_cmdLine.hasOption<opt::EGLPixmapType>())
867                 return m_cmdLine.getOption<opt::EGLPixmapType>().c_str();
868         else
869                 return DE_NULL;
870 }
871
872 static bool checkTestGroupName (const CaseTreeNode* root, const char* groupPath)
873 {
874         const CaseTreeNode* node = findNode(root, groupPath);
875         return node && node->hasChildren();
876 }
877
878 static bool checkTestCaseName (const CaseTreeNode* root, const char* casePath)
879 {
880         const CaseTreeNode* node = findNode(root, casePath);
881         return node && !node->hasChildren();
882 }
883
884 bool CommandLine::checkTestGroupName (const char* groupName) const
885 {
886         if (m_casePaths)
887                 return m_casePaths->matches(groupName, true);
888         else if (m_caseTree)
889                 return groupName[0] == 0 || tcu::checkTestGroupName(m_caseTree, groupName);
890         else
891                 return true;
892 }
893
894 bool CommandLine::checkTestCaseName (const char* caseName) const
895 {
896         if (m_casePaths)
897                 return m_casePaths->matches(caseName, false);
898         else if (m_caseTree)
899                 return tcu::checkTestCaseName(m_caseTree, caseName);
900         else
901                 return true;
902 }
903
904 } // tcu