xref: /aosp_15_r20/external/deqp/executor/xeTestCase.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Test Executor
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.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "xeTestCase.hpp"
25 
26 using std::vector;
27 
28 namespace xe
29 {
30 
getTestCaseTypeName(TestCaseType caseType)31 const char *getTestCaseTypeName(TestCaseType caseType)
32 {
33     switch (caseType)
34     {
35     case TESTCASETYPE_SELF_VALIDATE:
36         return "SelfValidate";
37     case TESTCASETYPE_CAPABILITY:
38         return "Capability";
39     case TESTCASETYPE_ACCURACY:
40         return "Accuracy";
41     case TESTCASETYPE_PERFORMANCE:
42         return "Performance";
43     default:
44         DE_ASSERT(false);
45         return DE_NULL;
46     }
47 }
48 
getFirstComponentLength(const char * path)49 static inline int getFirstComponentLength(const char *path)
50 {
51     int compLen = 0;
52     while (path[compLen] != 0 && path[compLen] != '.')
53         compLen++;
54     return compLen;
55 }
56 
compareNameToPathComponent(const char * name,const char * path,int compLen)57 static bool compareNameToPathComponent(const char *name, const char *path, int compLen)
58 {
59     for (int pos = 0; pos < compLen; pos++)
60     {
61         if (name[pos] != path[pos])
62             return false;
63     }
64 
65     if (name[compLen] != 0)
66         return false;
67 
68     return true;
69 }
70 
splitPath(const char * path,std::vector<std::string> & components)71 static void splitPath(const char *path, std::vector<std::string> &components)
72 {
73     std::string pathStr(path);
74     int compStart = 0;
75 
76     for (int pos = 0; pos < (int)pathStr.length(); pos++)
77     {
78         if (pathStr[pos] == '.')
79         {
80             components.push_back(pathStr.substr(compStart, pos - compStart));
81             compStart = pos + 1;
82         }
83     }
84 
85     DE_ASSERT(compStart < (int)pathStr.length());
86     components.push_back(pathStr.substr(compStart));
87 }
88 
89 // TestNode
90 
TestNode(TestGroup * parent,TestNodeType nodeType,const char * name)91 TestNode::TestNode(TestGroup *parent, TestNodeType nodeType, const char *name)
92     : m_parent(parent)
93     , m_nodeType(nodeType)
94     , m_name(name)
95 {
96     if (m_parent)
97     {
98         // Verify that the name is unique.
99         if (parent->m_childNames.find(name) != parent->m_childNames.end())
100             throw Error(std::string("Duplicate node '") + name + "' in '" + parent->getFullPath());
101 
102         m_parent->m_children.push_back(this);
103         m_parent->m_childNames.insert(name);
104     }
105 }
106 
getFullPath(std::string & dst) const107 void TestNode::getFullPath(std::string &dst) const
108 {
109     dst.clear();
110 
111     int nameLen             = 0;
112     const TestNode *curNode = this;
113 
114     for (;;)
115     {
116         nameLen += (int)curNode->m_name.length();
117 
118         DE_ASSERT(curNode->m_parent);
119         if (curNode->m_parent->getNodeType() != TESTNODETYPE_ROOT)
120         {
121             nameLen += 1;
122             curNode = curNode->m_parent;
123         }
124         else
125             break;
126     }
127 
128     dst.resize(nameLen);
129 
130     curNode = this;
131     int pos = nameLen;
132 
133     for (;;)
134     {
135         std::copy(curNode->m_name.begin(), curNode->m_name.end(), dst.begin() + (pos - curNode->m_name.length()));
136         pos -= (int)curNode->m_name.length();
137 
138         DE_ASSERT(curNode->m_parent);
139         if (curNode->m_parent->getNodeType() != TESTNODETYPE_ROOT)
140         {
141             dst[--pos] = '.';
142             curNode    = curNode->m_parent;
143         }
144         else
145             break;
146     }
147 }
148 
find(const char * path) const149 const TestNode *TestNode::find(const char *path) const
150 {
151     if (m_nodeType == TESTNODETYPE_ROOT)
152     {
153         // Don't need to consider current node.
154         return static_cast<const TestGroup *>(this)->findChildNode(path);
155     }
156     else
157     {
158         // Check if first component matches this node.
159         int compLen = getFirstComponentLength(path);
160         XE_CHECK(compLen > 0);
161 
162         if (compareNameToPathComponent(getName(), path, compLen))
163         {
164             if (path[compLen] == 0)
165                 return this;
166             else if (getNodeType() == TESTNODETYPE_GROUP)
167                 return static_cast<const TestGroup *>(this)->findChildNode(path + compLen + 1);
168             else
169                 return DE_NULL;
170         }
171         else
172             return DE_NULL;
173     }
174 }
175 
find(const char * path)176 TestNode *TestNode::find(const char *path)
177 {
178     return const_cast<TestNode *>(const_cast<const TestNode *>(this)->find(path));
179 }
180 
181 // TestGroup
182 
TestGroup(TestGroup * parent,TestNodeType nodeType,const char * name)183 TestGroup::TestGroup(TestGroup *parent, TestNodeType nodeType, const char *name) : TestNode(parent, nodeType, name)
184 {
185     DE_ASSERT(nodeType == TESTNODETYPE_GROUP || nodeType == TESTNODETYPE_ROOT);
186     DE_ASSERT(!parent == (nodeType == TESTNODETYPE_ROOT));
187 }
188 
~TestGroup(void)189 TestGroup::~TestGroup(void)
190 {
191     for (std::vector<TestNode *>::iterator i = m_children.begin(); i != m_children.end(); i++)
192         delete *i;
193 }
194 
createGroup(const char * name)195 TestGroup *TestGroup::createGroup(const char *name)
196 {
197     return new TestGroup(this, TESTNODETYPE_GROUP, name);
198 }
199 
createCase(TestCaseType caseType,const char * name)200 TestCase *TestGroup::createCase(TestCaseType caseType, const char *name)
201 {
202     return TestCase::createAsChild(this, caseType, name);
203 }
204 
findChildNode(const char * path) const205 const TestNode *TestGroup::findChildNode(const char *path) const
206 {
207     int compLen = getFirstComponentLength(path);
208     XE_CHECK(compLen > 0);
209 
210     // Try to find matching children.
211     const TestNode *matchingNode = DE_NULL;
212     for (vector<TestNode *>::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++)
213     {
214         if (compareNameToPathComponent((*iter)->getName(), path, compLen))
215         {
216             matchingNode = *iter;
217             break;
218         }
219     }
220 
221     if (matchingNode)
222     {
223         if (path[compLen] == 0)
224             return matchingNode; // Last element in path, return matching node.
225         else if (matchingNode->getNodeType() == TESTNODETYPE_GROUP)
226             return static_cast<const TestGroup *>(matchingNode)->findChildNode(path + compLen + 1);
227         else
228             return DE_NULL;
229     }
230     else
231         return DE_NULL;
232 }
233 
234 // TestRoot
235 
TestRoot(void)236 TestRoot::TestRoot(void) : TestGroup(DE_NULL, TESTNODETYPE_ROOT, "")
237 {
238 }
239 
240 // TestCase
241 
createAsChild(TestGroup * parent,TestCaseType caseType,const char * name)242 TestCase *TestCase::createAsChild(TestGroup *parent, TestCaseType caseType, const char *name)
243 {
244     return new TestCase(parent, caseType, name);
245 }
246 
TestCase(TestGroup * parent,TestCaseType caseType,const char * name)247 TestCase::TestCase(TestGroup *parent, TestCaseType caseType, const char *name)
248     : TestNode(parent, TESTNODETYPE_TEST_CASE, name)
249     , m_caseType(caseType)
250 {
251 }
252 
~TestCase(void)253 TestCase::~TestCase(void)
254 {
255 }
256 
257 // TestHierarchyBuilder helpers
258 
addChildGroupsToMap(std::map<std::string,TestGroup * > & groupMap,TestGroup * group)259 void addChildGroupsToMap(std::map<std::string, TestGroup *> &groupMap, TestGroup *group)
260 {
261     for (int ndx = 0; ndx < group->getNumChildren(); ndx++)
262     {
263         TestNode *node = group->getChild(ndx);
264         if (node->getNodeType() == TESTNODETYPE_GROUP)
265         {
266             TestGroup *childGroup = static_cast<TestGroup *>(node);
267             std::string fullPath;
268             childGroup->getFullPath(fullPath);
269 
270             groupMap.insert(std::make_pair(fullPath, childGroup));
271             addChildGroupsToMap(groupMap, childGroup);
272         }
273     }
274 }
275 
276 // TestHierarchyBuilder
277 
TestHierarchyBuilder(TestRoot * root)278 TestHierarchyBuilder::TestHierarchyBuilder(TestRoot *root) : m_root(root)
279 {
280     addChildGroupsToMap(m_groupMap, root);
281 }
282 
~TestHierarchyBuilder(void)283 TestHierarchyBuilder::~TestHierarchyBuilder(void)
284 {
285 }
286 
createCase(const char * path,TestCaseType caseType)287 TestCase *TestHierarchyBuilder::createCase(const char *path, TestCaseType caseType)
288 {
289     // \todo [2012-09-05 pyry] This can be done with less string manipulations.
290     std::vector<std::string> components;
291     splitPath(path, components);
292     DE_ASSERT(!components.empty());
293 
294     // Create all parents if necessary.
295     TestGroup *curGroup = m_root;
296     std::string curGroupPath;
297     for (int ndx = 0; ndx < (int)components.size() - 1; ndx++)
298     {
299         if (!curGroupPath.empty())
300             curGroupPath += ".";
301         curGroupPath += components[ndx];
302 
303         std::map<std::string, TestGroup *>::const_iterator groupPos = m_groupMap.find(curGroupPath);
304         if (groupPos == m_groupMap.end())
305         {
306             TestGroup *newGroup = curGroup->createGroup(components[ndx].c_str());
307             m_groupMap.insert(std::make_pair(curGroupPath, newGroup));
308             curGroup = newGroup;
309         }
310         else
311             curGroup = groupPos->second;
312     }
313 
314     return curGroup->createCase(caseType, components.back().c_str());
315 }
316 
317 // TestSet helpers
318 
addNodeAndParents(std::set<const TestNode * > & nodeSet,const TestNode * node)319 static void addNodeAndParents(std::set<const TestNode *> &nodeSet, const TestNode *node)
320 {
321     while (node != DE_NULL)
322     {
323         nodeSet.insert(node);
324         node = node->getParent();
325     }
326 }
327 
addChildren(std::set<const TestNode * > & nodeSet,const TestGroup * group)328 static void addChildren(std::set<const TestNode *> &nodeSet, const TestGroup *group)
329 {
330     for (int ndx = 0; ndx < group->getNumChildren(); ndx++)
331     {
332         const TestNode *child = group->getChild(ndx);
333         nodeSet.insert(child);
334 
335         if (child->getNodeType() == TESTNODETYPE_GROUP)
336             addChildren(nodeSet, static_cast<const TestGroup *>(child));
337     }
338 }
339 
removeChildren(std::set<const TestNode * > & nodeSet,const TestGroup * group)340 static void removeChildren(std::set<const TestNode *> &nodeSet, const TestGroup *group)
341 {
342     for (int ndx = 0; ndx < group->getNumChildren(); ndx++)
343     {
344         const TestNode *child = group->getChild(ndx);
345         nodeSet.erase(child);
346 
347         if (child->getNodeType() == TESTNODETYPE_GROUP)
348             removeChildren(nodeSet, static_cast<const TestGroup *>(child));
349     }
350 }
351 
hasChildrenInSet(const std::set<const TestNode * > & nodeSet,const TestGroup * group)352 static bool hasChildrenInSet(const std::set<const TestNode *> &nodeSet, const TestGroup *group)
353 {
354     for (int ndx = 0; ndx < group->getNumChildren(); ndx++)
355     {
356         if (nodeSet.find(group->getChild(ndx)) != nodeSet.end())
357             return true;
358     }
359     return false;
360 }
361 
removeEmptyGroups(std::set<const TestNode * > & nodeSet,const TestGroup * group)362 static void removeEmptyGroups(std::set<const TestNode *> &nodeSet, const TestGroup *group)
363 {
364     if (!hasChildrenInSet(nodeSet, group))
365     {
366         nodeSet.erase(group);
367         if (group->getParent() != DE_NULL)
368             removeEmptyGroups(nodeSet, group->getParent());
369     }
370 }
371 
372 // TestSet
373 
add(const TestNode * node)374 void TestSet::add(const TestNode *node)
375 {
376     if (node->getNodeType() == TESTNODETYPE_TEST_CASE)
377         addCase(static_cast<const TestCase *>(node));
378     else
379     {
380         XE_CHECK(node->getNodeType() == TESTNODETYPE_GROUP || node->getNodeType() == TESTNODETYPE_ROOT);
381         addGroup(static_cast<const TestGroup *>(node));
382     }
383 }
384 
addCase(const TestCase * testCase)385 void TestSet::addCase(const TestCase *testCase)
386 {
387     addNodeAndParents(m_set, testCase);
388 }
389 
addGroup(const TestGroup * testGroup)390 void TestSet::addGroup(const TestGroup *testGroup)
391 {
392     addNodeAndParents(m_set, testGroup);
393     addChildren(m_set, testGroup);
394 }
395 
remove(const TestNode * node)396 void TestSet::remove(const TestNode *node)
397 {
398     if (node->getNodeType() == TESTNODETYPE_TEST_CASE)
399         removeCase(static_cast<const TestCase *>(node));
400     else
401     {
402         XE_CHECK(node->getNodeType() == TESTNODETYPE_GROUP || node->getNodeType() == TESTNODETYPE_ROOT);
403         removeGroup(static_cast<const TestGroup *>(node));
404     }
405 }
406 
removeCase(const TestCase * testCase)407 void TestSet::removeCase(const TestCase *testCase)
408 {
409     if (m_set.find(testCase) != m_set.end())
410     {
411         m_set.erase(testCase);
412         removeEmptyGroups(m_set, testCase->getParent());
413     }
414 }
415 
removeGroup(const TestGroup * testGroup)416 void TestSet::removeGroup(const TestGroup *testGroup)
417 {
418     if (m_set.find(testGroup) != m_set.end())
419     {
420         m_set.erase(testGroup);
421         removeChildren(m_set, testGroup);
422         if (testGroup->getParent() != DE_NULL)
423             removeEmptyGroups(m_set, testGroup->getParent());
424     }
425 }
426 
427 // ConstTestNodeIterator
428 
ConstTestNodeIterator(const TestNode * root)429 ConstTestNodeIterator::ConstTestNodeIterator(const TestNode *root) : m_root(root)
430 {
431 }
432 
begin(const TestNode * root)433 ConstTestNodeIterator ConstTestNodeIterator::begin(const TestNode *root)
434 {
435     ConstTestNodeIterator iter(root);
436     iter.m_iterStack.push_back(GroupState(DE_NULL));
437     return iter;
438 }
439 
end(const TestNode * root)440 ConstTestNodeIterator ConstTestNodeIterator::end(const TestNode *root)
441 {
442     DE_UNREF(root);
443     return ConstTestNodeIterator(root);
444 }
445 
operator ++(void)446 ConstTestNodeIterator &ConstTestNodeIterator::operator++(void)
447 {
448     DE_ASSERT(!m_iterStack.empty());
449 
450     const TestNode *curNode  = **this;
451     TestNodeType curNodeType = curNode->getNodeType();
452 
453     if ((curNodeType == TESTNODETYPE_GROUP || curNodeType == TESTNODETYPE_ROOT) &&
454         static_cast<const TestGroup *>(curNode)->getNumChildren() > 0)
455     {
456         m_iterStack.push_back(GroupState(static_cast<const TestGroup *>(curNode)));
457     }
458     else
459     {
460         for (;;)
461         {
462             const TestGroup *group = m_iterStack.back().group;
463             int &childNdx          = m_iterStack.back().childNdx;
464             int numChildren        = group ? group->getNumChildren() : 1;
465 
466             childNdx += 1;
467             if (childNdx == numChildren)
468             {
469                 m_iterStack.pop_back();
470                 if (m_iterStack.empty())
471                     break;
472             }
473             else
474                 break;
475         }
476     }
477 
478     return *this;
479 }
480 
operator ++(int)481 ConstTestNodeIterator ConstTestNodeIterator::operator++(int)
482 {
483     ConstTestNodeIterator copy(*this);
484     ++(*this);
485     return copy;
486 }
487 
operator *(void) const488 const TestNode *ConstTestNodeIterator::operator*(void) const
489 {
490     DE_ASSERT(!m_iterStack.empty());
491     if (m_iterStack.size() == 1)
492     {
493         DE_ASSERT(m_iterStack[0].group == DE_NULL && m_iterStack[0].childNdx == 0);
494         return m_root;
495     }
496     else
497         return m_iterStack.back().group->getChild(m_iterStack.back().childNdx);
498 }
499 
operator !=(const ConstTestNodeIterator & other) const500 bool ConstTestNodeIterator::operator!=(const ConstTestNodeIterator &other) const
501 {
502     return m_root != other.m_root || m_iterStack != other.m_iterStack;
503 }
504 
505 } // namespace xe
506