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