275 lines
7.2 KiB
C++
275 lines
7.2 KiB
C++
/*-------------------------------------------------------------------------
|
|
* 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 Test case hierarchy iterator.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "tcuTestHierarchyIterator.hpp"
|
|
#include "tcuCommandLine.hpp"
|
|
|
|
namespace tcu
|
|
{
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
|
|
// TestHierarchyInflater
|
|
|
|
TestHierarchyInflater::TestHierarchyInflater (void)
|
|
{
|
|
}
|
|
|
|
TestHierarchyInflater::~TestHierarchyInflater (void)
|
|
{
|
|
}
|
|
|
|
// DefaultHierarchyInflater
|
|
|
|
DefaultHierarchyInflater::DefaultHierarchyInflater (TestContext& testCtx)
|
|
: m_testCtx(testCtx)
|
|
{
|
|
}
|
|
|
|
DefaultHierarchyInflater::~DefaultHierarchyInflater (void)
|
|
{
|
|
}
|
|
|
|
void DefaultHierarchyInflater::enterTestPackage (TestPackage* testPackage, vector<TestNode*>& children)
|
|
{
|
|
{
|
|
Archive* const pkgArchive = testPackage->getArchive();
|
|
|
|
if (pkgArchive)
|
|
m_testCtx.setCurrentArchive(*pkgArchive);
|
|
else
|
|
m_testCtx.setCurrentArchive(m_testCtx.getRootArchive());
|
|
}
|
|
|
|
testPackage->init();
|
|
testPackage->getChildren(children);
|
|
|
|
// write default session info if it was not done by package
|
|
m_testCtx.writeSessionInfo();
|
|
}
|
|
|
|
void DefaultHierarchyInflater::leaveTestPackage (TestPackage* testPackage)
|
|
{
|
|
m_testCtx.setCurrentArchive(m_testCtx.getRootArchive());
|
|
testPackage->deinit();
|
|
}
|
|
|
|
void DefaultHierarchyInflater::enterGroupNode (TestCaseGroup* testGroup, vector<TestNode*>& children)
|
|
{
|
|
testGroup->init();
|
|
testGroup->getChildren(children);
|
|
}
|
|
|
|
void DefaultHierarchyInflater::leaveGroupNode (TestCaseGroup* testGroup)
|
|
{
|
|
testGroup->deinit();
|
|
}
|
|
|
|
// TestHierarchyIterator
|
|
|
|
TestHierarchyIterator::TestHierarchyIterator (TestPackageRoot& rootNode,
|
|
TestHierarchyInflater& inflater,
|
|
const CaseListFilter& caseListFilter)
|
|
: m_inflater (inflater)
|
|
, m_caseListFilter (caseListFilter)
|
|
, m_groupNumber (0)
|
|
{
|
|
// Init traverse state and "seek" to first reportable node.
|
|
NodeIter iter(&rootNode);
|
|
iter.setState(NodeIter::NISTATE_ENTER); // Root is never reported
|
|
m_sessionStack.push_back(iter);
|
|
next();
|
|
}
|
|
|
|
TestHierarchyIterator::~TestHierarchyIterator (void)
|
|
{
|
|
// Tear down inflated nodes in m_sessionStack
|
|
for (vector<NodeIter>::reverse_iterator iter = m_sessionStack.rbegin(); iter != m_sessionStack.rend(); ++iter)
|
|
{
|
|
TestNode* const node = iter->node;
|
|
const TestNodeType nodeType = node->getNodeType();
|
|
|
|
switch (nodeType)
|
|
{
|
|
case NODETYPE_ROOT: /* root is not de-initialized */ break;
|
|
case NODETYPE_PACKAGE: m_inflater.leaveTestPackage(static_cast<TestPackage*>(node)); break;
|
|
case NODETYPE_GROUP: m_inflater.leaveGroupNode(static_cast<TestCaseGroup*>(node)); break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
TestHierarchyIterator::State TestHierarchyIterator::getState (void) const
|
|
{
|
|
if (!m_sessionStack.empty())
|
|
{
|
|
const NodeIter& iter = m_sessionStack.back();
|
|
|
|
DE_ASSERT(iter.getState() == NodeIter::NISTATE_ENTER ||
|
|
iter.getState() == NodeIter::NISTATE_LEAVE);
|
|
|
|
return iter.getState() == NodeIter::NISTATE_ENTER ? STATE_ENTER_NODE : STATE_LEAVE_NODE;
|
|
}
|
|
else
|
|
return STATE_FINISHED;
|
|
}
|
|
|
|
TestNode* TestHierarchyIterator::getNode (void) const
|
|
{
|
|
DE_ASSERT(getState() != STATE_FINISHED);
|
|
return m_sessionStack.back().node;
|
|
}
|
|
|
|
const std::string& TestHierarchyIterator::getNodePath (void) const
|
|
{
|
|
DE_ASSERT(getState() != STATE_FINISHED);
|
|
return m_nodePath;
|
|
}
|
|
|
|
std::string TestHierarchyIterator::buildNodePath (const vector<NodeIter>& nodeStack)
|
|
{
|
|
string nodePath;
|
|
for (size_t ndx = 1; ndx < nodeStack.size(); ndx++)
|
|
{
|
|
const NodeIter& iter = nodeStack[ndx];
|
|
if (ndx > 1) // ignore root package
|
|
nodePath += ".";
|
|
nodePath += iter.node->getName();
|
|
}
|
|
return nodePath;
|
|
}
|
|
|
|
void TestHierarchyIterator::next (void)
|
|
{
|
|
while (!m_sessionStack.empty())
|
|
{
|
|
NodeIter& iter = m_sessionStack.back();
|
|
TestNode* const node = iter.node;
|
|
const bool isLeaf = isTestNodeTypeExecutable(node->getNodeType());
|
|
|
|
switch (iter.getState())
|
|
{
|
|
case NodeIter::NISTATE_INIT:
|
|
{
|
|
const std::string nodePath = buildNodePath(m_sessionStack);
|
|
|
|
// Return to parent if name or runner type doesn't match filter.
|
|
if (!(isLeaf ? (m_caseListFilter.checkRunnerType(node->getRunnerType()) && m_caseListFilter.checkTestCaseName(nodePath.c_str()))
|
|
: m_caseListFilter.checkTestGroupName(nodePath.c_str())))
|
|
{
|
|
m_sessionStack.pop_back();
|
|
break;
|
|
}
|
|
|
|
m_nodePath = nodePath;
|
|
iter.setState(NodeIter::NISTATE_ENTER);
|
|
return; // Yield enter event
|
|
}
|
|
|
|
case NodeIter::NISTATE_ENTER:
|
|
{
|
|
if (isLeaf)
|
|
{
|
|
iter.setState(NodeIter::NISTATE_LEAVE);
|
|
return; // Yield leave event
|
|
}
|
|
else
|
|
{
|
|
iter.setState(NodeIter::NISTATE_TRAVERSE_CHILDREN);
|
|
iter.children.clear();
|
|
|
|
switch (node->getNodeType())
|
|
{
|
|
case NODETYPE_ROOT: static_cast<TestPackageRoot*>(node)->getChildren(iter.children); break;
|
|
case NODETYPE_PACKAGE: m_inflater.enterTestPackage(static_cast<TestPackage*>(node), iter.children); break;
|
|
case NODETYPE_GROUP: m_inflater.enterGroupNode(static_cast<TestCaseGroup*>(node), iter.children); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NodeIter::NISTATE_TRAVERSE_CHILDREN:
|
|
{
|
|
int numChildren = (int)iter.children.size();
|
|
if (++iter.curChildNdx < numChildren)
|
|
{
|
|
// Push child to stack.
|
|
TestNode* childNode = iter.children[iter.curChildNdx];
|
|
|
|
// Check whether this is a bottom-level group (child is executable)
|
|
// and whether that group should be filtered out.
|
|
if ( isTestNodeTypeExecutable(childNode->getNodeType()) )
|
|
{
|
|
const std::string testName = m_nodePath + "." + childNode->getName();
|
|
if(!m_caseListFilter.checkCaseFraction(m_groupNumber, testName))
|
|
break;
|
|
}
|
|
m_sessionStack.push_back(NodeIter(childNode));
|
|
}
|
|
else
|
|
{
|
|
iter.setState(NodeIter::NISTATE_LEAVE);
|
|
if (node->getNodeType() != NODETYPE_ROOT)
|
|
return; // Yield leave event
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NodeIter::NISTATE_LEAVE:
|
|
{
|
|
// Leave node.
|
|
if (!isLeaf)
|
|
{
|
|
switch (node->getNodeType())
|
|
{
|
|
case NODETYPE_ROOT: /* root is not de-initialized */ break;
|
|
case NODETYPE_PACKAGE: m_inflater.leaveTestPackage(static_cast<TestPackage*>(node)); break;
|
|
case NODETYPE_GROUP: m_inflater.leaveGroupNode(static_cast<TestCaseGroup*>(node)); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
m_groupNumber++;
|
|
}
|
|
|
|
m_sessionStack.pop_back();
|
|
m_nodePath = buildNodePath(m_sessionStack);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DE_ASSERT(false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
DE_ASSERT(m_sessionStack.empty() && getState() == STATE_FINISHED);
|
|
}
|
|
|
|
} // tcu
|