Nektar++
TestData.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: TestData.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10// Department of Aeronautics, Imperial College London (UK), and Scientific
11// Computing and Imaging Institute, University of Utah (USA).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description: Encapsulation of test XML file.
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include <boost/algorithm/string.hpp>
36#include <boost/core/ignore_unused.hpp>
37#include <boost/lexical_cast.hpp>
38
39#include <TestData.h>
40#include <TestException.hpp>
41
42using namespace std;
43
44namespace Nektar
45{
46
47/**
48 * @brief TestData constructor.
49 *
50 * The class is constructed with the path to the test XML file and a
51 * `po::variables_map` object containing the command-line options passed to the
52 * program.
53 *
54 * @param pFilename
55 * @param pVm
56 */
57
58TestData::TestData(const fs::path &pFilename, po::variables_map &pVm)
59 : m_cmdoptions(pVm)
60{
61 // Process test file format.
62 m_doc = new TiXmlDocument(pFilename.string().c_str());
63
64 bool loadOkay = m_doc->LoadFile();
65
66 ASSERTL0(loadOkay,
67 "Failed to load test definition file: " + pFilename.string() +
68 "\n" + string(m_doc->ErrorDesc()));
69
70 Parse(m_doc);
71}
72
74{
75 boost::ignore_unused(pSrc);
76}
77
78/// Returns the description of a test.
79const std::string &TestData::GetDescription() const
80{
81 return m_description;
82}
83
84const Command &TestData::GetCommand(unsigned int pId) const
85{
86 ASSERTL0(pId < m_commands.size(),
87 "Command ID '" + std::to_string(pId) + "' not found");
88 return m_commands[pId];
89}
90
91unsigned int TestData::GetNumCommands() const
92{
93 return m_commands.size();
94}
95
96/// Returns the type of metric to be collected for a given metric ID.
97std::string TestData::GetMetricType(unsigned int pId) const
98{
99 ASSERTL0(pId < m_metrics.size(), "Metric ID out of range.");
100
101 // read the property name
102 ASSERTL0(m_metrics[pId]->Attribute("type"),
103 "Missing 'type' attribute in metric " +
104 boost::lexical_cast<string>(pId) + ").");
105 return boost::to_upper_copy(string(m_metrics[pId]->Attribute("type")));
106}
107
108/// Returns the number of metrics to be collected for the test.
109unsigned int TestData::GetNumMetrics() const
110{
111 return m_metrics.size();
112}
113
114/// Returns a pointer to the `TiXmlElement` object representing the metric for a
115/// given metric ID.
116TiXmlElement *TestData::GetMetric(unsigned int pId)
117{
118 ASSERTL0(pId < m_metrics.size(), "Metric index out of range.");
119 return m_metrics[pId];
120}
121
122/// Returns the ID of the metric for a given metric ID.
123unsigned int TestData::GetMetricId(unsigned int pId)
124{
125 ASSERTL0(pId < m_metrics.size(), "Metric index out of range.");
126 const char *id = m_metrics[pId]->Attribute("id");
127 ASSERTL0(id, "No ID found for metric!");
128 return boost::lexical_cast<unsigned int>(id);
129}
130
132{
133 ASSERTL0(pId < m_files.size(), "File index out of range.");
134 return m_files[pId];
135}
136
137/// Returns the number of dependent files required for the test.
139{
140 return m_files.size();
141}
142
143/// Returns the number of runs to be performed for the test.
144unsigned int TestData::GetNumRuns() const
145{
146 return m_runs;
147}
148
149Command TestData::ParseCommand(TiXmlElement *elmt) const
150{
151 Command cmd;
152 TiXmlElement *tmp;
153
154 cmd.m_pythonTest = false;
155
156 std::string commandType = "none";
157 if (elmt->Attribute("type"))
158 {
159 commandType = elmt->Attribute("type");
160
161 if (commandType == "none")
162 {
163 cmd.m_commandType = eNone;
164 }
165 else if (commandType == "parallel")
166 {
168 }
169 else if (commandType == "sequential")
170 {
172 }
173 }
174
175 // Parse executable tag. Do not enforce a check because this might be
176 // overridden on the command line.
177 if (elmt->FirstChildElement("executable"))
178 {
179 tmp = elmt->FirstChildElement("executable");
180 cmd.m_executable = fs::path(tmp->GetText());
181 // Test to see if this test requires Python
182 std::string needsPython;
183 tmp->QueryStringAttribute("python", &needsPython);
184 cmd.m_pythonTest = needsPython == "true";
185
186#if defined(RELWITHDEBINFO)
187 cmd.m_executable += cmd.m_pythonTest ? "" : "-rg";
188#elif !defined(NDEBUG)
189 cmd.m_executable += cmd.m_pythonTest ? "" : "-g";
190#endif
191 }
192
193 // Find associated parameters.
194 tmp = elmt->FirstChildElement("parameters");
195 ASSERTL0(tmp, "Cannot find 'parameters' for test.");
196 if (tmp->GetText())
197 {
198 cmd.m_parameters = string(tmp->GetText());
199 }
200
201 // Find parallel processes tah.
202 tmp = elmt->FirstChildElement("processes");
203 if (tmp)
204 {
205 cmd.m_processes = atoi(tmp->GetText());
206 }
207 else
208 {
209 cmd.m_processes = 1;
210 }
211
212 return cmd;
213}
214
215/// Parse the test file and populate member variables for the test.
216void TestData::Parse(TiXmlDocument *pDoc)
217{
218 TiXmlHandle handle(pDoc);
219 TiXmlElement *testElement, *tmp, *metrics, *files;
220 testElement = handle.FirstChildElement("test").Element();
221 ASSERTL0(testElement, "Cannot find 'test' root element.");
222
223 // Find the desired number of test runs
224 unsigned int runs = 1;
225 testElement->QueryUnsignedAttribute("runs", &runs);
226 ASSERTL0(runs > 0, "Number of runs must be greater than zero.");
227 m_runs = runs;
228
229 // Find description tag.
230 tmp = testElement->FirstChildElement("description");
231 ASSERTL0(tmp, "Cannot find 'description' for test.");
232 m_description = string(tmp->GetText());
233
234 // Find command(s) to run.
235 if (m_cmdoptions.count("executable"))
236 {
237 m_commands.push_back(ParseCommand(testElement));
238 m_commands.back().m_executable =
239 fs::path(m_cmdoptions["executable"].as<std::string>());
240 }
241 else if (testElement->FirstChildElement("executable"))
242 {
243 m_commands.push_back(ParseCommand(testElement));
244 }
245 else if ((tmp = testElement->FirstChildElement("segment")))
246 {
247 ASSERTL0(m_cmdoptions.count("executable") == 0,
248 "Test files defining more than one command in segment "
249 "blocks cannot use --executable.");
250
251 while (tmp)
252 {
253 m_commands.push_back(ParseCommand(tmp));
254 tmp = tmp->NextSiblingElement("segment");
255 }
256
257 for (int i = 1; i < m_commands.size(); ++i)
258 {
259 ASSERTL0(m_commands[i].m_commandType == m_commands[0].m_commandType,
260 "All segment commands should be of the same type.");
261 }
262 }
263
264 ASSERTL0(m_commands.size() > 0,
265 "No executable / command segments specified for test.");
266
267 // Extract metric tags
268 metrics = testElement->FirstChildElement("metrics");
269 ASSERTL0(metrics, "No metrics defined for test.");
270
271 tmp = metrics->FirstChildElement("metric");
272 while (tmp)
273 {
274 m_metrics.push_back(tmp);
275 tmp = tmp->NextSiblingElement("metric");
276 }
277
278 // Extract list of dependent files
279 files = testElement->FirstChildElement("files");
280 if (files)
281 {
282 tmp = files->FirstChildElement("file");
283 while (tmp)
284 {
286 f.m_filename = string(tmp->GetText());
287 if (tmp->Attribute("description"))
288 {
289 f.m_description = string(tmp->Attribute("description"));
290 }
291 m_files.push_back(f);
292 tmp = tmp->NextSiblingElement("file");
293 }
294 }
295}
296
298{
299 m_doc->SaveFile();
300}
301} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
The TestData class is responsible for parsing a test XML file and storing the data.
Definition: TestData.h:79
TestData(const fs::path &pFilename, po::variables_map &pVm)
TestData constructor.
Definition: TestData.cpp:58
std::vector< TiXmlElement * > m_metrics
Definition: TestData.h:105
DependentFile GetDependentFile(unsigned int pId) const
Definition: TestData.cpp:131
unsigned int GetMetricId(unsigned int pId)
Returns the ID of the metric for a given metric ID.
Definition: TestData.cpp:123
void Parse(TiXmlDocument *pDoc)
Parse the test file and populate member variables for the test.
Definition: TestData.cpp:216
std::vector< Command > m_commands
Definition: TestData.h:103
unsigned int GetNumDependentFiles() const
Returns the number of dependent files required for the test.
Definition: TestData.cpp:138
TiXmlDocument * m_doc
Definition: TestData.h:104
unsigned int GetNumMetrics() const
Returns the number of metrics to be collected for the test.
Definition: TestData.cpp:109
unsigned int m_runs
The number of times to run the test.
Definition: TestData.h:108
Command ParseCommand(TiXmlElement *pElmt) const
Definition: TestData.cpp:149
unsigned int GetNumRuns() const
Returns the number of runs to be performed for the test.
Definition: TestData.cpp:144
TiXmlElement * GetMetric(unsigned int pId)
Returns a pointer to the TiXmlElement object representing the metric for a given metric ID.
Definition: TestData.cpp:116
unsigned int GetNumCommands() const
Definition: TestData.cpp:91
const std::string & GetDescription() const
Returns the description of a test.
Definition: TestData.cpp:79
std::string GetMetricType(unsigned int pId) const
Returns the type of metric to be collected for a given metric ID.
Definition: TestData.cpp:97
po::variables_map m_cmdoptions
Definition: TestData.h:101
const Command & GetCommand(unsigned int pId) const
Definition: TestData.cpp:84
std::vector< DependentFile > m_files
Definition: TestData.h:106
std::string m_description
Definition: TestData.h:102
@ eSequential
Definition: TestData.h:60
@ eParallel
Definition: TestData.h:61
@ eNone
Definition: TestData.h:59
STL namespace.
bool m_pythonTest
Definition: TestData.h:69
fs::path m_executable
Definition: TestData.h:66
std::string m_parameters
Definition: TestData.h:67
CommandType m_commandType
Definition: TestData.h:70
unsigned int m_processes
Definition: TestData.h:68
std::string m_filename
Definition: TestData.h:54
std::string m_description
Definition: TestData.h:53