198b9e7df75d63b1afd92a64dc69ee71f4850760
[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 and c <= '~' and c != '\\' and c != '"' and c != '>' and c != '<')
56 {
57 escaped_string+= c;
58 }
59 else if (c == '>')
60 {
61 escaped_string+= '&';
62 escaped_string+= 'g';
63 escaped_string+= 't';
64 escaped_string+= ';';
65 }
66 else if (c == '<')
67 {
68 escaped_string+= '&';
69 escaped_string+= 'l';
70 escaped_string+= 't';
71 escaped_string+= ';';
72 }
73 else
74 {
75 escaped_string+= '\\';
76 switch (c) {
77 case '"': escaped_string+= '"'; break;
78 case '\\': escaped_string+= '\\'; break;
79 case '\t': escaped_string+='t'; break;
80 case '\r': escaped_string+='r'; break;
81 case '\n': escaped_string+='n'; break;
82 default:
83 char const* const hexdig= "0123456789ABCDEF";
84 escaped_string+= 'x';
85 escaped_string+= hexdig[c >> 4];
86 escaped_string+= hexdig[c & 0xF];
87 }
88 }
89 }
90 escaped_string+= '"';
91
92 return escaped_string;
93 }
94
95 class TestCase {
96 public:
97 TestCase(const std::string& arg):
98 _name(arg),
99 _result(TEST_FAILURE)
100 {
101 }
102
103 const std::string& name() const
104 {
105 return _name;
106 }
107
108 test_return_t result() const
109 {
110 return _result;
111 }
112
113 void result(test_return_t arg)
114 {
115 _result= arg;
116 }
117
118 void result(test_return_t arg, const libtest::Timer& timer_)
119 {
120 _result= arg;
121 _timer= timer_;
122 }
123
124 const libtest::Timer& timer() const
125 {
126 return _timer;
127 }
128
129 void timer(libtest::Timer& arg)
130 {
131 _timer= arg;
132 }
133
134 private:
135 std::string _name;
136 test_return_t _result;
137 libtest::Timer _timer;
138 };
139
140 Formatter::Formatter(const std::string& frame_name, const std::string& arg)
141 {
142 _suite_name= frame_name;
143 _suite_name+= ".";
144 _suite_name+= arg;
145 }
146
147 Formatter::~Formatter()
148 {
149 std::for_each(_testcases.begin(), _testcases.end(), DeleteFromVector());
150 _testcases.clear();
151 }
152
153 TestCase* Formatter::current()
154 {
155 return _testcases.back();
156 }
157
158 void Formatter::skipped()
159 {
160 current()->result(TEST_SKIPPED);
161 Out << name() << "."
162 << current()->name()
163 << "\t\t\t\t\t"
164 << "[ " << test_strerror(current()->result()) << " ]";
165
166 reset();
167 }
168
169 void Formatter::failed()
170 {
171 assert(current());
172 current()->result(TEST_FAILURE);
173
174 Out << name()
175 << "." << current()->name() << "\t\t\t\t\t"
176 << "[ " << test_strerror(current()->result()) << " ]";
177
178 reset();
179 }
180
181 void Formatter::success(const libtest::Timer& timer_)
182 {
183 assert(current());
184 current()->result(TEST_SUCCESS, timer_);
185 std::string escaped_string;
186
187 Out << name() << "."
188 << current()->name()
189 << "\t\t\t\t\t"
190 << current()->timer()
191 << " [ " << test_strerror(current()->result()) << " ]";
192
193 reset();
194 }
195
196 void Formatter::xml(libtest::Framework& framework_, std::ofstream& output)
197 {
198 std::string escaped_string;
199
200 output << "<testsuites name="
201 << escape4XML(framework_.name(), escaped_string) << ">" << std::endl;
202
203 for (Suites::iterator framework_iter= framework_.suites().begin();
204 framework_iter != framework_.suites().end();
205 ++framework_iter)
206 {
207 output << "\t<testsuite name="
208 << escape4XML((*framework_iter)->name(), escaped_string)
209 #if 0
210 << " classname=\"\" package=\"\""
211 #endif
212 << ">" << std::endl;
213
214 for (TestCases::iterator case_iter= (*framework_iter)->formatter()->testcases().begin();
215 case_iter != (*framework_iter)->formatter()->testcases().end();
216 ++case_iter)
217 {
218 output << "\t\t<testcase name="
219 << escape4XML((*case_iter)->name(), escaped_string)
220 << " time=\""
221 << (*case_iter)->timer().elapsed_milliseconds()
222 << "\""
223 << std::endl;
224
225 switch ((*case_iter)->result())
226 {
227 case TEST_SKIPPED:
228 output << ">" << std::endl;
229 output << "\t\t <skipped/>" << std::endl;
230 output << "\t\t</testcase>" << std::endl;
231 break;
232
233 case TEST_FAILURE:
234 output << ">" << std::endl;
235 output << "\t\t <failure message=\"\" type=\"\"/>"<< std::endl;
236 output << "\t\t</testcase>" << std::endl;
237 break;
238
239 case TEST_SUCCESS:
240 output << "/>" << std::endl;
241 break;
242 }
243 }
244 output << "\t</testsuite>" << std::endl;
245 }
246 output << "</testsuites>" << std::endl;
247 }
248
249 void Formatter::push_testcase(const std::string& arg)
250 {
251 assert(_suite_name.empty() == false);
252 TestCase* _current_testcase= new TestCase(arg);
253 _testcases.push_back(_current_testcase);
254 }
255
256 void Formatter::reset()
257 {
258 }
259 } // namespace libtest