1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  *  Copyright (C) 2008-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 "cut-stream-parser.h"
29 #include "cut-backtrace-entry.h"
30 
31 typedef enum {
32     IN_TOP_LEVEL,
33     IN_TOP_LEVEL_RESULT,
34 
35     IN_STREAM,
36     IN_STREAM_SUCCESS,
37 
38     IN_TEST_SUITE,
39     IN_TEST_CASE,
40     IN_TEST_ITERATOR,
41     IN_TEST,
42     IN_ITERATED_TEST,
43     IN_TEST_DATA,
44 
45     IN_TEST_NAME,
46     IN_TEST_DESCRIPTION,
47     IN_TEST_OPTION,
48     IN_TEST_START_TIME,
49     IN_TEST_ELAPSED,
50 
51     IN_TEST_DATA_NAME,
52 
53     IN_TEST_OPTION_NAME,
54     IN_TEST_OPTION_VALUE,
55 
56     IN_TEST_CONTEXT,
57     IN_TEST_CONTEXT_FAILED,
58 
59     IN_READY_TEST_SUITE,
60     IN_READY_TEST_SUITE_N_TEST_CASES,
61     IN_READY_TEST_SUITE_N_TESTS,
62 
63     IN_START_TEST_SUITE,
64 
65     IN_READY_TEST_CASE,
66     IN_READY_TEST_CASE_N_TESTS,
67 
68     IN_READY_TEST_ITERATOR,
69     IN_READY_TEST_ITERATOR_N_TESTS,
70 
71     IN_START_TEST_CASE,
72 
73     IN_START_TEST_ITERATOR,
74 
75     IN_START_TEST,
76 
77     IN_START_ITERATED_TEST,
78 
79     IN_PASS_ASSERTION,
80 
81     IN_TEST_RESULT,
82 
83     IN_RESULT,
84     IN_RESULT_STATUS,
85     IN_RESULT_DETAIL,
86     IN_RESULT_BACKTRACE,
87     IN_RESULT_BACKTRACE_ENTRY,
88     IN_RESULT_BACKTRACE_ENTRY_FILE,
89     IN_RESULT_BACKTRACE_ENTRY_LINE,
90     IN_RESULT_BACKTRACE_ENTRY_INFO,
91     IN_RESULT_START_TIME,
92     IN_RESULT_ELAPSED,
93     IN_RESULT_EXPECTED,
94     IN_RESULT_ACTUAL,
95     IN_RESULT_DIFF,
96     IN_RESULT_FOLDED_DIFF,
97 
98     IN_COMPLETE_ITERATED_TEST,
99 
100     IN_COMPLETE_TEST,
101 
102     IN_TEST_ITERATOR_RESULT,
103 
104     IN_TEST_CASE_RESULT,
105 
106     IN_COMPLETE_TEST_ITERATOR,
107 
108     IN_COMPLETE_TEST_CASE,
109 
110     IN_COMPLETE_TEST_SUITE,
111 
112     IN_COMPLETE_SUCCESS
113 } ParseState;
114 
115 #define CUT_STREAM_PARSER_GET_PRIVATE(obj)                              \
116     (G_TYPE_INSTANCE_GET_PRIVATE((obj), CUT_TYPE_STREAM_PARSER,         \
117                                  CutStreamParserPrivate))
118 
119 typedef struct _ReadyTestSuite ReadyTestSuite;
120 struct _ReadyTestSuite
121 {
122     CutTestSuite *test_suite;
123     gint n_test_cases;
124     gint n_tests;
125 };
126 
127 typedef struct _ReadyTestCase ReadyTestCase;
128 struct _ReadyTestCase
129 {
130     CutTestCase *test_case;
131     gint n_tests;
132 };
133 
134 typedef struct _ReadyTestIterator ReadyTestIterator;
135 struct _ReadyTestIterator
136 {
137     CutTestIterator *test_iterator;
138     gint n_tests;
139 };
140 
141 typedef struct _StartTest StartTest;
142 struct _StartTest
143 {
144     CutTest *test;
145     CutTestContext *test_context;
146 };
147 
148 typedef struct _StartIteratedTest StartIteratedTest;
149 struct _StartIteratedTest
150 {
151     CutIteratedTest *iterated_test;
152     CutTestContext *test_context;
153 };
154 
155 typedef struct _PassAssertion PassAssertion;
156 struct _PassAssertion
157 {
158     CutTest *test;
159     CutTestContext *test_context;
160 };
161 
162 typedef struct _TestResult TestResult;
163 struct _TestResult
164 {
165     CutTest *test;
166     CutTestContext *test_context;
167     CutTestResult *result;
168 };
169 
170 typedef struct _CompleteIteratedTest CompleteIteratedTest;
171 struct _CompleteIteratedTest
172 {
173     CutIteratedTest *iterated_test;
174     CutTestContext *test_context;
175 };
176 
177 typedef struct _CompleteTest CompleteTest;
178 struct _CompleteTest
179 {
180     CutTest *test;
181     CutTestContext *test_context;
182 };
183 
184 typedef struct _TestIteratorResult TestIteratorResult;
185 struct _TestIteratorResult
186 {
187     CutTestIterator *test_iterator;
188     CutTestResult *result;
189 };
190 
191 typedef struct _TestCaseResult TestCaseResult;
192 struct _TestCaseResult
193 {
194     CutTestCase *test_case;
195     CutTestResult *result;
196 };
197 
198 typedef struct _CutStreamParserPrivate	CutStreamParserPrivate;
199 struct _CutStreamParserPrivate
200 {
201     GMarkupParseContext *context;
202     CutRunContext *run_context;
203 
204     GQueue *states;
205     GQueue *iterated_tests;
206     GQueue *tests;
207     GQueue *test_iterators;
208     GQueue *test_cases;
209     GQueue *test_suites;
210     GQueue *test_contexts;
211     GQueue *test_data;
212 
213     ReadyTestSuite *ready_test_suite;
214     ReadyTestCase *ready_test_case;
215     ReadyTestIterator *ready_test_iterator;
216     StartTest *start_test;
217     StartIteratedTest *start_iterated_test;
218     PassAssertion *pass_assertion;
219     TestResult *test_result;
220     CompleteIteratedTest *complete_iterated_test;
221     CompleteTest *complete_test;
222     TestIteratorResult *test_iterator_result;
223     TestCaseResult *test_case_result;
224 
225     CutTestResult *result;
226     GList *backtrace;
227     CutBacktraceEntry *backtrace_entry;
228     gchar *option_name;
229     gchar *option_value;
230     gboolean complete_success;
231     gboolean stream_success;
232 
233     GQueue *element_stack;
234 };
235 
236 #define PUSH_STATE(priv, state)                                 \
237     (g_queue_push_head((priv)->states, GINT_TO_POINTER(state)))
238 #define POP_STATE(priv)                                 \
239     (GPOINTER_TO_INT(g_queue_pop_head((priv)->states)))
240 #define DROP_STATE(priv)                        \
241     (g_queue_pop_head((priv)->states))
242 #define PEEK_STATE(priv)                                        \
243     (GPOINTER_TO_INT(g_queue_peek_head((priv)->states)))
244 #define PEEK_NTH_STATE(priv, n)                                 \
245     (GPOINTER_TO_INT(g_queue_peek_nth((priv)->states, n)))
246 
247 #define PUSH_TEST(priv, test)                                   \
248     (g_queue_push_head((priv)->tests, g_object_ref(test)))
249 #define POP_TEST(priv)                          \
250     (g_queue_pop_head((priv)->tests))
251 #define DROP_TEST(priv)                         \
252     (g_object_unref(POP_TEST(priv)))
253 #define PEEK_TEST(priv)                         \
254     (g_queue_peek_head((priv)->tests))
255 
256 #define PUSH_TEST_ITERATOR(priv, test_iterator)                         \
257     (g_queue_push_head((priv)->test_iterators, g_object_ref(test_iterator)))
258 #define POP_TEST_ITERATOR(priv)                 \
259     (g_queue_pop_head((priv)->test_iterators))
260 #define DROP_TEST_ITERATOR(priv)                \
261     (g_object_unref(POP_TEST_ITERATOR(priv)))
262 #define PEEK_TEST_ITERATOR(priv)                \
263     (g_queue_peek_head((priv)->test_iterators))
264 
265 #define PUSH_TEST_CASE(priv, test_case)                                 \
266     (g_queue_push_head((priv)->test_cases, g_object_ref(test_case)))
267 #define POP_TEST_CASE(priv)                     \
268     (g_queue_pop_head((priv)->test_cases))
269 #define DROP_TEST_CASE(priv)                    \
270     (g_object_unref(POP_TEST_CASE(priv)))
271 #define PEEK_TEST_CASE(priv)                    \
272     (g_queue_peek_head((priv)->test_cases))
273 
274 #define PUSH_TEST_SUITE(priv, test_suite)                               \
275     (g_queue_push_head((priv)->test_suites, g_object_ref(test_suite)))
276 #define POP_TEST_SUITE(priv)                    \
277     (g_queue_pop_head((priv)->test_suites))
278 #define DROP_TEST_SUITE(priv)                   \
279     (g_object_unref(POP_TEST_SUITE(priv)))
280 #define PEEK_TEST_SUITE(priv)                   \
281     (g_queue_peek_head((priv)->test_suites))
282 
283 #define PUSH_TEST_CONTEXT(priv, test_context)                           \
284     (g_queue_push_head((priv)->test_contexts, g_object_ref(test_context)))
285 #define POP_TEST_CONTEXT(priv)                  \
286     (g_queue_pop_head((priv)->test_contexts))
287 #define DROP_TEST_CONTEXT(priv)                 \
288     (g_object_unref(POP_TEST_CONTEXT(priv)))
289 #define PEEK_TEST_CONTEXT(priv)                 \
290     (g_queue_peek_head((priv)->test_contexts))
291 
292 #define PUSH_TEST_DATA(priv, current_test_data)                         \
293     (g_queue_push_head((priv)->test_data, g_object_ref(current_test_data)))
294 #define POP_TEST_DATA(priv)                     \
295     (g_queue_pop_head((priv)->test_data))
296 #define DROP_TEST_DATA(priv)                    \
297     (g_object_unref(POP_TEST_DATA(priv)))
298 #define PEEK_TEST_DATA(priv)                    \
299     (g_queue_peek_head((priv)->test_data))
300 
301 enum
302 {
303     PROP_0,
304     PROP_RUN_CONTEXT,
305 };
306 
307 enum
308 {
309     RESULT,
310     LAST_SIGNAL
311 };
312 
313 static gint signals[LAST_SIGNAL] = {0};
314 
315 G_DEFINE_TYPE(CutStreamParser, cut_stream_parser, G_TYPE_OBJECT)
316 
317 static void dispose        (GObject         *object);
318 static void set_property   (GObject         *object,
319                             guint            prop_id,
320                             const GValue    *value,
321                             GParamSpec      *pspec);
322 static void get_property   (GObject         *object,
323                             guint            prop_id,
324                             GValue          *value,
325                             GParamSpec      *pspec);
326 
327 static void start_element_handler (GMarkupParseContext *context,
328                                    const gchar         *element_name,
329                                    const gchar        **attribute_names,
330                                    const gchar        **attribute_values,
331                                    gpointer             user_data,
332                                    GError             **error);
333 static void end_element_handler   (GMarkupParseContext *context,
334                                    const gchar         *element_name,
335                                    gpointer             user_data,
336                                    GError             **error);
337 static void text_handler          (GMarkupParseContext *context,
338                                    const gchar         *text,
339                                    gsize                text_len,
340                                    gpointer             user_data,
341                                    GError             **error);
342 static void error_handler         (GMarkupParseContext *context,
343                                    GError              *error,
344                                    gpointer             user_data);
345 
346 static GMarkupParser markup_parser = {
347     start_element_handler,
348     end_element_handler,
349     text_handler,
350     NULL,
351     error_handler,
352 };
353 
354 static void
cut_stream_parser_class_init(CutStreamParserClass * klass)355 cut_stream_parser_class_init (CutStreamParserClass *klass)
356 {
357     GObjectClass *gobject_class;
358     GParamSpec *spec;
359 
360     gobject_class = G_OBJECT_CLASS(klass);
361 
362     gobject_class->dispose      = dispose;
363     gobject_class->set_property = set_property;
364     gobject_class->get_property = get_property;
365 
366     spec = g_param_spec_object("run-context",
367                                "run context",
368                                "The run context of the stream parser",
369                                CUT_TYPE_RUN_CONTEXT,
370                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
371     g_object_class_install_property(gobject_class, PROP_RUN_CONTEXT, spec);
372 
373     signals[RESULT]
374         = g_signal_new("result",
375                        G_TYPE_FROM_CLASS(klass),
376                        G_SIGNAL_RUN_LAST,
377                        G_STRUCT_OFFSET(CutStreamParserClass, result),
378                        NULL, NULL,
379                        g_cclosure_marshal_VOID__OBJECT,
380                        G_TYPE_NONE, 1, CUT_TYPE_TEST_RESULT);
381 
382     g_type_class_add_private(gobject_class, sizeof(CutStreamParserPrivate));
383 }
384 
385 static void
cut_stream_parser_init(CutStreamParser * stream_parser)386 cut_stream_parser_init (CutStreamParser *stream_parser)
387 {
388     CutStreamParserPrivate *priv = CUT_STREAM_PARSER_GET_PRIVATE(stream_parser);
389 
390     priv->context = g_markup_parse_context_new(&markup_parser,
391                                                G_MARKUP_TREAT_CDATA_AS_TEXT,
392                                                stream_parser, NULL);
393     priv->run_context = NULL;
394 
395     priv->states = g_queue_new();
396     PUSH_STATE(priv, IN_TOP_LEVEL);
397     priv->iterated_tests = g_queue_new();
398     priv->tests = g_queue_new();
399     priv->test_cases = g_queue_new();
400     priv->test_iterators = g_queue_new();
401     priv->test_suites = g_queue_new();
402     priv->test_contexts = g_queue_new();
403     priv->test_data = g_queue_new();
404 
405     priv->ready_test_suite = NULL;
406     priv->ready_test_case = NULL;
407     priv->ready_test_iterator = NULL;
408     priv->start_test = NULL;
409     priv->start_iterated_test = NULL;
410     priv->pass_assertion = NULL;
411     priv->complete_iterated_test = NULL;
412     priv->complete_test = NULL;
413     priv->test_result = NULL;
414     priv->test_iterator_result = NULL;
415     priv->test_case_result = NULL;
416 
417     priv->result = NULL;
418     priv->backtrace = NULL;
419     priv->backtrace_entry = NULL;
420     priv->option_name = NULL;
421     priv->option_value = NULL;
422     priv->complete_success = TRUE;
423     priv->stream_success = TRUE;
424 
425     priv->element_stack = g_queue_new();
426 }
427 
428 static ReadyTestSuite *
ready_test_suite_new(void)429 ready_test_suite_new (void)
430 {
431     return g_slice_new0(ReadyTestSuite);
432 }
433 
434 static void
ready_test_suite_free(ReadyTestSuite * ready_test_suite)435 ready_test_suite_free (ReadyTestSuite *ready_test_suite)
436 {
437     if (ready_test_suite->test_suite)
438         g_object_unref(ready_test_suite->test_suite);
439     g_slice_free(ReadyTestSuite, ready_test_suite);
440 }
441 
442 static ReadyTestCase *
ready_test_case_new(void)443 ready_test_case_new (void)
444 {
445     return g_slice_new0(ReadyTestCase);
446 }
447 
448 static void
ready_test_case_free(ReadyTestCase * ready_test_case)449 ready_test_case_free (ReadyTestCase *ready_test_case)
450 {
451     if (ready_test_case->test_case)
452         g_object_unref(ready_test_case->test_case);
453     g_slice_free(ReadyTestCase, ready_test_case);
454 }
455 
456 static ReadyTestIterator *
ready_test_iterator_new(void)457 ready_test_iterator_new (void)
458 {
459     return g_slice_new0(ReadyTestIterator);
460 }
461 
462 static void
ready_test_iterator_free(ReadyTestIterator * ready_test_iterator)463 ready_test_iterator_free (ReadyTestIterator *ready_test_iterator)
464 {
465     if (ready_test_iterator->test_iterator)
466         g_object_unref(ready_test_iterator->test_iterator);
467     g_slice_free(ReadyTestIterator, ready_test_iterator);
468 }
469 
470 static StartTest *
start_test_new(void)471 start_test_new (void)
472 {
473     return g_slice_new0(StartTest);
474 }
475 
476 static void
start_test_free(StartTest * start_test)477 start_test_free (StartTest *start_test)
478 {
479     if (start_test->test)
480         g_object_unref(start_test->test);
481     if (start_test->test_context)
482         g_object_unref(start_test->test_context);
483     g_slice_free(StartTest, start_test);
484 }
485 
486 static StartIteratedTest *
start_iterated_test_new(void)487 start_iterated_test_new (void)
488 {
489     return g_slice_new0(StartIteratedTest);
490 }
491 
492 static void
start_iterated_test_free(StartIteratedTest * start_iterated_test)493 start_iterated_test_free (StartIteratedTest *start_iterated_test)
494 {
495     if (start_iterated_test->iterated_test)
496         g_object_unref(start_iterated_test->iterated_test);
497     if (start_iterated_test->test_context)
498         g_object_unref(start_iterated_test->test_context);
499     g_slice_free(StartIteratedTest, start_iterated_test);
500 }
501 
502 static PassAssertion *
pass_assertion_new(void)503 pass_assertion_new (void)
504 {
505     return g_slice_new0(PassAssertion);
506 }
507 
508 static void
pass_assertion_free(PassAssertion * pass_assertion)509 pass_assertion_free (PassAssertion *pass_assertion)
510 {
511     if (pass_assertion->test)
512         g_object_unref(pass_assertion->test);
513     if (pass_assertion->test_context)
514         g_object_unref(pass_assertion->test_context);
515     g_slice_free(PassAssertion, pass_assertion);
516 }
517 
518 static TestResult *
test_result_new(void)519 test_result_new (void)
520 {
521     return g_slice_new0(TestResult);
522 }
523 
524 static void
test_result_free(TestResult * test_result)525 test_result_free (TestResult *test_result)
526 {
527     if (test_result->test)
528         g_object_unref(test_result->test);
529     if (test_result->test_context)
530         g_object_unref(test_result->test_context);
531     if (test_result->result)
532         g_object_unref(test_result->result);
533     g_slice_free(TestResult, test_result);
534 }
535 
536 static CompleteIteratedTest *
complete_iterated_test_new(void)537 complete_iterated_test_new (void)
538 {
539     return g_slice_new0(CompleteIteratedTest);
540 }
541 
542 static void
complete_iterated_test_free(CompleteIteratedTest * complete_iterated_test)543 complete_iterated_test_free (CompleteIteratedTest *complete_iterated_test)
544 {
545     if (complete_iterated_test->iterated_test)
546         g_object_unref(complete_iterated_test->iterated_test);
547     if (complete_iterated_test->test_context)
548         g_object_unref(complete_iterated_test->test_context);
549     g_slice_free(CompleteIteratedTest, complete_iterated_test);
550 }
551 
552 static CompleteTest *
complete_test_new(void)553 complete_test_new (void)
554 {
555     return g_slice_new0(CompleteTest);
556 }
557 
558 static void
complete_test_free(CompleteTest * complete_test)559 complete_test_free (CompleteTest *complete_test)
560 {
561     if (complete_test->test)
562         g_object_unref(complete_test->test);
563     if (complete_test->test_context)
564         g_object_unref(complete_test->test_context);
565     g_slice_free(CompleteTest, complete_test);
566 }
567 
568 static TestIteratorResult *
test_iterator_result_new(void)569 test_iterator_result_new (void)
570 {
571     return g_slice_new0(TestIteratorResult);
572 }
573 
574 static void
test_iterator_result_free(TestIteratorResult * test_iterator_result)575 test_iterator_result_free (TestIteratorResult *test_iterator_result)
576 {
577     if (test_iterator_result->test_iterator)
578         g_object_unref(test_iterator_result->test_iterator);
579     if (test_iterator_result->result)
580         g_object_unref(test_iterator_result->result);
581     g_slice_free(TestIteratorResult, test_iterator_result);
582 }
583 
584 static TestCaseResult *
test_case_result_new(void)585 test_case_result_new (void)
586 {
587     return g_slice_new0(TestCaseResult);
588 }
589 
590 static void
test_case_result_free(TestCaseResult * test_case_result)591 test_case_result_free (TestCaseResult *test_case_result)
592 {
593     if (test_case_result->test_case)
594         g_object_unref(test_case_result->test_case);
595     if (test_case_result->result)
596         g_object_unref(test_case_result->result);
597     g_slice_free(TestCaseResult, test_case_result);
598 }
599 
600 static void
run_context_weak_notify(gpointer data,GObject * where_the_object_was)601 run_context_weak_notify (gpointer data, GObject *where_the_object_was)
602 {
603     CutStreamParser *parser = data;
604     CutStreamParserPrivate *priv;
605 
606     priv = CUT_STREAM_PARSER_GET_PRIVATE(parser);
607     priv->run_context = NULL;
608 }
609 
610 static void
dispose(GObject * object)611 dispose (GObject *object)
612 {
613     CutStreamParserPrivate *priv = CUT_STREAM_PARSER_GET_PRIVATE(object);
614 
615     if (priv->context) {
616         g_markup_parse_context_free(priv->context);
617         priv->context = NULL;
618     }
619 
620     if (priv->run_context) {
621         g_object_weak_unref(G_OBJECT(priv->run_context),
622                             run_context_weak_notify, object);
623         priv->run_context = NULL;
624     }
625 
626     if (priv->states) {
627         g_queue_free(priv->states);
628         priv->states = NULL;
629     }
630 
631     if (priv->iterated_tests) {
632         g_queue_foreach(priv->iterated_tests, (GFunc)g_object_unref, NULL);
633         g_queue_free(priv->iterated_tests);
634         priv->iterated_tests = NULL;
635     }
636 
637     if (priv->tests) {
638         g_queue_foreach(priv->tests, (GFunc)g_object_unref, NULL);
639         g_queue_free(priv->tests);
640         priv->tests = NULL;
641     }
642 
643     if (priv->test_cases) {
644         g_queue_foreach(priv->test_cases, (GFunc)g_object_unref, NULL);
645         g_queue_free(priv->test_cases);
646         priv->test_cases = NULL;
647     }
648 
649     if (priv->test_suites) {
650         g_queue_foreach(priv->test_suites, (GFunc)g_object_unref, NULL);
651         g_queue_free(priv->test_suites);
652         priv->test_suites = NULL;
653     }
654 
655     if (priv->test_contexts) {
656         g_queue_foreach(priv->test_contexts, (GFunc)g_object_unref, NULL);
657         g_queue_free(priv->test_contexts);
658         priv->test_contexts = NULL;
659     }
660 
661     if (priv->test_data) {
662         g_queue_foreach(priv->test_data, (GFunc)g_object_unref, NULL);
663         g_queue_free(priv->test_data);
664         priv->test_data = NULL;
665     }
666 
667     if (priv->ready_test_suite) {
668         ready_test_suite_free(priv->ready_test_suite);
669         priv->ready_test_suite = NULL;
670     }
671 
672     if (priv->ready_test_case) {
673         ready_test_case_free(priv->ready_test_case);
674         priv->ready_test_case = NULL;
675     }
676 
677     if (priv->start_test) {
678         start_test_free(priv->start_test);
679         priv->start_test = NULL;
680     }
681 
682     if (priv->start_iterated_test) {
683         start_iterated_test_free(priv->start_iterated_test);
684         priv->start_iterated_test = NULL;
685     }
686 
687     if (priv->pass_assertion) {
688         pass_assertion_free(priv->pass_assertion);
689         priv->pass_assertion = NULL;
690     }
691 
692     if (priv->test_result) {
693         test_result_free(priv->test_result);
694         priv->test_result = NULL;
695     }
696 
697     if (priv->complete_iterated_test) {
698         complete_iterated_test_free(priv->complete_iterated_test);
699         priv->complete_iterated_test = NULL;
700     }
701 
702     if (priv->complete_test) {
703         complete_test_free(priv->complete_test);
704         priv->complete_test = NULL;
705     }
706 
707     if (priv->test_case_result) {
708         test_case_result_free(priv->test_case_result);
709         priv->test_case_result = NULL;
710     }
711 
712     if (priv->result) {
713         g_object_unref(priv->result);
714         priv->result = NULL;
715     }
716 
717     if (priv->backtrace) {
718         g_list_foreach(priv->backtrace, (GFunc)g_object_unref, NULL);
719         g_list_free(priv->backtrace);
720         priv->backtrace = NULL;
721     }
722 
723     if (priv->backtrace_entry) {
724         g_object_unref(priv->backtrace_entry);
725         priv->backtrace_entry = NULL;
726     }
727 
728     if (priv->option_name) {
729         g_free(priv->option_name);
730         priv->option_name = NULL;
731     }
732 
733     if (priv->option_value) {
734         g_free(priv->option_value);
735         priv->option_value = NULL;
736     }
737 
738     if (priv->element_stack) {
739         g_queue_foreach(priv->element_stack, (GFunc)g_free, NULL);
740         g_queue_free(priv->element_stack);
741         priv->element_stack = NULL;
742     }
743 
744     G_OBJECT_CLASS(cut_stream_parser_parent_class)->dispose(object);
745 }
746 
747 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)748 set_property (GObject      *object,
749               guint         prop_id,
750               const GValue *value,
751               GParamSpec   *pspec)
752 {
753     CutStreamParserPrivate *priv = CUT_STREAM_PARSER_GET_PRIVATE(object);
754 
755     switch (prop_id) {
756       case PROP_RUN_CONTEXT:
757         priv->run_context = g_value_get_object(value);
758         if (priv->run_context)
759             g_object_weak_ref(G_OBJECT(priv->run_context),
760                               run_context_weak_notify, object);
761         break;
762       default:
763         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
764         break;
765     }
766 }
767 
768 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)769 get_property (GObject    *object,
770               guint       prop_id,
771               GValue     *value,
772               GParamSpec *pspec)
773 {
774     CutStreamParserPrivate *priv = CUT_STREAM_PARSER_GET_PRIVATE(object);
775 
776     switch (prop_id) {
777       case PROP_RUN_CONTEXT:
778         g_value_set_object(value, priv->run_context);
779         break;
780       default:
781         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
782         break;
783     }
784 }
785 
786 CutStreamParser *
cut_stream_parser_new(CutRunContext * run_context)787 cut_stream_parser_new (CutRunContext *run_context)
788 {
789     return g_object_new(CUT_TYPE_STREAM_PARSER,
790                         "run-context", run_context,
791                         NULL);
792 }
793 
794 CutStreamParser *
cut_test_result_parser_new(void)795 cut_test_result_parser_new (void)
796 {
797     CutStreamParser *parser;
798     CutStreamParserPrivate *priv;
799 
800     parser = cut_stream_parser_new(NULL);
801     priv = CUT_STREAM_PARSER_GET_PRIVATE(parser);
802 
803     DROP_STATE(priv);
804     PUSH_STATE(priv, IN_TOP_LEVEL_RESULT);
805 
806     return parser;
807 }
808 
809 gboolean
cut_stream_parser_parse(CutStreamParser * stream_parser,const gchar * text,gssize text_len,GError ** error)810 cut_stream_parser_parse (CutStreamParser *stream_parser,
811                          const gchar *text, gssize text_len, GError **error)
812 {
813     CutStreamParserPrivate *priv = CUT_STREAM_PARSER_GET_PRIVATE(stream_parser);
814 
815     return g_markup_parse_context_parse(priv->context, text, text_len, error);
816 }
817 
818 gboolean
cut_stream_parser_end_parse(CutStreamParser * stream_parser,GError ** error)819 cut_stream_parser_end_parse (CutStreamParser *stream_parser, GError **error)
820 {
821     CutStreamParserPrivate *priv = CUT_STREAM_PARSER_GET_PRIVATE(stream_parser);
822 
823     return g_markup_parse_context_end_parse(priv->context, error);
824 }
825 
826 static gchar *
element_path(const GList * elements)827 element_path (const GList *elements)
828 {
829     GString *string;
830     const GList *node;
831 
832     string = g_string_new(NULL);
833     for (node = elements; node; node = g_list_next(node)) {
834         g_string_append(string, "/");
835         g_string_append(string, node->data);
836     }
837 
838     return g_string_free(string, FALSE);
839 }
840 
841 static void
set_parse_error(CutStreamParserPrivate * priv,GMarkupParseContext * context,GError ** error,const gchar * format,...)842 set_parse_error (CutStreamParserPrivate *priv,
843                  GMarkupParseContext *context,
844                  GError **error,
845                  const gchar *format, ...)
846 {
847     gint line = 0, chr = 0;
848     gchar *message, *path;
849     va_list var_args;
850 
851     va_start(var_args, format);
852     message = g_strdup_vprintf(format, var_args);
853     va_end(var_args);
854 
855     g_markup_parse_context_get_position(context, &line, &chr);
856     path = element_path(priv->element_stack->head);
857     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
858                 "Error on line %d char %d: %s: %s",
859                 line, chr, path, message);
860     g_free(path);
861     g_free(message);
862 }
863 
864 static void
invalid_element(CutStreamParserPrivate * priv,GMarkupParseContext * context,GError ** error)865 invalid_element (CutStreamParserPrivate *priv,
866                  GMarkupParseContext *context, GError **error)
867 {
868     set_parse_error(priv, context, error, "invalid element");
869 }
870 
871 static void
start_top_level(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)872 start_top_level (CutStreamParserPrivate *priv, GMarkupParseContext *context,
873                  const gchar *element_name, GError **error)
874 {
875     if (g_str_equal("stream", element_name)) {
876         PUSH_STATE(priv, IN_STREAM);
877         if (priv->run_context)
878             g_signal_emit_by_name(priv->run_context, "start-run");
879     } else {
880         invalid_element(priv, context, error);
881     }
882 }
883 
884 static void
start_stream(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)885 start_stream (CutStreamParserPrivate *priv,
886                       GMarkupParseContext *context,
887                       const gchar *element_name, GError **error)
888 {
889     if (g_str_equal("pass-assertion", element_name)) {
890         PUSH_STATE(priv, IN_PASS_ASSERTION);
891         priv->pass_assertion = pass_assertion_new();
892     } else if (g_str_equal("test-result", element_name)) {
893         PUSH_STATE(priv, IN_TEST_RESULT);
894         priv->test_result = test_result_new();
895     } else if (g_str_equal("ready-test-suite", element_name)) {
896         PUSH_STATE(priv, IN_READY_TEST_SUITE);
897         priv->ready_test_suite = ready_test_suite_new();
898     } else if (g_str_equal("start-test-suite", element_name)) {
899         PUSH_STATE(priv, IN_START_TEST_SUITE);
900         PUSH_TEST_SUITE(priv, cut_test_suite_new_empty());
901     } else if (g_str_equal("ready-test-case", element_name)) {
902         PUSH_STATE(priv, IN_READY_TEST_CASE);
903         priv->ready_test_case = ready_test_case_new();;
904     } else if (g_str_equal("start-test-case", element_name)) {
905         PUSH_STATE(priv, IN_START_TEST_CASE);
906         PUSH_TEST_CASE(priv, cut_test_case_new_empty());
907     } else if (g_str_equal("ready-test-iterator", element_name)) {
908         PUSH_STATE(priv, IN_READY_TEST_ITERATOR);
909         priv->ready_test_iterator = ready_test_iterator_new();;
910     } else if (g_str_equal("start-test-iterator", element_name)) {
911         PUSH_STATE(priv, IN_START_TEST_ITERATOR);
912         PUSH_TEST_ITERATOR(priv, cut_test_iterator_new_empty());
913     } else if (g_str_equal("start-test", element_name)) {
914         PUSH_STATE(priv, IN_START_TEST);
915         priv->start_test = start_test_new();
916     } else if (g_str_equal("start-iterated-test", element_name)) {
917         PUSH_STATE(priv, IN_START_ITERATED_TEST);
918         priv->start_iterated_test = start_iterated_test_new();
919     } else if (g_str_equal("complete-iterated-test", element_name)) {
920         PUSH_STATE(priv, IN_COMPLETE_ITERATED_TEST);
921         priv->complete_iterated_test = complete_iterated_test_new();
922     } else if (g_str_equal("complete-test", element_name)) {
923         PUSH_STATE(priv, IN_COMPLETE_TEST);
924         priv->complete_test = complete_test_new();
925     } else if (g_str_equal("test-iterator-result", element_name)) {
926         PUSH_STATE(priv, IN_TEST_ITERATOR_RESULT);
927         priv->test_iterator_result = test_iterator_result_new();
928     } else if (g_str_equal("complete-test-iterator", element_name)) {
929         PUSH_STATE(priv, IN_COMPLETE_TEST_ITERATOR);
930     } else if (g_str_equal("test-case-result", element_name)) {
931         PUSH_STATE(priv, IN_TEST_CASE_RESULT);
932         priv->test_case_result = test_case_result_new();
933     } else if (g_str_equal("complete-test-case", element_name)) {
934         PUSH_STATE(priv, IN_COMPLETE_TEST_CASE);
935     } else if (g_str_equal("complete-test-suite", element_name)) {
936         PUSH_STATE(priv, IN_COMPLETE_TEST_SUITE);
937     } else if (g_str_equal("success", element_name)) {
938         PUSH_STATE(priv, IN_STREAM_SUCCESS);
939     } else {
940         invalid_element(priv, context, error);
941     }
942 }
943 
944 static void
start_ready_test_suite(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)945 start_ready_test_suite (CutStreamParserPrivate *priv,
946                         GMarkupParseContext *context,
947                         const gchar *element_name, GError **error)
948 {
949     if (g_str_equal("test-suite", element_name)) {
950         PUSH_STATE(priv, IN_TEST_SUITE);
951         priv->ready_test_suite->test_suite = cut_test_suite_new_empty();
952         PUSH_TEST_SUITE(priv, priv->ready_test_suite->test_suite);
953     } else if (g_str_equal("n-test-cases", element_name)) {
954         PUSH_STATE(priv, IN_READY_TEST_SUITE_N_TEST_CASES);
955     } else if (g_str_equal("n-tests", element_name)) {
956         PUSH_STATE(priv, IN_READY_TEST_SUITE_N_TESTS);
957     } else {
958         invalid_element(priv, context, error);
959     }
960 }
961 
962 static void
start_start_test_suite(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)963 start_start_test_suite (CutStreamParserPrivate *priv,
964                         GMarkupParseContext *context,
965                         const gchar *element_name, GError **error)
966 {
967     if (g_str_equal("test-suite", element_name)) {
968         PUSH_STATE(priv, IN_TEST_SUITE);
969         PUSH_TEST_SUITE(priv, cut_test_suite_new_empty());
970     } else {
971         invalid_element(priv, context, error);
972     }
973 }
974 
975 static void
start_ready_test_case(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)976 start_ready_test_case (CutStreamParserPrivate *priv,
977                        GMarkupParseContext *context,
978                        const gchar *element_name, GError **error)
979 {
980     if (g_str_equal("test-case", element_name)) {
981         PUSH_STATE(priv, IN_TEST_CASE);
982         priv->ready_test_case->test_case = cut_test_case_new_empty();
983         PUSH_TEST_CASE(priv, priv->ready_test_case->test_case);
984     } else if (g_str_equal("n-tests", element_name)) {
985         PUSH_STATE(priv, IN_READY_TEST_CASE_N_TESTS);
986     } else {
987         invalid_element(priv, context, error);
988     }
989 }
990 
991 static void
start_start_test_case(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)992 start_start_test_case (CutStreamParserPrivate *priv,
993                        GMarkupParseContext *context,
994                        const gchar *element_name, GError **error)
995 {
996     if (g_str_equal("test-case", element_name)) {
997         PUSH_STATE(priv, IN_TEST_CASE);
998         PUSH_TEST_CASE(priv, cut_test_case_new_empty());
999     } else {
1000         invalid_element(priv, context, error);
1001     }
1002 }
1003 
1004 static void
start_ready_test_iterator(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1005 start_ready_test_iterator (CutStreamParserPrivate *priv,
1006                            GMarkupParseContext *context,
1007                            const gchar *element_name, GError **error)
1008 {
1009     if (g_str_equal("test-iterator", element_name)) {
1010         PUSH_STATE(priv, IN_TEST_ITERATOR);
1011         priv->ready_test_iterator->test_iterator = cut_test_iterator_new_empty();
1012         PUSH_TEST_ITERATOR(priv, priv->ready_test_iterator->test_iterator);
1013     } else if (g_str_equal("n-tests", element_name)) {
1014         PUSH_STATE(priv, IN_READY_TEST_ITERATOR_N_TESTS);
1015     } else {
1016         invalid_element(priv, context, error);
1017     }
1018 }
1019 
1020 static void
start_start_test_iterator(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1021 start_start_test_iterator (CutStreamParserPrivate *priv,
1022                           GMarkupParseContext *context,
1023                           const gchar *element_name, GError **error)
1024 {
1025     if (g_str_equal("test-iterator", element_name)) {
1026         PUSH_STATE(priv, IN_TEST_ITERATOR);
1027         PUSH_TEST_ITERATOR(priv, cut_test_iterator_new_empty());
1028     } else {
1029         invalid_element(priv, context, error);
1030     }
1031 }
1032 
1033 static void
start_start_test(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1034 start_start_test (CutStreamParserPrivate *priv,
1035                   GMarkupParseContext *context,
1036                   const gchar *element_name, GError **error)
1037 {
1038     if (g_str_equal("test", element_name)) {
1039         PUSH_STATE(priv, IN_TEST);
1040         priv->start_test->test = cut_test_new_empty();
1041         PUSH_TEST(priv, priv->start_test->test);
1042     } else if (g_str_equal("test-context", element_name)) {
1043         PUSH_STATE(priv, IN_TEST_CONTEXT);
1044         priv->start_test->test_context = cut_test_context_new_empty();
1045         PUSH_TEST_CONTEXT(priv,  priv->start_test->test_context);
1046     } else {
1047         invalid_element(priv, context, error);
1048     }
1049 }
1050 
1051 static void
start_start_iterated_test(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1052 start_start_iterated_test (CutStreamParserPrivate *priv,
1053                            GMarkupParseContext *context,
1054                            const gchar *element_name, GError **error)
1055 {
1056     if (g_str_equal("iterated-test", element_name)) {
1057         PUSH_STATE(priv, IN_ITERATED_TEST);
1058         priv->start_iterated_test->iterated_test = cut_iterated_test_new_empty();
1059         PUSH_TEST(priv, CUT_TEST(priv->start_iterated_test->iterated_test));
1060     } else if (g_str_equal("test-context", element_name)) {
1061         PUSH_STATE(priv, IN_TEST_CONTEXT);
1062         priv->start_iterated_test->test_context = cut_test_context_new_empty();
1063         PUSH_TEST_CONTEXT(priv,  priv->start_iterated_test->test_context);
1064     } else {
1065         invalid_element(priv, context, error);
1066     }
1067 }
1068 
1069 static void
start_pass_assertion(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1070 start_pass_assertion (CutStreamParserPrivate *priv,
1071                       GMarkupParseContext *context,
1072                       const gchar *element_name, GError **error)
1073 {
1074     if (g_str_equal("test", element_name)) {
1075         PUSH_STATE(priv, IN_TEST);
1076         priv->pass_assertion->test = cut_test_new_empty();
1077         PUSH_TEST(priv, priv->pass_assertion->test);
1078     } else if (g_str_equal("iterated-test", element_name)) {
1079         PUSH_STATE(priv, IN_ITERATED_TEST);
1080         priv->pass_assertion->test = CUT_TEST(cut_iterated_test_new_empty());
1081         PUSH_TEST(priv, priv->pass_assertion->test);
1082     } else if (g_str_equal("test-context", element_name)) {
1083         PUSH_STATE(priv, IN_TEST_CONTEXT);
1084         priv->pass_assertion->test_context = cut_test_context_new_empty();
1085         PUSH_TEST_CONTEXT(priv,  priv->pass_assertion->test_context);
1086     } else {
1087         invalid_element(priv, context, error);
1088     }
1089 }
1090 
1091 static void
start_test_result(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1092 start_test_result (CutStreamParserPrivate *priv,
1093                    GMarkupParseContext *context,
1094                    const gchar *element_name, GError **error)
1095 {
1096     if (g_str_equal("test", element_name)) {
1097         PUSH_STATE(priv, IN_TEST);
1098         priv->test_result->test = cut_test_new_empty();
1099         PUSH_TEST(priv, priv->test_result->test);
1100     } else if (g_str_equal("iterated-test", element_name)) {
1101         PUSH_STATE(priv, IN_ITERATED_TEST);
1102         priv->test_result->test = CUT_TEST(cut_iterated_test_new_empty());
1103         PUSH_TEST(priv, priv->test_result->test);
1104     } else if (g_str_equal("test-context", element_name)) {
1105         PUSH_STATE(priv, IN_TEST_CONTEXT);
1106         priv->test_result->test_context = cut_test_context_new_empty();
1107         PUSH_TEST_CONTEXT(priv, priv->test_result->test_context);
1108     } else if (g_str_equal("result", element_name)) {
1109         PUSH_STATE(priv, IN_RESULT);
1110         priv->test_result->result = cut_test_result_new_empty();
1111         priv->result = g_object_ref(priv->test_result->result);
1112     } else {
1113         invalid_element(priv, context, error);
1114     }
1115 }
1116 
1117 static void
start_top_level_result(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1118 start_top_level_result (CutStreamParserPrivate *priv,
1119                         GMarkupParseContext *context,
1120                         const gchar *element_name, GError **error)
1121 {
1122     if (g_str_equal("result", element_name)) {
1123         PUSH_STATE(priv, IN_RESULT);
1124         priv->result = cut_test_result_new_empty();
1125     } else {
1126         invalid_element(priv, context, error);
1127     }
1128 }
1129 
1130 static void
start_result(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1131 start_result (CutStreamParserPrivate *priv, GMarkupParseContext *context,
1132               const gchar *element_name, GError **error)
1133 {
1134     if (g_str_equal("test-case", element_name)) {
1135         CutTestCase *test_case;
1136 
1137         PUSH_STATE(priv, IN_TEST_CASE);
1138         test_case = cut_test_case_new_empty();
1139         cut_test_result_set_test_case(priv->result, test_case);
1140         PUSH_TEST_CASE(priv, test_case);
1141         g_object_unref(test_case);
1142     } else if (g_str_equal("test-iterator", element_name)) {
1143         CutTestIterator *test_iterator;
1144 
1145         PUSH_STATE(priv, IN_TEST_ITERATOR);
1146         test_iterator = cut_test_iterator_new_empty();
1147         cut_test_result_set_test_iterator(priv->result, test_iterator);
1148         PUSH_TEST_ITERATOR(priv, test_iterator);
1149         g_object_unref(test_iterator);
1150     } else if (g_str_equal("test", element_name) ||
1151                g_str_equal("iterated-test", element_name)) {
1152         CutTest *test;
1153 
1154         PUSH_STATE(priv, IN_TEST);
1155         if (g_str_equal("iterated-test", element_name))
1156             test = CUT_TEST(cut_iterated_test_new_empty());
1157         else
1158             test = cut_test_new_empty();
1159         cut_test_result_set_test(priv->result, test);
1160         PUSH_TEST(priv, test);
1161         g_object_unref(test);
1162     } else if (g_str_equal("test-data", element_name)) {
1163         CutTestData *test_data;
1164 
1165         PUSH_STATE(priv, IN_TEST_DATA);
1166         test_data = cut_test_data_new_empty();
1167         cut_test_result_set_test_data(priv->result, test_data);
1168         PUSH_TEST_DATA(priv, test_data);
1169         g_object_unref(test_data);
1170     } else if (g_str_equal("status", element_name)) {
1171         PUSH_STATE(priv, IN_RESULT_STATUS);
1172     } else if (g_str_equal("detail", element_name)) {
1173         PUSH_STATE(priv, IN_RESULT_DETAIL);
1174     } else if (g_str_equal("backtrace", element_name)) {
1175         PUSH_STATE(priv, IN_RESULT_BACKTRACE);
1176     } else if (g_str_equal("start-time", element_name)) {
1177         PUSH_STATE(priv, IN_RESULT_START_TIME);
1178     } else if (g_str_equal("elapsed", element_name)) {
1179         PUSH_STATE(priv, IN_RESULT_ELAPSED);
1180     } else if (g_str_equal("expected", element_name)) {
1181         PUSH_STATE(priv, IN_RESULT_EXPECTED);
1182     } else if (g_str_equal("actual", element_name)) {
1183         PUSH_STATE(priv, IN_RESULT_ACTUAL);
1184     } else if (g_str_equal("diff", element_name)) {
1185         PUSH_STATE(priv, IN_RESULT_DIFF);
1186     } else if (g_str_equal("folded-diff", element_name)) {
1187         PUSH_STATE(priv, IN_RESULT_FOLDED_DIFF);
1188     } else {
1189         invalid_element(priv, context, error);
1190     }
1191 }
1192 
1193 static void
start_complete_iterated_test(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1194 start_complete_iterated_test (CutStreamParserPrivate *priv,
1195                               GMarkupParseContext *context,
1196                               const gchar *element_name, GError **error)
1197 {
1198     if (g_str_equal("iterated-test", element_name)) {
1199         PUSH_STATE(priv, IN_ITERATED_TEST);
1200         priv->complete_iterated_test->iterated_test =
1201             cut_iterated_test_new_empty();
1202         PUSH_TEST(priv, CUT_TEST(priv->complete_iterated_test->iterated_test));
1203     } else if (g_str_equal("test-context", element_name)) {
1204         PUSH_STATE(priv, IN_TEST_CONTEXT);
1205         priv->complete_iterated_test->test_context =
1206             cut_test_context_new_empty();
1207         PUSH_TEST_CONTEXT(priv, priv->complete_iterated_test->test_context);
1208     } else if (g_str_equal("success", element_name)) {
1209         PUSH_STATE(priv, IN_COMPLETE_SUCCESS);
1210     } else {
1211         invalid_element(priv, context, error);
1212     }
1213 }
1214 
1215 static void
start_complete_test(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1216 start_complete_test (CutStreamParserPrivate *priv, GMarkupParseContext *context,
1217                      const gchar *element_name, GError **error)
1218 {
1219     if (g_str_equal("test", element_name)) {
1220         PUSH_STATE(priv, IN_TEST);
1221         priv->complete_test->test = cut_test_new_empty();
1222         PUSH_TEST(priv, priv->complete_test->test);
1223     } else if (g_str_equal("test-context", element_name)) {
1224         PUSH_STATE(priv, IN_TEST_CONTEXT);
1225         priv->complete_test->test_context = cut_test_context_new_empty();
1226         PUSH_TEST_CONTEXT(priv, priv->complete_test->test_context);
1227     } else if (g_str_equal("success", element_name)) {
1228         PUSH_STATE(priv, IN_COMPLETE_SUCCESS);
1229     } else {
1230         invalid_element(priv, context, error);
1231     }
1232 }
1233 
1234 static void
start_test_iterator_result(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1235 start_test_iterator_result (CutStreamParserPrivate *priv,
1236                         GMarkupParseContext *context,
1237                         const gchar *element_name, GError **error)
1238 {
1239     if (g_str_equal("test-iterator", element_name)) {
1240         PUSH_STATE(priv, IN_TEST_ITERATOR);
1241         priv->test_iterator_result->test_iterator =
1242             cut_test_iterator_new_empty();
1243         PUSH_TEST_ITERATOR(priv, priv->test_iterator_result->test_iterator);
1244     } else if (g_str_equal("result", element_name)) {
1245         PUSH_STATE(priv, IN_RESULT);
1246         priv->test_iterator_result->result = cut_test_result_new_empty();
1247         priv->result = g_object_ref(priv->test_iterator_result->result);
1248     } else {
1249         invalid_element(priv, context, error);
1250     }
1251 }
1252 
1253 static void
start_complete_test_iterator(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1254 start_complete_test_iterator (CutStreamParserPrivate *priv,
1255                               GMarkupParseContext *context,
1256                               const gchar *element_name, GError **error)
1257 {
1258     if (g_str_equal("test-iterator", element_name)) {
1259         PUSH_STATE(priv, IN_TEST_ITERATOR);
1260         PUSH_TEST_ITERATOR(priv, cut_test_iterator_new_empty());
1261     } else if (g_str_equal("success", element_name)) {
1262         PUSH_STATE(priv, IN_COMPLETE_SUCCESS);
1263     } else {
1264         invalid_element(priv, context, error);
1265     }
1266 }
1267 
1268 static void
start_test_case_result(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1269 start_test_case_result (CutStreamParserPrivate *priv,
1270                         GMarkupParseContext *context,
1271                         const gchar *element_name, GError **error)
1272 {
1273     if (g_str_equal("test-case", element_name)) {
1274         PUSH_STATE(priv, IN_TEST_CASE);
1275         priv->test_case_result->test_case = cut_test_case_new_empty();
1276         PUSH_TEST_CASE(priv, priv->test_case_result->test_case);
1277     } else if (g_str_equal("result", element_name)) {
1278         PUSH_STATE(priv, IN_RESULT);
1279         priv->test_case_result->result = cut_test_result_new_empty();
1280         priv->result = g_object_ref(priv->test_case_result->result);
1281     } else {
1282         invalid_element(priv, context, error);
1283     }
1284 }
1285 
1286 static void
start_complete_test_case(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1287 start_complete_test_case (CutStreamParserPrivate *priv,
1288                           GMarkupParseContext *context,
1289                           const gchar *element_name, GError **error)
1290 {
1291     if (g_str_equal("test-case", element_name)) {
1292         PUSH_STATE(priv, IN_TEST_CASE);
1293         PUSH_TEST_CASE(priv, cut_test_case_new_empty());
1294     } else if (g_str_equal("success", element_name)) {
1295         PUSH_STATE(priv, IN_COMPLETE_SUCCESS);
1296     } else {
1297         invalid_element(priv, context, error);
1298     }
1299 }
1300 
1301 static void
start_complete_test_suite(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1302 start_complete_test_suite (CutStreamParserPrivate *priv,
1303                            GMarkupParseContext *context,
1304                            const gchar *element_name, GError **error)
1305 {
1306     if (g_str_equal("test-suite", element_name)) {
1307         PUSH_STATE(priv, IN_TEST_SUITE);
1308         PUSH_TEST_SUITE(priv, cut_test_suite_new_empty());
1309     } else if (g_str_equal("success", element_name)) {
1310         PUSH_STATE(priv, IN_COMPLETE_SUCCESS);
1311     } else {
1312         invalid_element(priv, context, error);
1313     }
1314 }
1315 
1316 static void
start_test_object(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1317 start_test_object (CutStreamParserPrivate *priv, GMarkupParseContext *context,
1318                    const gchar *element_name, GError **error)
1319 {
1320     if (g_str_equal("name", element_name)) {
1321         PUSH_STATE(priv, IN_TEST_NAME);
1322     } else if (g_str_equal("description", element_name)) {
1323         PUSH_STATE(priv, IN_TEST_DESCRIPTION);
1324     } else if (g_str_equal("option", element_name)) {
1325         PUSH_STATE(priv, IN_TEST_OPTION);
1326     } else if (g_str_equal("start-time", element_name)) {
1327         PUSH_STATE(priv, IN_TEST_START_TIME);
1328     } else if (g_str_equal("elapsed", element_name)) {
1329         PUSH_STATE(priv, IN_TEST_ELAPSED);
1330     } else {
1331         invalid_element(priv, context, error);
1332     }
1333 }
1334 
1335 static void
start_test_option(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1336 start_test_option (CutStreamParserPrivate *priv, GMarkupParseContext *context,
1337                    const gchar *element_name, GError **error)
1338 {
1339     if (g_str_equal("name", element_name)) {
1340         PUSH_STATE(priv, IN_TEST_OPTION_NAME);
1341     } else if (g_str_equal("value", element_name)) {
1342         PUSH_STATE(priv, IN_TEST_OPTION_VALUE);
1343     } else {
1344         invalid_element(priv, context, error);
1345     }
1346 }
1347 
1348 static void
start_result_backtrace(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1349 start_result_backtrace (CutStreamParserPrivate *priv,
1350                         GMarkupParseContext *context,
1351                         const gchar *element_name, GError **error)
1352 {
1353     if (g_str_equal("entry", element_name)) {
1354         PUSH_STATE(priv, IN_RESULT_BACKTRACE_ENTRY);
1355         priv->backtrace_entry = cut_backtrace_entry_new_empty();
1356     } else {
1357         invalid_element(priv, context, error);
1358     }
1359 }
1360 
1361 static void
start_result_backtrace_entry(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1362 start_result_backtrace_entry (CutStreamParserPrivate *priv,
1363                               GMarkupParseContext *context,
1364                               const gchar *element_name, GError **error)
1365 {
1366     if (g_str_equal("file", element_name)) {
1367         PUSH_STATE(priv, IN_RESULT_BACKTRACE_ENTRY_FILE);
1368     } else if (g_str_equal("line", element_name)) {
1369         PUSH_STATE(priv, IN_RESULT_BACKTRACE_ENTRY_LINE);
1370     } else if (g_str_equal("info", element_name)) {
1371         PUSH_STATE(priv, IN_RESULT_BACKTRACE_ENTRY_INFO);
1372     } else {
1373         invalid_element(priv, context, error);
1374     }
1375 }
1376 
1377 static void
start_test_context(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1378 start_test_context (CutStreamParserPrivate *priv, GMarkupParseContext *context,
1379                     const gchar *element_name, GError **error)
1380 {
1381     if (g_str_equal("test-suite", element_name)) {
1382         CutTestSuite *test_suite;
1383 
1384         PUSH_STATE(priv, IN_TEST_SUITE);
1385         test_suite = cut_test_suite_new_empty();
1386         cut_test_context_set_test_suite(PEEK_TEST_CONTEXT(priv), test_suite);
1387         PUSH_TEST_SUITE(priv, test_suite);
1388         g_object_unref(test_suite);
1389     } else if (g_str_equal("test-case", element_name)) {
1390         CutTestCase *test_case;
1391 
1392         PUSH_STATE(priv, IN_TEST_CASE);
1393         test_case = cut_test_case_new_empty();
1394         cut_test_context_set_test_case(PEEK_TEST_CONTEXT(priv), test_case);
1395         PUSH_TEST_CASE(priv, test_case);
1396         g_object_unref(test_case);
1397     } else if (g_str_equal("test-iterator", element_name)) {
1398         CutTestIterator *test_iterator;
1399 
1400         PUSH_STATE(priv, IN_TEST_ITERATOR);
1401         test_iterator = cut_test_iterator_new_empty();
1402         cut_test_context_set_test_iterator(PEEK_TEST_CONTEXT(priv),
1403                                            test_iterator);
1404         PUSH_TEST_ITERATOR(priv, test_iterator);
1405         g_object_unref(test_iterator);
1406     } else if (g_str_equal("test", element_name)) {
1407         CutTest *test;
1408 
1409         PUSH_STATE(priv, IN_TEST);
1410         test = cut_test_new_empty();
1411         cut_test_context_set_test(PEEK_TEST_CONTEXT(priv), test);
1412         PUSH_TEST(priv, test);
1413         g_object_unref(test);
1414     } else if (g_str_equal("iterated-test", element_name)) {
1415         CutIteratedTest *iterated_test;
1416 
1417         PUSH_STATE(priv, IN_ITERATED_TEST);
1418         iterated_test = cut_iterated_test_new_empty();
1419         cut_test_context_set_test(PEEK_TEST_CONTEXT(priv),
1420                                   CUT_TEST(iterated_test));
1421         PUSH_TEST(priv, CUT_TEST(iterated_test));
1422         g_object_unref(iterated_test);
1423     } else if (g_str_equal("test-data", element_name)) {
1424         CutTestData *test_data;
1425 
1426         PUSH_STATE(priv, IN_TEST_DATA);
1427         test_data = cut_test_data_new_empty();
1428         cut_test_context_set_data(PEEK_TEST_CONTEXT(priv), test_data);
1429         PUSH_TEST_DATA(priv, test_data);
1430         g_object_unref(test_data);
1431     } else if (g_str_equal("failed", element_name)) {
1432         PUSH_STATE(priv, IN_TEST_CONTEXT_FAILED);
1433     } else {
1434         invalid_element(priv, context, error);
1435     }
1436 }
1437 
1438 static void
start_test_data(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1439 start_test_data (CutStreamParserPrivate *priv, GMarkupParseContext *context,
1440                  const gchar *element_name, GError **error)
1441 {
1442     if (g_str_equal("name", element_name)) {
1443         PUSH_STATE(priv, IN_TEST_DATA_NAME);
1444     } else {
1445         invalid_element(priv, context, error);
1446     }
1447 }
1448 
1449 static void
start_element_handler(GMarkupParseContext * context,const gchar * element_name,const gchar ** attr_names,const gchar ** attr_values,gpointer user_data,GError ** error)1450 start_element_handler (GMarkupParseContext *context,
1451                        const gchar         *element_name,
1452                        const gchar        **attr_names,
1453                        const gchar        **attr_values,
1454                        gpointer             user_data,
1455                        GError             **error)
1456 {
1457     CutStreamParser *parser = user_data;
1458     CutStreamParserPrivate *priv;
1459     ParseState state;
1460 
1461     priv = CUT_STREAM_PARSER_GET_PRIVATE(parser);
1462     g_queue_push_tail(priv->element_stack, g_strdup(element_name));
1463 
1464     state = PEEK_STATE(priv);
1465     switch (state) {
1466       case IN_TOP_LEVEL:
1467         start_top_level(priv, context, element_name, error);
1468         break;
1469       case IN_STREAM:
1470         start_stream(priv, context, element_name, error);
1471         break;
1472       case IN_READY_TEST_SUITE:
1473         start_ready_test_suite(priv, context, element_name, error);
1474         break;
1475       case IN_START_TEST_SUITE:
1476         start_start_test_suite(priv, context, element_name, error);
1477         break;
1478       case IN_READY_TEST_CASE:
1479         start_ready_test_case(priv, context, element_name, error);
1480         break;
1481       case IN_START_TEST_CASE:
1482         start_start_test_case(priv, context, element_name, error);
1483         break;
1484       case IN_READY_TEST_ITERATOR:
1485         start_ready_test_iterator(priv, context, element_name, error);
1486         break;
1487       case IN_START_TEST_ITERATOR:
1488         start_start_test_iterator(priv, context, element_name, error);
1489         break;
1490       case IN_START_TEST:
1491         start_start_test(priv, context, element_name, error);
1492         break;
1493       case IN_START_ITERATED_TEST:
1494         start_start_iterated_test(priv, context, element_name, error);
1495         break;
1496       case IN_PASS_ASSERTION:
1497         start_pass_assertion(priv, context, element_name, error);
1498         break;
1499       case IN_TEST_RESULT:
1500         start_test_result(priv, context, element_name, error);
1501         break;
1502       case IN_TOP_LEVEL_RESULT:
1503         start_top_level_result(priv, context, element_name, error);
1504         break;
1505       case IN_RESULT:
1506         start_result(priv, context, element_name, error);
1507         break;
1508       case IN_COMPLETE_ITERATED_TEST:
1509         start_complete_iterated_test(priv, context, element_name, error);
1510         break;
1511       case IN_COMPLETE_TEST:
1512         start_complete_test(priv, context, element_name, error);
1513         break;
1514       case IN_TEST_ITERATOR_RESULT:
1515         start_test_iterator_result(priv, context, element_name, error);
1516         break;
1517       case IN_COMPLETE_TEST_ITERATOR:
1518         start_complete_test_iterator(priv, context, element_name, error);
1519         break;
1520       case IN_TEST_CASE_RESULT:
1521         start_test_case_result(priv, context, element_name, error);
1522         break;
1523       case IN_COMPLETE_TEST_CASE:
1524         start_complete_test_case(priv, context, element_name, error);
1525         break;
1526       case IN_COMPLETE_TEST_SUITE:
1527         start_complete_test_suite(priv, context, element_name, error);
1528         break;
1529       case IN_TEST_SUITE:
1530       case IN_TEST_CASE:
1531       case IN_TEST_ITERATOR:
1532       case IN_TEST:
1533       case IN_ITERATED_TEST:
1534         start_test_object(priv, context, element_name, error);
1535         break;
1536       case IN_TEST_OPTION:
1537         start_test_option(priv, context, element_name, error);
1538         break;
1539       case IN_RESULT_BACKTRACE:
1540         start_result_backtrace(priv, context, element_name, error);
1541         break;
1542       case IN_RESULT_BACKTRACE_ENTRY:
1543         start_result_backtrace_entry(priv, context, element_name, error);
1544         break;
1545       case IN_TEST_CONTEXT:
1546         start_test_context(priv, context, element_name, error);
1547         break;
1548       case IN_TEST_DATA:
1549         start_test_data(priv, context, element_name, error);
1550         break;
1551       default:
1552         invalid_element(priv, context, error);
1553         break;
1554     }
1555 }
1556 
1557 static void
end_top_level_result(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1558 end_top_level_result (CutStreamParser *parser, CutStreamParserPrivate *priv,
1559                       GMarkupParseContext *context,
1560                       const gchar *element_name, GError **error)
1561 {
1562     if (priv->result) {
1563         g_object_unref(priv->result);
1564         priv->result = NULL;
1565     }
1566 }
1567 
1568 static void
end_stream(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1569 end_stream (CutStreamParser *parser, CutStreamParserPrivate *priv,
1570             GMarkupParseContext *context,
1571             const gchar *element_name, GError **error)
1572 {
1573     if (priv->run_context)
1574         cut_run_context_emit_complete_run(priv->run_context,
1575                                           priv->stream_success);
1576 }
1577 
1578 static void
end_result(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1579 end_result (CutStreamParser *parser, CutStreamParserPrivate *priv,
1580             GMarkupParseContext *context,
1581             const gchar *element_name, GError **error)
1582 {
1583     if (priv->result)
1584         g_signal_emit_by_name(parser, "result", priv->result);
1585 }
1586 
1587 static void
end_test_context(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1588 end_test_context (CutStreamParser *parser, CutStreamParserPrivate *priv,
1589                   GMarkupParseContext *context,
1590                   const gchar *element_name, GError **error)
1591 {
1592     CutTestContext *test_context;
1593 
1594     test_context = PEEK_TEST_CONTEXT(priv);
1595 
1596     if (cut_test_context_get_test_suite(test_context))
1597         DROP_TEST_SUITE(priv);
1598     if (cut_test_context_get_test_case(test_context))
1599         DROP_TEST_CASE(priv);
1600     if (cut_test_context_get_test_iterator(test_context))
1601         DROP_TEST_ITERATOR(priv);
1602     if (cut_test_context_get_test(test_context))
1603         DROP_TEST(priv);
1604     if (cut_test_context_have_data(test_context))
1605         DROP_TEST_DATA(priv);
1606 }
1607 
1608 static void
end_test_option(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1609 end_test_option (CutStreamParser *parser, CutStreamParserPrivate *priv,
1610                  GMarkupParseContext *context,
1611                  const gchar *element_name, GError **error)
1612 {
1613     if (!priv->option_name) {
1614         set_parse_error(priv, context, error, "option name is not set");
1615     } else if (!priv->option_value) {
1616         set_parse_error(priv, context, error, "option value is not set");
1617     } else {
1618         cut_test_set_attribute(PEEK_TEST(priv),
1619                                priv->option_name,
1620                                priv->option_value);
1621     }
1622 
1623     if (priv->option_name) {
1624         g_free(priv->option_name);
1625         priv->option_name = NULL;
1626     }
1627 
1628     if (priv->option_value) {
1629         g_free(priv->option_value);
1630         priv->option_value = NULL;
1631     }
1632 }
1633 
1634 static void
end_result_backtrace(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1635 end_result_backtrace (CutStreamParser *parser, CutStreamParserPrivate *priv,
1636                       GMarkupParseContext *context,
1637                       const gchar *element_name, GError **error)
1638 {
1639     if (!priv->backtrace)
1640         return;
1641 
1642     priv->backtrace = g_list_reverse(priv->backtrace);
1643     if (priv->result)
1644         cut_test_result_set_backtrace(priv->result, priv->backtrace);
1645 
1646     g_list_foreach(priv->backtrace, (GFunc)g_object_unref, NULL);
1647     g_list_free(priv->backtrace);
1648     priv->backtrace = NULL;
1649 }
1650 
1651 static void
end_result_backtrace_entry(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1652 end_result_backtrace_entry (CutStreamParser *parser,
1653                             CutStreamParserPrivate *priv,
1654                             GMarkupParseContext *context,
1655                             const gchar *element_name, GError **error)
1656 {
1657     if (!priv->backtrace_entry)
1658         return; /* should check file name, line, info? */
1659 
1660     priv->backtrace = g_list_prepend(priv->backtrace, priv->backtrace_entry);
1661     priv->backtrace_entry = NULL;
1662 }
1663 
1664 static void
end_ready_test_suite(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1665 end_ready_test_suite (CutStreamParser *parser, CutStreamParserPrivate *priv,
1666                       GMarkupParseContext *context,
1667                       const gchar *element_name, GError **error)
1668 {
1669     if (!priv->ready_test_suite)
1670         return;
1671 
1672     if (priv->run_context) {
1673         g_signal_emit_by_name(priv->run_context, "ready-test-suite",
1674                               priv->ready_test_suite->test_suite,
1675                               priv->ready_test_suite->n_test_cases,
1676                               priv->ready_test_suite->n_tests);
1677     }
1678 
1679     if (priv->ready_test_suite->test_suite)
1680         DROP_TEST_SUITE(priv);
1681     ready_test_suite_free(priv->ready_test_suite);
1682     priv->ready_test_suite = NULL;
1683 }
1684 
1685 static void
end_start_test_suite(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1686 end_start_test_suite (CutStreamParser *parser, CutStreamParserPrivate *priv,
1687                       GMarkupParseContext *context,
1688                       const gchar *element_name, GError **error)
1689 {
1690     CutTestSuite *test_suite;
1691 
1692     test_suite = POP_TEST_SUITE(priv);
1693     if (!test_suite)
1694         return;
1695 
1696     if (priv->run_context)
1697         g_signal_emit_by_name(priv->run_context, "start-test-suite", test_suite);
1698     g_object_unref(test_suite);
1699 }
1700 
1701 static void
end_ready_test_case(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1702 end_ready_test_case (CutStreamParser *parser, CutStreamParserPrivate *priv,
1703                      GMarkupParseContext *context,
1704                      const gchar *element_name, GError **error)
1705 {
1706     if (!priv->ready_test_case)
1707         return;
1708 
1709     if (priv->run_context) {
1710         g_signal_emit_by_name(priv->run_context, "ready-test-case",
1711                               priv->ready_test_case->test_case,
1712                               priv->ready_test_case->n_tests);
1713     }
1714 
1715     if (priv->ready_test_case->test_case)
1716         DROP_TEST_CASE(priv);
1717     ready_test_case_free(priv->ready_test_case);
1718     priv->ready_test_case = NULL;
1719 }
1720 
1721 static void
end_start_test_case(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1722 end_start_test_case (CutStreamParser *parser, CutStreamParserPrivate *priv,
1723                      GMarkupParseContext *context,
1724                      const gchar *element_name, GError **error)
1725 {
1726     CutTestCase *test_case;
1727 
1728     test_case = POP_TEST_CASE(priv);
1729     if (!test_case)
1730         return;
1731 
1732     if (priv->run_context)
1733         g_signal_emit_by_name(priv->run_context, "start-test-case", test_case);
1734 
1735     g_object_unref(test_case);
1736 }
1737 
1738 static void
end_ready_test_iterator(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1739 end_ready_test_iterator (CutStreamParser *parser, CutStreamParserPrivate *priv,
1740                          GMarkupParseContext *context,
1741                          const gchar *element_name, GError **error)
1742 {
1743     if (!priv->ready_test_iterator)
1744         return;
1745 
1746     if (priv->run_context) {
1747         g_signal_emit_by_name(priv->run_context, "ready-test-iterator",
1748                               priv->ready_test_iterator->test_iterator,
1749                               priv->ready_test_iterator->n_tests);
1750     }
1751 
1752     if (priv->ready_test_iterator->test_iterator)
1753         DROP_TEST_ITERATOR(priv);
1754     ready_test_iterator_free(priv->ready_test_iterator);
1755     priv->ready_test_iterator = NULL;
1756 }
1757 
1758 static void
end_start_test_iterator(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1759 end_start_test_iterator (CutStreamParser *parser, CutStreamParserPrivate *priv,
1760                          GMarkupParseContext *context,
1761                          const gchar *element_name, GError **error)
1762 {
1763     CutTestIterator *test_iterator;
1764 
1765     test_iterator = POP_TEST_ITERATOR(priv);
1766     if (!test_iterator)
1767         return;
1768 
1769     if (priv->run_context)
1770         g_signal_emit_by_name(priv->run_context,
1771                               "start-test-iterator",
1772                               test_iterator);
1773 
1774     g_object_unref(test_iterator);
1775 }
1776 
1777 static void
end_start_test(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1778 end_start_test (CutStreamParser *parser, CutStreamParserPrivate *priv,
1779                 GMarkupParseContext *context,
1780                 const gchar *element_name, GError **error)
1781 {
1782     if (!priv->start_test)
1783         return;
1784 
1785     if (priv->run_context) {
1786         g_signal_emit_by_name(priv->run_context, "start-test",
1787                               priv->start_test->test,
1788                               priv->start_test->test_context);
1789     }
1790 
1791     if (priv->start_test->test)
1792         DROP_TEST(priv);
1793     if (priv->start_test->test_context)
1794         DROP_TEST_CONTEXT(priv);
1795     start_test_free(priv->start_test);
1796     priv->start_test = NULL;
1797 }
1798 
1799 static void
end_start_iterated_test(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1800 end_start_iterated_test (CutStreamParser *parser, CutStreamParserPrivate *priv,
1801                          GMarkupParseContext *context,
1802                          const gchar *element_name, GError **error)
1803 {
1804     if (!priv->start_iterated_test)
1805         return;
1806 
1807     if (priv->run_context) {
1808         g_signal_emit_by_name(priv->run_context, "start-iterated-test",
1809                               priv->start_iterated_test->iterated_test,
1810                               priv->start_iterated_test->test_context);
1811     }
1812 
1813     if (priv->start_iterated_test->iterated_test)
1814         DROP_TEST(priv);
1815     if (priv->start_iterated_test->test_context)
1816         DROP_TEST_CONTEXT(priv);
1817     start_iterated_test_free(priv->start_iterated_test);
1818     priv->start_iterated_test = NULL;
1819 }
1820 
1821 static void
end_pass_assertion(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1822 end_pass_assertion (CutStreamParser *parser, CutStreamParserPrivate *priv,
1823                     GMarkupParseContext *context,
1824                     const gchar *element_name, GError **error)
1825 {
1826     if (!priv->pass_assertion)
1827         return;
1828 
1829     if (priv->run_context)
1830         g_signal_emit_by_name(priv->run_context, "pass-assertion",
1831                               priv->pass_assertion->test,
1832                               priv->pass_assertion->test_context);
1833 
1834     if (priv->pass_assertion->test)
1835         DROP_TEST(priv);
1836     if (priv->pass_assertion->test_context)
1837         DROP_TEST_CONTEXT(priv);
1838     pass_assertion_free(priv->pass_assertion);
1839     priv->pass_assertion = NULL;
1840 }
1841 
1842 static void
end_test_result(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1843 end_test_result (CutStreamParser *parser, CutStreamParserPrivate *priv,
1844                  GMarkupParseContext *context,
1845                  const gchar *element_name, GError **error)
1846 {
1847     if (!priv->test_result)
1848         return;
1849 
1850     if (priv->run_context) {
1851         CutTestResult *result;
1852         CutTestResultStatus status;
1853         const gchar *signal_name;
1854         gchar *full_signal_name;
1855 
1856         result = priv->test_result->result;
1857         status = cut_test_result_get_status(result);
1858         signal_name = cut_test_result_status_to_signal_name(status);
1859         full_signal_name = g_strdup_printf("%s-test", signal_name);
1860         g_signal_emit_by_name(priv->run_context, full_signal_name,
1861                               priv->test_result->test,
1862                               priv->test_result->test_context,
1863                               result);
1864         g_free(full_signal_name);
1865     }
1866 
1867     if (priv->test_result->test)
1868         DROP_TEST(priv);
1869     if (priv->test_result->test_context)
1870         DROP_TEST_CONTEXT(priv);
1871     test_result_free(priv->test_result);
1872     priv->test_result = NULL;
1873     priv->result = NULL;
1874 }
1875 
1876 static void
end_complete_iterated_test(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1877 end_complete_iterated_test (CutStreamParser *parser,
1878                             CutStreamParserPrivate *priv,
1879                             GMarkupParseContext *context,
1880                             const gchar *element_name, GError **error)
1881 {
1882     if (!priv->complete_iterated_test)
1883         return;
1884 
1885     if (priv->run_context)
1886         g_signal_emit_by_name(priv->run_context, "complete-iterated-test",
1887                               priv->complete_iterated_test->iterated_test,
1888                               priv->complete_iterated_test->test_context,
1889                               priv->complete_success);
1890 
1891     if (priv->complete_iterated_test->iterated_test)
1892         DROP_TEST(priv);
1893     if (priv->complete_iterated_test->test_context)
1894         DROP_TEST_CONTEXT(priv);
1895     complete_iterated_test_free(priv->complete_iterated_test);
1896     priv->complete_iterated_test = NULL;
1897 }
1898 
1899 static void
end_complete_test(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1900 end_complete_test (CutStreamParser *parser, CutStreamParserPrivate *priv,
1901                    GMarkupParseContext *context,
1902                    const gchar *element_name, GError **error)
1903 {
1904     if (!priv->complete_test)
1905         return;
1906 
1907     if (priv->run_context)
1908         g_signal_emit_by_name(priv->run_context, "complete-test",
1909                               priv->complete_test->test,
1910                               priv->complete_test->test_context,
1911                               priv->complete_success);
1912 
1913     if (priv->complete_test->test)
1914         DROP_TEST(priv);
1915     if (priv->complete_test->test_context)
1916         DROP_TEST_CONTEXT(priv);
1917     complete_test_free(priv->complete_test);
1918     priv->complete_test = NULL;
1919     priv->complete_success = TRUE;
1920 }
1921 
1922 static void
end_test_iterator_result(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1923 end_test_iterator_result (CutStreamParser *parser, CutStreamParserPrivate *priv,
1924                           GMarkupParseContext *context,
1925                           const gchar *element_name, GError **error)
1926 {
1927     if (!priv->test_iterator_result)
1928         return;
1929 
1930     if (priv->run_context) {
1931         CutTestResult *result;
1932         CutTestResultStatus status;
1933         const gchar *signal_name;
1934         gchar *full_signal_name;
1935 
1936         result = priv->test_iterator_result->result;
1937         status = cut_test_result_get_status(result);
1938         signal_name = cut_test_result_status_to_signal_name(status);
1939         full_signal_name = g_strdup_printf("%s-test-iterator", signal_name);
1940         g_signal_emit_by_name(priv->run_context, full_signal_name,
1941                               priv->test_iterator_result->test_iterator,
1942                               priv->test_iterator_result->result);
1943         g_free(full_signal_name);
1944     }
1945 
1946     if (priv->test_iterator_result->test_iterator)
1947         DROP_TEST_ITERATOR(priv);
1948     test_iterator_result_free(priv->test_iterator_result);
1949     priv->test_iterator_result = NULL;
1950     g_object_unref(priv->result);
1951     priv->result = NULL;
1952 }
1953 
1954 static void
end_complete_test_iterator(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1955 end_complete_test_iterator (CutStreamParser *parser,
1956                             CutStreamParserPrivate *priv,
1957                             GMarkupParseContext *context,
1958                             const gchar *element_name, GError **error)
1959 {
1960     CutTestIterator *test_iterator;
1961 
1962     test_iterator = POP_TEST_ITERATOR(priv);
1963     if (!test_iterator)
1964         return;
1965 
1966     if (priv->run_context)
1967         g_signal_emit_by_name(priv->run_context,
1968                               "complete-test-iterator", test_iterator,
1969                               priv->complete_success);
1970     g_object_unref(test_iterator);
1971     priv->complete_success = TRUE;
1972 }
1973 
1974 static void
end_test_case_result(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)1975 end_test_case_result (CutStreamParser *parser, CutStreamParserPrivate *priv,
1976                       GMarkupParseContext *context,
1977                       const gchar *element_name, GError **error)
1978 {
1979     if (!priv->test_case_result)
1980         return;
1981 
1982     if (priv->run_context) {
1983         CutTestResult *result;
1984         CutTestResultStatus status;
1985         const gchar *signal_name;
1986         gchar *full_signal_name;
1987 
1988         result = priv->test_case_result->result;
1989         status = cut_test_result_get_status(result);
1990         signal_name = cut_test_result_status_to_signal_name(status);
1991         full_signal_name = g_strdup_printf("%s-test-case", signal_name);
1992         g_signal_emit_by_name(priv->run_context, full_signal_name,
1993                               priv->test_case_result->test_case,
1994                               priv->test_case_result->result);
1995         g_free(full_signal_name);
1996     }
1997 
1998     if (priv->test_case_result->test_case)
1999         DROP_TEST_CASE(priv);
2000     test_case_result_free(priv->test_case_result);
2001     priv->test_case_result = NULL;
2002     g_object_unref(priv->result);
2003     priv->result = NULL;
2004 }
2005 
2006 static void
end_complete_test_case(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)2007 end_complete_test_case (CutStreamParser *parser, CutStreamParserPrivate *priv,
2008                         GMarkupParseContext *context,
2009                         const gchar *element_name, GError **error)
2010 {
2011     CutTestCase *test_case;
2012 
2013     test_case = POP_TEST_CASE(priv);
2014     if (!test_case)
2015         return;
2016 
2017     if (priv->run_context)
2018         g_signal_emit_by_name(priv->run_context,
2019                               "complete-test-case", test_case,
2020                               priv->complete_success);
2021     g_object_unref(test_case);
2022     priv->complete_success = TRUE;
2023 }
2024 
2025 static void
end_complete_test_suite(CutStreamParser * parser,CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * element_name,GError ** error)2026 end_complete_test_suite (CutStreamParser *parser, CutStreamParserPrivate *priv,
2027                          GMarkupParseContext *context,
2028                          const gchar *element_name, GError **error)
2029 {
2030     CutTestSuite *test_suite;
2031 
2032     test_suite = POP_TEST_SUITE(priv);
2033     if (!test_suite)
2034         return;
2035 
2036     if (priv->run_context)
2037         g_signal_emit_by_name(priv->run_context,
2038                               "complete-test-suite", test_suite,
2039                               priv->complete_success);
2040     g_object_unref(test_suite);
2041     priv->complete_success = TRUE;
2042 }
2043 
2044 static void
end_element_handler(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)2045 end_element_handler (GMarkupParseContext *context,
2046                      const gchar         *element_name,
2047                      gpointer             user_data,
2048                      GError             **error)
2049 {
2050     CutStreamParser *parser = user_data;
2051     CutStreamParserPrivate *priv;
2052     ParseState state;
2053 
2054     priv = CUT_STREAM_PARSER_GET_PRIVATE(parser);
2055 
2056     state = POP_STATE(priv);
2057     switch (state) {
2058     case IN_TOP_LEVEL_RESULT:
2059         end_top_level_result(parser, priv, context, element_name, error);
2060         break;
2061     case IN_STREAM:
2062         end_stream(parser, priv, context, element_name, error);
2063         break;
2064     case IN_RESULT:
2065         end_result(parser, priv, context, element_name, error);
2066         break;
2067     case IN_TEST_CONTEXT:
2068         end_test_context(parser, priv, context, element_name, error);
2069         break;
2070     case IN_TEST_OPTION:
2071         end_test_option(parser, priv, context, element_name, error);
2072         break;
2073     case IN_RESULT_BACKTRACE:
2074         end_result_backtrace(parser, priv, context, element_name, error);
2075         break;
2076     case IN_RESULT_BACKTRACE_ENTRY:
2077         end_result_backtrace_entry(parser, priv, context, element_name, error);
2078         break;
2079     case IN_READY_TEST_SUITE:
2080         end_ready_test_suite(parser, priv, context, element_name, error);
2081         break;
2082     case IN_START_TEST_SUITE:
2083         end_start_test_suite(parser, priv, context, element_name, error);
2084         break;
2085     case IN_READY_TEST_CASE:
2086         end_ready_test_case(parser, priv, context, element_name, error);
2087         break;
2088     case IN_START_TEST_CASE:
2089         end_start_test_case(parser, priv, context, element_name, error);
2090         break;
2091     case IN_READY_TEST_ITERATOR:
2092         end_ready_test_iterator(parser, priv, context, element_name, error);
2093         break;
2094     case IN_START_TEST_ITERATOR:
2095         end_start_test_iterator(parser, priv, context, element_name, error);
2096         break;
2097     case IN_START_TEST:
2098         end_start_test(parser, priv, context, element_name, error);
2099         break;
2100     case IN_START_ITERATED_TEST:
2101         end_start_iterated_test(parser, priv, context, element_name, error);
2102         break;
2103     case IN_PASS_ASSERTION:
2104         end_pass_assertion(parser, priv, context, element_name, error);
2105         break;
2106     case IN_TEST_RESULT:
2107         end_test_result(parser, priv, context, element_name, error);
2108         break;
2109     case IN_COMPLETE_ITERATED_TEST:
2110         end_complete_iterated_test(parser, priv, context, element_name, error);
2111         break;
2112     case IN_COMPLETE_TEST:
2113         end_complete_test(parser, priv, context, element_name, error);
2114         break;
2115     case IN_TEST_ITERATOR_RESULT:
2116         end_test_iterator_result(parser, priv, context, element_name, error);
2117         break;
2118     case IN_COMPLETE_TEST_ITERATOR:
2119         end_complete_test_iterator(parser, priv, context, element_name, error);
2120         break;
2121     case IN_TEST_CASE_RESULT:
2122         end_test_case_result(parser, priv, context, element_name, error);
2123         break;
2124     case IN_COMPLETE_TEST_CASE:
2125         end_complete_test_case(parser, priv, context, element_name, error);
2126         break;
2127     case IN_COMPLETE_TEST_SUITE:
2128         end_complete_test_suite(parser, priv, context, element_name, error);
2129         break;
2130     default:
2131         break;
2132     }
2133 
2134     g_free(g_queue_pop_tail(priv->element_stack));
2135 }
2136 
2137 static CutTestResultStatus
result_name_to_status(const gchar * name)2138 result_name_to_status (const gchar *name)
2139 {
2140     if (g_str_equal(name, "success"))
2141         return CUT_TEST_RESULT_SUCCESS;
2142     else if (g_str_equal(name, "failure"))
2143         return CUT_TEST_RESULT_FAILURE;
2144     else if (g_str_equal(name, "error"))
2145          return CUT_TEST_RESULT_ERROR;
2146     else if (g_str_equal(name, "pending"))
2147          return CUT_TEST_RESULT_PENDING;
2148     else if (g_str_equal(name, "notification"))
2149         return CUT_TEST_RESULT_NOTIFICATION;
2150     else if (g_str_equal(name, "omission"))
2151         return CUT_TEST_RESULT_OMISSION;
2152     else if (g_str_equal(name, "crash"))
2153         return CUT_TEST_RESULT_CRASH;
2154 
2155     return CUT_TEST_RESULT_INVALID;
2156 }
2157 
2158 static gboolean
is_integer(const gchar * str)2159 is_integer (const gchar *str)
2160 {
2161     gint i = 0;
2162 
2163     if (!str)
2164         return FALSE;
2165 
2166     while (str[i]) {
2167         if (!g_ascii_isdigit(str[i]))
2168             return FALSE;
2169         i++;
2170     }
2171     return TRUE;
2172 }
2173 
2174 static gboolean
is_boolean(const gchar * str)2175 is_boolean (const gchar *str)
2176 {
2177     if (!str)
2178         return FALSE;
2179 
2180     return g_ascii_strcasecmp(str, "true") == 0 ||
2181         g_ascii_strcasecmp(str, "false") == 0;
2182 }
2183 
2184 static gboolean
string_to_boolean(const gchar * string)2185 string_to_boolean (const gchar *string)
2186 {
2187     return g_ascii_strcasecmp("true", string) == 0;
2188 }
2189 
2190 static CutTest *
target_test_object(CutStreamParserPrivate * priv,ParseState parent_state)2191 target_test_object (CutStreamParserPrivate *priv, ParseState parent_state)
2192 {
2193     CutTest *target = NULL;
2194 
2195     switch (parent_state) {
2196       case IN_TEST_SUITE:
2197         target = CUT_TEST(PEEK_TEST_SUITE(priv));
2198         break;
2199       case IN_TEST_CASE:
2200         target = CUT_TEST(PEEK_TEST_CASE(priv));
2201         break;
2202       case IN_TEST_ITERATOR:
2203         target = CUT_TEST(PEEK_TEST_ITERATOR(priv));
2204         break;
2205       case IN_TEST:
2206       case IN_ITERATED_TEST:
2207         target = PEEK_TEST(priv);
2208         break;
2209       default:
2210         break;
2211     }
2212 
2213     return target;
2214 }
2215 
2216 static void
text_test_name(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2217 text_test_name (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2218                 const gchar *text, gsize text_len, GError **error)
2219 {
2220     CutTest *target;
2221 
2222     target = target_test_object(priv, PEEK_NTH_STATE(priv, 1));
2223     if (target) {
2224         cut_test_set_name(target, text);
2225     } else {
2226         set_parse_error(priv, context, error, "can't find test name target");
2227     }
2228 }
2229 
2230 static void
text_test_description(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2231 text_test_description (CutStreamParserPrivate *priv,
2232                        GMarkupParseContext *context,
2233                        const gchar *text, gsize text_len, GError **error)
2234 {
2235     CutTest *target;
2236 
2237     target = target_test_object(priv, PEEK_NTH_STATE(priv, 1));
2238     if (target) {
2239         cut_test_set_attribute(target, "description", text);
2240     } else {
2241         set_parse_error(priv, context, error,
2242                         "can't find test description target");
2243     }
2244 }
2245 
2246 static void
text_test_option_name(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2247 text_test_option_name (CutStreamParserPrivate *priv,
2248                        GMarkupParseContext *context,
2249                        const gchar *text, gsize text_len, GError **error)
2250 {
2251     if (priv->option_name) {
2252         set_parse_error(priv, context, error, "multiple option name: %s", text);
2253     } else {
2254         priv->option_name = g_strdup(text);
2255     }
2256 }
2257 
2258 static void
text_test_option_value(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2259 text_test_option_value (CutStreamParserPrivate *priv,
2260                         GMarkupParseContext *context,
2261                         const gchar *text, gsize text_len, GError **error)
2262 {
2263     if (priv->option_value) {
2264         set_parse_error(priv, context, error, "multiple option value: %s", text);
2265     } else {
2266         priv->option_value = g_strdup(text);
2267     }
2268 }
2269 
2270 static void
text_test_start_time(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2271 text_test_start_time (CutStreamParserPrivate *priv,
2272                       GMarkupParseContext *context,
2273                       const gchar *text, gsize text_len, GError **error)
2274 {
2275     CutTest *target;
2276 
2277     target = target_test_object(priv, PEEK_NTH_STATE(priv, 1));
2278     if (target) {
2279         GTimeVal start_time;
2280 
2281         if (g_time_val_from_iso8601(text, &start_time)) {
2282             cut_test_set_start_time(target, &start_time);
2283         } else {
2284             set_parse_error(priv, context, error,
2285                             "invalid start-time value (not ISO 8601 format): %s",
2286                             text);
2287         }
2288     } else {
2289         set_parse_error(priv, context, error,
2290                         "can't find test start time target");
2291     }
2292 }
2293 
2294 static void
text_test_elapsed(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2295 text_test_elapsed (CutStreamParserPrivate *priv,
2296                    GMarkupParseContext *context,
2297                    const gchar *text, gsize text_len, GError **error)
2298 {
2299     CutTest *target;
2300 
2301     target = target_test_object(priv, PEEK_NTH_STATE(priv, 1));
2302     if (target) {
2303         gdouble elapsed;
2304         gchar *end_position;
2305 
2306         elapsed = g_ascii_strtod(text, &end_position);
2307         if (text != end_position && end_position[0] == '\0') {
2308             cut_test_set_elapsed(target, elapsed);
2309         } else {
2310             set_parse_error(priv, context, error,
2311                             "invalid elapsed value: %s", text);
2312         }
2313     } else {
2314         set_parse_error(priv, context, error, "can't find test elapsed target");
2315     }
2316 }
2317 
2318 static void
text_result_status(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2319 text_result_status (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2320                     const gchar *text, gsize text_len, GError **error)
2321 {
2322     CutTestResultStatus status;
2323 
2324     status = result_name_to_status(text);
2325     if (status == CUT_TEST_RESULT_INVALID) {
2326         set_parse_error(priv, context, error, "invalid status: %s", text);
2327     } else {
2328         cut_test_result_set_status(priv->result, status);
2329     }
2330 }
2331 
2332 static void
text_result_detail(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2333 text_result_detail (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2334                     const gchar *text, gsize text_len, GError **error)
2335 {
2336     cut_test_result_set_message(priv->result, text);
2337 }
2338 
2339 static void
text_result_backtrace_entry_file(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2340 text_result_backtrace_entry_file (CutStreamParserPrivate *priv,
2341                                   GMarkupParseContext *context,
2342                                   const gchar *text, gsize text_len,
2343                                   GError **error)
2344 {
2345     cut_backtrace_entry_set_file(priv->backtrace_entry, text);
2346 }
2347 
2348 static void
text_result_backtrace_entry_line(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2349 text_result_backtrace_entry_line (CutStreamParserPrivate *priv,
2350                                   GMarkupParseContext *context,
2351                                   const gchar *text, gsize text_len,
2352                                   GError **error)
2353 {
2354     if (is_integer(text)) {
2355         cut_backtrace_entry_set_line(priv->backtrace_entry, atoi(text));
2356     } else {
2357         set_parse_error(priv, context, error, "invalid line number: %s", text);
2358     }
2359 }
2360 
2361 static void
text_result_backtrace_entry_info(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2362 text_result_backtrace_entry_info (CutStreamParserPrivate *priv,
2363                                   GMarkupParseContext *context,
2364                                   const gchar *text, gsize text_len,
2365                                   GError **error)
2366 {
2367     const gchar *info_start;
2368 
2369     info_start = strstr(text, "):");
2370     if (info_start) {
2371         gchar *function;
2372 
2373         function = g_strndup(text, info_start - text + strlen(")"));
2374         info_start += strlen("):");
2375         while (info_start[0] && info_start[0] == ' ')
2376             info_start++;
2377         cut_backtrace_entry_set_function(priv->backtrace_entry, function);
2378         cut_backtrace_entry_set_info(priv->backtrace_entry, info_start);
2379         g_free(function);
2380     } else if (g_str_has_suffix(text, ")") && strstr(text, "(")) {
2381         cut_backtrace_entry_set_function(priv->backtrace_entry, text);
2382     } else {
2383         cut_backtrace_entry_set_info(priv->backtrace_entry, text);
2384     }
2385 }
2386 
2387 
2388 static void
text_result_start_time(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2389 text_result_start_time (CutStreamParserPrivate *priv,
2390                         GMarkupParseContext *context,
2391                         const gchar *text, gsize text_len, GError **error)
2392 {
2393     GTimeVal start_time;
2394 
2395     if (g_time_val_from_iso8601(text, &start_time)) {
2396         cut_test_result_set_start_time(priv->result, &start_time);
2397     } else {
2398         set_parse_error(priv, context, error,
2399                         "invalid start-time value (not ISO 8601 format): %s",
2400                         text);
2401     }
2402 }
2403 
2404 static void
text_result_elapsed(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2405 text_result_elapsed (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2406                      const gchar *text, gsize text_len, GError **error)
2407 {
2408     gdouble elapsed;
2409     gchar *end_position;
2410 
2411     elapsed = g_ascii_strtod(text, &end_position);
2412     if (text != end_position && end_position[0] == '\0') {
2413         cut_test_result_set_elapsed(priv->result, elapsed);
2414     } else {
2415         set_parse_error(priv, context, error, "invalid elapsed value: %s", text);
2416     }
2417 }
2418 
2419 static void
text_result_expected(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2420 text_result_expected (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2421                       const gchar *text, gsize text_len, GError **error)
2422 {
2423     cut_test_result_set_expected(priv->result, text);
2424 }
2425 
2426 static void
text_result_actual(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2427 text_result_actual (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2428                     const gchar *text, gsize text_len, GError **error)
2429 {
2430     cut_test_result_set_actual(priv->result, text);
2431 }
2432 
2433 static void
text_result_diff(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2434 text_result_diff (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2435                   const gchar *text, gsize text_len, GError **error)
2436 {
2437     cut_test_result_set_diff(priv->result, text);
2438 }
2439 
2440 static void
text_result_folded_diff(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2441 text_result_folded_diff (CutStreamParserPrivate *priv,
2442                          GMarkupParseContext *context,
2443                          const gchar *text, gsize text_len, GError **error)
2444 {
2445     cut_test_result_set_folded_diff(priv->result, text);
2446 }
2447 
2448 static void
text_ready_test_suite_n_test_cases(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2449 text_ready_test_suite_n_test_cases (CutStreamParserPrivate *priv,
2450                                     GMarkupParseContext *context,
2451                                     const gchar *text, gsize text_len,
2452                                     GError **error)
2453 {
2454     if (is_integer(text)) {
2455         priv->ready_test_suite->n_test_cases = atoi(text);
2456     } else {
2457         set_parse_error(priv, context, error,
2458                         "invalid # of test cases: %s", text);
2459     }
2460 }
2461 
2462 static void
text_ready_test_suite_n_tests(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2463 text_ready_test_suite_n_tests (CutStreamParserPrivate *priv,
2464                                GMarkupParseContext *context,
2465                                const gchar *text, gsize text_len,
2466                                GError **error)
2467 {
2468     if (is_integer(text)) {
2469         priv->ready_test_suite->n_tests = atoi(text);
2470     } else {
2471         set_parse_error(priv, context, error, "invalid # of tests: %s", text);
2472     }
2473 }
2474 
2475 static void
text_ready_test_case_n_tests(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2476 text_ready_test_case_n_tests (CutStreamParserPrivate *priv,
2477                               GMarkupParseContext *context,
2478                               const gchar *text, gsize text_len, GError **error)
2479 {
2480     if (is_integer(text)) {
2481         priv->ready_test_case->n_tests = atoi(text);
2482     } else {
2483         set_parse_error(priv, context, error, "invalid # of tests: %s", text);
2484     }
2485 }
2486 
2487 static void
text_ready_test_iterator_n_tests(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2488 text_ready_test_iterator_n_tests (CutStreamParserPrivate *priv,
2489                                   GMarkupParseContext *context,
2490                                   const gchar *text, gsize text_len,
2491                                   GError **error)
2492 {
2493     if (is_integer(text)) {
2494         priv->ready_test_iterator->n_tests = atoi(text);
2495     } else {
2496         set_parse_error(priv, context, error, "invalid # of tests: %s", text);
2497     }
2498 }
2499 
2500 static void
text_test_data_name(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2501 text_test_data_name (CutStreamParserPrivate *priv,
2502                      GMarkupParseContext *context,
2503                      const gchar *text, gsize text_len, GError **error)
2504 {
2505     CutTestData *test_data;
2506 
2507     test_data = PEEK_TEST_DATA(priv);
2508     cut_test_data_set_name(test_data, text);
2509 }
2510 
2511 static void
text_test_context_failed(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2512 text_test_context_failed (CutStreamParserPrivate *priv,
2513                           GMarkupParseContext *context,
2514                           const gchar *text, gsize text_len, GError **error)
2515 {
2516     if (is_boolean(text)) {
2517         cut_test_context_set_failed(PEEK_TEST_CONTEXT(priv),
2518                                     string_to_boolean(text));
2519     } else {
2520         set_parse_error(priv, context, error, "invalid boolean value: %s", text);
2521     }
2522 }
2523 
2524 static void
text_complete_success(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2525 text_complete_success (CutStreamParserPrivate *priv,
2526                        GMarkupParseContext *context,
2527                        const gchar *text, gsize text_len, GError **error)
2528 {
2529     if (is_boolean(text)) {
2530         priv->complete_success = string_to_boolean(text);
2531     } else {
2532         set_parse_error(priv, context, error, "invalid boolean value: %s", text);
2533     }
2534 }
2535 
2536 static void
text_stream_success(CutStreamParserPrivate * priv,GMarkupParseContext * context,const gchar * text,gsize text_len,GError ** error)2537 text_stream_success (CutStreamParserPrivate *priv, GMarkupParseContext *context,
2538                      const gchar *text, gsize text_len, GError **error)
2539 {
2540     if (is_boolean(text)) {
2541         priv->stream_success = string_to_boolean(text);
2542     } else {
2543         set_parse_error(priv, context, error, "invalid boolean value: %s", text);
2544     }
2545 }
2546 
2547 static void
text_handler(GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** error)2548 text_handler (GMarkupParseContext *context,
2549               const gchar         *text,
2550               gsize                text_len,
2551               gpointer             user_data,
2552               GError             **error)
2553 {
2554     CutStreamParser *parser = user_data;
2555     CutStreamParserPrivate *priv;
2556     ParseState state;
2557 
2558     priv = CUT_STREAM_PARSER_GET_PRIVATE(parser);
2559 
2560     state = PEEK_STATE(priv);
2561     switch (state) {
2562     case IN_TEST_NAME:
2563         text_test_name(priv, context, text, text_len, error);
2564         break;
2565     case IN_TEST_DESCRIPTION:
2566         text_test_description(priv, context, text, text_len, error);
2567         break;
2568     case IN_TEST_OPTION_NAME:
2569         text_test_option_name(priv, context, text, text_len, error);
2570         break;
2571     case IN_TEST_OPTION_VALUE:
2572         text_test_option_value(priv, context, text, text_len, error);
2573         break;
2574     case IN_TEST_START_TIME:
2575         text_test_start_time(priv, context, text, text_len, error);
2576         break;
2577     case IN_TEST_ELAPSED:
2578         text_test_elapsed(priv, context, text, text_len, error);
2579         break;
2580     case IN_RESULT_STATUS:
2581         text_result_status(priv, context, text, text_len, error);
2582         break;
2583     case IN_RESULT_DETAIL:
2584         text_result_detail(priv, context, text, text_len, error);
2585         break;
2586     case IN_RESULT_BACKTRACE_ENTRY_FILE:
2587         text_result_backtrace_entry_file(priv, context, text, text_len, error);
2588         break;
2589     case IN_RESULT_BACKTRACE_ENTRY_LINE:
2590         text_result_backtrace_entry_line(priv, context, text, text_len, error);
2591         break;
2592     case IN_RESULT_BACKTRACE_ENTRY_INFO:
2593         text_result_backtrace_entry_info(priv, context, text, text_len, error);
2594         break;
2595     case IN_RESULT_START_TIME:
2596         text_result_start_time(priv, context, text, text_len, error);
2597         break;
2598     case IN_RESULT_ELAPSED:
2599         text_result_elapsed(priv, context, text, text_len, error);
2600         break;
2601     case IN_RESULT_EXPECTED:
2602         text_result_expected(priv, context, text, text_len, error);
2603         break;
2604     case IN_RESULT_ACTUAL:
2605         text_result_actual(priv, context, text, text_len, error);
2606         break;
2607     case IN_RESULT_DIFF:
2608         text_result_diff(priv, context, text, text_len, error);
2609         break;
2610     case IN_RESULT_FOLDED_DIFF:
2611         text_result_folded_diff(priv, context, text, text_len, error);
2612         break;
2613     case IN_READY_TEST_SUITE_N_TEST_CASES:
2614         text_ready_test_suite_n_test_cases(priv, context, text, text_len, error);
2615         break;
2616     case IN_READY_TEST_SUITE_N_TESTS:
2617         text_ready_test_suite_n_tests(priv, context, text, text_len, error);
2618         break;
2619     case IN_READY_TEST_CASE_N_TESTS:
2620         text_ready_test_case_n_tests(priv, context, text, text_len, error);
2621         break;
2622     case IN_READY_TEST_ITERATOR_N_TESTS:
2623         text_ready_test_iterator_n_tests(priv, context, text, text_len, error);
2624         break;
2625     case IN_TEST_DATA_NAME:
2626         text_test_data_name(priv, context, text, text_len, error);
2627         break;
2628     case IN_TEST_CONTEXT_FAILED:
2629         text_test_context_failed(priv, context, text, text_len, error);
2630         break;
2631     case IN_COMPLETE_SUCCESS:
2632         text_complete_success(priv, context, text, text_len, error);
2633     case IN_STREAM_SUCCESS:
2634         text_stream_success(priv, context, text, text_len, error);
2635         break;
2636     default:
2637         break;
2638     }
2639 }
2640 
2641 static void
error_handler(GMarkupParseContext * context,GError * error,gpointer user_data)2642 error_handler (GMarkupParseContext *context,
2643                GError              *error,
2644                gpointer             user_data)
2645 {
2646     /* should emit error signal to run_context? */
2647 }
2648 
2649 /*
2650 vi:ts=4:nowrap:ai:expandtab:sw=4
2651 */
2652