1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
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 "cut-main.h"
25 #include "cut-sub-process.h"
26 #include "cut-pipeline.h"
27 #include "cut-test-context.h"
28
29 #define CUT_SUB_PROCESS_GET_PRIVATE(obj) \
30 (G_TYPE_INSTANCE_GET_PRIVATE((obj), CUT_TYPE_SUB_PROCESS, CutSubProcessPrivate))
31
32 typedef struct _CutSubProcessPrivate CutSubProcessPrivate;
33 struct _CutSubProcessPrivate
34 {
35 CutRunContext *pipeline;
36 CutTestContext *test_context;
37 gboolean running;
38 gboolean is_success;
39 gboolean is_ran;
40 };
41
42 enum {
43 PROP_0,
44 PROP_PIPELINE,
45 PROP_TEST_CONTEXT
46 };
47
48 G_DEFINE_TYPE(CutSubProcess, cut_sub_process, G_TYPE_OBJECT)
49
50 static void dispose (GObject *object);
51 static void set_property (GObject *object,
52 guint prop_id,
53 const GValue *value,
54 GParamSpec *pspec);
55 static void get_property (GObject *object,
56 guint prop_id,
57 GValue *value,
58 GParamSpec *pspec);
59
60 static void
cut_sub_process_class_init(CutSubProcessClass * klass)61 cut_sub_process_class_init (CutSubProcessClass *klass)
62 {
63 GObjectClass *gobject_class;
64 GParamSpec *spec;
65
66 gobject_class = G_OBJECT_CLASS(klass);
67
68 gobject_class->dispose = dispose;
69 gobject_class->set_property = set_property;
70 gobject_class->get_property = get_property;
71
72 spec = g_param_spec_object("pipeline",
73 "Pipeline",
74 "The pipeline",
75 CUT_TYPE_PIPELINE,
76 G_PARAM_READABLE | G_PARAM_WRITABLE);
77 g_object_class_install_property(gobject_class, PROP_PIPELINE, spec);
78
79 spec = g_param_spec_object("test-context",
80 "Test context",
81 "The test context",
82 CUT_TYPE_TEST_CONTEXT,
83 G_PARAM_READABLE | G_PARAM_WRITABLE);
84 g_object_class_install_property(gobject_class, PROP_TEST_CONTEXT, spec);
85
86 g_type_class_add_private(gobject_class, sizeof(CutSubProcessPrivate));
87 }
88
89 static void
cut_sub_process_init(CutSubProcess * sub_process)90 cut_sub_process_init (CutSubProcess *sub_process)
91 {
92 CutSubProcessPrivate *priv;
93
94 priv = CUT_SUB_PROCESS_GET_PRIVATE(sub_process);
95 priv->pipeline = NULL;
96 priv->test_context = NULL;
97 priv->running = FALSE;
98 priv->is_success = TRUE;
99 priv->is_ran = FALSE;
100 }
101
102 static void
dispose(GObject * object)103 dispose (GObject *object)
104 {
105 CutSubProcessPrivate *priv;
106
107 priv = CUT_SUB_PROCESS_GET_PRIVATE(object);
108
109 if (priv->running) {
110 if (priv->pipeline)
111 cut_run_context_emit_complete_run(priv->pipeline, FALSE);
112 priv->running = FALSE;
113 }
114
115 if (priv->pipeline) {
116 g_object_unref(priv->pipeline);
117 priv->pipeline = NULL;
118 }
119
120 if (priv->test_context) {
121 g_object_unref(priv->test_context);
122 priv->test_context = NULL;
123 }
124
125 G_OBJECT_CLASS(cut_sub_process_parent_class)->dispose(object);
126 }
127
128 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)129 set_property (GObject *object,
130 guint prop_id,
131 const GValue *value,
132 GParamSpec *pspec)
133 {
134 CutSubProcess *sub_process;
135
136 sub_process = CUT_SUB_PROCESS(object);
137 switch (prop_id) {
138 case PROP_PIPELINE:
139 cut_sub_process_set_pipeline(sub_process, g_value_get_object(value));
140 break;
141 case PROP_TEST_CONTEXT:
142 cut_sub_process_set_test_context(sub_process, g_value_get_object(value));
143 break;
144 default:
145 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
146 break;
147 }
148 }
149
150 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)151 get_property (GObject *object,
152 guint prop_id,
153 GValue *value,
154 GParamSpec *pspec)
155 {
156 CutSubProcessPrivate *priv = CUT_SUB_PROCESS_GET_PRIVATE(object);
157
158 switch (prop_id) {
159 case PROP_PIPELINE:
160 g_value_set_object(value, priv->pipeline);
161 break;
162 case PROP_TEST_CONTEXT:
163 g_value_set_object(value, priv->test_context);
164 break;
165 default:
166 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
167 break;
168 }
169 }
170
171 CutSubProcess *
cut_sub_process_new(const char * test_directory,CutTestContext * test_context)172 cut_sub_process_new (const char *test_directory, CutTestContext *test_context)
173 {
174 CutSubProcess *sub_process;
175 CutRunContext *parent_run_context = NULL;
176 CutRunContext *pipeline;
177
178 if (test_context)
179 parent_run_context = cut_test_context_get_run_context(test_context);
180
181 pipeline = cut_pipeline_new();
182 cut_run_context_set_source_directory(pipeline, test_directory);
183 cut_run_context_set_test_directory(pipeline, test_directory);
184
185 if (parent_run_context) {
186 gint max_threads;
187
188 if (cut_run_context_get_multi_thread(parent_run_context))
189 cut_run_context_set_multi_thread(pipeline, TRUE);
190
191 max_threads = cut_run_context_get_max_threads(parent_run_context);
192 cut_run_context_set_max_threads(pipeline, max_threads);
193
194 cut_run_context_delegate_signals(pipeline, parent_run_context);
195 }
196
197 sub_process = g_object_new(CUT_TYPE_SUB_PROCESS,
198 "test-context", test_context,
199 "pipeline", pipeline,
200 NULL);
201 g_object_unref(pipeline);
202
203 return sub_process;
204 }
205
206 CutRunContext *
cut_sub_process_get_pipeline(CutSubProcess * sub_process)207 cut_sub_process_get_pipeline (CutSubProcess *sub_process)
208 {
209 return CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
210 }
211
212 void
cut_sub_process_set_pipeline(CutSubProcess * sub_process,CutRunContext * pipeline)213 cut_sub_process_set_pipeline (CutSubProcess *sub_process,
214 CutRunContext *pipeline)
215 {
216 CutSubProcessPrivate *priv;
217
218 priv = CUT_SUB_PROCESS_GET_PRIVATE(sub_process);
219 if (priv->pipeline)
220 g_object_unref(priv->pipeline);
221 if (pipeline)
222 g_object_ref(pipeline);
223 priv->pipeline = pipeline;
224 }
225
226 CutTestContext *
cut_sub_process_get_test_context(CutSubProcess * sub_process)227 cut_sub_process_get_test_context (CutSubProcess *sub_process)
228 {
229 return CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->test_context;
230 }
231
232 void
cut_sub_process_set_test_context(CutSubProcess * sub_process,CutTestContext * test_context)233 cut_sub_process_set_test_context (CutSubProcess *sub_process,
234 CutTestContext *test_context)
235 {
236 CutSubProcessPrivate *priv;
237
238 priv = CUT_SUB_PROCESS_GET_PRIVATE(sub_process);
239 if (priv->test_context)
240 g_object_unref(priv->test_context);
241 if (test_context)
242 g_object_ref(test_context);
243 priv->test_context = test_context;
244 }
245
246 gboolean
cut_sub_process_run(CutSubProcess * sub_process)247 cut_sub_process_run (CutSubProcess *sub_process)
248 {
249 CutSubProcessPrivate *priv;
250
251 priv = CUT_SUB_PROCESS_GET_PRIVATE(sub_process);
252 if (!priv->is_ran) {
253 priv->running = TRUE;
254 priv->is_success = cut_run_context_start(priv->pipeline);
255 priv->running = FALSE;
256 priv->is_ran = TRUE;
257 }
258 return priv->is_success;
259 }
260
261 static void
cb_complete_run(CutRunContext * pipeline,gboolean success,gpointer user_data)262 cb_complete_run (CutRunContext *pipeline, gboolean success, gpointer user_data)
263 {
264 CutSubProcess *sub_process = user_data;
265 CutSubProcessPrivate *priv;
266
267 g_signal_handlers_disconnect_by_func(pipeline,
268 G_CALLBACK(cb_complete_run),
269 user_data);
270
271 priv = CUT_SUB_PROCESS_GET_PRIVATE(sub_process);
272 priv->is_success = success;
273 priv->running = FALSE;
274 priv->is_ran = TRUE;
275 }
276
277 void
cut_sub_process_run_async(CutSubProcess * sub_process)278 cut_sub_process_run_async (CutSubProcess *sub_process)
279 {
280 CutSubProcessPrivate *priv;
281
282 priv = CUT_SUB_PROCESS_GET_PRIVATE(sub_process);
283 if (!priv->is_ran && !priv->running) {
284 priv->running = TRUE;
285 priv->is_success = TRUE;
286 g_signal_connect(priv->pipeline, "complete-run",
287 G_CALLBACK(cb_complete_run), sub_process);
288 cut_run_context_start_async(priv->pipeline);
289 }
290 }
291
292 gboolean
cut_sub_process_wait(CutSubProcess * sub_process)293 cut_sub_process_wait (CutSubProcess *sub_process)
294 {
295 CutSubProcessPrivate *priv;
296
297 priv = CUT_SUB_PROCESS_GET_PRIVATE(sub_process);
298 if (!priv->is_ran) {
299 while (priv->running)
300 cut_run_iteration();
301 }
302 return priv->is_success;
303 }
304
305 gboolean
cut_sub_process_is_success(CutSubProcess * sub_process)306 cut_sub_process_is_success (CutSubProcess *sub_process)
307 {
308 return CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->is_success;
309 }
310
311 gboolean
cut_sub_process_is_running(CutSubProcess * sub_process)312 cut_sub_process_is_running (CutSubProcess *sub_process)
313 {
314 return CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->running;
315 }
316
317
318 const char *
cut_sub_process_get_test_directory(CutSubProcess * sub_process)319 cut_sub_process_get_test_directory (CutSubProcess *sub_process)
320 {
321 CutRunContext *pipeline;
322
323 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
324 return cut_run_context_get_test_directory(pipeline);
325 }
326
cut_sub_process_set_test_directory(CutSubProcess * sub_process,const char * test_directory)327 void cut_sub_process_set_test_directory (CutSubProcess *sub_process,
328 const char *test_directory)
329 {
330 CutRunContext *pipeline;
331
332 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
333 cut_run_context_set_test_directory(pipeline, test_directory);
334 }
335
336 const char *
cut_sub_process_get_source_directory(CutSubProcess * sub_process)337 cut_sub_process_get_source_directory (CutSubProcess *sub_process)
338 {
339 CutRunContext *pipeline;
340
341 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
342 return cut_run_context_get_source_directory(pipeline);
343 }
344
345 void
cut_sub_process_set_source_directory(CutSubProcess * sub_process,const char * source_directory)346 cut_sub_process_set_source_directory (CutSubProcess *sub_process,
347 const char *source_directory)
348 {
349 CutRunContext *pipeline;
350
351 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
352 cut_run_context_set_source_directory(pipeline, source_directory);
353 }
354
355 gboolean
cut_sub_process_get_multi_thread(CutSubProcess * sub_process)356 cut_sub_process_get_multi_thread (CutSubProcess *sub_process)
357 {
358 CutRunContext *pipeline;
359
360 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
361 return cut_run_context_get_multi_thread(pipeline);
362 }
363
364 void
cut_sub_process_set_multi_thread(CutSubProcess * sub_process,gboolean multi_thread)365 cut_sub_process_set_multi_thread (CutSubProcess *sub_process,
366 gboolean multi_thread)
367 {
368 CutRunContext *pipeline;
369
370 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
371 cut_run_context_set_multi_thread(pipeline, multi_thread);
372 }
373
374 gint
cut_sub_process_get_max_threads(CutSubProcess * sub_process)375 cut_sub_process_get_max_threads (CutSubProcess *sub_process)
376 {
377 CutRunContext *pipeline;
378
379 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
380 return cut_run_context_get_max_threads(pipeline);
381 }
382
383 void
cut_sub_process_set_max_threads(CutSubProcess * sub_process,gint max_threads)384 cut_sub_process_set_max_threads (CutSubProcess *sub_process,
385 gint max_threads)
386 {
387 CutRunContext *pipeline;
388
389 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
390 cut_run_context_set_max_threads(pipeline, max_threads);
391 }
392
393 const char **
cut_sub_process_get_exclude_files(CutSubProcess * sub_process)394 cut_sub_process_get_exclude_files (CutSubProcess *sub_process)
395 {
396 CutRunContext *pipeline;
397
398 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
399 return cut_run_context_get_exclude_files(pipeline);
400 }
401
402 void
cut_sub_process_set_exclude_files(CutSubProcess * sub_process,const char ** files)403 cut_sub_process_set_exclude_files (CutSubProcess *sub_process,
404 const char **files)
405 {
406 CutRunContext *pipeline;
407
408 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
409 cut_run_context_set_exclude_files(pipeline, files);
410 }
411
412
413 const char **
cut_sub_process_get_exclude_directories(CutSubProcess * sub_process)414 cut_sub_process_get_exclude_directories (CutSubProcess *sub_process)
415 {
416 CutRunContext *pipeline;
417
418 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
419 return cut_run_context_get_exclude_directories(pipeline);
420 }
421
422 void
cut_sub_process_set_exclude_directories(CutSubProcess * sub_process,const char ** directories)423 cut_sub_process_set_exclude_directories (CutSubProcess *sub_process,
424 const char **directories)
425 {
426 CutRunContext *pipeline;
427
428 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
429 cut_run_context_set_exclude_directories(pipeline, directories);
430 }
431
432
433 const char **
cut_sub_process_get_target_test_case_names(CutSubProcess * sub_process)434 cut_sub_process_get_target_test_case_names (CutSubProcess *sub_process)
435 {
436 CutRunContext *pipeline;
437
438 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
439 return cut_run_context_get_target_test_case_names(pipeline);
440 }
441
442 void
cut_sub_process_set_target_test_case_names(CutSubProcess * sub_process,const char ** names)443 cut_sub_process_set_target_test_case_names (CutSubProcess *sub_process,
444 const char **names)
445 {
446 CutRunContext *pipeline;
447
448 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
449 cut_run_context_set_target_test_case_names(pipeline, names);
450 }
451
452 const char **
cut_sub_process_get_target_test_names(CutSubProcess * sub_process)453 cut_sub_process_get_target_test_names (CutSubProcess *sub_process)
454 {
455 CutRunContext *pipeline;
456
457 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
458 return cut_run_context_get_target_test_names(pipeline);
459 }
460
461 void
cut_sub_process_set_target_test_names(CutSubProcess * sub_process,const char ** names)462 cut_sub_process_set_target_test_names (CutSubProcess *sub_process,
463 const char **names)
464 {
465 CutRunContext *pipeline;
466
467 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
468 cut_run_context_set_target_test_names(pipeline, names);
469 }
470
471 double
cut_sub_process_get_elapsed(CutSubProcess * sub_process)472 cut_sub_process_get_elapsed (CutSubProcess *sub_process)
473 {
474 CutRunContext *pipeline;
475
476 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
477 return cut_run_context_get_elapsed(pipeline);
478 }
479
480 double
cut_sub_process_get_total_elapsed(CutSubProcess * sub_process)481 cut_sub_process_get_total_elapsed (CutSubProcess *sub_process)
482 {
483 CutRunContext *pipeline;
484
485 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
486 return cut_run_context_get_total_elapsed(pipeline);
487 }
488
489 gboolean
cut_sub_process_is_crashed(CutSubProcess * sub_process)490 cut_sub_process_is_crashed (CutSubProcess *sub_process)
491 {
492 CutRunContext *pipeline;
493
494 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
495 return cut_run_context_is_crashed(pipeline);
496 }
497
498 gboolean
cut_sub_process_get_fatal_failures(CutSubProcess * sub_process)499 cut_sub_process_get_fatal_failures (CutSubProcess *sub_process)
500 {
501 CutRunContext *pipeline;
502
503 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
504 return cut_run_context_get_fatal_failures(pipeline);
505 }
506
507 void
cut_sub_process_set_fatal_failures(CutSubProcess * sub_process,gboolean fatal_failures)508 cut_sub_process_set_fatal_failures (CutSubProcess *sub_process,
509 gboolean fatal_failures)
510 {
511 CutRunContext *pipeline;
512
513 pipeline = CUT_SUB_PROCESS_GET_PRIVATE(sub_process)->pipeline;
514 cut_run_context_set_fatal_failures(pipeline, fatal_failures);
515 }
516
517
518 /*
519 vi:ts=4:nowrap:ai:expandtab:sw=4
520 */
521