1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2007-2009 Kouhei Sutou <kou@clear-code.com>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif /* HAVE_CONFIG_H */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib.h>
27
28 #include "cut-test-result.h"
29 #include "cut-enum-types.h"
30 #include "cut-test.h"
31 #include "cut-test-iterator.h"
32 #include "cut-test-case.h"
33 #include "cut-test-suite.h"
34 #include "cut-stream-parser.h"
35 #include "cut-backtrace-entry.h"
36 #include "cut-utils.h"
37 #include "cut-readable-differ.h"
38
39 #define MAX_DIFF_TARGET_SIZE 8092
40
41 #define CUT_TEST_RESULT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CUT_TYPE_TEST_RESULT, CutTestResultPrivate))
42
43 typedef struct _CutTestResultPrivate CutTestResultPrivate;
44 struct _CutTestResultPrivate
45 {
46 CutTestResultStatus status;
47 CutTest *test;
48 CutTestIterator *test_iterator;
49 CutTestCase *test_case;
50 CutTestSuite *test_suite;
51 CutTestData *test_data;
52 gchar *message;
53 gboolean user_set_message;
54 gchar *user_message;
55 gchar *system_message;
56 GList *backtrace;
57 GTimeVal start_time;
58 gdouble elapsed;
59 gchar *expected;
60 gchar *actual;
61 gchar *diff;
62 gchar *folded_diff;
63 gboolean user_set_diff;
64 gboolean user_set_folded_diff;
65 };
66
67 enum
68 {
69 PROP_0,
70 PROP_STATUS,
71 PROP_TEST,
72 PROP_TEST_ITERATOR,
73 PROP_TEST_CASE,
74 PROP_TEST_SUITE,
75 PROP_TEST_DATA,
76 PROP_USER_MESSAGE,
77 PROP_SYSTEM_MESSAGE,
78 PROP_BACKTRACE,
79 PROP_ELAPSED,
80 PROP_EXPECTED,
81 PROP_ACTUAL,
82 PROP_DIFF,
83 PROP_FOLDED_DIFF,
84 };
85
86
87 G_DEFINE_TYPE (CutTestResult, cut_test_result, G_TYPE_OBJECT)
88
89 static void dispose (GObject *object);
90 static void set_property (GObject *object,
91 guint prop_id,
92 const GValue *value,
93 GParamSpec *pspec);
94 static void get_property (GObject *object,
95 guint prop_id,
96 GValue *value,
97 GParamSpec *pspec);
98
99 static void
cut_test_result_class_init(CutTestResultClass * klass)100 cut_test_result_class_init (CutTestResultClass *klass)
101 {
102 GObjectClass *gobject_class;
103 GParamSpec *spec;
104
105 gobject_class = G_OBJECT_CLASS(klass);
106
107 gobject_class->dispose = dispose;
108 gobject_class->set_property = set_property;
109 gobject_class->get_property = get_property;
110
111 spec = g_param_spec_enum("status",
112 "Status",
113 "The status of the result",
114 CUT_TYPE_TEST_RESULT_STATUS,
115 CUT_TEST_RESULT_SUCCESS,
116 G_PARAM_READWRITE);
117 g_object_class_install_property(gobject_class, PROP_STATUS, spec);
118
119 spec = g_param_spec_object("test",
120 "CutTest object",
121 "A CutTest object",
122 CUT_TYPE_TEST,
123 G_PARAM_READWRITE);
124 g_object_class_install_property(gobject_class, PROP_TEST, spec);
125
126 spec = g_param_spec_object("test-iterator",
127 "CutTestIterator object",
128 "A CutTestIterator object",
129 CUT_TYPE_TEST_ITERATOR,
130 G_PARAM_READWRITE);
131 g_object_class_install_property(gobject_class, PROP_TEST_ITERATOR, spec);
132
133 spec = g_param_spec_object("test-case",
134 "CutTestCase object",
135 "A CutTestCase object",
136 CUT_TYPE_TEST_CASE,
137 G_PARAM_READWRITE);
138 g_object_class_install_property(gobject_class, PROP_TEST_CASE, spec);
139
140 spec = g_param_spec_object("test-suite",
141 "CutTestSuite object",
142 "A CutTestSuite object",
143 CUT_TYPE_TEST_SUITE,
144 G_PARAM_READWRITE);
145 g_object_class_install_property(gobject_class, PROP_TEST_SUITE, spec);
146
147 spec = g_param_spec_object("test-data",
148 "CutTestData object",
149 "A CutTestData object",
150 CUT_TYPE_TEST_DATA,
151 G_PARAM_READWRITE);
152 g_object_class_install_property(gobject_class, PROP_TEST_DATA, spec);
153
154 spec = g_param_spec_string("user-message",
155 "User Message",
156 "The message from user of the result",
157 NULL,
158 G_PARAM_READWRITE);
159 g_object_class_install_property(gobject_class, PROP_USER_MESSAGE, spec);
160
161 spec = g_param_spec_string("system-message",
162 "System Message",
163 "The message from system of the result",
164 NULL,
165 G_PARAM_READWRITE);
166 g_object_class_install_property(gobject_class, PROP_SYSTEM_MESSAGE, spec);
167
168 spec = g_param_spec_pointer("backtrace",
169 "backtrace",
170 "The backtrace of the result",
171 G_PARAM_READWRITE);
172 g_object_class_install_property(gobject_class, PROP_BACKTRACE, spec);
173
174 spec = g_param_spec_double("elapsed",
175 "Elapsed time",
176 "The time of the result",
177 0, G_MAXDOUBLE, 0,
178 G_PARAM_READWRITE);
179 g_object_class_install_property(gobject_class, PROP_ELAPSED, spec);
180
181 spec = g_param_spec_string("expected",
182 "Expected object",
183 "The inspected string of expected object",
184 NULL,
185 G_PARAM_READWRITE);
186 g_object_class_install_property(gobject_class, PROP_EXPECTED, spec);
187
188 spec = g_param_spec_string("actual",
189 "Actual object",
190 "The inspected string of actual object",
191 NULL,
192 G_PARAM_READWRITE);
193 g_object_class_install_property(gobject_class, PROP_ACTUAL, spec);
194
195 spec = g_param_spec_string("diff",
196 "Difference",
197 "The difference between expected object "
198 "and actual object",
199 NULL,
200 G_PARAM_READWRITE);
201 g_object_class_install_property(gobject_class, PROP_DIFF, spec);
202
203 spec = g_param_spec_string("folded-diff",
204 "Folded difference",
205 "The difference between folded expected object "
206 "and folded actual object",
207 NULL,
208 G_PARAM_READWRITE);
209 g_object_class_install_property(gobject_class, PROP_FOLDED_DIFF, spec);
210
211 g_type_class_add_private(gobject_class, sizeof(CutTestResultPrivate));
212 }
213
214 static void
cut_test_result_init(CutTestResult * result)215 cut_test_result_init (CutTestResult *result)
216 {
217 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
218
219 priv->status = CUT_TEST_RESULT_SUCCESS;
220 priv->test = NULL;
221 priv->test_iterator = NULL;
222 priv->test_case = NULL;
223 priv->test_suite = NULL;
224 priv->test_data = NULL;
225 priv->message = NULL;
226 priv->user_set_message = FALSE;
227 priv->user_message = NULL;
228 priv->system_message = NULL;
229 priv->backtrace = NULL;
230 priv->start_time.tv_sec = 0;
231 priv->start_time.tv_usec = 0;
232 priv->elapsed = 0.0;
233 priv->expected = NULL;
234 priv->actual = NULL;
235 priv->diff = NULL;
236 priv->folded_diff= NULL;
237 priv->user_set_diff = FALSE;
238 priv->user_set_folded_diff = FALSE;
239 }
240
241 static void
dispose(GObject * object)242 dispose (GObject *object)
243 {
244 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(object);
245
246 if (priv->test) {
247 g_object_unref(priv->test);
248 priv->test = NULL;
249 }
250
251 if (priv->test_iterator) {
252 g_object_unref(priv->test_iterator);
253 priv->test_iterator = NULL;
254 }
255
256 if (priv->test_case) {
257 g_object_unref(priv->test_case);
258 priv->test_case = NULL;
259 }
260
261 if (priv->test_suite) {
262 g_object_unref(priv->test_suite);
263 priv->test_suite = NULL;
264 }
265
266 if (priv->test_data) {
267 g_object_unref(priv->test_data);
268 priv->test_data = NULL;
269 }
270
271 if (priv->message) {
272 g_free(priv->message);
273 priv->message = NULL;
274 }
275
276 if (priv->user_message) {
277 g_free(priv->user_message);
278 priv->user_message = NULL;
279 }
280
281 if (priv->system_message) {
282 g_free(priv->system_message);
283 priv->system_message = NULL;
284 }
285
286 if (priv->backtrace) {
287 g_list_foreach(priv->backtrace, (GFunc)g_object_unref, NULL);
288 g_list_free(priv->backtrace);
289 priv->backtrace = NULL;
290 }
291
292 if (priv->expected) {
293 g_free(priv->expected);
294 priv->expected = NULL;
295 }
296
297 if (priv->actual) {
298 g_free(priv->actual);
299 priv->actual = NULL;
300 }
301
302 if (priv->diff) {
303 g_free(priv->diff);
304 priv->diff = NULL;
305 }
306
307 if (priv->folded_diff) {
308 g_free(priv->folded_diff);
309 priv->folded_diff = NULL;
310 }
311
312 G_OBJECT_CLASS(cut_test_result_parent_class)->dispose(object);
313 }
314
315 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)316 set_property (GObject *object,
317 guint prop_id,
318 const GValue *value,
319 GParamSpec *pspec)
320 {
321 CutTestResult *result;
322 CutTestResultPrivate *priv;
323
324 result = CUT_TEST_RESULT(object);
325 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
326
327 switch (prop_id) {
328 case PROP_STATUS:
329 priv->status = g_value_get_enum(value);
330 break;
331 case PROP_TEST:
332 cut_test_result_set_test(result, g_value_get_object(value));
333 break;
334 case PROP_TEST_ITERATOR:
335 cut_test_result_set_test_iterator(result,
336 g_value_get_object(value));
337 break;
338 case PROP_TEST_CASE:
339 cut_test_result_set_test_case(result, g_value_get_object(value));
340 break;
341 case PROP_TEST_SUITE:
342 cut_test_result_set_test_suite(result, g_value_get_object(value));
343 break;
344 case PROP_TEST_DATA:
345 cut_test_result_set_test_data(result, g_value_get_object(value));
346 break;
347 case PROP_USER_MESSAGE:
348 cut_test_result_set_user_message(result, g_value_get_string(value));
349 break;
350 case PROP_SYSTEM_MESSAGE:
351 cut_test_result_set_system_message(result, g_value_get_string(value));
352 break;
353 case PROP_BACKTRACE:
354 cut_test_result_set_backtrace(result, g_value_get_pointer(value));
355 break;
356 case PROP_ELAPSED:
357 priv->elapsed = g_value_get_double(value);
358 break;
359 case PROP_EXPECTED:
360 cut_test_result_set_expected(result, g_value_get_string(value));
361 break;
362 case PROP_ACTUAL:
363 cut_test_result_set_actual(result, g_value_get_string(value));
364 break;
365 case PROP_DIFF:
366 cut_test_result_set_diff(result, g_value_get_string(value));
367 break;
368 case PROP_FOLDED_DIFF:
369 cut_test_result_set_folded_diff(result, g_value_get_string(value));
370 break;
371 default:
372 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
373 break;
374 }
375 }
376
377 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)378 get_property (GObject *object,
379 guint prop_id,
380 GValue *value,
381 GParamSpec *pspec)
382 {
383 CutTestResult *result;
384 CutTestResultPrivate *priv;
385
386 result = CUT_TEST_RESULT(object);
387 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
388
389 switch (prop_id) {
390 case PROP_STATUS:
391 g_value_set_enum(value, priv->status);
392 break;
393 case PROP_TEST:
394 g_value_set_object(value, G_OBJECT(priv->test));
395 break;
396 case PROP_TEST_ITERATOR:
397 g_value_set_object(value, G_OBJECT(priv->test_iterator));
398 break;
399 case PROP_TEST_CASE:
400 g_value_set_object(value, G_OBJECT(priv->test_case));
401 break;
402 case PROP_TEST_SUITE:
403 g_value_set_object(value, G_OBJECT(priv->test_suite));
404 break;
405 case PROP_TEST_DATA:
406 g_value_set_object(value, G_OBJECT(priv->test_data));
407 break;
408 case PROP_USER_MESSAGE:
409 g_value_set_string(value, priv->user_message);
410 break;
411 case PROP_SYSTEM_MESSAGE:
412 g_value_set_string(value, priv->system_message);
413 break;
414 case PROP_BACKTRACE:
415 g_value_set_pointer(value, priv->backtrace);
416 break;
417 case PROP_ELAPSED:
418 g_value_set_double(value, priv->elapsed);
419 break;
420 case PROP_EXPECTED:
421 g_value_set_string(value, priv->expected);
422 break;
423 case PROP_ACTUAL:
424 g_value_set_string(value, priv->actual);
425 break;
426 case PROP_DIFF:
427 g_value_set_string(value, cut_test_result_get_diff(result));
428 break;
429 case PROP_FOLDED_DIFF:
430 g_value_set_string(value, cut_test_result_get_folded_diff(result));
431 break;
432 default:
433 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
434 break;
435 }
436 }
437
438 CutTestResult *
cut_test_result_new(CutTestResultStatus status,CutTest * test,CutTestIterator * test_iterator,CutTestCase * test_case,CutTestSuite * test_suite,CutTestData * test_data,const gchar * user_message,const gchar * system_message,const GList * backtrace)439 cut_test_result_new (CutTestResultStatus status,
440 CutTest *test,
441 CutTestIterator *test_iterator,
442 CutTestCase *test_case,
443 CutTestSuite *test_suite,
444 CutTestData *test_data,
445 const gchar *user_message,
446 const gchar *system_message,
447 const GList *backtrace)
448 {
449 return g_object_new(CUT_TYPE_TEST_RESULT,
450 "status", status,
451 "test", test,
452 "test-iterator", test_iterator,
453 "test-case", test_case,
454 "test-suite", test_suite,
455 "test-data", test_data,
456 "user-message", user_message,
457 "system-message", system_message,
458 "backtrace", backtrace,
459 NULL);
460 }
461
462 CutTestResult *
cut_test_result_new_empty(void)463 cut_test_result_new_empty (void)
464 {
465 return cut_test_result_new(CUT_TEST_RESULT_SUCCESS,
466 NULL, NULL, NULL, NULL, NULL,
467 NULL, NULL, NULL);
468 }
469
470 static void
collect_result(CutStreamParser * parser,CutTestResult * result,gpointer user_data)471 collect_result (CutStreamParser *parser, CutTestResult *result,
472 gpointer user_data)
473 {
474 CutTestResult **result_store = (CutTestResult **)user_data;
475
476 *result_store = result;
477 g_object_ref(*result_store);
478 }
479
480 CutTestResult *
cut_test_result_new_from_xml(const gchar * xml,gssize length,GError ** error)481 cut_test_result_new_from_xml (const gchar *xml, gssize length, GError **error)
482 {
483 CutStreamParser *parser;
484 CutTestResult *result = NULL;
485
486 if (!xml)
487 return NULL;
488
489 parser = cut_test_result_parser_new();
490 g_signal_connect(parser, "result",
491 G_CALLBACK(collect_result), (gpointer)(&result));
492
493 cut_stream_parser_parse(parser, xml, length, error);
494
495 g_signal_handlers_disconnect_by_func(parser,
496 collect_result,
497 (gpointer)&result);
498 g_object_unref(parser);
499
500 return result;
501 }
502
503 CutTestResultStatus
cut_test_result_get_status(CutTestResult * result)504 cut_test_result_get_status (CutTestResult *result)
505 {
506 return CUT_TEST_RESULT_GET_PRIVATE(result)->status;
507 }
508
509 static void
reset_message(CutTestResultPrivate * priv)510 reset_message (CutTestResultPrivate *priv)
511 {
512 if (priv->user_set_message)
513 return;
514
515 if (priv->message) {
516 g_free(priv->message);
517 priv->message = NULL;
518 }
519 }
520
521 const gchar *
cut_test_result_get_message(CutTestResult * result)522 cut_test_result_get_message (CutTestResult *result)
523 {
524 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
525
526 if (!priv->message) {
527 GString *message;
528 const gchar *diff, *folded_diff;
529
530 message = g_string_new(NULL);
531 if (priv->user_message)
532 g_string_append(message, priv->user_message);
533
534 if (priv->system_message) {
535 if (message->len > 0)
536 g_string_append(message, "\n");
537 g_string_append(message, priv->system_message);
538 }
539
540 if (priv->expected) {
541 if (message->len > 0)
542 g_string_append(message, "\n");
543 g_string_append_printf(message, "expected: <%s>", priv->expected);
544 }
545
546 if (priv->actual) {
547 if (message->len > 0)
548 g_string_append(message, "\n");
549 g_string_append_printf(message, " actual: <%s>", priv->actual);
550 }
551
552 diff = cut_test_result_get_diff(result);
553 if (diff) {
554 if (message->len > 0)
555 g_string_append(message, "\n\n");
556 g_string_append(message, "diff:\n");
557 g_string_append(message, diff);
558 }
559
560 folded_diff = cut_test_result_get_folded_diff(result);
561 if (folded_diff) {
562 if (message->len > 0)
563 g_string_append(message, "\n\n");
564 g_string_append(message, "folded diff:\n");
565 g_string_append(message, folded_diff);
566 }
567
568 if (message->len > 0) {
569 priv->message = g_string_free(message, FALSE);
570 } else {
571 g_string_free(message, TRUE);
572 }
573 }
574
575 return priv->message;
576 }
577
578 CutTest *
cut_test_result_get_test(CutTestResult * result)579 cut_test_result_get_test (CutTestResult *result)
580 {
581 return CUT_TEST_RESULT_GET_PRIVATE(result)->test;
582 }
583
584 CutTestIterator *
cut_test_result_get_test_iterator(CutTestResult * result)585 cut_test_result_get_test_iterator (CutTestResult *result)
586 {
587 return CUT_TEST_RESULT_GET_PRIVATE(result)->test_iterator;
588 }
589
590 CutTestCase *
cut_test_result_get_test_case(CutTestResult * result)591 cut_test_result_get_test_case (CutTestResult *result)
592 {
593 return CUT_TEST_RESULT_GET_PRIVATE(result)->test_case;
594 }
595
596 const gchar *
cut_test_result_get_test_name(CutTestResult * result)597 cut_test_result_get_test_name (CutTestResult *result)
598 {
599 CutTestResultPrivate *priv;
600
601 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
602
603 if (priv->test)
604 return cut_test_get_full_name(priv->test);
605
606 return NULL;
607 }
608
609 const gchar *
cut_test_result_get_test_iterator_name(CutTestResult * result)610 cut_test_result_get_test_iterator_name (CutTestResult *result)
611 {
612 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
613
614 if (priv->test_iterator)
615 return cut_test_get_name(CUT_TEST(priv->test_iterator));
616 return NULL;
617 }
618
619 const gchar *
cut_test_result_get_test_case_name(CutTestResult * result)620 cut_test_result_get_test_case_name (CutTestResult *result)
621 {
622 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
623
624 if (priv->test_case)
625 return cut_test_get_name(CUT_TEST(priv->test_case));
626 return NULL;
627 }
628
629 CutTestSuite *
cut_test_result_get_test_suite(CutTestResult * result)630 cut_test_result_get_test_suite (CutTestResult *result)
631 {
632 return CUT_TEST_RESULT_GET_PRIVATE(result)->test_suite;
633 }
634
635 const gchar *
cut_test_result_get_test_suite_name(CutTestResult * result)636 cut_test_result_get_test_suite_name (CutTestResult *result)
637 {
638 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
639
640 if (priv->test_suite)
641 return cut_test_get_name(CUT_TEST(priv->test_suite));
642 return NULL;
643 }
644
645 CutTestData *
cut_test_result_get_test_data(CutTestResult * result)646 cut_test_result_get_test_data (CutTestResult *result)
647 {
648 return CUT_TEST_RESULT_GET_PRIVATE(result)->test_data;
649 }
650
651 const gchar *
cut_test_result_get_user_message(CutTestResult * result)652 cut_test_result_get_user_message (CutTestResult *result)
653 {
654 return CUT_TEST_RESULT_GET_PRIVATE(result)->user_message;
655 }
656
657 const gchar *
cut_test_result_get_system_message(CutTestResult * result)658 cut_test_result_get_system_message (CutTestResult *result)
659 {
660 return CUT_TEST_RESULT_GET_PRIVATE(result)->system_message;
661 }
662
663 const GList *
cut_test_result_get_backtrace(CutTestResult * result)664 cut_test_result_get_backtrace (CutTestResult *result)
665 {
666 return CUT_TEST_RESULT_GET_PRIVATE(result)->backtrace;
667 }
668
669 void
cut_test_result_get_start_time(CutTestResult * result,GTimeVal * start_time)670 cut_test_result_get_start_time (CutTestResult *result, GTimeVal *start_time)
671 {
672 memcpy(start_time, &(CUT_TEST_RESULT_GET_PRIVATE(result)->start_time),
673 sizeof(GTimeVal));
674 }
675
676 gdouble
cut_test_result_get_elapsed(CutTestResult * result)677 cut_test_result_get_elapsed (CutTestResult *result)
678 {
679 return CUT_TEST_RESULT_GET_PRIVATE(result)->elapsed;
680 }
681
682 const gchar *
cut_test_result_get_expected(CutTestResult * result)683 cut_test_result_get_expected (CutTestResult *result)
684 {
685 return CUT_TEST_RESULT_GET_PRIVATE(result)->expected;
686 }
687
688 const gchar *
cut_test_result_get_actual(CutTestResult * result)689 cut_test_result_get_actual (CutTestResult *result)
690 {
691 return CUT_TEST_RESULT_GET_PRIVATE(result)->actual;
692 }
693
694 const gchar *
cut_test_result_get_diff(CutTestResult * result)695 cut_test_result_get_diff (CutTestResult *result)
696 {
697 CutTestResultPrivate *priv;
698
699 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
700
701 if (priv->diff)
702 return priv->diff;
703
704 if (priv->expected && priv->actual &&
705 strlen(priv->expected) < MAX_DIFF_TARGET_SIZE &&
706 strlen(priv->actual) < MAX_DIFF_TARGET_SIZE) {
707 priv->diff = cut_diff_readable(priv->expected, priv->actual);
708 if (!cut_diff_readable_is_interested(priv->diff)) {
709 g_free(priv->diff);
710 priv->diff = NULL;
711 }
712 }
713
714 return priv->diff;
715 }
716
717 const gchar *
cut_test_result_get_folded_diff(CutTestResult * result)718 cut_test_result_get_folded_diff (CutTestResult *result)
719 {
720 CutTestResultPrivate *priv;
721 const gchar *diff;
722
723 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
724
725 if (priv->folded_diff)
726 return priv->folded_diff;
727
728 diff = cut_test_result_get_diff(result);
729 if (cut_diff_readable_need_fold(diff)) {
730 priv->folded_diff =
731 cut_diff_readable_folded(priv->expected, priv->actual);
732 }
733
734 return priv->folded_diff;
735 }
736
737 gchar *
cut_test_result_to_xml(CutTestResult * result)738 cut_test_result_to_xml (CutTestResult *result)
739 {
740 GString *string;
741
742 string = g_string_new(NULL);
743 cut_test_result_to_xml_string(result, string, 0);
744 return g_string_free(string, FALSE);
745 }
746
747 static const gchar *
result_status_to_name(CutTestResultStatus status)748 result_status_to_name (CutTestResultStatus status)
749 {
750 switch (status) {
751 case CUT_TEST_RESULT_SUCCESS:
752 return "success";
753 break;
754 case CUT_TEST_RESULT_NOTIFICATION:
755 return "notification";
756 break;
757 case CUT_TEST_RESULT_OMISSION:
758 return "omission";
759 break;
760 case CUT_TEST_RESULT_PENDING:
761 return "pending";
762 break;
763 case CUT_TEST_RESULT_FAILURE:
764 return "failure";
765 break;
766 case CUT_TEST_RESULT_ERROR:
767 return "error";
768 break;
769 case CUT_TEST_RESULT_CRASH:
770 return "crash";
771 break;
772 default:
773 return "unknown status";
774 break;
775 }
776 }
777
778 static void
append_backtrace_to_string(GString * string,CutTestResult * result,guint indent)779 append_backtrace_to_string (GString *string, CutTestResult *result, guint indent)
780 {
781 CutTestResultPrivate *priv;
782 GList *node;
783
784 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
785 if (priv->backtrace == NULL)
786 return;
787
788 cut_utils_append_indent(string, indent);
789 g_string_append(string, "<backtrace>\n");
790 for (node = priv->backtrace; node; node = g_list_next(node)) {
791 CutBacktraceEntry *entry = node->data;
792
793 cut_backtrace_entry_to_xml_string(entry, string, indent + 2);
794 }
795 cut_utils_append_indent(string, indent);
796 g_string_append(string, "</backtrace>\n");
797 }
798
799 static void
append_test_result_to_string(GString * string,CutTestResult * result,guint indent)800 append_test_result_to_string (GString *string, CutTestResult *result,
801 guint indent)
802 {
803 CutTestResultStatus status;
804 GTimeVal start_time;
805 gchar *elapsed_string, *start_time_string;
806 const gchar *message, *expected, *actual, *diff, *folded_diff;
807
808 status = cut_test_result_get_status(result);
809 message = cut_test_result_get_message(result);
810 expected = cut_test_result_get_expected(result);
811 actual = cut_test_result_get_actual(result);
812 diff = cut_test_result_get_diff(result);
813 folded_diff = cut_test_result_get_folded_diff(result);
814
815 cut_utils_append_xml_element_with_value(string, indent, "status",
816 result_status_to_name(status));
817 if (message)
818 cut_utils_append_xml_element_with_value(string, indent,
819 "detail", message);
820 if (status != CUT_TEST_RESULT_SUCCESS)
821 append_backtrace_to_string(string, result, indent);
822
823 cut_test_result_get_start_time(result, &start_time);
824 start_time_string = g_time_val_to_iso8601(&start_time);
825 cut_utils_append_xml_element_with_value(string, indent, "start-time",
826 start_time_string);
827 g_free(start_time_string);
828
829 elapsed_string =
830 cut_utils_double_to_string(cut_test_result_get_elapsed(result));
831 cut_utils_append_xml_element_with_value(string, indent, "elapsed",
832 elapsed_string);
833 g_free(elapsed_string);
834
835 if (expected)
836 cut_utils_append_xml_element_with_value(string, indent,
837 "expected", expected);
838 if (actual)
839 cut_utils_append_xml_element_with_value(string, indent,
840 "actual", actual);
841 if (diff)
842 cut_utils_append_xml_element_with_value(string, indent,
843 "diff", diff);
844 if (folded_diff)
845 cut_utils_append_xml_element_with_value(string, indent,
846 "folded-diff", folded_diff);
847 }
848
849 void
cut_test_result_to_xml_string(CutTestResult * result,GString * string,guint indent)850 cut_test_result_to_xml_string (CutTestResult *result, GString *string,
851 guint indent)
852 {
853 CutTestCase *test_case;
854 CutTestIterator *test_iterator;
855 CutTest *test;
856 CutTestData *test_data;
857
858 cut_utils_append_indent(string, indent);
859 g_string_append(string, "<result>\n");
860
861 test_case = cut_test_result_get_test_case(result);
862 if (test_case)
863 cut_test_to_xml_string(CUT_TEST(test_case), string, indent + 2);
864 test_iterator = cut_test_result_get_test_iterator(result);
865 if (test_iterator)
866 cut_test_to_xml_string(CUT_TEST(test_iterator), string, indent + 2);
867 test = cut_test_result_get_test(result);
868 if (test)
869 cut_test_to_xml_string(test, string, indent + 2);
870 test_data = cut_test_result_get_test_data(result);
871 if (test_data)
872 cut_test_data_to_xml_string(test_data, string, indent + 2);
873 append_test_result_to_string(string, result, indent + 2);
874
875 cut_utils_append_indent(string, indent);
876 g_string_append(string, "</result>\n");
877 }
878
879 const gchar *
cut_test_result_status_to_signal_name(CutTestResultStatus status)880 cut_test_result_status_to_signal_name (CutTestResultStatus status)
881 {
882 const gchar *signal_name = NULL;
883
884 switch (status) {
885 case CUT_TEST_RESULT_SUCCESS:
886 signal_name = "success";
887 break;
888 case CUT_TEST_RESULT_NOTIFICATION:
889 signal_name = "notification";
890 break;
891 case CUT_TEST_RESULT_OMISSION:
892 signal_name = "omission";
893 break;
894 case CUT_TEST_RESULT_PENDING:
895 signal_name = "pending";
896 break;
897 case CUT_TEST_RESULT_FAILURE:
898 signal_name = "failure";
899 break;
900 case CUT_TEST_RESULT_ERROR:
901 signal_name = "error";
902 break;
903 case CUT_TEST_RESULT_CRASH:
904 signal_name = "crash";
905 break;
906 default:
907 signal_name = "invalid status";
908 break;
909 }
910
911 return signal_name;
912 }
913
914 gboolean
cut_test_result_status_is_critical(CutTestResultStatus status)915 cut_test_result_status_is_critical (CutTestResultStatus status)
916 {
917 return status > CUT_TEST_RESULT_OMISSION;
918 }
919
920 void
cut_test_result_set_status(CutTestResult * result,CutTestResultStatus status)921 cut_test_result_set_status (CutTestResult *result, CutTestResultStatus status)
922 {
923 CUT_TEST_RESULT_GET_PRIVATE(result)->status = status;
924 }
925
926 void
cut_test_result_set_test(CutTestResult * result,CutTest * test)927 cut_test_result_set_test (CutTestResult *result, CutTest *test)
928 {
929 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
930
931 if (priv->test) {
932 g_object_unref(priv->test);
933 priv->test = NULL;
934 }
935 if (test)
936 priv->test = g_object_ref(test);
937 }
938
939 void
cut_test_result_set_test_iterator(CutTestResult * result,CutTestIterator * test_iterator)940 cut_test_result_set_test_iterator (CutTestResult *result,
941 CutTestIterator *test_iterator)
942 {
943 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
944
945 if (priv->test_iterator) {
946 g_object_unref(priv->test_iterator);
947 priv->test_iterator = NULL;
948 }
949 if (test_iterator)
950 priv->test_iterator = g_object_ref(test_iterator);
951 }
952
953 void
cut_test_result_set_test_case(CutTestResult * result,CutTestCase * test_case)954 cut_test_result_set_test_case (CutTestResult *result, CutTestCase *test_case)
955 {
956 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
957
958 if (priv->test_case) {
959 g_object_unref(priv->test_case);
960 priv->test_case = NULL;
961 }
962 if (test_case)
963 priv->test_case = g_object_ref(test_case);
964 }
965
966 void
cut_test_result_set_test_suite(CutTestResult * result,CutTestSuite * test_suite)967 cut_test_result_set_test_suite (CutTestResult *result, CutTestSuite *test_suite)
968 {
969 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
970
971 if (priv->test_suite) {
972 g_object_unref(priv->test_suite);
973 priv->test_suite = NULL;
974 }
975 if (test_suite)
976 priv->test_suite = g_object_ref(test_suite);
977 }
978
979 void
cut_test_result_set_test_data(CutTestResult * result,CutTestData * test_data)980 cut_test_result_set_test_data (CutTestResult *result, CutTestData *test_data)
981 {
982 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
983
984 if (priv->test_data) {
985 g_object_unref(priv->test_data);
986 priv->test_data = NULL;
987 }
988 if (test_data)
989 priv->test_data = g_object_ref(test_data);
990 }
991
992 void
cut_test_result_set_user_message(CutTestResult * result,const gchar * user_message)993 cut_test_result_set_user_message (CutTestResult *result,
994 const gchar *user_message)
995 {
996 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
997
998 if (priv->user_message) {
999 g_free(priv->user_message);
1000 priv->user_message = NULL;
1001 }
1002 if (user_message && user_message[0])
1003 priv->user_message = g_strdup(user_message);
1004
1005 reset_message(priv);
1006 }
1007
1008 void
cut_test_result_set_message(CutTestResult * result,const gchar * message)1009 cut_test_result_set_message (CutTestResult *result,
1010 const gchar *message)
1011 {
1012 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
1013
1014 if (priv->message) {
1015 g_free(priv->message);
1016 priv->message = NULL;
1017 }
1018
1019 if (message) {
1020 priv->message = g_strdup(message);
1021 priv->user_set_message = TRUE;
1022 } else {
1023 priv->user_set_message = FALSE;
1024 }
1025 }
1026
1027 void
cut_test_result_set_system_message(CutTestResult * result,const gchar * system_message)1028 cut_test_result_set_system_message (CutTestResult *result,
1029 const gchar *system_message)
1030 {
1031 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
1032
1033 if (priv->system_message) {
1034 g_free(priv->system_message);
1035 priv->system_message = NULL;
1036 }
1037 if (system_message && system_message[0])
1038 priv->system_message = g_strdup(system_message);
1039
1040 reset_message(priv);
1041 }
1042
1043 void
cut_test_result_set_backtrace(CutTestResult * result,const GList * backtrace)1044 cut_test_result_set_backtrace (CutTestResult *result, const GList *backtrace)
1045 {
1046 CutTestResultPrivate *priv = CUT_TEST_RESULT_GET_PRIVATE(result);
1047
1048 if (priv->backtrace) {
1049 g_list_foreach(priv->backtrace, (GFunc)g_object_unref, NULL);
1050 g_list_free(priv->backtrace);
1051 priv->backtrace = NULL;
1052 }
1053 priv->backtrace = g_list_copy((GList *)backtrace);
1054 g_list_foreach(priv->backtrace, (GFunc)g_object_ref, NULL);
1055 }
1056
1057 void
cut_test_result_set_start_time(CutTestResult * result,GTimeVal * start_time)1058 cut_test_result_set_start_time (CutTestResult *result, GTimeVal *start_time)
1059 {
1060 memcpy(&(CUT_TEST_RESULT_GET_PRIVATE(result)->start_time), start_time,
1061 sizeof(GTimeVal));
1062 }
1063
1064 void
cut_test_result_set_elapsed(CutTestResult * result,gdouble elapsed)1065 cut_test_result_set_elapsed (CutTestResult *result,
1066 gdouble elapsed)
1067 {
1068 CUT_TEST_RESULT_GET_PRIVATE(result)->elapsed = elapsed;
1069 }
1070
1071 static void
reset_diff(CutTestResultPrivate * priv)1072 reset_diff (CutTestResultPrivate *priv)
1073 {
1074 gboolean need_message_regeneration = FALSE;
1075
1076 if (!priv->user_set_diff) {
1077 if (priv->diff)
1078 g_free(priv->diff);
1079 priv->diff = NULL;
1080 need_message_regeneration = TRUE;
1081 }
1082
1083 if (!priv->user_set_folded_diff) {
1084 if (priv->folded_diff)
1085 g_free(priv->folded_diff);
1086 priv->folded_diff = NULL;
1087 need_message_regeneration = TRUE;
1088 }
1089
1090 if (need_message_regeneration)
1091 reset_message(priv);
1092 }
1093
1094 void
cut_test_result_set_expected(CutTestResult * result,const gchar * expected)1095 cut_test_result_set_expected (CutTestResult *result, const gchar *expected)
1096 {
1097 CutTestResultPrivate *priv;
1098
1099 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
1100
1101 if (priv->expected) {
1102 g_free(priv->expected);
1103 priv->expected = NULL;
1104 }
1105
1106 if (expected)
1107 priv->expected = g_strdup(expected);
1108
1109 if (priv->expected)
1110 reset_diff(priv);
1111 }
1112
1113 void
cut_test_result_set_actual(CutTestResult * result,const gchar * actual)1114 cut_test_result_set_actual (CutTestResult *result, const gchar *actual)
1115 {
1116 CutTestResultPrivate *priv;
1117
1118 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
1119
1120 if (priv->actual) {
1121 g_free(priv->actual);
1122 priv->actual = NULL;
1123 }
1124
1125 if (actual)
1126 priv->actual = g_strdup(actual);
1127
1128 if (priv->actual)
1129 reset_diff(priv);
1130 }
1131
1132 void
cut_test_result_set_diff(CutTestResult * result,const gchar * diff)1133 cut_test_result_set_diff (CutTestResult *result, const gchar *diff)
1134 {
1135 CutTestResultPrivate *priv;
1136
1137 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
1138
1139 if (priv->diff) {
1140 g_free(priv->diff);
1141 priv->diff = NULL;
1142 }
1143
1144 if (diff && diff[0]) {
1145 priv->diff = g_strdup(diff);
1146 priv->user_set_diff = TRUE;
1147 } else {
1148 priv->user_set_diff = FALSE;
1149 }
1150 }
1151
1152 void
cut_test_result_set_folded_diff(CutTestResult * result,const gchar * folded_diff)1153 cut_test_result_set_folded_diff (CutTestResult *result, const gchar *folded_diff)
1154 {
1155 CutTestResultPrivate *priv;
1156
1157 priv = CUT_TEST_RESULT_GET_PRIVATE(result);
1158
1159 if (priv->folded_diff) {
1160 g_free(priv->folded_diff);
1161 priv->folded_diff = NULL;
1162 }
1163
1164 if (folded_diff && folded_diff[0]) {
1165 priv->folded_diff = g_strdup(folded_diff);
1166 priv->user_set_folded_diff = TRUE;
1167 } else {
1168 priv->user_set_folded_diff = FALSE;
1169 }
1170 }
1171
1172 /*
1173 vi:ts=4:nowrap:ai:expandtab:sw=4
1174 */
1175