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