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 Test case hierarchy iterator. 22 *//*--------------------------------------------------------------------*/ 23 24#include "tcuTestHierarchyIterator.hpp" 25#include "tcuCommandLine.hpp" 26 27namespace tcu 28{ 29 30using std::string; 31using std::vector; 32 33// TestHierarchyInflater 34 35TestHierarchyInflater::TestHierarchyInflater (void) 36{ 37} 38 39TestHierarchyInflater::~TestHierarchyInflater (void) 40{ 41} 42 43// DefaultHierarchyInflater 44 45DefaultHierarchyInflater::DefaultHierarchyInflater (TestContext& testCtx) 46 : m_testCtx(testCtx) 47{ 48} 49 50DefaultHierarchyInflater::~DefaultHierarchyInflater (void) 51{ 52} 53 54void DefaultHierarchyInflater::enterTestPackage (TestPackage* testPackage, vector<TestNode*>& children) 55{ 56 { 57 Archive* const pkgArchive = testPackage->getArchive(); 58 59 if (pkgArchive) 60 m_testCtx.setCurrentArchive(*pkgArchive); 61 else 62 m_testCtx.setCurrentArchive(m_testCtx.getRootArchive()); 63 } 64 65 testPackage->init(); 66 testPackage->getChildren(children); 67 68 // write default session info if it was not done by package 69 m_testCtx.writeSessionInfo(); 70} 71 72void DefaultHierarchyInflater::leaveTestPackage (TestPackage* testPackage) 73{ 74 m_testCtx.setCurrentArchive(m_testCtx.getRootArchive()); 75 testPackage->deinit(); 76} 77 78void DefaultHierarchyInflater::enterGroupNode (TestCaseGroup* testGroup, vector<TestNode*>& children) 79{ 80 testGroup->init(); 81 testGroup->getChildren(children); 82} 83 84void DefaultHierarchyInflater::leaveGroupNode (TestCaseGroup* testGroup) 85{ 86 testGroup->deinit(); 87} 88 89// TestHierarchyIterator 90 91TestHierarchyIterator::TestHierarchyIterator (TestPackageRoot& rootNode, 92 TestHierarchyInflater& inflater, 93 const CaseListFilter& caseListFilter) 94 : m_inflater (inflater) 95 , m_caseListFilter (caseListFilter) 96 , m_groupNumber (0) 97{ 98 // Init traverse state and "seek" to first reportable node. 99 NodeIter iter(&rootNode); 100 iter.setState(NodeIter::NISTATE_ENTER); // Root is never reported 101 m_sessionStack.push_back(iter); 102 next(); 103} 104 105TestHierarchyIterator::~TestHierarchyIterator (void) 106{ 107 // Tear down inflated nodes in m_sessionStack 108 for (vector<NodeIter>::reverse_iterator iter = m_sessionStack.rbegin(); iter != m_sessionStack.rend(); ++iter) 109 { 110 TestNode* const node = iter->node; 111 const TestNodeType nodeType = node->getNodeType(); 112 113 switch (nodeType) 114 { 115 case NODETYPE_ROOT: /* root is not de-initialized */ break; 116 case NODETYPE_PACKAGE: m_inflater.leaveTestPackage(static_cast<TestPackage*>(node)); break; 117 case NODETYPE_GROUP: m_inflater.leaveGroupNode(static_cast<TestCaseGroup*>(node)); break; 118 default: 119 break; 120 } 121 } 122} 123 124TestHierarchyIterator::State TestHierarchyIterator::getState (void) const 125{ 126 if (!m_sessionStack.empty()) 127 { 128 const NodeIter& iter = m_sessionStack.back(); 129 130 DE_ASSERT(iter.getState() == NodeIter::NISTATE_ENTER || 131 iter.getState() == NodeIter::NISTATE_LEAVE); 132 133 return iter.getState() == NodeIter::NISTATE_ENTER ? STATE_ENTER_NODE : STATE_LEAVE_NODE; 134 } 135 else 136 return STATE_FINISHED; 137} 138 139TestNode* TestHierarchyIterator::getNode (void) const 140{ 141 DE_ASSERT(getState() != STATE_FINISHED); 142 return m_sessionStack.back().node; 143} 144 145const std::string& TestHierarchyIterator::getNodePath (void) const 146{ 147 DE_ASSERT(getState() != STATE_FINISHED); 148 return m_nodePath; 149} 150 151std::string TestHierarchyIterator::buildNodePath (const vector<NodeIter>& nodeStack) 152{ 153 string nodePath; 154 for (size_t ndx = 1; ndx < nodeStack.size(); ndx++) 155 { 156 const NodeIter& iter = nodeStack[ndx]; 157 if (ndx > 1) // ignore root package 158 nodePath += "."; 159 nodePath += iter.node->getName(); 160 } 161 return nodePath; 162} 163 164void TestHierarchyIterator::next (void) 165{ 166 while (!m_sessionStack.empty()) 167 { 168 NodeIter& iter = m_sessionStack.back(); 169 TestNode* const node = iter.node; 170 const bool isLeaf = isTestNodeTypeExecutable(node->getNodeType()); 171 172 switch (iter.getState()) 173 { 174 case NodeIter::NISTATE_INIT: 175 { 176 const std::string nodePath = buildNodePath(m_sessionStack); 177 178 // Return to parent if name or runner type doesn't match filter. 179 if (!(isLeaf ? (m_caseListFilter.checkRunnerType(node->getRunnerType()) && m_caseListFilter.checkTestCaseName(nodePath.c_str())) 180 : m_caseListFilter.checkTestGroupName(nodePath.c_str()))) 181 { 182 m_sessionStack.pop_back(); 183 break; 184 } 185 186 m_nodePath = nodePath; 187 iter.setState(NodeIter::NISTATE_ENTER); 188 return; // Yield enter event 189 } 190 191 case NodeIter::NISTATE_ENTER: 192 { 193 if (isLeaf) 194 { 195 iter.setState(NodeIter::NISTATE_LEAVE); 196 return; // Yield leave event 197 } 198 else 199 { 200 iter.setState(NodeIter::NISTATE_TRAVERSE_CHILDREN); 201 iter.children.clear(); 202 203 switch (node->getNodeType()) 204 { 205 case NODETYPE_ROOT: static_cast<TestPackageRoot*>(node)->getChildren(iter.children); break; 206 case NODETYPE_PACKAGE: m_inflater.enterTestPackage(static_cast<TestPackage*>(node), iter.children); break; 207 case NODETYPE_GROUP: m_inflater.enterGroupNode(static_cast<TestCaseGroup*>(node), iter.children); break; 208 default: 209 DE_ASSERT(false); 210 } 211 } 212 213 break; 214 } 215 216 case NodeIter::NISTATE_TRAVERSE_CHILDREN: 217 { 218 int numChildren = (int)iter.children.size(); 219 if (++iter.curChildNdx < numChildren) 220 { 221 // Push child to stack. 222 TestNode* childNode = iter.children[iter.curChildNdx]; 223 224 // Check whether this is a bottom-level group (child is executable) 225 // and whether that group should be filtered out. 226 if ( isTestNodeTypeExecutable(childNode->getNodeType()) ) 227 { 228 const std::string testName = m_nodePath + "." + childNode->getName(); 229 if(!m_caseListFilter.checkCaseFraction(m_groupNumber, testName)) 230 break; 231 } 232 m_sessionStack.push_back(NodeIter(childNode)); 233 } 234 else 235 { 236 iter.setState(NodeIter::NISTATE_LEAVE); 237 if (node->getNodeType() != NODETYPE_ROOT) 238 return; // Yield leave event 239 } 240 241 break; 242 } 243 244 case NodeIter::NISTATE_LEAVE: 245 { 246 // Leave node. 247 if (!isLeaf) 248 { 249 switch (node->getNodeType()) 250 { 251 case NODETYPE_ROOT: /* root is not de-initialized */ break; 252 case NODETYPE_PACKAGE: m_inflater.leaveTestPackage(static_cast<TestPackage*>(node)); break; 253 case NODETYPE_GROUP: m_inflater.leaveGroupNode(static_cast<TestCaseGroup*>(node)); break; 254 default: 255 DE_ASSERT(false); 256 } 257 m_groupNumber++; 258 } 259 260 m_sessionStack.pop_back(); 261 m_nodePath = buildNodePath(m_sessionStack); 262 break; 263 } 264 265 default: 266 DE_ASSERT(false); 267 return; 268 } 269 } 270 271 DE_ASSERT(m_sessionStack.empty() && getState() == STATE_FINISHED); 272} 273 274} // tcu 275