/*------------------------------------------------------------------------- * 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& 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& 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::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(node)); break; case NODETYPE_GROUP: m_inflater.leaveGroupNode(static_cast(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& 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(node)->getChildren(iter.children); break; case NODETYPE_PACKAGE: m_inflater.enterTestPackage(static_cast(node), iter.children); break; case NODETYPE_GROUP: m_inflater.enterGroupNode(static_cast(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(node)); break; case NODETYPE_GROUP: m_inflater.leaveGroupNode(static_cast(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