xref: /aosp_15_r20/external/deqp/framework/common/tcuTestHierarchyUtil.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 hierarchy utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuTestHierarchyUtil.hpp"
25 #include "tcuStringTemplate.hpp"
26 #include "tcuCommandLine.hpp"
27 
28 #include "qpXmlWriter.h"
29 
30 #include <fstream>
31 
32 namespace tcu
33 {
34 
35 using std::string;
36 
getNodeTypeName(TestNodeType nodeType)37 static const char *getNodeTypeName(TestNodeType nodeType)
38 {
39     switch (nodeType)
40     {
41     case NODETYPE_SELF_VALIDATE:
42         return "SelfValidate";
43     case NODETYPE_CAPABILITY:
44         return "Capability";
45     case NODETYPE_ACCURACY:
46         return "Accuracy";
47     case NODETYPE_PERFORMANCE:
48         return "Performance";
49     case NODETYPE_GROUP:
50         return "TestGroup";
51     default:
52         DE_ASSERT(false);
53         return DE_NULL;
54     }
55 }
56 
57 // Utilities
58 
makePackageFilename(const std::string & pattern,const std::string & packageName,const std::string & typeExtension)59 static std::string makePackageFilename(const std::string &pattern, const std::string &packageName,
60                                        const std::string &typeExtension)
61 {
62     std::map<string, string> args;
63     args["packageName"]   = packageName;
64     args["typeExtension"] = typeExtension;
65     return StringTemplate(pattern).specialize(args);
66 }
67 
writeXmlCaselist(TestHierarchyIterator & iter,qpXmlWriter * writer)68 static void writeXmlCaselist(TestHierarchyIterator &iter, qpXmlWriter *writer)
69 {
70     DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
71               iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
72 
73     {
74         const TestNode *node = iter.getNode();
75         qpXmlAttribute attribs[1];
76         int numAttribs        = 0;
77         attribs[numAttribs++] = qpSetStringAttrib("PackageName", node->getName());
78         DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));
79 
80         if (!qpXmlWriter_startDocument(writer, true) ||
81             !qpXmlWriter_startElement(writer, "TestCaseList", numAttribs, attribs))
82             throw Exception("Failed to start XML document");
83     }
84 
85     iter.next();
86 
87     while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
88     {
89         const TestNode *const node  = iter.getNode();
90         const TestNodeType nodeType = node->getNodeType();
91         const bool isEnter          = iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE;
92 
93         DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE ||
94                   iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE);
95         {
96             if (isEnter)
97             {
98                 const string caseName = node->getName();
99                 qpXmlAttribute attribs[2];
100                 int numAttribs = 0;
101 
102                 attribs[numAttribs++] = qpSetStringAttrib("Name", caseName.c_str());
103                 attribs[numAttribs++] = qpSetStringAttrib("CaseType", getNodeTypeName(nodeType));
104                 DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));
105 
106                 if (!qpXmlWriter_startElement(writer, "TestCase", numAttribs, attribs))
107                     throw Exception("Writing to case list file failed");
108             }
109             else
110             {
111                 if (!qpXmlWriter_endElement(writer, "TestCase"))
112                     throw tcu::Exception("Writing to case list file failed");
113             }
114         }
115 
116         iter.next();
117     }
118 
119     // This could be done in catch, but the file is corrupt at that point anyways.
120     if (!qpXmlWriter_endElement(writer, "TestCaseList") || !qpXmlWriter_endDocument(writer))
121         throw Exception("Failed to terminate XML document");
122 }
123 
124 /*--------------------------------------------------------------------*//*!
125  * \brief Export the test list of each package into a separate XML file.
126  *//*--------------------------------------------------------------------*/
writeXmlCaselistsToFiles(TestPackageRoot & root,TestContext & testCtx,const CommandLine & cmdLine)127 void writeXmlCaselistsToFiles(TestPackageRoot &root, TestContext &testCtx, const CommandLine &cmdLine)
128 {
129     DefaultHierarchyInflater inflater(testCtx);
130     de::MovePtr<const CaseListFilter> caseListFilter(
131         testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
132 
133     TestHierarchyIterator iter(root, inflater, *caseListFilter);
134     const char *const filenamePattern = cmdLine.getCaseListExportFile();
135 
136     while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
137     {
138         const TestNode *node  = iter.getNode();
139         const char *pkgName   = node->getName();
140         const string filename = makePackageFilename(filenamePattern, pkgName, "xml");
141 
142         DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
143                   node->getNodeType() == NODETYPE_PACKAGE);
144 
145         FILE *file          = DE_NULL;
146         qpXmlWriter *writer = DE_NULL;
147 
148         try
149         {
150             file = fopen(filename.c_str(), "wb");
151             if (!file)
152                 throw Exception("Failed to open " + filename);
153 
154             writer = qpXmlWriter_createFileWriter(file, false, false);
155             if (!writer)
156                 throw Exception("XML writer creation failed");
157 
158             print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());
159 
160             writeXmlCaselist(iter, writer);
161 
162             qpXmlWriter_destroy(writer);
163             writer = DE_NULL;
164 
165             fclose(file);
166             file = DE_NULL;
167         }
168         catch (...)
169         {
170             if (writer)
171                 qpXmlWriter_destroy(writer);
172             if (file)
173                 fclose(file);
174             throw;
175         }
176 
177         DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
178                   iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
179         iter.next();
180     }
181 }
182 
183 /*--------------------------------------------------------------------*//*!
184  * \brief Export the test list of each package into a separate ascii file.
185  *//*--------------------------------------------------------------------*/
writeTxtCaselistsToFiles(TestPackageRoot & root,TestContext & testCtx,const CommandLine & cmdLine)186 void writeTxtCaselistsToFiles(TestPackageRoot &root, TestContext &testCtx, const CommandLine &cmdLine)
187 {
188     DefaultHierarchyInflater inflater(testCtx);
189     de::MovePtr<const CaseListFilter> caseListFilter(
190         testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
191 
192     TestHierarchyIterator iter(root, inflater, *caseListFilter);
193     const char *const filenamePattern = cmdLine.getCaseListExportFile();
194 
195     while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
196     {
197         const TestNode *node  = iter.getNode();
198         const char *pkgName   = node->getName();
199         const string filename = makePackageFilename(filenamePattern, pkgName, "txt");
200 
201         DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
202                   node->getNodeType() == NODETYPE_PACKAGE);
203 
204         std::ofstream out(filename.c_str(), std::ios_base::binary);
205         if (!out.is_open() || !out.good())
206             throw Exception("Failed to open " + filename);
207 
208         print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());
209 
210         try
211         {
212             iter.next();
213         }
214         catch (const tcu::NotSupportedError &)
215         {
216             return;
217         }
218 
219         while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
220         {
221             if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE)
222                 out << (isTestNodeTypeExecutable(iter.getNode()->getNodeType()) ? "TEST" : "GROUP") << ": "
223                     << iter.getNodePath() << "\n";
224             iter.next();
225         }
226 
227         DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
228                   iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
229         iter.next();
230     }
231 }
232 
233 } // namespace tcu
234