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(&current_context_private);
524     if (contexts) {
525         g_ptr_array_free(contexts, TRUE);
526     }
527     g_private_set(&current_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(&current_context_private);
542     if (!contexts) {
543         contexts = g_ptr_array_new();
544         g_private_set(&current_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(&current_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(&current_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