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