1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2007-2014 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 <setjmp.h>
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_WAIT_H
29 # include <sys/wait.h>
30 #endif
31 #include <glib.h>
32 #include <glib/gi18n-lib.h>
33
34 #ifdef G_OS_WIN32
35 # ifdef __MINGW32__
36 # define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
37 # endif
38 # include <winsock2.h>
39 # include <process.h> /* For getpid() */
40 # include <io.h>
41 #else
42 # ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 # endif
45 #endif
46
47 #include "cut-run-context.h"
48 #include "cut-test-context.h"
49 #include "cut-test-suite.h"
50 #include "cut-test-iterator.h"
51 #include "cut-test-result.h"
52 #include "cut-test-data.h"
53 #include "cut-process.h"
54 #include "cut-backtrace-entry.h"
55 #include "cut-utils.h"
56 #include "cut-glib-compatible.h"
57
58 #define CUT_SIGNAL_EXPLICIT_JUMP G_MININT
59
60 #define cut_omit(context, message) do \
61 { \
62 cut_test_context_register_result(context, \
63 CUT_TEST_RESULT_OMISSION, \
64 message); \
65 cut_test_context_long_jump(context); \
66 } while (0)
67
68 #define CUT_TEST_CONTEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CUT_TYPE_TEST_CONTEXT, CutTestContextPrivate))
69
70 typedef struct _CutTestContextPrivate CutTestContextPrivate;
71 struct _CutTestContextPrivate
72 {
73 CutRunContext *run_context;
74 CutTestSuite *test_suite;
75 CutTestCase *test_case;
76 CutTestIterator *test_iterator;
77 CutTest *test;
78 gboolean failed;
79 gboolean omitted;
80 gboolean is_multi_thread;
81 jmp_buf *jump_buffer;
82 GList *taken_objects;
83 GList *taken_string_arrays;
84 GList *taken_g_objects;
85 GList *taken_errors;
86 GList *taken_lists;
87 GList *taken_hash_tables;
88 GList *current_data;
89 GList *data_list;
90 GList *processes;
91 gchar *fixture_data_dir;
92 GHashTable *cached_fixture_data;
93 GList *backtrace;
94 gchar *user_message;
95 guint user_message_keep_count;
96 GMutex *mutex;
97 gchar *expected;
98 gchar *actual;
99 CutTestResult *current_result;
100 guint user_message_jump_nest;
101 GThread *main_thread;
102 CutTestContext *parent;
103 };
104
105 enum
106 {
107 PROP_0,
108 PROP_RUN_CONTEXT,
109 PROP_TEST_SUITE,
110 PROP_TEST_CASE,
111 PROP_TEST_ITERATOR,
112 PROP_TEST,
113 PROP_PARENT
114 };
115
116 G_DEFINE_TYPE (CutTestContext, cut_test_context, G_TYPE_OBJECT)
117
118 typedef struct _TakenObject TakenObject;
119 struct _TakenObject
120 {
121 gpointer object;
122 CutDestroyFunction destroy_function;
123 };
124
125 static TakenObject *
taken_object_new(gpointer object,CutDestroyFunction destroy_function)126 taken_object_new (gpointer object, CutDestroyFunction destroy_function)
127 {
128 TakenObject *taken_object;
129
130 taken_object = g_slice_new(TakenObject);
131 taken_object->object = object;
132 taken_object->destroy_function = destroy_function;
133 return taken_object;
134 }
135
136 static void
taken_object_free(TakenObject * taken_object)137 taken_object_free (TakenObject *taken_object)
138 {
139 if (taken_object->object)
140 taken_object->destroy_function(taken_object->object);
141 g_slice_free(TakenObject, taken_object);
142 }
143
144 typedef struct _TakenList TakenList;
145 struct _TakenList
146 {
147 GList *list;
148 CutDestroyFunction destroy_function;
149 };
150
151 static TakenList *
taken_list_new(GList * list,CutDestroyFunction destroy_function)152 taken_list_new (GList *list, CutDestroyFunction destroy_function)
153 {
154 TakenList *taken_list;
155
156 taken_list = g_slice_new(TakenList);
157 taken_list->list = list;
158 taken_list->destroy_function = destroy_function;
159 return taken_list;
160 }
161
162 static void
taken_list_free(TakenList * taken_list)163 taken_list_free (TakenList *taken_list)
164 {
165 if (taken_list->destroy_function) {
166 GList *node;
167
168 for (node = taken_list->list; node; node = g_list_next(node)) {
169 if (node->data)
170 taken_list->destroy_function(node->data);
171 }
172 }
173 g_list_free(taken_list->list);
174
175 g_slice_free(TakenList, taken_list);
176 }
177
178 static GPrivate current_context_private = G_PRIVATE_INIT(NULL);
179
180 static void dispose (GObject *object);
181 static void set_property (GObject *object,
182 guint prop_id,
183 const GValue *value,
184 GParamSpec *pspec);
185 static void get_property (GObject *object,
186 guint prop_id,
187 GValue *value,
188 GParamSpec *pspec);
189
190
191 static void
cut_test_context_class_init(CutTestContextClass * klass)192 cut_test_context_class_init (CutTestContextClass *klass)
193 {
194 GObjectClass *gobject_class;
195 GParamSpec *spec;
196
197 gobject_class = G_OBJECT_CLASS(klass);
198
199 gobject_class->dispose = dispose;
200 gobject_class->set_property = set_property;
201 gobject_class->get_property = get_property;
202
203 spec = g_param_spec_object("run-context",
204 "Run context",
205 "The run context of the test context",
206 CUT_TYPE_RUN_CONTEXT,
207 G_PARAM_READWRITE);
208 g_object_class_install_property(gobject_class, PROP_RUN_CONTEXT, spec);
209
210 spec = g_param_spec_object("test-suite",
211 "Test suite",
212 "The test suite of the test context",
213 CUT_TYPE_TEST_SUITE,
214 G_PARAM_READWRITE);
215 g_object_class_install_property(gobject_class, PROP_TEST_SUITE, spec);
216
217 spec = g_param_spec_object("test-case",
218 "Test case",
219 "The test case of the test context",
220 CUT_TYPE_TEST_CASE,
221 G_PARAM_READWRITE);
222 g_object_class_install_property(gobject_class, PROP_TEST_CASE, spec);
223
224 spec = g_param_spec_object("test-iterator",
225 "Test iterator",
226 "The test iterator of the test context",
227 CUT_TYPE_TEST_ITERATOR,
228 G_PARAM_READWRITE);
229 g_object_class_install_property(gobject_class, PROP_TEST_ITERATOR, spec);
230
231 spec = g_param_spec_object("test",
232 "Test",
233 "The test of the test context",
234 CUT_TYPE_TEST,
235 G_PARAM_READWRITE);
236 g_object_class_install_property(gobject_class, PROP_TEST, spec);
237
238 spec = g_param_spec_object("parent",
239 "Parent",
240 "The parent test context of the test context",
241 CUT_TYPE_TEST_CONTEXT,
242 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
243 g_object_class_install_property(gobject_class, PROP_PARENT, spec);
244
245 g_type_class_add_private(gobject_class, sizeof(CutTestContextPrivate));
246 }
247
248 static void
fixture_data_free(gpointer data)249 fixture_data_free (gpointer data)
250 {
251 GString *string = data;
252 g_string_free(string, TRUE);
253 }
254
255 static void
cut_test_context_init(CutTestContext * context)256 cut_test_context_init (CutTestContext *context)
257 {
258 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
259
260 priv->run_context = NULL;
261 priv->test_suite = NULL;
262 priv->test_case = NULL;
263 priv->test_iterator = NULL;
264 priv->test = NULL;
265
266 priv->failed = FALSE;
267 priv->omitted = FALSE;
268 priv->is_multi_thread = FALSE;
269
270 priv->taken_objects = NULL;
271
272 priv->data_list = NULL;
273 priv->current_data = NULL;
274
275 priv->processes = NULL;
276
277 priv->fixture_data_dir = NULL;
278 priv->cached_fixture_data = g_hash_table_new_full(g_str_hash, g_str_equal,
279 g_free, fixture_data_free);
280
281 priv->backtrace = NULL;
282
283 priv->user_message = NULL;
284 priv->user_message_keep_count = 0;
285
286 priv->mutex = g_mutex_new();
287
288 priv->expected = NULL;
289 priv->actual = NULL;
290
291 priv->current_result = NULL;
292
293 priv->user_message_jump_nest = 0;
294
295 priv->main_thread = g_thread_self();
296
297 priv->parent = NULL;
298 }
299
300 static void
free_data_list(CutTestContextPrivate * priv)301 free_data_list (CutTestContextPrivate *priv)
302 {
303 if (priv->data_list) {
304 g_list_foreach(priv->data_list, (GFunc)g_object_unref, NULL);
305 g_list_free(priv->data_list);
306 priv->data_list = NULL;
307 }
308 priv->current_data = NULL;
309 }
310
311 static void
clear_user_message(CutTestContextPrivate * priv)312 clear_user_message (CutTestContextPrivate *priv)
313 {
314 if (priv->user_message_keep_count > 0)
315 priv->user_message_keep_count--;
316
317 if (priv->user_message_keep_count == 0) {
318 if (priv->user_message) {
319 g_free(priv->user_message);
320 priv->user_message = NULL;
321 }
322 }
323 }
324
325 static void
clear_additional_test_result_data(CutTestContextPrivate * priv)326 clear_additional_test_result_data (CutTestContextPrivate *priv)
327 {
328 if (priv->expected) {
329 g_free(priv->expected);
330 priv->expected = NULL;
331 }
332
333 if (priv->actual) {
334 g_free(priv->actual);
335 priv->actual = NULL;
336 }
337 }
338
339 static void
clear_current_result(CutTestContextPrivate * priv)340 clear_current_result (CutTestContextPrivate *priv)
341 {
342 if (priv->current_result) {
343 g_object_unref(priv->current_result);
344 priv->current_result = NULL;
345 }
346 }
347
348 static void
dispose(GObject * object)349 dispose (GObject *object)
350 {
351 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(object);
352
353 if (priv->run_context) {
354 g_object_unref(priv->run_context);
355 priv->run_context = NULL;
356 }
357
358 if (priv->test_suite) {
359 g_object_unref(priv->test_suite);
360 priv->test_suite = NULL;
361 }
362
363 if (priv->test_case) {
364 g_object_unref(priv->test_case);
365 priv->test_case = NULL;
366 }
367
368 if (priv->test_iterator) {
369 g_object_unref(priv->test_iterator);
370 priv->test_iterator = NULL;
371 }
372
373 if (priv->test) {
374 g_object_unref(priv->test);
375 priv->test = NULL;
376 }
377
378 if (priv->processes) {
379 g_list_foreach(priv->processes, (GFunc)g_object_unref, NULL);
380 g_list_free(priv->processes);
381 priv->processes = NULL;
382 }
383
384 if (priv->taken_objects) {
385 g_list_foreach(priv->taken_objects, (GFunc)taken_object_free, NULL);
386 g_list_free(priv->taken_objects);
387 priv->taken_objects = NULL;
388 }
389
390 free_data_list(priv);
391
392 if (priv->fixture_data_dir) {
393 g_free(priv->fixture_data_dir);
394 priv->fixture_data_dir = NULL;
395 }
396
397 if (priv->cached_fixture_data) {
398 g_hash_table_unref(priv->cached_fixture_data);
399 priv->cached_fixture_data = NULL;
400 }
401
402 if (priv->backtrace) {
403 g_list_foreach(priv->backtrace, (GFunc)g_object_unref, NULL);
404 g_list_free(priv->backtrace);
405 priv->backtrace = NULL;
406 }
407
408 clear_user_message(priv);
409
410 if (priv->mutex) {
411 g_mutex_free(priv->mutex);
412 priv->mutex = NULL;
413 }
414
415 clear_additional_test_result_data(priv);
416 clear_current_result(priv);
417
418 if (priv->parent) {
419 g_object_unref(priv->parent);
420 priv->parent = NULL;
421 }
422
423 G_OBJECT_CLASS(cut_test_context_parent_class)->dispose(object);
424 }
425
426 static void
set_parent(CutTestContext * context,CutTestContext * parent)427 set_parent (CutTestContext *context, CutTestContext *parent)
428 {
429 CutTestContextPrivate *priv;
430
431 if (!parent)
432 return;
433
434 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
435 priv->parent = g_object_ref(parent);
436 g_object_set(G_OBJECT(context),
437 "run-context", cut_test_context_get_run_context(parent),
438 "test-suite", cut_test_context_get_test_suite(parent),
439 "test-case", cut_test_context_get_test_case(parent),
440 "test-iterator", cut_test_context_get_test_iterator(parent),
441 "test", cut_test_context_get_test(parent),
442 NULL);
443 }
444
445 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)446 set_property (GObject *object,
447 guint prop_id,
448 const GValue *value,
449 GParamSpec *pspec)
450 {
451 CutTestContext *context = CUT_TEST_CONTEXT(object);
452
453 switch (prop_id) {
454 case PROP_RUN_CONTEXT:
455 cut_test_context_set_run_context(context, g_value_get_object(value));
456 break;
457 case PROP_TEST_SUITE:
458 cut_test_context_set_test_suite(context, g_value_get_object(value));
459 break;
460 case PROP_TEST_CASE:
461 cut_test_context_set_test_case(context, g_value_get_object(value));
462 break;
463 case PROP_TEST_ITERATOR:
464 cut_test_context_set_test_iterator(context, g_value_get_object(value));
465 break;
466 case PROP_TEST:
467 cut_test_context_set_test(context, g_value_get_object(value));
468 break;
469 case PROP_PARENT:
470 set_parent(context, g_value_get_object(value));
471 break;
472 default:
473 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
474 break;
475 }
476 }
477
478 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)479 get_property (GObject *object,
480 guint prop_id,
481 GValue *value,
482 GParamSpec *pspec)
483 {
484 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(object);
485
486 switch (prop_id) {
487 case PROP_RUN_CONTEXT:
488 g_value_set_object(value, priv->run_context);
489 break;
490 case PROP_TEST_SUITE:
491 g_value_set_object(value, priv->test_suite);
492 break;
493 case PROP_TEST_CASE:
494 g_value_set_object(value, priv->test_case);
495 break;
496 case PROP_TEST_ITERATOR:
497 g_value_set_object(value, priv->test_iterator);
498 break;
499 case PROP_TEST:
500 g_value_set_object(value, priv->test);
501 break;
502 default:
503 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
504 break;
505 }
506 }
507
508 GQuark
cut_test_context_error_quark(void)509 cut_test_context_error_quark (void)
510 {
511 return g_quark_from_static_string("cut-test-context-error-quark");
512 }
513
514 void
cut_test_context_current_init(void)515 cut_test_context_current_init (void)
516 {
517 }
518
519 void
cut_test_context_current_quit(void)520 cut_test_context_current_quit (void)
521 {
522 GPtrArray *contexts;
523 contexts = g_private_get(¤t_context_private);
524 if (contexts) {
525 g_ptr_array_free(contexts, TRUE);
526 }
527 g_private_set(¤t_context_private, NULL);
528 }
529
530 void
cut_test_context_current_push(CutTestContext * context)531 cut_test_context_current_push (CutTestContext *context)
532 {
533 GPtrArray *contexts;
534 CutTestContextPrivate *priv;
535
536 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
537 if (priv->main_thread != g_thread_self()) {
538 context = cut_test_context_new_sub(context);
539 }
540
541 contexts = g_private_get(¤t_context_private);
542 if (!contexts) {
543 contexts = g_ptr_array_new();
544 g_private_set(¤t_context_private, contexts);
545 }
546 g_ptr_array_add(contexts, context);
547 }
548
549 CutTestContext *
cut_test_context_current_pop(void)550 cut_test_context_current_pop (void)
551 {
552 GPtrArray *contexts;
553 CutTestContext *context = NULL;
554
555 contexts = g_private_get(¤t_context_private);
556 if (contexts) {
557 context = g_ptr_array_index(contexts, contexts->len - 1);
558 g_ptr_array_remove_index(contexts, contexts->len - 1);
559 }
560
561 return context;
562 }
563
564 CutTestContext *
cut_test_context_current_peek(void)565 cut_test_context_current_peek (void)
566 {
567 GPtrArray *contexts;
568
569 contexts = g_private_get(¤t_context_private);
570 if (contexts)
571 return g_ptr_array_index(contexts, contexts->len - 1);
572 else
573 return NULL;
574 }
575
576 CutTestContext *
cut_test_context_new(CutRunContext * run_context,CutTestSuite * test_suite,CutTestCase * test_case,CutTestIterator * test_iterator,CutTest * test)577 cut_test_context_new (CutRunContext *run_context,
578 CutTestSuite *test_suite, CutTestCase *test_case,
579 CutTestIterator *test_iterator, CutTest *test)
580 {
581 return g_object_new(CUT_TYPE_TEST_CONTEXT,
582 "run-context", run_context,
583 "test-suite", test_suite,
584 "test-case", test_case,
585 "test-iterator", test_iterator,
586 "test", test,
587 NULL);
588 }
589
590 CutTestContext *
cut_test_context_new_empty(void)591 cut_test_context_new_empty (void)
592 {
593 return cut_test_context_new(NULL, NULL, NULL, NULL, NULL);
594 }
595
596 CutTestContext *
cut_test_context_new_sub(CutTestContext * parent)597 cut_test_context_new_sub (CutTestContext *parent)
598 {
599 return g_object_new(CUT_TYPE_TEST_CONTEXT,
600 "parent", parent,
601 NULL);
602 }
603
604 CutRunContext *
cut_test_context_get_run_context(CutTestContext * context)605 cut_test_context_get_run_context (CutTestContext *context)
606 {
607 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->run_context;
608 }
609
610 void
cut_test_context_set_run_context(CutTestContext * context,CutRunContext * run_context)611 cut_test_context_set_run_context (CutTestContext *context, CutRunContext *run_context)
612 {
613 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
614
615 if (priv->run_context)
616 g_object_unref(priv->run_context);
617 if (run_context)
618 g_object_ref(run_context);
619
620 priv->run_context = run_context;
621 }
622
623 CutTestSuite *
cut_test_context_get_test_suite(CutTestContext * context)624 cut_test_context_get_test_suite (CutTestContext *context)
625 {
626 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->test_suite;
627 }
628
629 void
cut_test_context_set_test_suite(CutTestContext * context,CutTestSuite * test_suite)630 cut_test_context_set_test_suite (CutTestContext *context, CutTestSuite *test_suite)
631 {
632 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
633
634 if (priv->test_suite)
635 g_object_unref(priv->test_suite);
636 if (test_suite)
637 g_object_ref(test_suite);
638 priv->test_suite = test_suite;
639 }
640
641 CutTestCase *
cut_test_context_get_test_case(CutTestContext * context)642 cut_test_context_get_test_case (CutTestContext *context)
643 {
644 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->test_case;
645 }
646
647 void
cut_test_context_set_test_case(CutTestContext * context,CutTestCase * test_case)648 cut_test_context_set_test_case (CutTestContext *context, CutTestCase *test_case)
649 {
650 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
651
652 if (priv->test_case)
653 g_object_unref(priv->test_case);
654 if (test_case)
655 g_object_ref(test_case);
656 priv->test_case = test_case;
657 }
658
659 CutTestIterator *
cut_test_context_get_test_iterator(CutTestContext * context)660 cut_test_context_get_test_iterator (CutTestContext *context)
661 {
662 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->test_iterator;
663 }
664
665 void
cut_test_context_set_test_iterator(CutTestContext * context,CutTestIterator * test_iterator)666 cut_test_context_set_test_iterator (CutTestContext *context,
667 CutTestIterator *test_iterator)
668 {
669 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
670
671 if (priv->test_iterator)
672 g_object_unref(priv->test_iterator);
673 if (test_iterator)
674 g_object_ref(test_iterator);
675 priv->test_iterator = test_iterator;
676 }
677
678 CutTest *
cut_test_context_get_test(CutTestContext * context)679 cut_test_context_get_test (CutTestContext *context)
680 {
681 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->test;
682 }
683
684 void
cut_test_context_set_test(CutTestContext * context,CutTest * test)685 cut_test_context_set_test (CutTestContext *context, CutTest *test)
686 {
687 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
688
689 if (priv->test)
690 g_object_unref(priv->test);
691 if (test)
692 g_object_ref(test);
693 priv->test = test;
694 }
695
696 void
cut_test_context_add_data(CutTestContext * context,const gchar * first_data_name,...)697 cut_test_context_add_data (CutTestContext *context, const gchar *first_data_name,
698 ...)
699 {
700 CutTestContextPrivate *priv;
701 const gchar *name;
702 va_list args;
703
704 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
705
706 name = first_data_name;
707 va_start(args, first_data_name);
708 while (name) {
709 CutTestData *test_data;
710 gpointer data;
711 CutDestroyFunction destroy_function;
712
713 data = va_arg(args, gpointer);
714 destroy_function = va_arg(args, CutDestroyFunction);
715 test_data = cut_test_data_new(name, data, destroy_function);
716 priv->data_list = g_list_prepend(priv->data_list, test_data);
717 if (!priv->current_data)
718 priv->current_data = priv->data_list;
719
720 name = va_arg(args, gchar *);
721 }
722 va_end(args);
723 }
724
725 void
cut_test_context_set_attributes(CutTestContext * context,const gchar * first_attribute_name,...)726 cut_test_context_set_attributes (CutTestContext *context,
727 const gchar *first_attribute_name,
728 ...)
729 {
730 CutTestContextPrivate *priv;
731 CutTest *target = NULL;
732 const gchar *name;
733 va_list args;
734
735 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
736
737 if (priv->test) {
738 target = priv->test;
739 } else if (priv->test_iterator) {
740 target = CUT_TEST(priv->test_iterator);
741 } else if (priv->test_case) {
742 target = CUT_TEST(priv->test_case);
743 } else if (priv->test_suite) {
744 target = CUT_TEST(priv->test_suite);
745 }
746
747 if (!target) {
748 g_warning("can't find a target to set attributes.");
749 return;
750 }
751
752 name = first_attribute_name;
753 va_start(args, first_attribute_name);
754 while (name) {
755 const gchar *value;
756
757 value = va_arg(args, gchar *);
758 cut_test_set_attribute(target, name, value);
759
760 name = va_arg(args, gchar *);
761 }
762 va_end(args);
763 }
764
765 void
cut_test_context_set_data(CutTestContext * context,CutTestData * test_data)766 cut_test_context_set_data (CutTestContext *context, CutTestData *test_data)
767 {
768 CutTestContextPrivate *priv;
769
770 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
771
772 free_data_list(priv);
773
774 if (test_data) {
775 g_object_ref(test_data);
776 priv->data_list = g_list_prepend(priv->data_list, test_data);
777 priv->current_data = priv->data_list;
778 }
779 }
780
781 CutTestData *
cut_test_context_get_data(CutTestContext * context,guint index)782 cut_test_context_get_data (CutTestContext *context, guint index)
783 {
784 CutTestContextPrivate *priv;
785
786 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
787
788 return g_list_nth_data(priv->data_list, index);
789 }
790
791 void
cut_test_context_shift_data(CutTestContext * context)792 cut_test_context_shift_data (CutTestContext *context)
793 {
794 CutTestContextPrivate *priv;
795
796 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
797
798 if (priv->current_data)
799 priv->current_data = g_list_previous(priv->current_data);
800 }
801
802 gboolean
cut_test_context_have_data(CutTestContext * context)803 cut_test_context_have_data (CutTestContext *context)
804 {
805 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->current_data != NULL;
806 }
807
808 CutTestData *
cut_test_context_get_current_data(CutTestContext * context)809 cut_test_context_get_current_data (CutTestContext *context)
810 {
811 CutTestContextPrivate *priv;
812
813 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
814 g_return_val_if_fail(priv->current_data != NULL, NULL);
815
816 return priv->current_data->data;
817 }
818
819 guint
cut_test_context_get_n_data(CutTestContext * context)820 cut_test_context_get_n_data (CutTestContext *context)
821 {
822 return g_list_length(CUT_TEST_CONTEXT_GET_PRIVATE(context)->data_list);
823 }
824
825 void
cut_test_context_set_jump_buffer(CutTestContext * context,jmp_buf * buffer)826 cut_test_context_set_jump_buffer (CutTestContext *context, jmp_buf *buffer)
827 {
828 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
829
830 priv->jump_buffer = buffer;
831 }
832
833 jmp_buf *
cut_test_context_get_jump_buffer(CutTestContext * context)834 cut_test_context_get_jump_buffer (CutTestContext *context)
835 {
836 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->jump_buffer;
837 }
838
839 void
cut_test_context_long_jump(CutTestContext * context)840 cut_test_context_long_jump (CutTestContext *context)
841 {
842 gboolean same_thread_p = TRUE;
843 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
844
845 if (priv->parent) {
846 CutTestContextPrivate *parent_priv;
847 parent_priv = CUT_TEST_CONTEXT_GET_PRIVATE(priv->parent);
848 if (parent_priv->main_thread != g_thread_self()) {
849 same_thread_p = FALSE;
850 }
851 } else {
852 if (priv->main_thread != g_thread_self()) {
853 same_thread_p = FALSE;
854 }
855 }
856
857 if (cut_test_context_in_user_message_jump(context) || same_thread_p) {
858 if (priv->test) {
859 cut_test_long_jump(priv->test,
860 priv->jump_buffer,
861 CUT_SIGNAL_EXPLICIT_JUMP);
862 } else {
863 longjmp(*(priv->jump_buffer), CUT_SIGNAL_EXPLICIT_JUMP);
864 }
865 } else {
866 if (priv->parent && cut_test_context_is_failed(context)) {
867 cut_test_context_set_failed(priv->parent, TRUE);
868 }
869 cut_test_context_current_pop();
870 g_object_unref(context);
871 g_thread_exit(NULL);
872 }
873 }
874
875 void
cut_test_context_pass_assertion(CutTestContext * context)876 cut_test_context_pass_assertion (CutTestContext *context)
877 {
878 CutTestContextPrivate *priv;
879
880 g_return_if_fail(CUT_IS_TEST_CONTEXT(context));
881
882 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
883 g_return_if_fail(priv->test);
884
885 clear_user_message(priv);
886 g_signal_emit_by_name(priv->test, "pass-assertion", context);
887 }
888
889 static CutProcess *
get_process_from_pid(CutTestContext * context,int pid)890 get_process_from_pid (CutTestContext *context, int pid)
891 {
892 GList *node;
893 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
894
895 for (node = priv->processes; node; node = g_list_next(node)) {
896 CutProcess *process = CUT_PROCESS(node->data);
897 if (pid == cut_process_get_pid(process))
898 return process;
899 }
900
901 return NULL;
902 }
903
904 void
cut_test_context_emit_signal(CutTestContext * context,CutTestResult * result)905 cut_test_context_emit_signal (CutTestContext *context,
906 CutTestResult *result)
907 {
908 CutTestContextPrivate *priv;
909 CutTest *target = NULL;
910
911 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
912 if (priv->test) {
913 target = priv->test;
914 } else if (priv->test_iterator) {
915 target = CUT_TEST(priv->test_iterator);
916 } else if (priv->test_case) {
917 target = CUT_TEST(priv->test_case);
918 }
919
920 if (target)
921 cut_test_emit_result_signal(target, context, result);
922 }
923
924 void
cut_test_context_set_current_result(CutTestContext * context,CutTestResultStatus status,const char * system_message)925 cut_test_context_set_current_result (CutTestContext *context,
926 CutTestResultStatus status,
927 const char *system_message)
928 {
929 CutTestContextPrivate *priv;
930 CutTestData *test_data = NULL;
931
932 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
933 clear_current_result(priv);
934 if (cut_test_result_status_is_critical(status)) {
935 priv->failed = TRUE;
936 }
937 priv->omitted = (status == CUT_TEST_RESULT_OMISSION);
938
939 if (priv->current_data)
940 test_data = priv->current_data->data;
941 priv->current_result = cut_test_result_new(status,
942 priv->test,
943 priv->test_iterator,
944 priv->test_case,
945 priv->test_suite,
946 test_data,
947 priv->user_message,
948 system_message,
949 priv->backtrace);
950 clear_user_message(priv);
951
952 cut_test_result_set_expected(priv->current_result, priv->expected);
953 cut_test_result_set_actual(priv->current_result, priv->actual);
954 clear_additional_test_result_data(priv);
955 }
956
957 void
cut_test_context_set_current_result_user_message(CutTestContext * context,const char * user_message)958 cut_test_context_set_current_result_user_message (CutTestContext *context,
959 const char *user_message)
960 {
961 CutTestContextPrivate *priv;
962
963 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
964 if (!priv->current_result)
965 return;
966
967 cut_test_result_set_user_message(priv->current_result, user_message);
968 }
969
970 gboolean
cut_test_context_get_have_current_result(CutTestContext * context)971 cut_test_context_get_have_current_result (CutTestContext *context)
972 {
973 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->current_result != NULL;
974 }
975
976 void
cut_test_context_process_current_result(CutTestContext * context)977 cut_test_context_process_current_result (CutTestContext *context)
978 {
979 CutTestContextPrivate *priv;
980 CutTestResultStatus status;
981
982 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
983 if (!priv->current_result)
984 return;
985
986 status = cut_test_result_get_status(priv->current_result);
987
988 if (priv->test) {
989 CutProcess *process;
990 /* If the current procss is a child process, the pid is 0. */
991 process = get_process_from_pid(context, 0);
992 if (process) {
993 cut_process_send_test_result_to_parent(process,
994 priv->current_result);
995 clear_current_result(priv);
996 if (status == CUT_TEST_RESULT_NOTIFICATION)
997 return;
998 cut_process_exit(process);
999 }
1000 }
1001
1002 cut_test_context_emit_signal(context, priv->current_result);
1003
1004 if (status == CUT_TEST_RESULT_FAILURE &&
1005 priv->run_context &&
1006 cut_run_context_get_fatal_failures(priv->run_context)) {
1007 const gchar *message;
1008
1009 message = _("Treat a failure as a fatal problem, aborting.");
1010 cut_run_context_emit_error(priv->run_context,
1011 CUT_TEST_CONTEXT_ERROR,
1012 CUT_TEST_CONTEXT_ERROR_FATAL,
1013 NULL, "%s", message);
1014 cut_run_context_emit_complete_run(priv->run_context, FALSE);
1015 #ifdef G_OS_WIN32
1016 if (IsDebuggerPresent())
1017 G_BREAKPOINT();
1018 else
1019 abort();
1020 #else
1021 # ifdef SIGTRAP
1022 G_BREAKPOINT();
1023 # else
1024 abort();
1025 # endif
1026 #endif
1027 }
1028 clear_current_result(priv);
1029 }
1030
1031 void
cut_test_context_register_result(CutTestContext * context,CutTestResultStatus status,const char * system_message)1032 cut_test_context_register_result (CutTestContext *context,
1033 CutTestResultStatus status,
1034 const char *system_message)
1035 {
1036 cut_test_context_set_current_result(context, status, system_message);
1037 cut_test_context_process_current_result(context);
1038 }
1039
1040 void
cut_test_context_start_user_message_jump(CutTestContext * context)1041 cut_test_context_start_user_message_jump (CutTestContext *context)
1042 {
1043 CUT_TEST_CONTEXT_GET_PRIVATE(context)->user_message_jump_nest++;
1044 }
1045
1046 void
cut_test_context_finish_user_message_jump(CutTestContext * context)1047 cut_test_context_finish_user_message_jump (CutTestContext *context)
1048 {
1049 CUT_TEST_CONTEXT_GET_PRIVATE(context)->user_message_jump_nest--;
1050 }
1051
1052 gboolean
cut_test_context_in_user_message_jump(CutTestContext * context)1053 cut_test_context_in_user_message_jump (CutTestContext *context)
1054 {
1055 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->user_message_jump_nest > 0;
1056 }
1057
1058 void
cut_test_context_set_failed(CutTestContext * context,gboolean failed)1059 cut_test_context_set_failed (CutTestContext *context, gboolean failed)
1060 {
1061 CUT_TEST_CONTEXT_GET_PRIVATE(context)->failed = failed;
1062 }
1063
1064 gboolean
cut_test_context_is_failed(CutTestContext * context)1065 cut_test_context_is_failed (CutTestContext *context)
1066 {
1067 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->failed;
1068 }
1069
1070 gboolean
cut_test_context_need_test_run(CutTestContext * context)1071 cut_test_context_need_test_run (CutTestContext *context)
1072 {
1073 return !cut_test_context_is_failed(context) &&
1074 !CUT_TEST_CONTEXT_GET_PRIVATE(context)->omitted;
1075 }
1076
1077 const void *
cut_test_context_take(CutTestContext * context,void * object,CutDestroyFunction destroy_function)1078 cut_test_context_take (CutTestContext *context,
1079 void *object,
1080 CutDestroyFunction destroy_function)
1081 {
1082 CutTestContextPrivate *priv;
1083 TakenObject *taken_object;
1084
1085 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1086 taken_object = taken_object_new(object, destroy_function);
1087 priv->taken_objects = g_list_prepend(priv->taken_objects, taken_object);
1088
1089 return object;
1090 }
1091
1092 const void *
cut_test_context_take_memory(CutTestContext * context,void * memory)1093 cut_test_context_take_memory (CutTestContext *context,
1094 void *memory)
1095 {
1096 return cut_test_context_take(context, memory, g_free);
1097 }
1098
1099 const char *
cut_test_context_take_string(CutTestContext * context,char * string)1100 cut_test_context_take_string (CutTestContext *context,
1101 char *string)
1102 {
1103 return cut_test_context_take(context, string, g_free);
1104 }
1105
1106 const char *
cut_test_context_take_strdup(CutTestContext * context,const char * string)1107 cut_test_context_take_strdup (CutTestContext *context,
1108 const char *string)
1109 {
1110 return cut_test_context_take_string(context, g_strdup(string));
1111 }
1112
1113 const char *
cut_test_context_take_strndup(CutTestContext * context,const char * string,size_t size)1114 cut_test_context_take_strndup (CutTestContext *context,
1115 const char *string,
1116 size_t size)
1117 {
1118 return cut_test_context_take_string(context, g_strndup(string, size));
1119 }
1120
1121 const void *
cut_test_context_take_memdup(CutTestContext * context,const void * memory,size_t size)1122 cut_test_context_take_memdup (CutTestContext *context,
1123 const void *memory,
1124 size_t size)
1125 {
1126 return cut_test_context_take_memory(context, g_memdup(memory, size));
1127 }
1128
1129 const char *
cut_test_context_take_printf(CutTestContext * context,const char * format,...)1130 cut_test_context_take_printf (CutTestContext *context, const char *format, ...)
1131 {
1132 const char *taken_string = NULL;
1133 va_list args;
1134
1135 va_start(args, format);
1136 if (format) {
1137 char *formatted_string;
1138 formatted_string = g_strdup_vprintf(format, args);
1139 taken_string = cut_test_context_take_string(context, formatted_string);
1140 }
1141 va_end(args);
1142
1143 return taken_string;
1144 }
1145
1146 const char **
cut_test_context_take_string_array(CutTestContext * context,char ** strings)1147 cut_test_context_take_string_array (CutTestContext *context,
1148 char **strings)
1149 {
1150 return (const char **)cut_test_context_take(context,
1151 (gpointer)strings,
1152 (CutDestroyFunction)g_strfreev);
1153 }
1154
1155 GObject *
cut_test_context_take_g_object(CutTestContext * context,GObject * object)1156 cut_test_context_take_g_object (CutTestContext *context,
1157 GObject *object)
1158 {
1159 return (GObject *)cut_test_context_take(context, object, g_object_unref);
1160 }
1161
1162 const GError *
cut_test_context_take_g_error(CutTestContext * context,GError * error)1163 cut_test_context_take_g_error (CutTestContext *context, GError *error)
1164 {
1165 return cut_test_context_take(context, error,
1166 (CutDestroyFunction)g_error_free);
1167 }
1168
1169 const GList *
cut_test_context_take_g_list(CutTestContext * context,GList * list,CutDestroyFunction destroy_function)1170 cut_test_context_take_g_list (CutTestContext *context, GList *list,
1171 CutDestroyFunction destroy_function)
1172 {
1173 TakenList *taken_list;
1174
1175 taken_list = taken_list_new(list, destroy_function);
1176 cut_test_context_take(context, taken_list,
1177 (CutDestroyFunction)taken_list_free);
1178
1179 return list;
1180 }
1181
1182 GHashTable *
cut_test_context_take_g_hash_table(CutTestContext * context,GHashTable * hash_table)1183 cut_test_context_take_g_hash_table (CutTestContext *context,
1184 GHashTable *hash_table)
1185 {
1186 return (GHashTable *)cut_test_context_take(context,
1187 hash_table,
1188 (CutDestroyFunction)g_hash_table_unref);
1189 }
1190
1191 static void
cut_test_context_g_string_free(GString * string)1192 cut_test_context_g_string_free (GString *string)
1193 {
1194 g_string_free(string, TRUE);
1195 }
1196
1197 GString *
cut_test_context_take_g_string(CutTestContext * context,GString * string)1198 cut_test_context_take_g_string (CutTestContext *context,
1199 GString *string)
1200 {
1201 return (GString *)cut_test_context_take(context,
1202 string,
1203 (CutDestroyFunction) cut_test_context_g_string_free);
1204 }
1205
1206 int
cut_test_context_trap_fork(CutTestContext * context)1207 cut_test_context_trap_fork (CutTestContext *context)
1208 {
1209 #ifdef G_OS_WIN32
1210 cut_omit(context,
1211 "cut_test_context_wait_process() doesn't "
1212 "work on the environment.");
1213 return 0;
1214 #else
1215 CutTestContextPrivate *priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1216 CutProcess *process;
1217
1218 if (cut_test_context_is_multi_thread(context)) {
1219 cut_test_context_register_result(context,
1220 CUT_TEST_RESULT_OMISSION,
1221 "can't use cut_fork() "
1222 "in multi thread mode");
1223 cut_test_context_long_jump(context);
1224 }
1225
1226 process = cut_process_new();
1227 priv->processes = g_list_prepend(priv->processes, process);
1228
1229 return cut_process_fork(process);
1230 #endif
1231 }
1232
1233 int
cut_test_context_wait_process(CutTestContext * context,int pid,unsigned int timeout)1234 cut_test_context_wait_process (CutTestContext *context,
1235 int pid, unsigned int timeout)
1236 {
1237 int exit_status = EXIT_SUCCESS;
1238 #ifdef G_OS_WIN32
1239 cut_omit(context,
1240 "cut_test_context_wait_process() doesn't "
1241 "work on the environment.");
1242 #else
1243 CutProcess *process;
1244
1245 process = get_process_from_pid(context, pid);
1246 if (process) {
1247 int process_status;
1248 const gchar *xml;
1249
1250 process_status = cut_process_wait(process, timeout);
1251 exit_status = WEXITSTATUS(process_status);
1252 xml = cut_process_get_result_from_child(process);
1253 if (xml)
1254 xml = strstr(xml, "<result>");
1255 while (xml) {
1256 CutTestResult *result;
1257 gchar *next_result_xml;
1258 gint result_xml_length = -1;
1259
1260 next_result_xml = strstr(xml + 1, "<result>");
1261 if (next_result_xml)
1262 result_xml_length = next_result_xml - xml;
1263
1264 result = cut_test_result_new_from_xml(xml, result_xml_length, NULL);
1265 if (result) {
1266 cut_test_context_emit_signal(context, result);
1267 g_object_unref(result);
1268 }
1269
1270 if (result_xml_length == -1)
1271 xml = NULL;
1272 else
1273 xml += result_xml_length;
1274 }
1275 }
1276 #endif
1277 return exit_status;
1278 }
1279
1280 const char *
cut_test_context_get_forked_stdout_message(CutTestContext * context,int pid)1281 cut_test_context_get_forked_stdout_message (CutTestContext *context,
1282 int pid)
1283 {
1284 CutProcess *process;
1285
1286 process = get_process_from_pid(context, pid);
1287 if (process)
1288 return cut_process_get_stdout_message(process);
1289
1290 return NULL;
1291 }
1292
1293 const char *
cut_test_context_get_forked_stderr_message(CutTestContext * context,int pid)1294 cut_test_context_get_forked_stderr_message (CutTestContext *context,
1295 int pid)
1296 {
1297 CutProcess *process;
1298
1299 process = get_process_from_pid(context, pid);
1300 if (process)
1301 return cut_process_get_stderr_message(process);
1302
1303 return NULL;
1304 }
1305
1306 void
cut_test_context_set_multi_thread(CutTestContext * context,gboolean is_multi_thread)1307 cut_test_context_set_multi_thread (CutTestContext *context,
1308 gboolean is_multi_thread)
1309 {
1310 CUT_TEST_CONTEXT_GET_PRIVATE(context)->is_multi_thread = is_multi_thread;
1311 }
1312
1313 gboolean
cut_test_context_is_multi_thread(CutTestContext * context)1314 cut_test_context_is_multi_thread (CutTestContext *context)
1315 {
1316 return CUT_TEST_CONTEXT_GET_PRIVATE(context)->is_multi_thread;
1317 }
1318
1319 gchar *
cut_test_context_to_xml(CutTestContext * context)1320 cut_test_context_to_xml (CutTestContext *context)
1321 {
1322 GString *string;
1323
1324 string = g_string_new(NULL);
1325 cut_test_context_to_xml_string(context, string, 0);
1326 return g_string_free(string, FALSE);
1327 }
1328
1329 void
cut_test_context_to_xml_string(CutTestContext * context,GString * string,guint indent)1330 cut_test_context_to_xml_string (CutTestContext *context, GString *string,
1331 guint indent)
1332 {
1333 CutTestContextPrivate *priv;
1334
1335 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1336
1337 cut_utils_append_indent(string, indent);
1338 g_string_append(string, "<test-context>\n");
1339
1340 if (priv->test_suite)
1341 cut_test_to_xml_string(CUT_TEST(priv->test_suite), string, indent + 2);
1342 if (priv->test_case)
1343 cut_test_to_xml_string(CUT_TEST(priv->test_case), string, indent + 2);
1344 if (priv->test_iterator)
1345 cut_test_to_xml_string(CUT_TEST(priv->test_iterator),
1346 string, indent + 2);
1347 if (priv->test)
1348 cut_test_to_xml_string(priv->test, string, indent + 2);
1349 if (priv->current_data)
1350 cut_test_data_to_xml_string(priv->current_data->data,
1351 string, indent + 2);
1352
1353 cut_utils_append_xml_element_with_boolean_value(string, indent + 2,
1354 "failed", priv->failed);
1355
1356
1357 cut_utils_append_indent(string, indent);
1358 g_string_append(string, "</test-context>\n");
1359 }
1360
1361 void
cut_test_context_set_fixture_data_dir(CutTestContext * context,const gchar * path,...)1362 cut_test_context_set_fixture_data_dir (CutTestContext *context,
1363 const gchar *path, ...)
1364 {
1365 CutTestContextPrivate *priv;
1366 va_list args;
1367
1368 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1369 if (priv->fixture_data_dir)
1370 g_free(priv->fixture_data_dir);
1371
1372 va_start(args, path);
1373 priv->fixture_data_dir = cut_utils_expand_path_va_list(path, args);
1374 va_end(args);
1375 }
1376
1377 const gchar *
cut_test_context_build_fixture_path_va_list(CutTestContext * context,const gchar * path,va_list args)1378 cut_test_context_build_fixture_path_va_list (CutTestContext *context,
1379 const gchar *path,
1380 va_list args)
1381 {
1382 CutTestContextPrivate *priv;
1383 gchar *concatenated_path;
1384 const gchar *full_path;
1385
1386 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1387
1388 concatenated_path = cut_utils_build_path_va_list(path, args);
1389 if (g_path_is_absolute(concatenated_path)) {
1390 full_path = cut_test_context_take_string(context, concatenated_path);
1391 } else {
1392 gchar *resolved_path;
1393 if (priv->fixture_data_dir) {
1394 resolved_path = g_build_filename(priv->fixture_data_dir,
1395 concatenated_path,
1396 NULL);
1397 } else {
1398 resolved_path = cut_utils_expand_path(concatenated_path);
1399 }
1400 full_path = cut_test_context_take_string(context, resolved_path);
1401 }
1402 g_free(concatenated_path);
1403
1404 return full_path;
1405 }
1406
1407 const gchar *
cut_test_context_build_fixture_path(CutTestContext * context,const gchar * path,...)1408 cut_test_context_build_fixture_path (CutTestContext *context,
1409 const gchar *path, ...)
1410 {
1411 va_list args;
1412 const gchar *full_path;
1413
1414 va_start(args, path);
1415 full_path = cut_test_context_build_fixture_path_va_list(context, path, args);
1416 va_end(args);
1417
1418 return full_path;
1419 }
1420
1421 GString *
cut_test_context_get_fixture_data_va_list(CutTestContext * context,GError ** error,const gchar ** full_path,const gchar * path,va_list args)1422 cut_test_context_get_fixture_data_va_list (CutTestContext *context,
1423 GError **error,
1424 const gchar **full_path,
1425 const gchar *path,
1426 va_list args)
1427 {
1428 CutTestContextPrivate *priv;
1429 GString *data;
1430 const gchar *fixture_full_path;
1431
1432 if (!path)
1433 return NULL;
1434
1435 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1436
1437 fixture_full_path = cut_test_context_build_fixture_path_va_list(context,
1438 path, args);
1439 data = g_hash_table_lookup(priv->cached_fixture_data, fixture_full_path);
1440 if (!data) {
1441 gchar *contents;
1442 gsize length;
1443
1444 if (g_file_get_contents(fixture_full_path, &contents, &length, error)) {
1445 data = g_string_new_len(contents, length);
1446 g_free(contents);
1447 g_hash_table_insert(priv->cached_fixture_data,
1448 g_strdup(fixture_full_path),
1449 data);
1450 }
1451 }
1452
1453 if (full_path)
1454 *full_path = fixture_full_path;
1455
1456 return data;
1457 }
1458
1459 GString *
cut_test_context_get_fixture_data(CutTestContext * context,GError ** error,const gchar ** full_path,const gchar * path,...)1460 cut_test_context_get_fixture_data (CutTestContext *context,
1461 GError **error,
1462 const gchar **full_path,
1463 const gchar *path, ...)
1464 {
1465 GString *data;
1466 va_list args;
1467
1468 if (!path)
1469 return NULL;
1470
1471 va_start(args, path);
1472 data = cut_test_context_get_fixture_data_va_list(context, error,
1473 full_path, path, args);
1474 va_end(args);
1475
1476 return data;
1477 }
1478
1479 gchar *
cut_test_context_build_source_filename(CutTestContext * context,const gchar * filename)1480 cut_test_context_build_source_filename (CutTestContext *context,
1481 const gchar *filename)
1482 {
1483 CutTestContextPrivate *priv;
1484 const gchar *base_directory = NULL;
1485
1486 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1487 if (priv->test)
1488 base_directory = cut_test_get_base_directory(priv->test);
1489 if (!base_directory && priv->test_case)
1490 base_directory = cut_test_get_base_directory(CUT_TEST(priv->test_case));
1491 if (!base_directory && priv->test_suite)
1492 base_directory = cut_test_get_base_directory(CUT_TEST(priv->test_suite));
1493
1494 if (base_directory) {
1495 gchar *relative_filename, *full_filename;
1496
1497 relative_filename = g_build_filename(base_directory, filename, NULL);
1498 if (priv->run_context) {
1499 full_filename =
1500 cut_run_context_build_source_filename(priv->run_context,
1501 relative_filename);
1502 g_free(relative_filename);
1503 return full_filename;
1504 } else {
1505 return relative_filename;
1506 }
1507 }
1508
1509
1510 if (priv->run_context)
1511 return cut_run_context_build_source_filename(priv->run_context,
1512 filename);
1513 else
1514 return g_strdup(filename);
1515 }
1516
1517 static gchar *
convert_directory_separator_in_relative_path(const gchar * relative_path)1518 convert_directory_separator_in_relative_path (const gchar *relative_path)
1519 {
1520 gchar *convert, *dirname, *basename;
1521
1522 dirname = g_path_get_dirname(relative_path);
1523 basename = g_path_get_basename(relative_path);
1524
1525 convert = g_build_filename(dirname, basename, NULL);
1526 g_free(dirname);
1527 g_free(basename);
1528
1529 return convert;
1530 }
1531
1532 void
cut_test_context_push_backtrace(CutTestContext * context,const char * relative_path,const char * filename,unsigned int line,const char * function_name,const char * info)1533 cut_test_context_push_backtrace (CutTestContext *context,
1534 const char *relative_path,
1535 const char *filename,
1536 unsigned int line,
1537 const char *function_name,
1538 const char *info)
1539 {
1540 CutTestContextPrivate *priv;
1541 CutBacktraceEntry *entry;
1542 gchar *full_filename = NULL;
1543
1544 g_return_if_fail(context != NULL);
1545 g_return_if_fail(CUT_IS_TEST_CONTEXT(context));
1546
1547 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1548
1549 g_mutex_lock(priv->mutex);
1550 if (relative_path) {
1551 const gchar *source_directory = NULL;
1552 gchar *convert_relative_path;
1553
1554 convert_relative_path =
1555 convert_directory_separator_in_relative_path(relative_path);
1556
1557 if (priv->run_context)
1558 source_directory =
1559 cut_run_context_get_source_directory(priv->run_context);
1560 if (source_directory)
1561 full_filename = g_build_filename(source_directory,
1562 convert_relative_path,
1563 filename,
1564 NULL);
1565 else
1566 full_filename = g_build_filename(convert_relative_path,
1567 filename, NULL);
1568 g_free(convert_relative_path);
1569 } else {
1570 full_filename = cut_test_context_build_source_filename(context,
1571 filename);
1572 }
1573 entry = cut_backtrace_entry_new(full_filename, line, function_name, info);
1574 g_free(full_filename);
1575 priv->backtrace = g_list_prepend(priv->backtrace, entry);
1576 g_mutex_unlock(priv->mutex);
1577 }
1578
1579 void
cut_test_context_pop_backtrace(CutTestContext * context)1580 cut_test_context_pop_backtrace (CutTestContext *context)
1581 {
1582 CutTestContextPrivate *priv;
1583 CutBacktraceEntry *entry;
1584
1585 g_return_if_fail(context != NULL);
1586 g_return_if_fail(CUT_IS_TEST_CONTEXT(context));
1587
1588 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1589 g_return_if_fail(priv->backtrace != NULL);
1590
1591 g_mutex_lock(priv->mutex);
1592 entry = priv->backtrace->data;
1593 g_object_unref(entry);
1594 priv->backtrace = g_list_delete_link(priv->backtrace, priv->backtrace);
1595 g_mutex_unlock(priv->mutex);
1596 }
1597
1598 void
cut_test_context_get_last_backtrace(CutTestContext * context,const char ** filename,unsigned int * line,const char ** function_name,const char ** info)1599 cut_test_context_get_last_backtrace (CutTestContext *context,
1600 const char **filename,
1601 unsigned int *line,
1602 const char **function_name,
1603 const char **info)
1604 {
1605 CutTestContextPrivate *priv;
1606 CutBacktraceEntry *entry;
1607
1608 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1609 g_return_if_fail(priv->backtrace != NULL);
1610
1611 entry = priv->backtrace->data;
1612 if (filename)
1613 *filename = cut_backtrace_entry_get_file(entry);
1614 if (line)
1615 *line = cut_backtrace_entry_get_line(entry);
1616 if (function_name)
1617 *function_name = cut_backtrace_entry_get_function(entry);
1618 if (info)
1619 *info = cut_backtrace_entry_get_info(entry);
1620 }
1621
1622 void
cut_test_context_set_user_message(CutTestContext * context,const char * format,...)1623 cut_test_context_set_user_message (CutTestContext *context,
1624 const char *format,
1625 ...)
1626 {
1627 va_list args;
1628
1629 va_start(args, format);
1630 cut_test_context_set_user_message_va_list(context, format, args);
1631 va_end(args);
1632 }
1633
1634 void
cut_test_context_set_user_message_backward_compatibility(CutTestContext * context,const char * format,...)1635 cut_test_context_set_user_message_backward_compatibility (CutTestContext *context,
1636 const char *format,
1637 ...)
1638 {
1639 va_list args;
1640
1641 if (!format)
1642 return;
1643
1644 va_start(args, format);
1645 cut_test_context_set_user_message_va_list(context, format, args);
1646 va_end(args);
1647 }
1648
1649 void
cut_test_context_set_user_message_va_list(CutTestContext * context,const char * format,va_list args)1650 cut_test_context_set_user_message_va_list (CutTestContext *context,
1651 const char *format,
1652 va_list args)
1653 {
1654 CutTestContextPrivate *priv;
1655
1656 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1657
1658 clear_user_message(priv);
1659 if (!format)
1660 return;
1661
1662 priv->user_message = g_strdup_vprintf(format, args);
1663 }
1664
1665 void
cut_test_context_check_optional_assertion_message(CutTestContext * context)1666 cut_test_context_check_optional_assertion_message (CutTestContext *context)
1667 {
1668 CutTestContextPrivate *priv;
1669
1670 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1671
1672 clear_user_message(priv);
1673 priv->user_message = g_strdup("optional assertion message "
1674 "on the current environment "
1675 "is unavailable");
1676 }
1677
1678 void
cut_test_context_keep_user_message(CutTestContext * context)1679 cut_test_context_keep_user_message (CutTestContext *context)
1680 {
1681 CUT_TEST_CONTEXT_GET_PRIVATE(context)->user_message_keep_count++;
1682 }
1683
1684 void
cut_test_context_set_expected(CutTestContext * context,const gchar * expected)1685 cut_test_context_set_expected (CutTestContext *context, const gchar *expected)
1686 {
1687 CutTestContextPrivate *priv;
1688
1689 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1690 if (priv->expected)
1691 g_free(priv->expected);
1692 priv->expected = g_strdup(expected);
1693 }
1694
1695 void
cut_test_context_set_actual(CutTestContext * context,const gchar * actual)1696 cut_test_context_set_actual (CutTestContext *context, const gchar *actual)
1697 {
1698 CutTestContextPrivate *priv;
1699
1700 priv = CUT_TEST_CONTEXT_GET_PRIVATE(context);
1701 if (priv->actual)
1702 g_free(priv->actual);
1703 priv->actual = g_strdup(actual);
1704 }
1705
1706 /*
1707 vi:ts=4:nowrap:ai:expandtab:sw=4
1708 */
1709