xref: /aosp_15_r20/external/deqp/framework/common/tcuTestHierarchyIterator.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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