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 <glib.h>
27
28 #include <signal.h>
29
30 #include "cut-test-case.h"
31 #include "cut-test.h"
32 #include "cut-run-context.h"
33 #include "cut-test-result.h"
34 #include "cut-crash-backtrace.h"
35
36 #include <gcutter/gcut-marshalers.h>
37
38 #define CUT_TEST_CASE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CUT_TYPE_TEST_CASE, CutTestCasePrivate))
39
40 typedef struct _CutTestCasePrivate CutTestCasePrivate;
41 struct _CutTestCasePrivate
42 {
43 CutSetupFunction setup;
44 CutTeardownFunction teardown;
45 CutStartupFunction startup;
46 CutShutdownFunction shutdown;
47 };
48
49 enum
50 {
51 PROP_0,
52 PROP_SETUP_FUNCTION,
53 PROP_TEARDOWN_FUNCTION,
54 PROP_STARTUP_FUNCTION,
55 PROP_SHUTDOWN_FUNCTION
56 };
57
58 enum
59 {
60 READY,
61 START_TEST,
62 COMPLETE_TEST,
63 START_TEST_ITERATOR,
64 COMPLETE_TEST_ITERATOR,
65
66 SUCCESS_IN,
67 FAILURE_IN,
68 ERROR_IN,
69 PENDING_IN,
70 NOTIFICATION_IN,
71 OMISSION_IN,
72 CRASH_IN,
73
74 LAST_SIGNAL
75 };
76
77 static gint cut_test_case_signals[LAST_SIGNAL] = {0};
78
79 G_DEFINE_TYPE (CutTestCase, cut_test_case, CUT_TYPE_TEST_CONTAINER)
80
81 static void dispose (GObject *object);
82 static void set_property (GObject *object,
83 guint prop_id,
84 const GValue *value,
85 GParamSpec *pspec);
86 static void get_property (GObject *object,
87 guint prop_id,
88 GValue *value,
89 GParamSpec *pspec);
90 static void emit_result_signal
91 (CutTest *test,
92 CutTestContext *test_context,
93 CutTestResult *result);
94
95 static void
cut_test_case_class_init(CutTestCaseClass * klass)96 cut_test_case_class_init (CutTestCaseClass *klass)
97 {
98 GObjectClass *gobject_class;
99 CutTestClass *test_class;
100 GParamSpec *spec;
101
102 gobject_class = G_OBJECT_CLASS(klass);
103 test_class = CUT_TEST_CLASS(klass);
104
105 gobject_class->dispose = dispose;
106 gobject_class->set_property = set_property;
107 gobject_class->get_property = get_property;
108
109 test_class->emit_result_signal = emit_result_signal;
110
111 spec = g_param_spec_pointer("setup-function",
112 "Setup Function",
113 "The function for setup",
114 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
115 g_object_class_install_property(gobject_class, PROP_SETUP_FUNCTION, spec);
116
117 spec = g_param_spec_pointer("teardown-function",
118 "Teardown Function",
119 "The function for teardown",
120 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
121 g_object_class_install_property(gobject_class, PROP_TEARDOWN_FUNCTION, spec);
122
123 spec = g_param_spec_pointer("startup-function",
124 "Startup Function",
125 "The function for initialization of TestCase",
126 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
127 g_object_class_install_property(gobject_class,
128 PROP_STARTUP_FUNCTION,
129 spec);
130
131 spec = g_param_spec_pointer("shutdown-function",
132 "Shutdown Function",
133 "The function for finalization of TestCase",
134 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
135 g_object_class_install_property(gobject_class,
136 PROP_SHUTDOWN_FUNCTION,
137 spec);
138
139
140 cut_test_case_signals[READY]
141 = g_signal_new("ready",
142 G_TYPE_FROM_CLASS(klass),
143 G_SIGNAL_RUN_LAST,
144 G_STRUCT_OFFSET(CutTestCaseClass, ready),
145 NULL, NULL,
146 g_cclosure_marshal_VOID__UINT,
147 G_TYPE_NONE, 1, G_TYPE_UINT);
148
149 cut_test_case_signals[START_TEST]
150 = g_signal_new("start-test",
151 G_TYPE_FROM_CLASS(klass),
152 G_SIGNAL_RUN_LAST,
153 G_STRUCT_OFFSET(CutTestCaseClass, start_test),
154 NULL, NULL,
155 _gcut_marshal_VOID__OBJECT_OBJECT,
156 G_TYPE_NONE, 2, CUT_TYPE_TEST, CUT_TYPE_TEST_CONTEXT);
157
158 cut_test_case_signals[COMPLETE_TEST]
159 = g_signal_new("complete-test",
160 G_TYPE_FROM_CLASS(klass),
161 G_SIGNAL_RUN_LAST,
162 G_STRUCT_OFFSET(CutTestCaseClass, complete_test),
163 NULL, NULL,
164 _gcut_marshal_VOID__OBJECT_OBJECT_BOOLEAN,
165 G_TYPE_NONE, 3,
166 CUT_TYPE_TEST, CUT_TYPE_TEST_CONTEXT, G_TYPE_BOOLEAN);
167
168 cut_test_case_signals[START_TEST_ITERATOR]
169 = g_signal_new("start-test-iterator",
170 G_TYPE_FROM_CLASS(klass),
171 G_SIGNAL_RUN_LAST,
172 G_STRUCT_OFFSET(CutTestCaseClass, start_test_iterator),
173 NULL, NULL,
174 _gcut_marshal_VOID__OBJECT_OBJECT,
175 G_TYPE_NONE,
176 2, CUT_TYPE_TEST_ITERATOR, CUT_TYPE_TEST_CONTEXT);
177
178 cut_test_case_signals[COMPLETE_TEST_ITERATOR]
179 = g_signal_new("complete-test-iterator",
180 G_TYPE_FROM_CLASS(klass),
181 G_SIGNAL_RUN_LAST,
182 G_STRUCT_OFFSET(CutTestCaseClass, complete_test_iterator),
183 NULL, NULL,
184 _gcut_marshal_VOID__OBJECT_OBJECT_BOOLEAN,
185 G_TYPE_NONE,
186 3, CUT_TYPE_TEST_ITERATOR, CUT_TYPE_TEST_CONTEXT,
187 G_TYPE_BOOLEAN);
188
189 cut_test_case_signals[FAILURE_IN]
190 = g_signal_new("failure-in",
191 G_TYPE_FROM_CLASS(klass),
192 G_SIGNAL_RUN_LAST,
193 G_STRUCT_OFFSET(CutTestCaseClass, failure_in),
194 NULL, NULL,
195 _gcut_marshal_VOID__OBJECT_OBJECT,
196 G_TYPE_NONE, 2,
197 CUT_TYPE_TEST_CONTEXT, CUT_TYPE_TEST_RESULT);
198
199 cut_test_case_signals[ERROR_IN]
200 = g_signal_new("error-in",
201 G_TYPE_FROM_CLASS(klass),
202 G_SIGNAL_RUN_LAST,
203 G_STRUCT_OFFSET(CutTestCaseClass, error_in),
204 NULL, NULL,
205 _gcut_marshal_VOID__OBJECT_OBJECT,
206 G_TYPE_NONE, 2,
207 CUT_TYPE_TEST_CONTEXT, CUT_TYPE_TEST_RESULT);
208
209 cut_test_case_signals[PENDING_IN]
210 = g_signal_new("pending-in",
211 G_TYPE_FROM_CLASS(klass),
212 G_SIGNAL_RUN_LAST,
213 G_STRUCT_OFFSET(CutTestCaseClass, pending_in),
214 NULL, NULL,
215 _gcut_marshal_VOID__OBJECT_OBJECT,
216 G_TYPE_NONE, 2,
217 CUT_TYPE_TEST_CONTEXT, CUT_TYPE_TEST_RESULT);
218
219 cut_test_case_signals[NOTIFICATION_IN]
220 = g_signal_new("notification-in",
221 G_TYPE_FROM_CLASS(klass),
222 G_SIGNAL_RUN_LAST,
223 G_STRUCT_OFFSET(CutTestCaseClass, notification_in),
224 NULL, NULL,
225 _gcut_marshal_VOID__OBJECT_OBJECT,
226 G_TYPE_NONE, 2,
227 CUT_TYPE_TEST_CONTEXT, CUT_TYPE_TEST_RESULT);
228
229 cut_test_case_signals[OMISSION_IN]
230 = g_signal_new("omission-in",
231 G_TYPE_FROM_CLASS(klass),
232 G_SIGNAL_RUN_LAST,
233 G_STRUCT_OFFSET(CutTestCaseClass, omission_in),
234 NULL, NULL,
235 _gcut_marshal_VOID__OBJECT_OBJECT,
236 G_TYPE_NONE, 2,
237 CUT_TYPE_TEST_CONTEXT, CUT_TYPE_TEST_RESULT);
238
239 cut_test_case_signals[CRASH_IN]
240 = g_signal_new("crash-in",
241 G_TYPE_FROM_CLASS(klass),
242 G_SIGNAL_RUN_LAST,
243 G_STRUCT_OFFSET(CutTestCaseClass, crash_in),
244 NULL, NULL,
245 _gcut_marshal_VOID__OBJECT_OBJECT,
246 G_TYPE_NONE, 2,
247 CUT_TYPE_TEST_CONTEXT, CUT_TYPE_TEST_RESULT);
248
249 g_type_class_add_private(gobject_class, sizeof(CutTestCasePrivate));
250 }
251
252 static void
cut_test_case_init(CutTestCase * test_case)253 cut_test_case_init (CutTestCase *test_case)
254 {
255 CutTestCasePrivate *priv = CUT_TEST_CASE_GET_PRIVATE(test_case);
256
257 priv->setup = NULL;
258 priv->teardown = NULL;
259 priv->startup = NULL;
260 priv->shutdown = NULL;
261 }
262
263 static void
dispose(GObject * object)264 dispose (GObject *object)
265 {
266 G_OBJECT_CLASS(cut_test_case_parent_class)->dispose(object);
267 }
268
269 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)270 set_property (GObject *object,
271 guint prop_id,
272 const GValue *value,
273 GParamSpec *pspec)
274 {
275 CutTestCasePrivate *priv = CUT_TEST_CASE_GET_PRIVATE(object);
276
277 switch (prop_id) {
278 case PROP_SETUP_FUNCTION:
279 priv->setup = g_value_get_pointer(value);
280 break;
281 case PROP_TEARDOWN_FUNCTION:
282 priv->teardown = g_value_get_pointer(value);
283 break;
284 case PROP_STARTUP_FUNCTION:
285 priv->startup = g_value_get_pointer(value);
286 break;
287 case PROP_SHUTDOWN_FUNCTION:
288 priv->shutdown = g_value_get_pointer(value);
289 break;
290 default:
291 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
292 break;
293 }
294 }
295
296 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)297 get_property (GObject *object,
298 guint prop_id,
299 GValue *value,
300 GParamSpec *pspec)
301 {
302 CutTestCasePrivate *priv = CUT_TEST_CASE_GET_PRIVATE(object);
303
304 switch (prop_id) {
305 case PROP_SETUP_FUNCTION:
306 g_value_set_pointer(value, priv->setup);
307 break;
308 case PROP_TEARDOWN_FUNCTION:
309 g_value_set_pointer(value, priv->teardown);
310 break;
311 case PROP_STARTUP_FUNCTION:
312 g_value_set_pointer(value, priv->startup);
313 break;
314 case PROP_SHUTDOWN_FUNCTION:
315 g_value_set_pointer(value, priv->shutdown);
316 break;
317 default:
318 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
319 break;
320 }
321 }
322
323 CutTestCase *
cut_test_case_new(const gchar * name,CutSetupFunction setup,CutTeardownFunction teardown,CutStartupFunction startup,CutShutdownFunction shutdown)324 cut_test_case_new (const gchar *name,
325 CutSetupFunction setup,
326 CutTeardownFunction teardown,
327 CutStartupFunction startup,
328 CutShutdownFunction shutdown)
329 {
330 return g_object_new(CUT_TYPE_TEST_CASE,
331 "name", name,
332 "element-name", "test-case",
333 "setup-function", setup,
334 "teardown-function", teardown,
335 "startup-function", startup,
336 "shutdown-function", shutdown,
337 NULL);
338 }
339
340 CutTestCase *
cut_test_case_new_empty(void)341 cut_test_case_new_empty (void)
342 {
343 return cut_test_case_new(NULL,
344 NULL, NULL,
345 NULL, NULL);
346 }
347
348 static GList *
get_filtered_tests(CutTestCase * test_case,const gchar ** test_names)349 get_filtered_tests (CutTestCase *test_case, const gchar **test_names)
350 {
351 CutTestContainer *container;
352
353 container = CUT_TEST_CONTAINER(test_case);
354 if (test_names && *test_names) {
355 return cut_test_container_filter_children(container, test_names);
356 } else {
357 return g_list_copy(cut_test_container_get_children(container));
358 }
359 }
360
361 void
cut_test_case_add_test(CutTestCase * test_case,CutTest * test)362 cut_test_case_add_test (CutTestCase *test_case, CutTest *test)
363 {
364 cut_test_container_add_test(CUT_TEST_CONTAINER(test_case), test);
365 }
366
367 void
cut_test_case_run_setup(CutTestCase * test_case,CutTestContext * test_context)368 cut_test_case_run_setup (CutTestCase *test_case, CutTestContext *test_context)
369 {
370 CutTestCasePrivate *priv;
371
372 priv = CUT_TEST_CASE_GET_PRIVATE(test_case);
373 if (priv->setup) {
374 jmp_buf jump_buffer;
375
376 cut_test_context_set_jump_buffer(test_context, &jump_buffer);
377 if (setjmp(jump_buffer) == 0) {
378 priv->setup();
379 }
380 }
381 }
382
383 void
cut_test_case_run_teardown(CutTestCase * test_case,CutTestContext * test_context)384 cut_test_case_run_teardown (CutTestCase *test_case, CutTestContext *test_context)
385 {
386 CutTestCasePrivate *priv;
387
388 priv = CUT_TEST_CASE_GET_PRIVATE(test_case);
389 if (priv->teardown) {
390 jmp_buf jump_buffer;
391
392 cut_test_context_set_jump_buffer(test_context, &jump_buffer);
393 if (setjmp(jump_buffer) == 0) {
394 priv->teardown();
395 }
396 }
397 }
398
399 static gboolean
run_test(CutTestCase * test_case,CutTest * test,CutTestContext * test_context,CutRunContext * run_context)400 run_test (CutTestCase *test_case, CutTest *test,
401 CutTestContext *test_context, CutRunContext *run_context)
402 {
403 gboolean success = TRUE;
404
405 if (CUT_IS_TEST_ITERATOR(test)) {
406 g_signal_emit_by_name(test_case, "start-test-iterator",
407 test, test_context);
408 } else {
409 g_signal_emit_by_name(test_case, "start-test", test, test_context);
410 cut_test_case_run_setup(test_case, test_context);
411 }
412
413 if (cut_test_context_is_failed(test_context)) {
414 success = FALSE;
415 } else if (cut_test_context_need_test_run(test_context)) {
416 success = cut_test_run(test, test_context, run_context);
417 }
418
419 if (CUT_IS_TEST_ITERATOR(test)) {
420 g_signal_emit_by_name(test_case, "complete-test-iterator",
421 test, test_context, success);
422 } else {
423 cut_test_case_run_teardown(test_case, test_context);
424 g_signal_emit_by_name(test_case, "complete-test",
425 test, test_context, success);
426 }
427
428 return success;
429 }
430
431 static gboolean
run(CutTestCase * test_case,CutTest * test,CutRunContext * run_context)432 run (CutTestCase *test_case, CutTest *test, CutRunContext *run_context)
433 {
434 CutTestContext *test_context;
435 gboolean success = TRUE;
436 gboolean is_multi_thread;
437 CutTestSuite *test_suite;
438
439 if (cut_run_context_is_canceled(run_context))
440 return TRUE;
441
442 test_suite = cut_run_context_get_test_suite(run_context);
443 is_multi_thread = cut_run_context_is_multi_thread(run_context);
444
445 test_context = cut_test_context_new(run_context,
446 test_suite, test_case, NULL, NULL);
447 cut_test_context_set_multi_thread(test_context, is_multi_thread);
448
449 cut_test_context_current_push(test_context);
450 cut_test_context_set_test(test_context, test);
451 success = run_test(test_case, test, test_context, run_context);
452 cut_test_context_set_test(test_context, NULL);
453
454 g_object_unref(test_context);
455 cut_test_context_current_pop();
456 /* FIXME: We want to use the code:
457 g_object_unref(cut_test_context_current_pop());
458 We need to hide cut_set_current_test_context() from user.
459 */
460
461 return success;
462 }
463
464 static void
cb_test_status(CutTest * test,CutTestContext * context,CutTestResult * result,gpointer data)465 cb_test_status (CutTest *test, CutTestContext *context, CutTestResult *result,
466 gpointer data)
467 {
468 CutTestResultStatus *status = data;
469
470 *status = MAX(*status, cut_test_result_get_status(result));
471 }
472
473 static void
cut_test_case_run_startup(CutTestCase * test_case,CutTestContext * test_context)474 cut_test_case_run_startup (CutTestCase *test_case, CutTestContext *test_context)
475 {
476 CutTestCasePrivate *priv;
477
478 priv = CUT_TEST_CASE_GET_PRIVATE(test_case);
479 if (priv->startup) {
480 jmp_buf jump_buffer;
481
482 cut_test_context_set_jump_buffer(test_context, &jump_buffer);
483 if (setjmp(jump_buffer) == 0) {
484 priv->startup();
485 }
486 }
487 }
488
489 static void
cut_test_case_run_shutdown(CutTestCase * test_case,CutTestContext * test_context)490 cut_test_case_run_shutdown (CutTestCase *test_case, CutTestContext *test_context)
491 {
492 CutTestCasePrivate *priv;
493
494 priv = CUT_TEST_CASE_GET_PRIVATE(test_case);
495 if (priv->shutdown) {
496 jmp_buf jump_buffer;
497
498 cut_test_context_set_jump_buffer(test_context, &jump_buffer);
499 if (setjmp(jump_buffer) == 0) {
500 priv->shutdown();
501 }
502 }
503 }
504
505 static void
emit_result_signal(CutTest * test,CutTestContext * test_context,CutTestResult * result)506 emit_result_signal (CutTest *test, CutTestContext *test_context,
507 CutTestResult *result)
508 {
509 const gchar *status_signal_name = NULL;
510 gchar *signal_name;
511 CutTestResultStatus status;
512
513 status = cut_test_result_get_status(result);
514 status_signal_name = cut_test_result_status_to_signal_name(status);
515 signal_name = g_strdup_printf("%s-in", status_signal_name);
516 g_signal_emit_by_name(test, signal_name, test_context, result);
517 g_free(signal_name);
518 }
519
520 static void
cut_test_case_emit_result_signal(CutTestCase * test_case,CutTestResult * result)521 cut_test_case_emit_result_signal (CutTestCase *test_case, CutTestResult *result)
522 {
523 const gchar *status_signal_name = NULL;
524 CutTestResultStatus status;
525
526 cut_test_set_result_elapsed(CUT_TEST(test_case), result);
527
528 status = cut_test_result_get_status(result);
529 status_signal_name = cut_test_result_status_to_signal_name(status);
530 g_signal_emit_by_name(test_case, status_signal_name, NULL, result);
531 }
532
533 static gboolean
run_tests(CutTestCase * test_case,CutRunContext * run_context,const GList * tests,CutTestResultStatus * status)534 run_tests (CutTestCase *test_case, CutRunContext *run_context,
535 const GList *tests, CutTestResultStatus *status)
536 {
537 const GList *list;
538 gboolean all_success = TRUE;
539
540 for (list = tests; list; list = g_list_next(list)) {
541 CutTest *test = list->data;
542
543 if (!test)
544 continue;
545
546 if (CUT_IS_TEST(test)) {
547 g_signal_connect(test, "success", G_CALLBACK(cb_test_status),
548 status);
549 g_signal_connect(test, "failure", G_CALLBACK(cb_test_status),
550 status);
551 g_signal_connect(test, "error", G_CALLBACK(cb_test_status),
552 status);
553 g_signal_connect(test, "pending", G_CALLBACK(cb_test_status),
554 status);
555 g_signal_connect(test, "notification", G_CALLBACK(cb_test_status),
556 status);
557 g_signal_connect(test, "omission", G_CALLBACK(cb_test_status),
558 status);
559 g_signal_connect(test, "crash", G_CALLBACK(cb_test_status),
560 status);
561 if (!run(test_case, test, run_context))
562 all_success = FALSE;
563 g_signal_handlers_disconnect_by_func(test,
564 G_CALLBACK(cb_test_status),
565 status);
566 } else {
567 g_warning("This object is not CutTest object");
568 }
569 }
570
571 return all_success;
572 }
573
574 static void
cb_test_case_status_in(CutTestCase * test_case,CutTestContext * test_context,CutTestResult * result,gpointer data)575 cb_test_case_status_in (CutTestCase *test_case, CutTestContext *test_context,
576 CutTestResult *result, gpointer data)
577 {
578 CutTestResultStatus *status = data;
579
580 *status = MAX(*status, cut_test_result_get_status(result));
581 }
582
583 static gboolean
cut_test_case_run_tests(CutTestCase * test_case,CutRunContext * run_context,const GList * tests)584 cut_test_case_run_tests (CutTestCase *test_case, CutRunContext *run_context,
585 const GList *tests)
586 {
587 CutTestContext *test_context;
588 gboolean all_success = TRUE;
589 CutTestResult *result;
590 CutTestResultStatus status = CUT_TEST_RESULT_SUCCESS;
591 gint signum;
592 jmp_buf jump_buffer;
593 CutTestSuite *test_suite;
594 CutCrashBacktrace *crash_backtrace = NULL;
595
596 g_signal_emit_by_name(test_case, "ready", g_list_length((GList *)tests));
597 g_signal_emit_by_name(CUT_TEST(test_case), "start", NULL);
598
599 test_suite = cut_run_context_get_test_suite(run_context);
600 test_context = cut_test_context_new(run_context,
601 test_suite, test_case, NULL, NULL);
602 cut_test_context_current_push(test_context);
603
604 #define CONNECT(event) \
605 g_signal_connect(test_case, #event "-in", \
606 G_CALLBACK(cb_test_case_status_in), \
607 &status)
608
609 CONNECT(failure);
610 CONNECT(error);
611 CONNECT(pending);
612 CONNECT(notification);
613 CONNECT(omission);
614 CONNECT(crash);
615
616 #undef CONNECT
617
618 if (cut_run_context_is_multi_thread(run_context) ||
619 !cut_run_context_get_handle_signals(run_context)) {
620 signum = 0;
621 } else {
622 crash_backtrace = cut_crash_backtrace_new(&jump_buffer);
623 signum = setjmp(jump_buffer);
624 }
625 switch (signum) {
626 case 0:
627 cut_test_case_run_startup(test_case, test_context);
628 if (cut_test_context_is_failed(test_context)) {
629 all_success = FALSE;
630 } else {
631 if (status != CUT_TEST_RESULT_OMISSION)
632 all_success = run_tests(test_case, run_context, tests, &status);
633 }
634
635 if (crash_backtrace)
636 cut_crash_backtrace_free(crash_backtrace);
637
638 break;
639 #ifndef G_OS_WIN32
640 case SIGSEGV:
641 case SIGABRT:
642 case SIGTERM:
643 case SIGBUS:
644 all_success = FALSE;
645 cut_crash_backtrace_emit(test_suite, test_case, NULL, NULL, NULL,
646 test_context);
647 break;
648 case SIGINT:
649 cut_run_context_cancel(run_context);
650 break;
651 #endif
652 default:
653 break;
654 }
655
656 cut_test_case_run_shutdown(test_case, test_context);
657
658 g_signal_handlers_disconnect_by_func(test_case,
659 G_CALLBACK(cb_test_case_status_in),
660 &status);
661 result = cut_test_result_new(status,
662 NULL, NULL, test_case, NULL, NULL,
663 NULL, NULL, NULL);
664 cut_test_case_emit_result_signal(test_case, result);
665 g_object_unref(result);
666
667 g_signal_emit_by_name(CUT_TEST(test_case), "complete", NULL, all_success);
668
669 g_object_unref(test_context);
670 cut_test_context_current_pop();
671 /* FIXME: We want to use the code:
672 g_object_unref(cut_test_context_current_pop());
673 We need to hide cut_set_current_test_context() from user.
674 */
675
676 return all_success;
677 }
678
679 gboolean
cut_test_case_run_test(CutTestCase * test_case,CutRunContext * run_context,const gchar * name)680 cut_test_case_run_test (CutTestCase *test_case, CutRunContext *run_context, const gchar *name)
681 {
682 const gchar *test_names[] = {NULL, NULL};
683
684 g_return_val_if_fail(CUT_IS_TEST_CASE(test_case), FALSE);
685
686 test_names[0] = name;
687 return cut_test_case_run_with_filter(test_case, run_context, test_names);
688 }
689
690 gboolean
cut_test_case_run_with_filter(CutTestCase * test_case,CutRunContext * run_context,const gchar ** test_names)691 cut_test_case_run_with_filter (CutTestCase *test_case,
692 CutRunContext *run_context,
693 const gchar **test_names)
694 {
695 GList *filtered_tests;
696 gboolean success = TRUE;
697
698 filtered_tests = get_filtered_tests(test_case, test_names);
699 if (!filtered_tests)
700 return TRUE;
701
702 success = cut_test_case_run_tests(test_case, run_context, filtered_tests);
703
704 g_list_free(filtered_tests);
705
706 return success;
707 }
708
709 gboolean
cut_test_case_run(CutTestCase * test_case,CutRunContext * run_context)710 cut_test_case_run (CutTestCase *test_case, CutRunContext *run_context)
711 {
712 const gchar **test_names;
713
714 test_names = cut_run_context_get_target_test_names(run_context);
715 return cut_test_case_run_with_filter(test_case, run_context, test_names);
716 }
717
718 /*
719 vi:nowrap:ai:expandtab:sw=4
720 */
721