Sync with 5.4.0
[deliverable/titan.core.git] / loggerplugins / JUnitLogger / JUnitLogger.cc
CommitLineData
970ed795 1///////////////////////////////////////////////////////////////////////////////
3abe9331 2// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
3// All rights reserved. This program and the accompanying materials
4// are made available under the terms of the Eclipse Public License v1.0
5// which accompanies this distribution, and is available at
6// http://www.eclipse.org/legal/epl-v10.html
7///////////////////////////////////////////////////////////////////////////////
8#include "JUnitLogger.hh"
9
10#ifndef TITAN_RUNTIME_2
11#include "RT1/TitanLoggerApi.hh"
12#else
13#include "RT2/TitanLoggerApi.hh"
14#endif
15
16#include <unistd.h>
17#include <sys/types.h>
18
19#include <sys/time.h>
20
21extern "C"
22{
23 // It's a static plug-in, destruction is done in the destructor. We need
24 // `extern "C"' for some reason.
25 ILoggerPlugin *create_junit_logger() { return new JUnitLogger(); }
26}
27
28extern "C" {
29 ILoggerPlugin *create_plugin() { return new JUnitLogger(); }
30 void destroy_plugin(ILoggerPlugin *plugin) { delete plugin; }
31}
32
33JUnitLogger::JUnitLogger()
34: filename_stem_(NULL), testsuite_name_(mcopystr("Titan"))
35, filename_(NULL), file_stream_(NULL)
36{
37 // Overwrite values set by the base class constructor
38 major_version_ = 1;
39 minor_version_ = 0;
40 name_ = mcopystr("JUnitLogger");
41 help_ = mcopystr("JUnitLogger writes JUnit-compatible XML");
42//printf("%5lu:constructed\n", (unsigned long)getpid());
43}
44
45JUnitLogger::~JUnitLogger()
46{
47//printf("%5lu:desstructed\n", (unsigned long)getpid());
48 close_file();
49
50 Free(name_);
51 Free(help_);
52 Free(filename_);
53 Free(testsuite_name_);
54 Free(filename_stem_);
55 name_ = help_ = filename_ = filename_stem_ = NULL;
56 file_stream_ = NULL;
57}
58
59void JUnitLogger::init(const char */*options*/)
60{
61//printf("%5lu:init\n", (unsigned long)getpid());
62 fprintf(stderr, "Initializing `%s' (v%u.%u): %s\n", name_,
63 major_version_, minor_version_, help_);
64}
65
66void JUnitLogger::fini()
67{
68//puts("fini");
69 //fprintf(stderr, "JUnitLogger finished logging for PID: `%lu'\n", (unsigned long)getpid());
70}
71
72void JUnitLogger::set_parameter(
73 const char *parameter_name, const char *parameter_value)
74{
75//puts("set_par");
76 if (!strcmp("filename_stem", parameter_name)) {
77 if (filename_stem_ != NULL)
78 Free(filename_stem_);
79 filename_stem_ = mcopystr(parameter_value);
80 } else if (!strcmp("testsuite_name", parameter_name)) {
81 if (filename_stem_ != NULL)
82 Free(testsuite_name_);
83 testsuite_name_ = mcopystr(parameter_value);
84 } else {
85 fprintf(stderr, "Unsupported parameter: `%s' with value: `%s'\n",
86 parameter_name, parameter_value);
87 }
88}
89
90void JUnitLogger::open_file(bool is_first)
91{
92 if (is_first) {
93 if (filename_stem_ == NULL) {
94 filename_stem_ = mcopystr("junit-xml");
95 }
96 }
97
98 if (file_stream_ != NULL) return; // already open
99
100 if (!TTCN_Runtime::is_single()
101 && !TTCN_Runtime::is_mtc()) return; // don't bother, only MTC has testcases
102
103 filename_ = mprintf("%s-%lu.log", filename_stem_, (unsigned long)getpid());
104//printf("\n%5lu:open [%s]\n", (unsigned long)getpid(), filename_);
105
106 file_stream_ = fopen(filename_, "w");
107 if (!file_stream_) {
108 fprintf(stderr, "%s was unable to open log file `%s', reinitialization "
109 "may help\n", plugin_name(), filename_);
110 return;
111 }
112
113 is_configured_ = true;
114
115 fprintf(file_stream_,
116 "<?xml version=\"1.0\"?>\n"
117 "<testsuite name='%s'>"
118 // We don't know the number of tests yet; leave out the tests=... attrib
119 "<!-- logger name=\"%s\" version=\"v%u.%u\" -->\n",
120 testsuite_name_,
121 plugin_name(), major_version(), minor_version());
122 fflush(file_stream_);
123}
124
125void JUnitLogger::close_file()
126{
127//printf("%5lu:close%c[%s]\n", (unsigned long)getpid(), file_stream_ ? ' ' : 'd', filename_ ? filename_ : "<none>");
128 if (file_stream_ != NULL) {
129 fputs("</testsuite>\n", file_stream_);
130 fflush(file_stream_);
131 fclose(file_stream_);
132 file_stream_ = NULL;
133 }
134 if (filename_) {
135 Free(filename_);
136 filename_ = NULL;
137 }
138}
139
140void JUnitLogger::log(const TitanLoggerApi::TitanLogEvent& event,
141 bool /*log_buffered*/, bool /*separate_file*/,
142 bool /*use_emergency_mask*/)
143{
144//puts("log");
145 if (file_stream_ == NULL) return;
146 static RInt seconds, microseconds;
147
148 const TitanLoggerApi::LogEventType_choice& choice = event.logEvent().choice();
149
150 switch (choice.get_selection()) {
151 case TitanLoggerApi::LogEventType_choice::ALT_testcaseOp: {
152 const TitanLoggerApi::TestcaseEvent_choice& tcev = choice.testcaseOp().choice();
153 switch (tcev.get_selection()) {
154 case TitanLoggerApi::TestcaseEvent_choice::ALT_testcaseStarted: {
155 fprintf(file_stream_, "<!-- Testcase %s started -->\n",
156 (const char*)tcev.testcaseStarted().testcase__name());
157 const TitanLoggerApi::TimestampType& ts = event.timestamp();
158 // remember the start time
159 seconds = ts.seconds();
160 microseconds = ts.microSeconds();
161 break; }
162
163 case TitanLoggerApi::TestcaseEvent_choice::ALT_testcaseFinished: {
164 const TitanLoggerApi::TestcaseType& tct = tcev.testcaseFinished();
165 const TitanLoggerApi::TimestampType& ts = event.timestamp();
166 long long now = 1000000LL * (long long)ts.seconds() + (long long)ts.microSeconds();
167 long long then= 1000000LL * (long long) seconds + (long long) microseconds ;
168 fprintf(file_stream_, "<!-- Testcase %s finished in %f, verdict: %s%s%s -->\n",
169 (const char*)tct.name().testcase__name(),
170 (now - then) / 1000000.0,
171 verdict_name[tct.verdict()],
172 (tct.reason().lengthof() > 0 ? ", reason: " : ""),
173 (const char*)tct.reason());
174
175 fprintf(file_stream_, " <testcase classname='%s' name='%s' time='%f'>\n",
176 (const char*)tct.name().module__name(),
177 (const char*)tct.name().testcase__name(),
178 (now - then) / 1000000.0);
179
180 switch (tct.verdict()) {
181 case TitanLoggerApi::Verdict::UNBOUND_VALUE:
182 case TitanLoggerApi::Verdict::UNKNOWN_VALUE:
183 // should not happen
184 break;
185
186 case TitanLoggerApi::Verdict::v0none:
187 fprintf(file_stream_, " <skipped>no verdict</skipped>\n");
188 break;
189
190 case TitanLoggerApi::Verdict::v1pass:
191 // do nothing; this counts as success
192 break;
193
194 case TitanLoggerApi::Verdict::v2inconc:
195 // JUnit doesn't seem to have the concept of "inconclusive"
196 // do nothing; this will appear as success
197 break;
198
199 case TitanLoggerApi::Verdict::v3fail: {
200 fprintf(file_stream_, " <failure type='fail-verdict'>%s\n",
201 (const char*)escape_xml_element(tct.reason()));
202
203 // Add a stack trace
204 const TitanLoggerApi::TitanLogEvent_sourceInfo__list& stack =
205 event.sourceInfo__list();
206 int stack_depth = stack.size_of();
207 for (int i=0; i < stack_depth; ++i) {
208 const TitanLoggerApi::LocationInfo& location = stack[i];
209 fprintf(file_stream_, "\n %s:%d %s ",
210 (const char*)location.filename(), (int)location.line(),
211 (const char*)location.ent__name());
212
213 // print the location type
214 switch (location.ent__type()) {
215 case TitanLoggerApi::LocationInfo_ent__type:: UNKNOWN_VALUE:
216 case TitanLoggerApi::LocationInfo_ent__type:: UNBOUND_VALUE:
217 // can't happen
218 break;
219 case TitanLoggerApi::LocationInfo_ent__type::unknown:
220 // do nothing
221 break;
222 case TitanLoggerApi::LocationInfo_ent__type::controlpart:
223 fputs("control part", file_stream_);
224 break;
225 case TitanLoggerApi::LocationInfo_ent__type::testcase__:
226 fputs("testcase", file_stream_);
227 break;
228 case TitanLoggerApi::LocationInfo_ent__type::altstep__:
229 fputs("altstep", file_stream_);
230 break;
231 case TitanLoggerApi::LocationInfo_ent__type::function__:
232 fputs("function", file_stream_);
233 break;
234 case TitanLoggerApi::LocationInfo_ent__type::external__function:
235 fputs("external function", file_stream_);
236 break;
237 case TitanLoggerApi::LocationInfo_ent__type::template__:
238 fputs("template", file_stream_);
239 break;
240 }
241 }
242 fputs("\n </failure>\n", file_stream_);
243 break; }
244
245 case TitanLoggerApi::Verdict::v4error:
246 fprintf(file_stream_, " <error type='DTE'>%s</error>\n",
247 (const char*)escape_xml_element(tct.reason()));
248 break;
249 }
250 // error or skip based on verdict
251 fputs(" </testcase>\n", file_stream_);
252 break; }
253
254 case TitanLoggerApi::TestcaseEvent_choice::UNBOUND_VALUE:
255 fputs("<!-- Unbound testcaseOp.choice !! -->\n", file_stream_);
256 break;
257 } // switch testcaseOp().choice.get_selection()
258
259 break; } // testcaseOp
260
261 case TitanLoggerApi::LogEventType_choice::ALT_errorLog: {
262 // A DTE is about to be thrown
263 const TitanLoggerApi::Categorized& cat = choice.errorLog();
264 fprintf(file_stream_, " <error type='DTE'>%s</error>\n",
265 (const char*)escape_xml_element(cat.text()));
266 break; }
267
268 default:
269 break; // NOP
270 } // switch event.logEvent().choice().get_selection()
271
272 fflush(file_stream_);
273}
274
275CHARSTRING JUnitLogger::escape_xml(const CHARSTRING& xml_str, int escape_chars)
276{
277 expstring_t escaped = NULL;
278 int len = xml_str.lengthof();
279 for (int i=0; i<len; i++) {
280 char c = *(((const char*)xml_str)+i);
281 switch (c) {
282 case '<':
283 if (escape_chars&LT) escaped = mputstr(escaped, "&lt;");
284 else escaped = mputc(escaped, c);
285 break;
286 case '>':
287 if (escape_chars&GT) escaped = mputstr(escaped, "&gt;");
288 else escaped = mputc(escaped, c);
289 break;
290 case '"':
291 if (escape_chars&QUOT) escaped = mputstr(escaped, "&quot;");
292 else escaped = mputc(escaped, c);
293 break;
294 case '\'':
295 if (escape_chars&APOS) escaped = mputstr(escaped, "&apos;");
296 else escaped = mputc(escaped, c);
297 break;
298 case '&':
299 if (escape_chars&AMP) escaped = mputstr(escaped, "&amp;");
300 else escaped = mputc(escaped, c);
301 break;
302 default:
303 escaped = mputc(escaped, c);
304 }
305 }
306 CHARSTRING ret_val(escaped);
307 Free(escaped);
308 return ret_val;
309}
This page took 0.044077 seconds and 5 git commands to generate.