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