blob: ea0620f6f1e0148519e0511432430ae2c05509c6 [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 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