Add CTS_ARB_gl_spirv test implementation
[platform/upstream/VK-GL-CTS.git] / executor / xeTestCase.cpp
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
31 const char* getTestCaseTypeName (TestCaseType caseType)
32 {
33         switch (caseType)
34         {
35                 case TESTCASETYPE_SELF_VALIDATE:        return "SelfValidate";
36                 case TESTCASETYPE_CAPABILITY:           return "Capability";
37                 case TESTCASETYPE_ACCURACY:                     return "Accuracy";
38                 case TESTCASETYPE_PERFORMANCE:          return "Performance";
39                 default:
40                         DE_ASSERT(false);
41                         return DE_NULL;
42         }
43 }
44
45 static inline int getFirstComponentLength (const char* path)
46 {
47         int compLen = 0;
48         while (path[compLen] != 0 && path[compLen] != '.')
49                 compLen++;
50         return compLen;
51 }
52
53 static bool compareNameToPathComponent (const char* name, const char* path, int compLen)
54 {
55         for (int pos = 0; pos < compLen; pos++)
56         {
57                 if (name[pos] != path[pos])
58                         return false;
59         }
60
61         if (name[compLen] != 0)
62                 return false;
63
64         return true;
65 }
66
67 static void splitPath (const char* path, std::vector<std::string>& components)
68 {
69         std::string     pathStr         (path);
70         int                     compStart       = 0;
71
72         for (int pos = 0; pos < (int)pathStr.length(); pos++)
73         {
74                 if (pathStr[pos] == '.')
75                 {
76                         components.push_back(pathStr.substr(compStart, pos-compStart));
77                         compStart = pos+1;
78                 }
79         }
80
81         DE_ASSERT(compStart < (int)pathStr.length());
82         components.push_back(pathStr.substr(compStart));
83 }
84
85 // TestNode
86
87 TestNode::TestNode (TestGroup* parent, TestNodeType nodeType, const char* name, const char* desc)
88         : m_parent              (parent)
89         , m_nodeType    (nodeType)
90         , m_name                (name)
91         , m_description (desc)
92 {
93         if (m_parent)
94         {
95                 // Verify that the name is unique.
96                 if (parent->m_childNames.find(name) != parent->m_childNames.end())
97                         throw Error(std::string("Duplicate node '") + name + "' in '" + parent->getFullPath());
98
99                 m_parent->m_children.push_back(this);
100                 m_parent->m_childNames.insert(name);
101         }
102 }
103
104 void TestNode::getFullPath (std::string& dst) const
105 {
106         dst.clear();
107
108         int                             nameLen = 0;
109         const TestNode* curNode = this;
110
111         for (;;)
112         {
113                 nameLen += (int)curNode->m_name.length();
114
115                 DE_ASSERT(curNode->m_parent);
116                 if (curNode->m_parent->getNodeType() != TESTNODETYPE_ROOT)
117                 {
118                         nameLen += 1;
119                         curNode  = curNode->m_parent;
120                 }
121                 else
122                         break;
123         }
124
125         dst.resize(nameLen);
126
127         curNode = this;
128         int pos = nameLen;
129
130         for (;;)
131         {
132                 std::copy(curNode->m_name.begin(), curNode->m_name.end(), dst.begin()+(pos-curNode->m_name.length()));
133                 pos -= (int)curNode->m_name.length();
134
135                 DE_ASSERT(curNode->m_parent);
136                 if (curNode->m_parent->getNodeType() != TESTNODETYPE_ROOT)
137                 {
138                         dst[--pos] = '.';
139                         curNode = curNode->m_parent;
140                 }
141                 else
142                         break;
143         }
144 }
145
146 const TestNode* TestNode::find (const char* path) const
147 {
148         if (m_nodeType == TESTNODETYPE_ROOT)
149         {
150                 // Don't need to consider current node.
151                 return static_cast<const TestGroup*>(this)->findChildNode(path);
152         }
153         else
154         {
155                 // Check if first component matches this node.
156                 int compLen = getFirstComponentLength(path);
157                 XE_CHECK(compLen > 0);
158
159                 if (compareNameToPathComponent(getName(), path, compLen))
160                 {
161                         if (path[compLen] == 0)
162                                 return this;
163                         else if (getNodeType() == TESTNODETYPE_GROUP)
164                                 return static_cast<const TestGroup*>(this)->findChildNode(path + compLen + 1);
165                         else
166                                 return DE_NULL;
167                 }
168                 else
169                         return DE_NULL;
170         }
171 }
172
173 TestNode* TestNode::find (const char* path)
174 {
175         return const_cast<TestNode*>(const_cast<const TestNode*>(this)->find(path));
176 }
177
178 // TestGroup
179
180 TestGroup::TestGroup (TestGroup* parent, TestNodeType nodeType, const char* name, const char* description)
181         : TestNode(parent, nodeType, name, description)
182 {
183         DE_ASSERT(nodeType == TESTNODETYPE_GROUP || nodeType == TESTNODETYPE_ROOT);
184         DE_ASSERT(!parent == (nodeType == TESTNODETYPE_ROOT));
185 }
186
187 TestGroup::~TestGroup (void)
188 {
189         for (std::vector<TestNode*>::iterator i = m_children.begin(); i != m_children.end(); i++)
190                 delete *i;
191 }
192
193 TestGroup* TestGroup::createGroup (const char* name, const char* description)
194 {
195         return new TestGroup(this, TESTNODETYPE_GROUP, name, description);
196 }
197
198 TestCase* TestGroup::createCase (TestCaseType caseType, const char* name, const char* description)
199 {
200         return TestCase::createAsChild(this, caseType, name, description);
201 }
202
203 const TestNode* TestGroup::findChildNode (const char* path) const
204 {
205         int compLen = getFirstComponentLength(path);
206         XE_CHECK(compLen > 0);
207
208         // Try to find matching children.
209         const TestNode* matchingNode = DE_NULL;
210         for (vector<TestNode*>::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++)
211         {
212                 if (compareNameToPathComponent((*iter)->getName(), path, compLen))
213                 {
214                         matchingNode = *iter;
215                         break;
216                 }
217         }
218
219         if (matchingNode)
220         {
221                 if (path[compLen] == 0)
222                         return matchingNode; // Last element in path, return matching node.
223                 else if (matchingNode->getNodeType() == TESTNODETYPE_GROUP)
224                         return static_cast<const TestGroup*>(matchingNode)->findChildNode(path + compLen + 1);
225                 else
226                         return DE_NULL;
227         }
228         else
229                 return DE_NULL;
230 }
231
232 // TestRoot
233
234 TestRoot::TestRoot (void)
235         : TestGroup(DE_NULL, TESTNODETYPE_ROOT, "", "")
236 {
237 }
238
239 // TestCase
240
241 TestCase* TestCase::createAsChild(TestGroup* parent, TestCaseType caseType, const char *name, const char *description)
242 {
243         return new TestCase(parent, caseType, name, description);
244 }
245
246 TestCase::TestCase (TestGroup* parent, TestCaseType caseType, const char* name, const char* description)
247         : TestNode              (parent, TESTNODETYPE_TEST_CASE, name, description)
248         , m_caseType    (caseType)
249 {
250 }
251
252 TestCase::~TestCase (void)
253 {
254 }
255
256 // TestHierarchyBuilder helpers
257
258 void addChildGroupsToMap (std::map<std::string, TestGroup*>& groupMap, TestGroup* group)
259 {
260         for (int ndx = 0; ndx < group->getNumChildren(); ndx++)
261         {
262                 TestNode* node = group->getChild(ndx);
263                 if (node->getNodeType() == TESTNODETYPE_GROUP)
264                 {
265                         TestGroup*      childGroup      = static_cast<TestGroup*>(node);
266                         std::string     fullPath;
267                         childGroup->getFullPath(fullPath);
268
269                         groupMap.insert(std::make_pair(fullPath, childGroup));
270                         addChildGroupsToMap(groupMap, childGroup);
271                 }
272         }
273 }
274
275 // TestHierarchyBuilder
276
277 TestHierarchyBuilder::TestHierarchyBuilder (TestRoot* root)
278         : m_root(root)
279 {
280         addChildGroupsToMap(m_groupMap, root);
281 }
282
283 TestHierarchyBuilder::~TestHierarchyBuilder (void)
284 {
285 }
286
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(), "" /* description */);
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(), "" /* description */);
315 }
316
317 // TestSet helpers
318
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
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
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
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
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
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 ||
381                                   node->getNodeType() == TESTNODETYPE_ROOT);
382                 addGroup(static_cast<const TestGroup*>(node));
383         }
384 }
385
386 void TestSet::addCase (const TestCase* testCase)
387 {
388         addNodeAndParents(m_set, testCase);
389 }
390
391 void TestSet::addGroup (const TestGroup* testGroup)
392 {
393         addNodeAndParents(m_set, testGroup);
394         addChildren(m_set, testGroup);
395 }
396
397 void TestSet::remove (const TestNode* node)
398 {
399         if (node->getNodeType() == TESTNODETYPE_TEST_CASE)
400                 removeCase(static_cast<const TestCase*>(node));
401         else
402         {
403                 XE_CHECK(node->getNodeType() == TESTNODETYPE_GROUP ||
404                                   node->getNodeType() == TESTNODETYPE_ROOT);
405                 removeGroup(static_cast<const TestGroup*>(node));
406         }
407 }
408
409 void TestSet::removeCase (const TestCase* testCase)
410 {
411         if (m_set.find(testCase) != m_set.end())
412         {
413                 m_set.erase(testCase);
414                 removeEmptyGroups(m_set, testCase->getParent());
415         }
416 }
417
418 void TestSet::removeGroup (const TestGroup* testGroup)
419 {
420         if (m_set.find(testGroup) != m_set.end())
421         {
422                 m_set.erase(testGroup);
423                 removeChildren(m_set, testGroup);
424                 if (testGroup->getParent() != DE_NULL)
425                         removeEmptyGroups(m_set, testGroup->getParent());
426         }
427 }
428
429 // ConstTestNodeIterator
430
431 ConstTestNodeIterator::ConstTestNodeIterator (const TestNode* root)
432         : m_root(root)
433 {
434 }
435
436 ConstTestNodeIterator ConstTestNodeIterator::begin (const TestNode* root)
437 {
438         ConstTestNodeIterator iter(root);
439         iter.m_iterStack.push_back(GroupState(DE_NULL));
440         return iter;
441 }
442
443 ConstTestNodeIterator ConstTestNodeIterator::end (const TestNode* root)
444 {
445         DE_UNREF(root);
446         return ConstTestNodeIterator(root);
447 }
448
449 ConstTestNodeIterator& ConstTestNodeIterator::operator++ (void)
450 {
451         DE_ASSERT(!m_iterStack.empty());
452
453         const TestNode* curNode                 = **this;
454         TestNodeType    curNodeType             = curNode->getNodeType();
455
456         if ((curNodeType == TESTNODETYPE_GROUP || curNodeType == TESTNODETYPE_ROOT) &&
457                 static_cast<const TestGroup*>(curNode)->getNumChildren() > 0)
458         {
459                 m_iterStack.push_back(GroupState(static_cast<const TestGroup*>(curNode)));
460         }
461         else
462         {
463                 for (;;)
464                 {
465                         const TestGroup*        group           = m_iterStack.back().group;
466                         int&                            childNdx        = m_iterStack.back().childNdx;
467                         int                                     numChildren     = group ? group->getNumChildren() : 1;
468
469                         childNdx += 1;
470                         if (childNdx == numChildren)
471                         {
472                                 m_iterStack.pop_back();
473                                 if (m_iterStack.empty())
474                                         break;
475                         }
476                         else
477                                 break;
478                 }
479         }
480
481         return *this;
482 }
483
484 ConstTestNodeIterator ConstTestNodeIterator::operator++ (int)
485 {
486         ConstTestNodeIterator copy(*this);
487         ++(*this);
488         return copy;
489 }
490
491 const TestNode* ConstTestNodeIterator::operator* (void) const
492 {
493         DE_ASSERT(!m_iterStack.empty());
494         if (m_iterStack.size() == 1)
495         {
496                 DE_ASSERT(m_iterStack[0].group == DE_NULL && m_iterStack[0].childNdx == 0);
497                 return m_root;
498         }
499         else
500                 return m_iterStack.back().group->getChild(m_iterStack.back().childNdx);
501 }
502
503 bool ConstTestNodeIterator::operator!= (const ConstTestNodeIterator& other) const
504 {
505         return m_root != other.m_root || m_iterStack != other.m_iterStack;
506 }
507
508 } // xe