7cb3ea0ab8fb55ca8b7e0083b66638527128017a
[awesomized/libmemcached] / libtest / formatter.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Data Differential YATL (i.e. libtest) library
4 *
5 * Copyright (C) 2012 Data Differential, http://datadifferential.com/
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 #include "libtest/yatlcon.h"
38
39 #include <libtest/common.h>
40
41 #include <algorithm>
42 #include <fstream>
43 #include <iostream>
44
45 namespace libtest {
46
47 std::string& escape4XML(std::string const& arg, std::string& escaped_string)
48 {
49 escaped_string.clear();
50
51 escaped_string+= '"';
52 for (std::string::const_iterator x= arg.begin(), end= arg.end(); x != end; ++x)
53 {
54 unsigned char c= *x;
55 if (c == '&')
56 {
57 escaped_string+= "&amp;";
58 }
59 else if (c == '>')
60 {
61 escaped_string+= "&gt;";
62 }
63 else if (c == '<')
64 {
65 escaped_string+= "&lt;";
66 }
67 else if (c == '\'')
68 {
69 escaped_string+= "&apos;"; break;
70 }
71 else if (c == '"')
72 {
73 escaped_string+= "&quot;";
74 }
75 else if (c == ' ')
76 {
77 escaped_string+= ' ';
78 }
79 else if (isalnum(c))
80 {
81 escaped_string+= c;
82 }
83 else
84 {
85 char const* const hexdig= "0123456789ABCDEF";
86 escaped_string+= "&#x";
87 escaped_string+= hexdig[c >> 4];
88 escaped_string+= hexdig[c & 0xF];
89 escaped_string+= ';';
90 }
91 }
92 escaped_string+= '"';
93
94 return escaped_string;
95 }
96
97 class TestCase {
98 public:
99 TestCase(const std::string& arg):
100 _name(arg),
101 _result(TEST_FAILURE)
102 {
103 }
104
105 const std::string& name() const
106 {
107 return _name;
108 }
109
110 test_return_t result() const
111 {
112 return _result;
113 }
114
115 void result(test_return_t arg)
116 {
117 _result= arg;
118 }
119
120 void result(test_return_t arg, const libtest::Timer& timer_)
121 {
122 _result= arg;
123 _timer= timer_;
124 }
125
126 const libtest::Timer& timer() const
127 {
128 return _timer;
129 }
130
131 void timer(libtest::Timer& arg)
132 {
133 _timer= arg;
134 }
135
136 private:
137 std::string _name;
138 test_return_t _result;
139 libtest::Timer _timer;
140 };
141
142 Formatter::Formatter(const std::string& frame_name, const std::string& arg)
143 {
144 _suite_name= frame_name;
145 _suite_name+= ".";
146 _suite_name+= arg;
147 }
148
149 Formatter::~Formatter()
150 {
151 std::for_each(_testcases.begin(), _testcases.end(), DeleteFromVector());
152 _testcases.clear();
153 }
154
155 TestCase* Formatter::current()
156 {
157 return _testcases.back();
158 }
159
160 void Formatter::skipped()
161 {
162 current()->result(TEST_SKIPPED);
163 Out << name() << "."
164 << current()->name()
165 << "\t\t\t\t\t"
166 << "[ " << test_strerror(current()->result()) << " ]";
167
168 reset();
169 }
170
171 void Formatter::failed()
172 {
173 assert(current());
174 current()->result(TEST_FAILURE);
175
176 Out << name()
177 << "." << current()->name() << "\t\t\t\t\t"
178 << "[ " << test_strerror(current()->result()) << " ]";
179
180 reset();
181 }
182
183 void Formatter::success(const libtest::Timer& timer_)
184 {
185 assert(current());
186 current()->result(TEST_SUCCESS, timer_);
187 std::string escaped_string;
188
189 Out << name() << "."
190 << current()->name()
191 << "\t\t\t\t\t"
192 << current()->timer()
193 << " [ " << test_strerror(current()->result()) << " ]";
194
195 reset();
196 }
197
198 void Formatter::xml(libtest::Framework& framework_, std::ofstream& output)
199 {
200 std::string escaped_string;
201
202 output << "<testsuites name="
203 << escape4XML(framework_.name(), escaped_string) << ">" << std::endl;
204
205 for (Suites::iterator framework_iter= framework_.suites().begin();
206 framework_iter != framework_.suites().end();
207 ++framework_iter)
208 {
209 output << "\t<testsuite name="
210 << escape4XML((*framework_iter)->name(), escaped_string)
211 #if 0
212 << " classname=\"\" package=\"\""
213 #endif
214 << ">" << std::endl;
215
216 for (TestCases::iterator case_iter= (*framework_iter)->formatter()->testcases().begin();
217 case_iter != (*framework_iter)->formatter()->testcases().end();
218 ++case_iter)
219 {
220 output << "\t\t<testcase name="
221 << escape4XML((*case_iter)->name(), escaped_string)
222 << " time=\""
223 << (*case_iter)->timer().elapsed_milliseconds()
224 << "\"";
225
226 switch ((*case_iter)->result())
227 {
228 case TEST_SKIPPED:
229 output << ">" << std::endl;
230 output << "\t\t <skipped/>" << std::endl;
231 output << "\t\t</testcase>" << std::endl;
232 break;
233
234 case TEST_FAILURE:
235 output << ">" << std::endl;
236 output << "\t\t <failure message=\"\" type=\"\"/>"<< std::endl;
237 output << "\t\t</testcase>" << std::endl;
238 break;
239
240 case TEST_SUCCESS:
241 output << "/>" << std::endl;
242 break;
243 }
244 }
245 output << "\t</testsuite>" << std::endl;
246 }
247 output << "</testsuites>" << std::endl;
248 }
249
250 void Formatter::push_testcase(const std::string& arg)
251 {
252 assert(_suite_name.empty() == false);
253 TestCase* _current_testcase= new TestCase(arg);
254 _testcases.push_back(_current_testcase);
255 }
256
257 void Formatter::reset()
258 {
259 }
260 } // namespace libtest