1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2010 The NetBSD Foundation, Inc.
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10// 1. Redistributions of source code must retain the above copyright
11//    notice, this list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright
13//    notice, this list of conditions and the following disclaimer in the
14//    documentation and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
30#include <fstream>
31#include <iostream>
32
33#include "atf-c++/macros.hpp"
34
35#include "atf-c++/detail/parser.hpp"
36#include "atf-c++/detail/test_helpers.hpp"
37#include "atf-c++/detail/text.hpp"
38
39#include "test-program.hpp"
40
41namespace impl = atf::atf_run;
42namespace detail = atf::atf_run::detail;
43
44using atf::tests::vars_map;
45
46// -------------------------------------------------------------------------
47// Auxiliary functions.
48// -------------------------------------------------------------------------
49
50static
51atf::fs::path
52get_helper(const atf::tests::tc& tc, const char* name)
53{
54    return atf::fs::path(tc.get_config_var("srcdir")) / name;
55}
56
57static
58void
59check_property(const vars_map& props, const char* name, const char* value)
60{
61    const vars_map::const_iterator iter = props.find(name);
62    ATF_REQUIRE(iter != props.end());
63    ATF_REQUIRE_EQ(value, (*iter).second);
64}
65
66static void
67check_result(const char* exp_state, const int exp_value, const char* exp_reason,
68             const impl::test_case_result& tcr)
69{
70    ATF_REQUIRE_EQ(exp_state, tcr.state());
71    ATF_REQUIRE_EQ(exp_value, tcr.value());
72    ATF_REQUIRE_EQ(exp_reason, tcr.reason());
73}
74
75static
76void
77write_test_case_result(const char *results_path, const std::string& contents)
78{
79    std::ofstream results_file(results_path);
80    ATF_REQUIRE(results_file);
81
82    results_file << contents;
83}
84
85static
86void
87print_indented(const std::string& str)
88{
89    std::vector< std::string > ws = atf::text::split(str, "\n");
90    for (std::vector< std::string >::const_iterator iter = ws.begin();
91         iter != ws.end(); iter++)
92        std::cout << ">>" << *iter << "<<\n";
93}
94
95// XXX Should this string handling and verbosity level be part of the
96// ATF_REQUIRE_EQ macro?  It may be hard to predict sometimes that a
97// string can have newlines in it, and so the error message generated
98// at the moment will be bogus if there are some.
99static
100void
101check_equal(const atf::tests::tc& tc, const std::string& str,
102            const std::string& exp)
103{
104    if (str != exp) {
105        std::cout << "String equality check failed.\n"
106                  << "Adding >> and << to delimit the string boundaries "
107                     "below.\n";
108        std::cout << "GOT:\n";
109        print_indented(str);
110        std::cout << "EXPECTED:\n";
111        print_indented(exp);
112        tc.fail("Constructed string differs from the expected one");
113    }
114}
115
116// -------------------------------------------------------------------------
117// Tests for the "tp" reader.
118// -------------------------------------------------------------------------
119
120class tp_reader : protected detail::atf_tp_reader {
121    void
122    got_tc(const std::string& ident,
123           const std::map< std::string, std::string >& md)
124    {
125        std::string call = "got_tc(" + ident + ", {";
126        for (std::map< std::string, std::string >::const_iterator iter =
127             md.begin(); iter != md.end(); iter++) {
128            if (iter != md.begin())
129                call += ", ";
130            call += (*iter).first + '=' + (*iter).second;
131        }
132        call += "})";
133        m_calls.push_back(call);
134    }
135
136    void
137    got_eof(void)
138    {
139        m_calls.push_back("got_eof()");
140    }
141
142public:
143    tp_reader(std::istream& is) :
144        detail::atf_tp_reader(is)
145    {
146    }
147
148    void
149    read(void)
150    {
151        atf_tp_reader::read();
152    }
153
154    std::vector< std::string > m_calls;
155};
156
157ATF_TEST_CASE_WITHOUT_HEAD(tp_1);
158ATF_TEST_CASE_BODY(tp_1)
159{
160    const char* input =
161        "Content-Type: application/X-atf-tp; version=\"1\"\n"
162        "\n"
163        "ident: test_case_1\n"
164        "\n"
165        "ident: test_case_2\n"
166        "\n"
167        "ident: test_case_3\n"
168    ;
169
170    const char* exp_calls[] = {
171        "got_tc(test_case_1, {ident=test_case_1})",
172        "got_tc(test_case_2, {ident=test_case_2})",
173        "got_tc(test_case_3, {ident=test_case_3})",
174        "got_eof()",
175        NULL
176    };
177
178    const char* exp_errors[] = {
179        NULL
180    };
181
182    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
183}
184
185ATF_TEST_CASE_WITHOUT_HEAD(tp_2);
186ATF_TEST_CASE_BODY(tp_2)
187{
188    const char* input =
189        "Content-Type: application/X-atf-tp; version=\"1\"\n"
190        "\n"
191        "ident: test_case_1\n"
192        "descr: This is the description\n"
193        "timeout: 30\n"
194        "\n"
195        "ident: test_case_2\n"
196        "\n"
197        "ident: test_case_3\n"
198        "X-prop1: A custom property\n"
199        "descr: Third test case\n"
200    ;
201
202    // NO_CHECK_STYLE_BEGIN
203    const char* exp_calls[] = {
204        "got_tc(test_case_1, {descr=This is the description, ident=test_case_1, timeout=30})",
205        "got_tc(test_case_2, {ident=test_case_2})",
206        "got_tc(test_case_3, {X-prop1=A custom property, descr=Third test case, ident=test_case_3})",
207        "got_eof()",
208        NULL
209    };
210    // NO_CHECK_STYLE_END
211
212    const char* exp_errors[] = {
213        NULL
214    };
215
216    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
217}
218
219ATF_TEST_CASE_WITHOUT_HEAD(tp_3);
220ATF_TEST_CASE_BODY(tp_3)
221{
222    const char* input =
223        "Content-Type: application/X-atf-tp; version=\"1\"\n"
224        "\n"
225        "ident: single_test\n"
226        "descr: Some description\n"
227        "timeout: 30\n"
228        "require.arch: thearch\n"
229        "require.config: foo-bar\n"
230        "require.machine: themachine\n"
231        "require.progs: /bin/cp mv\n"
232        "require.user: root\n"
233    ;
234
235    // NO_CHECK_STYLE_BEGIN
236    const char* exp_calls[] = {
237        "got_tc(single_test, {descr=Some description, ident=single_test, require.arch=thearch, require.config=foo-bar, require.machine=themachine, require.progs=/bin/cp mv, require.user=root, timeout=30})",
238        "got_eof()",
239        NULL
240    };
241    // NO_CHECK_STYLE_END
242
243    const char* exp_errors[] = {
244        NULL
245    };
246
247    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
248}
249
250ATF_TEST_CASE_WITHOUT_HEAD(tp_4);
251ATF_TEST_CASE_BODY(tp_4)
252{
253    const char* input =
254        "Content-Type: application/X-atf-tp; version=\"1\"\n"
255        "\n"
256        "ident:   single_test    \n"
257        "descr:      Some description	\n"
258    ;
259
260    const char* exp_calls[] = {
261        "got_tc(single_test, {descr=Some description, ident=single_test})",
262        "got_eof()",
263        NULL
264    };
265
266    const char* exp_errors[] = {
267        NULL
268    };
269
270    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
271}
272
273ATF_TEST_CASE_WITHOUT_HEAD(tp_50);
274ATF_TEST_CASE_BODY(tp_50)
275{
276    const char* input =
277        "Content-Type: application/X-atf-tp; version=\"1\"\n"
278        "\n"
279    ;
280
281    const char* exp_calls[] = {
282        NULL
283    };
284
285    const char* exp_errors[] = {
286        "3: Unexpected token `<<EOF>>'; expected property name",
287        NULL
288    };
289
290    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
291}
292
293ATF_TEST_CASE_WITHOUT_HEAD(tp_51);
294ATF_TEST_CASE_BODY(tp_51)
295{
296    const char* input =
297        "Content-Type: application/X-atf-tp; version=\"1\"\n"
298        "\n"
299        "\n"
300        "\n"
301        "\n"
302    ;
303
304    const char* exp_calls[] = {
305        NULL
306    };
307
308    const char* exp_errors[] = {
309        "3: Unexpected token `<<NEWLINE>>'; expected property name",
310        NULL
311    };
312
313    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
314}
315
316ATF_TEST_CASE_WITHOUT_HEAD(tp_52);
317ATF_TEST_CASE_BODY(tp_52)
318{
319    const char* input =
320        "Content-Type: application/X-atf-tp; version=\"1\"\n"
321        "\n"
322        "ident: test1\n"
323        "ident: test2\n"
324    ;
325
326    const char* exp_calls[] = {
327        "got_tc(test1, {ident=test1})",
328        "got_eof()",
329        NULL
330    };
331
332    const char* exp_errors[] = {
333        NULL
334    };
335
336    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
337}
338
339ATF_TEST_CASE_WITHOUT_HEAD(tp_53);
340ATF_TEST_CASE_BODY(tp_53)
341{
342    const char* input =
343        "Content-Type: application/X-atf-tp; version=\"1\"\n"
344        "\n"
345        "descr: Out of order\n"
346        "ident: test1\n"
347    ;
348
349    const char* exp_calls[] = {
350        NULL
351    };
352
353    const char* exp_errors[] = {
354        "3: First property of a test case must be 'ident'",
355        NULL
356    };
357
358    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
359}
360
361ATF_TEST_CASE_WITHOUT_HEAD(tp_54);
362ATF_TEST_CASE_BODY(tp_54)
363{
364    const char* input =
365        "Content-Type: application/X-atf-tp; version=\"1\"\n"
366        "\n"
367        "ident:\n"
368    ;
369
370    const char* exp_calls[] = {
371        NULL
372    };
373
374    const char* exp_errors[] = {
375        "3: The value for 'ident' cannot be empty",
376        NULL
377    };
378
379    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
380}
381
382ATF_TEST_CASE_WITHOUT_HEAD(tp_55);
383ATF_TEST_CASE_BODY(tp_55)
384{
385    const char* input =
386        "Content-Type: application/X-atf-tp; version=\"1\"\n"
387        "\n"
388        "ident: +*,\n"
389    ;
390
391    const char* exp_calls[] = {
392        NULL
393    };
394
395    const char* exp_errors[] = {
396        "3: The identifier must match ^[_A-Za-z0-9]+$; was '+*,'",
397        NULL
398    };
399
400    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
401}
402
403ATF_TEST_CASE_WITHOUT_HEAD(tp_56);
404ATF_TEST_CASE_BODY(tp_56)
405{
406    const char* input =
407        "Content-Type: application/X-atf-tp; version=\"1\"\n"
408        "\n"
409        "ident: test\n"
410        "timeout: hello\n"
411    ;
412
413    const char* exp_calls[] = {
414        NULL
415    };
416
417    const char* exp_errors[] = {
418        "4: The timeout property requires an integer value",
419        NULL
420    };
421
422    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
423}
424
425ATF_TEST_CASE_WITHOUT_HEAD(tp_57);
426ATF_TEST_CASE_BODY(tp_57)
427{
428    const char* input =
429        "Content-Type: application/X-atf-tp; version=\"1\"\n"
430        "\n"
431        "ident: test\n"
432        "unknown: property\n"
433    ;
434
435    const char* exp_calls[] = {
436        NULL
437    };
438
439    const char* exp_errors[] = {
440        "4: Unknown property 'unknown'",
441        NULL
442    };
443
444    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
445}
446
447ATF_TEST_CASE_WITHOUT_HEAD(tp_58);
448ATF_TEST_CASE_BODY(tp_58)
449{
450    const char* input =
451        "Content-Type: application/X-atf-tp; version=\"1\"\n"
452        "\n"
453        "ident: test\n"
454        "X-foo:\n"
455    ;
456
457    const char* exp_calls[] = {
458        NULL
459    };
460
461    const char* exp_errors[] = {
462        "4: The value for 'X-foo' cannot be empty",
463        NULL
464    };
465
466    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
467}
468
469ATF_TEST_CASE_WITHOUT_HEAD(tp_59);
470ATF_TEST_CASE_BODY(tp_59)
471{
472    const char* input =
473        "Content-Type: application/X-atf-tp; version=\"1\"\n"
474        "\n"
475        "\n"
476        "ident: test\n"
477        "timeout: 30\n"
478    ;
479
480    const char* exp_calls[] = {
481        NULL
482    };
483
484    const char* exp_errors[] = {
485        "3: Unexpected token `<<NEWLINE>>'; expected property name",
486        NULL
487    };
488
489    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
490}
491
492// -------------------------------------------------------------------------
493// Tests for the "tps" writer.
494// -------------------------------------------------------------------------
495
496ATF_TEST_CASE(atf_tps_writer);
497ATF_TEST_CASE_HEAD(atf_tps_writer)
498{
499    set_md_var("descr", "Verifies the application/X-atf-tps writer");
500}
501ATF_TEST_CASE_BODY(atf_tps_writer)
502{
503    std::ostringstream expss;
504    std::ostringstream ss;
505
506#define RESET \
507    expss.str(""); \
508    ss.str("")
509
510#define CHECK \
511    check_equal(*this, ss.str(), expss.str())
512
513    {
514        RESET;
515
516        impl::atf_tps_writer w(ss);
517        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
518        CHECK;
519    }
520
521    {
522        RESET;
523
524        impl::atf_tps_writer w(ss);
525        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
526        CHECK;
527
528        w.info("foo", "bar");
529        expss << "info: foo, bar\n";
530        CHECK;
531
532        w.info("baz", "second info");
533        expss << "info: baz, second info\n";
534        CHECK;
535    }
536
537    {
538        RESET;
539
540        impl::atf_tps_writer w(ss);
541        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
542        CHECK;
543
544        w.ntps(0);
545        expss << "tps-count: 0\n";
546        CHECK;
547    }
548
549    {
550        RESET;
551
552        impl::atf_tps_writer w(ss);
553        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
554        CHECK;
555
556        w.ntps(123);
557        expss << "tps-count: 123\n";
558        CHECK;
559    }
560
561    {
562        RESET;
563
564        impl::atf_tps_writer w(ss);
565        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
566        CHECK;
567
568        w.ntps(2);
569        expss << "tps-count: 2\n";
570        CHECK;
571
572        w.start_tp("foo", 0);
573        expss << "tp-start: foo, 0\n";
574        CHECK;
575
576        w.end_tp("");
577        expss << "tp-end: foo\n";
578        CHECK;
579
580        w.start_tp("bar", 0);
581        expss << "tp-start: bar, 0\n";
582        CHECK;
583
584        w.end_tp("failed program");
585        expss << "tp-end: bar, failed program\n";
586        CHECK;
587    }
588
589    {
590        RESET;
591
592        impl::atf_tps_writer w(ss);
593        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
594        CHECK;
595
596        w.ntps(1);
597        expss << "tps-count: 1\n";
598        CHECK;
599
600        w.start_tp("foo", 1);
601        expss << "tp-start: foo, 1\n";
602        CHECK;
603
604        w.start_tc("brokentc");
605        expss << "tc-start: brokentc\n";
606        CHECK;
607
608        w.end_tp("aborted");
609        expss << "tp-end: foo, aborted\n";
610        CHECK;
611    }
612
613    {
614        RESET;
615
616        impl::atf_tps_writer w(ss);
617        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
618        CHECK;
619
620        w.ntps(1);
621        expss << "tps-count: 1\n";
622        CHECK;
623
624        w.start_tp("thetp", 3);
625        expss << "tp-start: thetp, 3\n";
626        CHECK;
627
628        w.start_tc("passtc");
629        expss << "tc-start: passtc\n";
630        CHECK;
631
632        w.end_tc("passed", "");
633        expss << "tc-end: passtc, passed\n";
634        CHECK;
635
636        w.start_tc("failtc");
637        expss << "tc-start: failtc\n";
638        CHECK;
639
640        w.end_tc("failed", "The reason");
641        expss << "tc-end: failtc, failed, The reason\n";
642        CHECK;
643
644        w.start_tc("skiptc");
645        expss << "tc-start: skiptc\n";
646        CHECK;
647
648        w.end_tc("skipped", "The reason");
649        expss << "tc-end: skiptc, skipped, The reason\n";
650        CHECK;
651
652        w.end_tp("");
653        expss << "tp-end: thetp\n";
654        CHECK;
655    }
656
657    {
658        RESET;
659
660        impl::atf_tps_writer w(ss);
661        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
662        CHECK;
663
664        w.ntps(1);
665        expss << "tps-count: 1\n";
666        CHECK;
667
668        w.start_tp("thetp", 1);
669        expss << "tp-start: thetp, 1\n";
670        CHECK;
671
672        w.start_tc("thetc");
673        expss << "tc-start: thetc\n";
674        CHECK;
675
676        w.stdout_tc("a line");
677        expss << "tc-so:a line\n";
678        CHECK;
679
680        w.stdout_tc("another line");
681        expss << "tc-so:another line\n";
682        CHECK;
683
684        w.stderr_tc("an error message");
685        expss << "tc-se:an error message\n";
686        CHECK;
687
688        w.end_tc("passed", "");
689        expss << "tc-end: thetc, passed\n";
690        CHECK;
691
692        w.end_tp("");
693        expss << "tp-end: thetp\n";
694        CHECK;
695    }
696
697    {
698        RESET;
699
700        impl::atf_tps_writer w(ss);
701        expss << "Content-Type: application/X-atf-tps; version=\"2\"\n\n";
702        CHECK;
703
704        w.ntps(1);
705        expss << "tps-count: 1\n";
706        CHECK;
707
708        w.start_tp("thetp", 0);
709        expss << "tp-start: thetp, 0\n";
710        CHECK;
711
712        w.end_tp("");
713        expss << "tp-end: thetp\n";
714        CHECK;
715
716        w.info("foo", "bar");
717        expss << "info: foo, bar\n";
718        CHECK;
719
720        w.info("baz", "second value");
721        expss << "info: baz, second value\n";
722        CHECK;
723    }
724
725#undef CHECK
726#undef RESET
727}
728
729// -------------------------------------------------------------------------
730// Tests for the free functions.
731// -------------------------------------------------------------------------
732
733ATF_TEST_CASE(get_metadata_bad);
734ATF_TEST_CASE_HEAD(get_metadata_bad) {}
735ATF_TEST_CASE_BODY(get_metadata_bad) {
736    const atf::fs::path executable = get_helper(*this, "bad_metadata_helper");
737    ATF_REQUIRE_THROW(atf::parser::parse_errors,
738                    impl::get_metadata(executable, vars_map()));
739}
740
741ATF_TEST_CASE(get_metadata_zero_tcs);
742ATF_TEST_CASE_HEAD(get_metadata_zero_tcs) {}
743ATF_TEST_CASE_BODY(get_metadata_zero_tcs) {
744    const atf::fs::path executable = get_helper(*this, "zero_tcs_helper");
745    ATF_REQUIRE_THROW(atf::parser::parse_errors,
746                    impl::get_metadata(executable, vars_map()));
747}
748
749ATF_TEST_CASE(get_metadata_several_tcs);
750ATF_TEST_CASE_HEAD(get_metadata_several_tcs) {}
751ATF_TEST_CASE_BODY(get_metadata_several_tcs) {
752    const atf::fs::path executable = get_helper(*this, "several_tcs_helper");
753    const impl::metadata md = impl::get_metadata(executable, vars_map());
754    ATF_REQUIRE_EQ(3, md.test_cases.size());
755
756    {
757        const impl::test_cases_map::const_iterator iter =
758            md.test_cases.find("first");
759        ATF_REQUIRE(iter != md.test_cases.end());
760
761        ATF_REQUIRE_EQ(4, (*iter).second.size());
762        check_property((*iter).second, "descr", "Description 1");
763        check_property((*iter).second, "has.cleanup", "false");
764        check_property((*iter).second, "ident", "first");
765        check_property((*iter).second, "timeout", "30");
766    }
767
768    {
769        const impl::test_cases_map::const_iterator iter =
770            md.test_cases.find("second");
771        ATF_REQUIRE(iter != md.test_cases.end());
772
773        ATF_REQUIRE_EQ(5, (*iter).second.size());
774        check_property((*iter).second, "descr", "Description 2");
775        check_property((*iter).second, "has.cleanup", "true");
776        check_property((*iter).second, "ident", "second");
777        check_property((*iter).second, "timeout", "500");
778        check_property((*iter).second, "X-property", "Custom property");
779    }
780
781    {
782        const impl::test_cases_map::const_iterator iter =
783            md.test_cases.find("third");
784        ATF_REQUIRE(iter != md.test_cases.end());
785
786        ATF_REQUIRE_EQ(3, (*iter).second.size());
787        check_property((*iter).second, "has.cleanup", "false");
788        check_property((*iter).second, "ident", "third");
789        check_property((*iter).second, "timeout", "30");
790    }
791}
792
793ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_death);
794ATF_TEST_CASE_BODY(parse_test_case_result_expected_death) {
795    check_result("expected_death", -1, "foo bar",
796                 detail::parse_test_case_result("expected_death: foo bar"));
797
798    ATF_REQUIRE_THROW(std::runtime_error,
799                    detail::parse_test_case_result("expected_death"));
800    ATF_REQUIRE_THROW(std::runtime_error,
801                    detail::parse_test_case_result("expected_death(3): foo"));
802}
803
804ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_exit);
805ATF_TEST_CASE_BODY(parse_test_case_result_expected_exit) {
806    check_result("expected_exit", -1, "foo bar",
807                 detail::parse_test_case_result("expected_exit: foo bar"));
808    check_result("expected_exit", -1, "foo bar",
809                 detail::parse_test_case_result("expected_exit(): foo bar"));
810    check_result("expected_exit", 5, "foo bar",
811                 detail::parse_test_case_result("expected_exit(5): foo bar"));
812
813    ATF_REQUIRE_THROW(std::runtime_error,
814                    detail::parse_test_case_result("expected_exit"));
815    ATF_REQUIRE_THROW(std::runtime_error,
816                    detail::parse_test_case_result("expected_exit("));
817}
818
819ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_failure);
820ATF_TEST_CASE_BODY(parse_test_case_result_expected_failure) {
821    check_result("expected_failure", -1, "foo bar",
822                 detail::parse_test_case_result("expected_failure: foo bar"));
823
824    ATF_REQUIRE_THROW(std::runtime_error,
825                    detail::parse_test_case_result("expected_failure"));
826    ATF_REQUIRE_THROW(std::runtime_error,
827                    detail::parse_test_case_result("expected_failure(3): foo"));
828}
829
830ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_signal);
831ATF_TEST_CASE_BODY(parse_test_case_result_expected_signal) {
832    check_result("expected_signal", -1, "foo bar",
833                 detail::parse_test_case_result("expected_signal: foo bar"));
834    check_result("expected_signal", -1, "foo bar",
835                 detail::parse_test_case_result("expected_signal(): foo bar"));
836    check_result("expected_signal", 5, "foo bar",
837                 detail::parse_test_case_result("expected_signal(5): foo bar"));
838
839    ATF_REQUIRE_THROW(std::runtime_error,
840                    detail::parse_test_case_result("expected_signal"));
841    ATF_REQUIRE_THROW(std::runtime_error,
842                    detail::parse_test_case_result("expected_signal("));
843}
844
845ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_timeout);
846ATF_TEST_CASE_BODY(parse_test_case_result_expected_timeout) {
847    check_result("expected_timeout", -1, "foo bar",
848                 detail::parse_test_case_result("expected_timeout: foo bar"));
849
850    ATF_REQUIRE_THROW(std::runtime_error,
851                    detail::parse_test_case_result("expected_timeout"));
852    ATF_REQUIRE_THROW(std::runtime_error,
853                    detail::parse_test_case_result("expected_timeout(3): foo"));
854}
855
856ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_failed);
857ATF_TEST_CASE_BODY(parse_test_case_result_failed) {
858    check_result("failed", -1, "foo bar",
859                 detail::parse_test_case_result("failed: foo bar"));
860
861    ATF_REQUIRE_THROW(std::runtime_error,
862                    detail::parse_test_case_result("failed"));
863    ATF_REQUIRE_THROW(std::runtime_error,
864                    detail::parse_test_case_result("failed(3): foo"));
865}
866
867ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_passed);
868ATF_TEST_CASE_BODY(parse_test_case_result_passed) {
869    check_result("passed", -1, "",
870                 detail::parse_test_case_result("passed"));
871
872    ATF_REQUIRE_THROW(std::runtime_error,
873                    detail::parse_test_case_result("passed: foo"));
874    ATF_REQUIRE_THROW(std::runtime_error,
875                    detail::parse_test_case_result("passed(3): foo"));
876}
877
878ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_skipped);
879ATF_TEST_CASE_BODY(parse_test_case_result_skipped) {
880    check_result("skipped", -1, "foo bar",
881                 detail::parse_test_case_result("skipped: foo bar"));
882
883    ATF_REQUIRE_THROW(std::runtime_error,
884                    detail::parse_test_case_result("skipped"));
885    ATF_REQUIRE_THROW(std::runtime_error,
886                    detail::parse_test_case_result("skipped(3): foo"));
887}
888
889ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_unknown);
890ATF_TEST_CASE_BODY(parse_test_case_result_unknown) {
891    ATF_REQUIRE_THROW(std::runtime_error,
892                    detail::parse_test_case_result("foo"));
893    ATF_REQUIRE_THROW(std::runtime_error,
894                    detail::parse_test_case_result("bar: foo"));
895    ATF_REQUIRE_THROW(std::runtime_error,
896                    detail::parse_test_case_result("baz: foo"));
897}
898
899ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_failed);
900ATF_TEST_CASE_BODY(read_test_case_result_failed) {
901    write_test_case_result("resfile", "failed: foo bar\n");
902    const impl::test_case_result tcr = impl::read_test_case_result(
903        atf::fs::path("resfile"));
904    ATF_REQUIRE_EQ("failed", tcr.state());
905    ATF_REQUIRE_EQ("foo bar", tcr.reason());
906}
907
908ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_skipped);
909ATF_TEST_CASE_BODY(read_test_case_result_skipped) {
910    write_test_case_result("resfile", "skipped: baz bar\n");
911    const impl::test_case_result tcr = impl::read_test_case_result(
912        atf::fs::path("resfile"));
913    ATF_REQUIRE_EQ("skipped", tcr.state());
914    ATF_REQUIRE_EQ("baz bar", tcr.reason());
915}
916
917
918ATF_TEST_CASE(read_test_case_result_no_file);
919ATF_TEST_CASE_HEAD(read_test_case_result_no_file) {}
920ATF_TEST_CASE_BODY(read_test_case_result_no_file) {
921    ATF_REQUIRE_THROW(std::runtime_error,
922                    impl::read_test_case_result(atf::fs::path("resfile")));
923}
924
925ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_empty_file);
926ATF_TEST_CASE_BODY(read_test_case_result_empty_file) {
927    write_test_case_result("resfile", "");
928    ATF_REQUIRE_THROW(std::runtime_error,
929                    impl::read_test_case_result(atf::fs::path("resfile")));
930}
931
932ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_invalid);
933ATF_TEST_CASE_BODY(read_test_case_result_invalid) {
934    write_test_case_result("resfile", "passed: hello\n");
935    ATF_REQUIRE_THROW(std::runtime_error,
936                    impl::read_test_case_result(atf::fs::path("resfile")));
937}
938
939ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_multiline);
940ATF_TEST_CASE_BODY(read_test_case_result_multiline) {
941    write_test_case_result("resfile", "skipped: foo\nbar\n");
942    const impl::test_case_result tcr = impl::read_test_case_result(
943        atf::fs::path("resfile"));
944    ATF_REQUIRE_EQ("skipped", tcr.state());
945    ATF_REQUIRE_EQ("foo<<NEWLINE UNEXPECTED>>bar", tcr.reason());
946}
947
948// -------------------------------------------------------------------------
949// Main.
950// -------------------------------------------------------------------------
951
952ATF_INIT_TEST_CASES(tcs)
953{
954    ATF_ADD_TEST_CASE(tcs, tp_1);
955    ATF_ADD_TEST_CASE(tcs, tp_2);
956    ATF_ADD_TEST_CASE(tcs, tp_3);
957    ATF_ADD_TEST_CASE(tcs, tp_4);
958    ATF_ADD_TEST_CASE(tcs, tp_50);
959    ATF_ADD_TEST_CASE(tcs, tp_51);
960    ATF_ADD_TEST_CASE(tcs, tp_52);
961    ATF_ADD_TEST_CASE(tcs, tp_53);
962    ATF_ADD_TEST_CASE(tcs, tp_54);
963    ATF_ADD_TEST_CASE(tcs, tp_55);
964    ATF_ADD_TEST_CASE(tcs, tp_56);
965    ATF_ADD_TEST_CASE(tcs, tp_57);
966    ATF_ADD_TEST_CASE(tcs, tp_58);
967    ATF_ADD_TEST_CASE(tcs, tp_59);
968
969    ATF_ADD_TEST_CASE(tcs, atf_tps_writer);
970
971    ATF_ADD_TEST_CASE(tcs, get_metadata_bad);
972    ATF_ADD_TEST_CASE(tcs, get_metadata_zero_tcs);
973    ATF_ADD_TEST_CASE(tcs, get_metadata_several_tcs);
974
975    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_death);
976    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_exit);
977    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_failure);
978    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_signal);
979    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_timeout);
980    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_failed);
981    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_passed);
982    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_skipped);
983    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_unknown);
984
985    ATF_ADD_TEST_CASE(tcs, read_test_case_result_no_file);
986    ATF_ADD_TEST_CASE(tcs, read_test_case_result_empty_file);
987    ATF_ADD_TEST_CASE(tcs, read_test_case_result_multiline);
988    ATF_ADD_TEST_CASE(tcs, read_test_case_result_invalid);
989
990    // TODO: Add tests for run_test_case once all the missing functionality
991    // is implemented.
992}
993