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
69void DefaultHierarchyInflater::leaveTestPackage (TestPackage* testPackage)
70{
71	m_testCtx.setCurrentArchive(m_testCtx.getRootArchive());
72	testPackage->deinit();
73}
74
75void DefaultHierarchyInflater::enterGroupNode (TestCaseGroup* testGroup, vector<TestNode*>& children)
76{
77	testGroup->init();
78	testGroup->getChildren(children);
79}
80
81void DefaultHierarchyInflater::leaveGroupNode (TestCaseGroup* testGroup)
82{
83	testGroup->deinit();
84}
85
86// TestHierarchyIterator
87
88TestHierarchyIterator::TestHierarchyIterator (TestPackageRoot&			rootNode,
89											  TestHierarchyInflater&	inflater,
90											  const CommandLine&		cmdLine)
91	: m_inflater	(inflater)
92	, m_cmdLine		(cmdLine)
93{
94	// Init traverse state and "seek" to first reportable node.
95	NodeIter iter(&rootNode);
96	iter.setState(NodeIter::STATE_ENTER); // Root is never reported
97	m_sessionStack.push_back(iter);
98	next();
99}
100
101TestHierarchyIterator::~TestHierarchyIterator (void)
102{
103	// Tear down inflated nodes in m_sessionStack
104	for (vector<NodeIter>::reverse_iterator iter = m_sessionStack.rbegin(); iter != m_sessionStack.rend(); ++iter)
105	{
106		TestNode* const		node		= iter->node;
107		const TestNodeType	nodeType	= node->getNodeType();
108
109		switch (nodeType)
110		{
111			case NODETYPE_ROOT:		/* root is not de-initialized */								break;
112			case NODETYPE_PACKAGE:	m_inflater.leaveTestPackage(static_cast<TestPackage*>(node));	break;
113			case NODETYPE_GROUP:	m_inflater.leaveGroupNode(static_cast<TestCaseGroup*>(node));	break;
114			default:
115				break;
116		}
117	}
118}
119
120TestHierarchyIterator::State TestHierarchyIterator::getState (void) const
121{
122	if (!m_sessionStack.empty())
123	{
124		const NodeIter&	iter	= m_sessionStack.back();
125
126		DE_ASSERT(iter.getState() == NodeIter::STATE_ENTER ||
127				  iter.getState() == NodeIter::STATE_LEAVE);
128
129		return iter.getState() == NodeIter::STATE_ENTER ? STATE_ENTER_NODE : STATE_LEAVE_NODE;
130	}
131	else
132		return STATE_FINISHED;
133}
134
135TestNode* TestHierarchyIterator::getNode (void) const
136{
137	DE_ASSERT(getState() != STATE_FINISHED);
138	return m_sessionStack.back().node;
139}
140
141const std::string& TestHierarchyIterator::getNodePath (void) const
142{
143	DE_ASSERT(getState() != STATE_FINISHED);
144	return m_nodePath;
145}
146
147std::string TestHierarchyIterator::buildNodePath (const vector<NodeIter>& nodeStack)
148{
149	string nodePath;
150	for (size_t ndx = 1; ndx < nodeStack.size(); ndx++)
151	{
152		const NodeIter& iter = nodeStack[ndx];
153		if (ndx > 1) // ignore root package
154			nodePath += ".";
155		nodePath += iter.node->getName();
156	}
157	return nodePath;
158}
159
160void TestHierarchyIterator::next (void)
161{
162	while (!m_sessionStack.empty())
163	{
164		NodeIter&			iter		= m_sessionStack.back();
165		TestNode* const		node		= iter.node;
166		const bool			isLeaf		= isTestNodeTypeExecutable(node->getNodeType());
167
168		switch (iter.getState())
169		{
170			case NodeIter::STATE_INIT:
171			{
172				const std::string nodePath = buildNodePath(m_sessionStack);
173
174				// Return to parent if name doesn't match filter.
175				if (!(isLeaf ? m_cmdLine.checkTestCaseName(nodePath.c_str()) : m_cmdLine.checkTestGroupName(nodePath.c_str())))
176				{
177					m_sessionStack.pop_back();
178					break;
179				}
180
181				m_nodePath = nodePath;
182				iter.setState(NodeIter::STATE_ENTER);
183				return; // Yield enter event
184			}
185
186			case NodeIter::STATE_ENTER:
187			{
188				if (isLeaf)
189				{
190					iter.setState(NodeIter::STATE_LEAVE);
191					return; // Yield leave event
192				}
193				else
194				{
195					iter.setState(NodeIter::STATE_TRAVERSE_CHILDREN);
196					iter.children.clear();
197
198					switch (node->getNodeType())
199					{
200						case NODETYPE_ROOT:		static_cast<TestPackageRoot*>(node)->getChildren(iter.children);				break;
201						case NODETYPE_PACKAGE:	m_inflater.enterTestPackage(static_cast<TestPackage*>(node), iter.children);	break;
202						case NODETYPE_GROUP:	m_inflater.enterGroupNode(static_cast<TestCaseGroup*>(node), iter.children);	break;
203						default:
204							DE_ASSERT(false);
205					}
206				}
207
208				break;
209			}
210
211			case NodeIter::STATE_TRAVERSE_CHILDREN:
212			{
213				int numChildren = (int)iter.children.size();
214				if (++iter.curChildNdx < numChildren)
215				{
216					// Push child to stack.
217					TestNode* childNode = iter.children[iter.curChildNdx];
218					m_sessionStack.push_back(NodeIter(childNode));
219				}
220				else
221				{
222					iter.setState(NodeIter::STATE_LEAVE);
223					if (node->getNodeType() != NODETYPE_ROOT)
224						return; // Yield leave event
225				}
226
227				break;
228			}
229
230			case NodeIter::STATE_LEAVE:
231			{
232				// Leave node.
233				if (!isLeaf)
234				{
235					switch (node->getNodeType())
236					{
237						case NODETYPE_ROOT:		/* root is not de-initialized */								break;
238						case NODETYPE_PACKAGE:	m_inflater.leaveTestPackage(static_cast<TestPackage*>(node));	break;
239						case NODETYPE_GROUP:	m_inflater.leaveGroupNode(static_cast<TestCaseGroup*>(node));	break;
240						default:
241							DE_ASSERT(false);
242					}
243				}
244
245				m_sessionStack.pop_back();
246				m_nodePath = buildNodePath(m_sessionStack);
247				break;
248			}
249
250			default:
251				DE_ASSERT(false);
252				return;
253		}
254	}
255
256	DE_ASSERT(m_sessionStack.empty() && getState() == STATE_FINISHED);
257}
258
259} // tcu
260