blob: 72d440229aa922ae9408eae80753e20f45671efd [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program Tester Core
* ----------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Command line parsing.
*//*--------------------------------------------------------------------*/
#include "tcuCommandLine.hpp"
#include "tcuPlatform.hpp"
#include "deFilePath.hpp"
#include "deStringUtil.hpp"
#include "deString.h"
#include "deInt32.h"
#include "deCommandLine.h"
#include "qpTestLog.h"
#include "qpDebugOut.h"
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
using std::string;
using std::vector;
// OOM tests are enabled by default only on platforms that don't do memory overcommit (Win32)
#if (DE_OS == DE_OS_WIN32)
# define TEST_OOM_DEFAULT "enable"
#else
# define TEST_OOM_DEFAULT "disable"
#endif
namespace tcu
{
namespace opt
{
DE_DECLARE_COMMAND_LINE_OPT(CasePath, std::string);
DE_DECLARE_COMMAND_LINE_OPT(CaseList, std::string);
DE_DECLARE_COMMAND_LINE_OPT(CaseListFile, std::string);
DE_DECLARE_COMMAND_LINE_OPT(StdinCaseList, bool);
DE_DECLARE_COMMAND_LINE_OPT(LogFilename, std::string);
DE_DECLARE_COMMAND_LINE_OPT(RunMode, tcu::RunMode);
DE_DECLARE_COMMAND_LINE_OPT(WatchDog, bool);
DE_DECLARE_COMMAND_LINE_OPT(CrashHandler, bool);
DE_DECLARE_COMMAND_LINE_OPT(BaseSeed, int);
DE_DECLARE_COMMAND_LINE_OPT(TestIterationCount, int);
DE_DECLARE_COMMAND_LINE_OPT(Visibility, WindowVisibility);
DE_DECLARE_COMMAND_LINE_OPT(SurfaceWidth, int);
DE_DECLARE_COMMAND_LINE_OPT(SurfaceHeight, int);
DE_DECLARE_COMMAND_LINE_OPT(SurfaceType, tcu::SurfaceType);
DE_DECLARE_COMMAND_LINE_OPT(ScreenRotation, tcu::ScreenRotation);
DE_DECLARE_COMMAND_LINE_OPT(GLContextType, std::string);
DE_DECLARE_COMMAND_LINE_OPT(GLConfigID, int);
DE_DECLARE_COMMAND_LINE_OPT(GLConfigName, std::string);
DE_DECLARE_COMMAND_LINE_OPT(GLContextFlags, std::string);
DE_DECLARE_COMMAND_LINE_OPT(CLPlatformID, int);
DE_DECLARE_COMMAND_LINE_OPT(CLDeviceIDs, std::vector<int>);
DE_DECLARE_COMMAND_LINE_OPT(CLBuildOptions, std::string);
DE_DECLARE_COMMAND_LINE_OPT(EGLDisplayType, std::string);
DE_DECLARE_COMMAND_LINE_OPT(EGLWindowType, std::string);
DE_DECLARE_COMMAND_LINE_OPT(EGLPixmapType, std::string);
DE_DECLARE_COMMAND_LINE_OPT(LogImages, bool);
DE_DECLARE_COMMAND_LINE_OPT(TestOOM, bool);
static void parseIntList (const char* src, std::vector<int>* dst)
{
std::istringstream str (src);
std::string val;
while (std::getline(str, val, ','))
{
int intVal = 0;
de::cmdline::parseType(val.c_str(), &intVal);
dst->push_back(intVal);
}
}
void registerOptions (de::cmdline::Parser& parser)
{
using de::cmdline::Option;
using de::cmdline::NamedValue;
static const NamedValue<bool> s_enableNames[] =
{
{ "enable", true },
{ "disable", false }
};
static const NamedValue<tcu::RunMode> s_runModes[] =
{
{ "execute", RUNMODE_EXECUTE },
{ "xml-caselist", RUNMODE_DUMP_XML_CASELIST },
{ "txt-caselist", RUNMODE_DUMP_TEXT_CASELIST }
};
static const NamedValue<WindowVisibility> s_visibilites[] =
{
{ "windowed", WINDOWVISIBILITY_WINDOWED },
{ "fullscreen", WINDOWVISIBILITY_FULLSCREEN },
{ "hidden", WINDOWVISIBILITY_HIDDEN }
};
static const NamedValue<tcu::SurfaceType> s_surfaceTypes[] =
{
{ "window", SURFACETYPE_WINDOW },
{ "pixmap", SURFACETYPE_OFFSCREEN_NATIVE },
{ "pbuffer", SURFACETYPE_OFFSCREEN_GENERIC },
{ "fbo", SURFACETYPE_FBO }
};
static const NamedValue<tcu::ScreenRotation> s_screenRotations[] =
{
{ "0", SCREENROTATION_0 },
{ "90", SCREENROTATION_90 },
{ "180", SCREENROTATION_180 },
{ "270", SCREENROTATION_270 }
};
parser
<< Option<CasePath> ("n", "deqp-case", "Test case(s) to run, supports wildcards (e.g. dEQP-GLES2.info.*)")
<< Option<CaseList> (DE_NULL, "deqp-caselist", "Case list to run in trie format (e.g. {dEQP-GLES2{info{version,renderer}}})")
<< Option<CaseListFile> (DE_NULL, "deqp-caselist-file", "Read case list (in trie format) from given file")
<< Option<StdinCaseList> (DE_NULL, "deqp-stdin-caselist", "Read case list (in trie format) from stdin")
<< Option<LogFilename> (DE_NULL, "deqp-log-filename", "Write test results to given file", "TestResults.qpa")
<< Option<RunMode> (DE_NULL, "deqp-runmode", "Execute tests, or write list of test cases into a file",
s_runModes, "execute")
<< Option<WatchDog> (DE_NULL, "deqp-watchdog", "Enable test watchdog", s_enableNames, "disable")
<< Option<CrashHandler> (DE_NULL, "deqp-crashhandler", "Enable crash handling", s_enableNames, "disable")
<< Option<BaseSeed> (DE_NULL, "deqp-base-seed", "Base seed for test cases that use randomization")
<< Option<TestIterationCount> (DE_NULL, "deqp-test-iteration-count", "Iteration count for cases that support variable number of iterations")
<< Option<Visibility> (DE_NULL, "deqp-visibility", "Default test window visibility", s_visibilites, "windowed")
<< Option<SurfaceWidth> (DE_NULL, "deqp-surface-width", "Use given surface width if possible", "-1")
<< Option<SurfaceHeight> (DE_NULL, "deqp-surface-height", "Use given surface height if possible", "-1")
<< Option<SurfaceType> (DE_NULL, "deqp-surface-type", "Use given surface type", s_surfaceTypes, "window")
<< Option<ScreenRotation> (DE_NULL, "deqp-screen-rotation", "Screen rotation for platforms that support it", s_screenRotations, "0")
<< Option<GLContextType> (DE_NULL, "deqp-gl-context-type", "OpenGL context type for platforms that support multiple")
<< Option<GLConfigID> (DE_NULL, "deqp-gl-config-id", "OpenGL (ES) render config ID (EGL config id on EGL platforms)", "-1")
<< Option<GLConfigName> (DE_NULL, "deqp-gl-config-name", "Symbolic OpenGL (ES) render config name")
<< Option<GLContextFlags> (DE_NULL, "deqp-gl-context-flags", "OpenGL context flags (comma-separated, supports debug and robust)")
<< Option<CLPlatformID> (DE_NULL, "deqp-cl-platform-id", "Execute tests on given OpenCL platform (IDs start from 1)", "1")
<< Option<CLDeviceIDs> (DE_NULL, "deqp-cl-device-ids", "Execute tests on given CL devices (comma-separated, IDs start from 1)", parseIntList)
<< Option<CLBuildOptions> (DE_NULL, "deqp-cl-build-options", "Extra build options for OpenCL compiler")
<< Option<EGLDisplayType> (DE_NULL, "deqp-egl-display-type", "EGL native display type")
<< Option<EGLWindowType> (DE_NULL, "deqp-egl-window-type", "EGL native window type")
<< Option<EGLPixmapType> (DE_NULL, "deqp-egl-pixmap-type", "EGL native pixmap type")
<< Option<LogImages> (DE_NULL, "deqp-log-images", "Enable or disable logging of result images", s_enableNames, "enable")
<< Option<TestOOM> (DE_NULL, "deqp-test-oom", "Run tests that exhaust memory on purpose", s_enableNames, TEST_OOM_DEFAULT);
}
void registerLegacyOptions (de::cmdline::Parser& parser)
{
using de::cmdline::Option;
parser
<< Option<GLConfigID> (DE_NULL, "deqp-egl-config-id", "Legacy name for --deqp-gl-config-id", "-1")
<< Option<GLConfigName> (DE_NULL, "deqp-egl-config-name", "Legacy name for --deqp-gl-config-name");
}
} // opt
// \todo [2014-02-13 pyry] This could be useful elsewhere as well.
class DebugOutStreambuf : public std::streambuf
{
public:
DebugOutStreambuf (void);
~DebugOutStreambuf (void);
protected:
std::streamsize xsputn (const char* s, std::streamsize count);
int overflow (int ch = -1);
private:
void flushLine (void);
std::ostringstream m_curLine;
};
DebugOutStreambuf::DebugOutStreambuf (void)
{
}
DebugOutStreambuf::~DebugOutStreambuf (void)
{
if (m_curLine.tellp() != std::streampos(0))
flushLine();
}
std::streamsize DebugOutStreambuf::xsputn (const char* s, std::streamsize count)
{
for (std::streamsize pos = 0; pos < count; pos++)
{
m_curLine.put(s[pos]);
if (s[pos] == '\n')
flushLine();
}
return count;
}
int DebugOutStreambuf::overflow (int ch)
{
if (ch == -1)
return -1;
else
{
DE_ASSERT((ch & 0xff) == ch);
const char chVal = (char)(deUint8)(ch & 0xff);
return xsputn(&chVal, 1) == 1 ? ch : -1;
}
}
void DebugOutStreambuf::flushLine (void)
{
qpPrint(m_curLine.str().c_str());
m_curLine.str("");
}
class CaseTreeNode
{
public:
CaseTreeNode (const std::string& name) : m_name(name) {}
~CaseTreeNode (void);
void addChild (CaseTreeNode* child) { m_children.push_back(child); }
const std::string& getName (void) const { return m_name; }
const std::vector<CaseTreeNode*>& getChildren (void) const { return m_children; }
private:
CaseTreeNode (const CaseTreeNode&);
CaseTreeNode& operator= (const CaseTreeNode&);
std::string m_name;
std::vector<CaseTreeNode*> m_children;
};
CaseTreeNode::~CaseTreeNode (void)
{
for (vector<CaseTreeNode*>::const_iterator i = m_children.begin(); i != m_children.end(); ++i)
delete *i;
}
static CaseTreeNode* parseCaseTree (std::istream& in)
{
vector<CaseTreeNode*> nodeStack;
string curName;
if (in.get() != '{')
throw std::invalid_argument("Malformed case tree");
nodeStack.reserve(1);
nodeStack.push_back(new CaseTreeNode(""));
try
{
for (;;)
{
const int curChr = in.get();
if (curChr == std::char_traits<char>::eof() || curChr == 0)
break;
if (nodeStack.empty())
throw std::invalid_argument("Trailing characters at end of case tree");
if (!curName.empty() && (curChr == '{' || curChr == ',' || curChr == '}'))
{
// Create child and push to stack.
nodeStack.reserve(nodeStack.size()+1);
nodeStack.push_back(new CaseTreeNode(curName));
curName.clear();
}
if (curChr == ',' || curChr == '}')
{
// Attach to parent
if (nodeStack.size() < 2)
throw std::invalid_argument("Malformed case tree");
(*(nodeStack.end()-2))->addChild(nodeStack.back());
nodeStack.pop_back();
}
else if (curChr != '{')
curName += (char)curChr;
}
if (nodeStack.size() != 1 || nodeStack[0]->getName() != "")
throw std::invalid_argument("Unterminated case tree");
}
catch (...)
{
// Nodes in stack are not attached to any parents and must be deleted individually.
for (vector<CaseTreeNode*>::const_iterator i = nodeStack.begin(); i != nodeStack.end(); ++i)
delete *i;
throw;
}
return nodeStack[0];
}
class CasePaths
{
public:
CasePaths (const string& pathList);
bool matches (const string& caseName, bool allowPrefix=false) const;
private:
const vector<string> m_casePatterns;
};
CasePaths::CasePaths (const string& pathList)
: m_casePatterns(de::splitString(pathList, ','))
{
}
// Match a single path component against a pattern component that may contain *-wildcards.
static bool matchWildcards(string::const_iterator patternStart,
string::const_iterator patternEnd,
string::const_iterator pathStart,
string::const_iterator pathEnd,
bool allowPrefix)
{
string::const_iterator pattern = patternStart;
string::const_iterator path = pathStart;
while (pattern != patternEnd && path != pathEnd && *pattern == *path)
{
++pattern;
++path;
}
if (pattern == patternEnd)
return (path == pathEnd);
else if (*pattern == '*')
{
for (; path != pathEnd; ++path)
{
if (matchWildcards(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
return true;
}
if (matchWildcards(pattern + 1, patternEnd, pathEnd, pathEnd, allowPrefix))
return true;
}
else if (path == pathEnd && allowPrefix)
return true;
return false;
}
#if defined(TCU_HIERARCHICAL_CASEPATHS)
// Match a list of pattern components to a list of path components. A pattern
// component may contain *-wildcards. A pattern component "**" matches zero or
// more whole path components.
static bool patternMatches(vector<string>::const_iterator patternStart,
vector<string>::const_iterator patternEnd,
vector<string>::const_iterator pathStart,
vector<string>::const_iterator pathEnd,
bool allowPrefix)
{
vector<string>::const_iterator pattern = patternStart;
vector<string>::const_iterator path = pathStart;
while (pattern != patternEnd && path != pathEnd && *pattern != "**" &&
(*pattern == *path || matchWildcards(pattern->begin(), pattern->end(),
path->begin(), path->end(), false)))
{
++pattern;
++path;
}
if (path == pathEnd && (allowPrefix || pattern == patternEnd))
return true;
else if (pattern != patternEnd && *pattern == "**")
{
for (; path != pathEnd; ++path)
if (patternMatches(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
return true;
if (patternMatches(pattern + 1, patternEnd, path, pathEnd, allowPrefix))
return true;
}
return false;
}
#endif
bool CasePaths::matches (const string& caseName, bool allowPrefix) const
{
const vector<string> components = de::splitString(caseName, '.');
for (size_t ndx = 0; ndx < m_casePatterns.size(); ++ndx)
{
#if defined(TCU_HIERARCHICAL_CASEPATHS)
const vector<string> patternComponents = de::splitString(m_casePatterns[ndx], '.');
if (patternMatches(patternComponents.begin(), patternComponents.end(),
components.begin(), components.end(), allowPrefix))
return true;
#else
if (matchWildcards(m_casePatterns[ndx].begin(), m_casePatterns[ndx].end(),
caseName.begin(), caseName.end(), allowPrefix))
return true;
#endif
}
return false;
}
/*--------------------------------------------------------------------*//*!
* \brief Construct command line
* \note CommandLine is not fully initialized until parse() has been called.
*//*--------------------------------------------------------------------*/
CommandLine::CommandLine (void)
: m_logFlags (0)
, m_caseTree (DE_NULL)
{
}
/*--------------------------------------------------------------------*//*!
* \brief Construct command line from standard argc, argv pair.
*
* Calls parse() with given arguments
* \param argc Number of arguments
* \param argv Command line arguments
*//*--------------------------------------------------------------------*/
CommandLine::CommandLine (int argc, const char* const* argv)
: m_logFlags (0)
, m_caseTree (DE_NULL)
{
if (!parse(argc, argv))
throw Exception("Failed to parse command line");
}
/*--------------------------------------------------------------------*//*!
* \brief Construct command line from string.
*
* Calls parse() with given argument.
* \param cmdLine Full command line string.
*//*--------------------------------------------------------------------*/
CommandLine::CommandLine (const std::string& cmdLine)
: m_logFlags (0)
, m_caseTree (DE_NULL)
{
if (!parse(cmdLine))
throw Exception("Failed to parse command line");
}
CommandLine::~CommandLine (void)
{
delete m_caseTree;
}
void CommandLine::clear (void)
{
m_cmdLine.clear();
m_logFlags = 0;
delete m_caseTree;
m_caseTree = DE_NULL;
}
/*--------------------------------------------------------------------*//*!
* \brief Parse command line from standard argc, argv pair.
* \note parse() must be called exactly once.
* \param argc Number of arguments
* \param argv Command line arguments
*//*--------------------------------------------------------------------*/
bool CommandLine::parse (int argc, const char* const* argv)
{
DebugOutStreambuf sbuf;
std::ostream debugOut (&sbuf);
de::cmdline::Parser parser;
opt::registerOptions(parser);
opt::registerLegacyOptions(parser);
clear();
if (!parser.parse(argc-1, argv+1, &m_cmdLine, std::cerr))
{
debugOut << "\n" << de::FilePath(argv[0]).getBaseName() << " [options]\n\n";
parser.help(debugOut);
clear();
return false;
}
if (!m_cmdLine.getOption<opt::LogImages>())
m_logFlags |= QP_TEST_LOG_EXCLUDE_IMAGES;
if ((m_cmdLine.getOption<opt::CasePath>().empty()?0:1) +
(m_cmdLine.getOption<opt::CaseList>().empty()?0:1) +
(m_cmdLine.getOption<opt::CaseListFile>().empty()?0:1) +
(m_cmdLine.getOption<opt::StdinCaseList>()?1:0) > 1)
{
debugOut << "ERROR: multiple test case list options given!\n" << std::endl;
clear();
return false;
}
try
{
if (!m_cmdLine.getOption<opt::CaseList>().empty())
{
std::istringstream str(m_cmdLine.getOption<opt::CaseList>());
m_caseTree = parseCaseTree(str);
}
else if (!m_cmdLine.getOption<opt::CaseListFile>().empty())
{
std::ifstream in(m_cmdLine.getOption<opt::CaseListFile>().c_str(), std::ios_base::binary);
if (!in.is_open() || !in.good())
throw Exception("Failed to open case list file '" + m_cmdLine.getOption<opt::CaseListFile>() + "'");
m_caseTree = parseCaseTree(in);
}
else if (m_cmdLine.getOption<opt::StdinCaseList>())
{
m_caseTree = parseCaseTree(std::cin);
}
else if (!m_cmdLine.getOption<opt::CasePath>().empty())
m_casePaths = de::MovePtr<const CasePaths>(new CasePaths(m_cmdLine.getOption<opt::CasePath>()));
}
catch (const std::exception& e)
{
debugOut << "ERROR: Failed to parse test case list: " << e.what() << "\n";
clear();
return false;
}
return true;
}
/*--------------------------------------------------------------------*//*!
* \brief Parse command line from string.
* \note parse() must be called exactly once.
* \param cmdLine Full command line string.
*//*--------------------------------------------------------------------*/
bool CommandLine::parse (const std::string& cmdLine)
{
deCommandLine* parsedCmdLine = deCommandLine_parse(cmdLine.c_str());
if (!parsedCmdLine)
throw std::bad_alloc();
bool isOk = false;
try
{
isOk = parse(parsedCmdLine->numArgs, parsedCmdLine->args);
}
catch (...)
{
deCommandLine_destroy(parsedCmdLine);
throw;
}
deCommandLine_destroy(parsedCmdLine);
return isOk;
}
const char* CommandLine::getLogFileName (void) const { return m_cmdLine.getOption<opt::LogFilename>().c_str(); }
deUint32 CommandLine::getLogFlags (void) const { return m_logFlags; }
RunMode CommandLine::getRunMode (void) const { return m_cmdLine.getOption<opt::RunMode>(); }
WindowVisibility CommandLine::getVisibility (void) const { return m_cmdLine.getOption<opt::Visibility>(); }
bool CommandLine::isWatchDogEnabled (void) const { return m_cmdLine.getOption<opt::WatchDog>(); }
bool CommandLine::isCrashHandlingEnabled (void) const { return m_cmdLine.getOption<opt::CrashHandler>(); }
int CommandLine::getBaseSeed (void) const { return m_cmdLine.getOption<opt::BaseSeed>(); }
int CommandLine::getTestIterationCount (void) const { return m_cmdLine.getOption<opt::TestIterationCount>(); }
int CommandLine::getSurfaceWidth (void) const { return m_cmdLine.getOption<opt::SurfaceWidth>(); }
int CommandLine::getSurfaceHeight (void) const { return m_cmdLine.getOption<opt::SurfaceHeight>(); }
SurfaceType CommandLine::getSurfaceType (void) const { return m_cmdLine.getOption<opt::SurfaceType>(); }
ScreenRotation CommandLine::getScreenRotation (void) const { return m_cmdLine.getOption<opt::ScreenRotation>(); }
int CommandLine::getGLConfigId (void) const { return m_cmdLine.getOption<opt::GLConfigID>(); }
int CommandLine::getCLPlatformId (void) const { return m_cmdLine.getOption<opt::CLPlatformID>(); }
const std::vector<int>& CommandLine::getCLDeviceIds (void) const { return m_cmdLine.getOption<opt::CLDeviceIDs>(); }
const char* CommandLine::getEGLDisplayType (void) const { return m_cmdLine.getOption<opt::EGLDisplayType>().c_str(); }
const char* CommandLine::getEGLWindowType (void) const { return m_cmdLine.getOption<opt::EGLWindowType>().c_str(); }
const char* CommandLine::getEGLPixmapType (void) const { return m_cmdLine.getOption<opt::EGLPixmapType>().c_str(); }
bool CommandLine::isOutOfMemoryTestEnabled (void) const { return m_cmdLine.getOption<opt::TestOOM>(); }
const char* CommandLine::getGLContextType (void) const
{
if (!m_cmdLine.getOption<opt::GLContextType>().empty())
return m_cmdLine.getOption<opt::GLContextType>().c_str();
else
return DE_NULL;
}
const char* CommandLine::getGLConfigName (void) const
{
if (!m_cmdLine.getOption<opt::GLConfigName>().empty())
return m_cmdLine.getOption<opt::GLConfigName>().c_str();
else
return DE_NULL;
}
const char* CommandLine::getGLContextFlags (void) const
{
if (!m_cmdLine.getOption<opt::GLContextFlags>().empty())
return m_cmdLine.getOption<opt::GLContextFlags>().c_str();
else
return DE_NULL;
}
const char* CommandLine::getCLBuildOptions (void) const
{
if (!m_cmdLine.getOption<opt::CLBuildOptions>().empty())
return m_cmdLine.getOption<opt::CLBuildOptions>().c_str();
else
return DE_NULL;
}
static bool checkTestGroupName (const CaseTreeNode* node, const char* groupName)
{
for (vector<CaseTreeNode*>::const_iterator childIter = node->getChildren().begin(); childIter != node->getChildren().end(); ++childIter)
{
const CaseTreeNode* const child = *childIter;
if (deStringBeginsWith(groupName, child->getName().c_str()))
{
const int prefixLen = (int)child->getName().length();
if (groupName[prefixLen] == 0)
return true;
else if (groupName[prefixLen] == '.')
return checkTestGroupName(child, groupName + prefixLen + 1);
}
}
return false;
}
static bool checkTestCaseName (const CaseTreeNode* node, const char* caseName)
{
for (vector<CaseTreeNode*>::const_iterator childIter = node->getChildren().begin(); childIter != node->getChildren().end(); ++childIter)
{
const CaseTreeNode* const child = *childIter;
if (deStringBeginsWith(caseName, child->getName().c_str()))
{
const int prefixLen = (int)child->getName().length();
if (caseName[prefixLen] == 0 && child->getChildren().empty())
return true;
else if (caseName[prefixLen] == '.')
return checkTestCaseName(child, caseName + prefixLen + 1);
}
}
return false;
}
bool CommandLine::checkTestGroupName (const char* groupName) const
{
if (m_casePaths)
return m_casePaths->matches(groupName, true);
else if (m_caseTree)
return groupName[0] == 0 || tcu::checkTestGroupName(m_caseTree, groupName);
else
return true;
}
bool CommandLine::checkTestCaseName (const char* caseName) const
{
if (m_casePaths)
return m_casePaths->matches(caseName, false);
else if (m_caseTree)
return tcu::checkTestCaseName(m_caseTree, caseName);
else
return true;
}
} // tcu