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_match(const atf::tests::tc& tc, const std::string& str,
102            const std::string& exp)
103{
104    if (!atf::text::match(str, exp)) {
105        std::cout << "String match 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: 300\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=300})",
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: 300\n"
228        "require.arch: thearch\n"
229        "require.config: foo-bar\n"
230        "require.files: /a/1 /b/2\n"
231        "require.machine: themachine\n"
232        "require.progs: /bin/cp mv\n"
233        "require.user: root\n"
234    ;
235
236    // NO_CHECK_STYLE_BEGIN
237    const char* exp_calls[] = {
238        "got_tc(single_test, {descr=Some description, ident=single_test, require.arch=thearch, require.config=foo-bar, require.files=/a/1 /b/2, require.machine=themachine, require.progs=/bin/cp mv, require.user=root, timeout=300})",
239        "got_eof()",
240        NULL
241    };
242    // NO_CHECK_STYLE_END
243
244    const char* exp_errors[] = {
245        NULL
246    };
247
248    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
249}
250
251ATF_TEST_CASE_WITHOUT_HEAD(tp_4);
252ATF_TEST_CASE_BODY(tp_4)
253{
254    const char* input =
255        "Content-Type: application/X-atf-tp; version=\"1\"\n"
256        "\n"
257        "ident:   single_test    \n"
258        "descr:      Some description	\n"
259    ;
260
261    const char* exp_calls[] = {
262        "got_tc(single_test, {descr=Some description, ident=single_test})",
263        "got_eof()",
264        NULL
265    };
266
267    const char* exp_errors[] = {
268        NULL
269    };
270
271    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
272}
273
274ATF_TEST_CASE_WITHOUT_HEAD(tp_50);
275ATF_TEST_CASE_BODY(tp_50)
276{
277    const char* input =
278        "Content-Type: application/X-atf-tp; version=\"1\"\n"
279        "\n"
280    ;
281
282    const char* exp_calls[] = {
283        NULL
284    };
285
286    const char* exp_errors[] = {
287        "3: Unexpected token `<<EOF>>'; expected property name",
288        NULL
289    };
290
291    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
292}
293
294ATF_TEST_CASE_WITHOUT_HEAD(tp_51);
295ATF_TEST_CASE_BODY(tp_51)
296{
297    const char* input =
298        "Content-Type: application/X-atf-tp; version=\"1\"\n"
299        "\n"
300        "\n"
301        "\n"
302        "\n"
303    ;
304
305    const char* exp_calls[] = {
306        NULL
307    };
308
309    const char* exp_errors[] = {
310        "3: Unexpected token `<<NEWLINE>>'; expected property name",
311        NULL
312    };
313
314    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
315}
316
317ATF_TEST_CASE_WITHOUT_HEAD(tp_52);
318ATF_TEST_CASE_BODY(tp_52)
319{
320    const char* input =
321        "Content-Type: application/X-atf-tp; version=\"1\"\n"
322        "\n"
323        "ident: test1\n"
324        "ident: test2\n"
325    ;
326
327    const char* exp_calls[] = {
328        "got_tc(test1, {ident=test1})",
329        "got_eof()",
330        NULL
331    };
332
333    const char* exp_errors[] = {
334        NULL
335    };
336
337    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
338}
339
340ATF_TEST_CASE_WITHOUT_HEAD(tp_53);
341ATF_TEST_CASE_BODY(tp_53)
342{
343    const char* input =
344        "Content-Type: application/X-atf-tp; version=\"1\"\n"
345        "\n"
346        "descr: Out of order\n"
347        "ident: test1\n"
348    ;
349
350    const char* exp_calls[] = {
351        NULL
352    };
353
354    const char* exp_errors[] = {
355        "3: First property of a test case must be 'ident'",
356        NULL
357    };
358
359    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
360}
361
362ATF_TEST_CASE_WITHOUT_HEAD(tp_54);
363ATF_TEST_CASE_BODY(tp_54)
364{
365    const char* input =
366        "Content-Type: application/X-atf-tp; version=\"1\"\n"
367        "\n"
368        "ident:\n"
369    ;
370
371    const char* exp_calls[] = {
372        NULL
373    };
374
375    const char* exp_errors[] = {
376        "3: The value for 'ident' cannot be empty",
377        NULL
378    };
379
380    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
381}
382
383ATF_TEST_CASE_WITHOUT_HEAD(tp_55);
384ATF_TEST_CASE_BODY(tp_55)
385{
386    const char* input =
387        "Content-Type: application/X-atf-tp; version=\"1\"\n"
388        "\n"
389        "ident: +*,\n"
390    ;
391
392    const char* exp_calls[] = {
393        NULL
394    };
395
396    const char* exp_errors[] = {
397        "3: The identifier must match ^[_A-Za-z0-9]+$; was '+*,'",
398        NULL
399    };
400
401    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
402}
403
404ATF_TEST_CASE_WITHOUT_HEAD(tp_56);
405ATF_TEST_CASE_BODY(tp_56)
406{
407    const char* input =
408        "Content-Type: application/X-atf-tp; version=\"1\"\n"
409        "\n"
410        "ident: test\n"
411        "timeout: hello\n"
412    ;
413
414    const char* exp_calls[] = {
415        NULL
416    };
417
418    const char* exp_errors[] = {
419        "4: The timeout property requires an integer value",
420        NULL
421    };
422
423    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
424}
425
426ATF_TEST_CASE_WITHOUT_HEAD(tp_57);
427ATF_TEST_CASE_BODY(tp_57)
428{
429    const char* input =
430        "Content-Type: application/X-atf-tp; version=\"1\"\n"
431        "\n"
432        "ident: test\n"
433        "unknown: property\n"
434    ;
435
436    const char* exp_calls[] = {
437        NULL
438    };
439
440    const char* exp_errors[] = {
441        "4: Unknown property 'unknown'",
442        NULL
443    };
444
445    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
446}
447
448ATF_TEST_CASE_WITHOUT_HEAD(tp_58);
449ATF_TEST_CASE_BODY(tp_58)
450{
451    const char* input =
452        "Content-Type: application/X-atf-tp; version=\"1\"\n"
453        "\n"
454        "ident: test\n"
455        "X-foo:\n"
456    ;
457
458    const char* exp_calls[] = {
459        NULL
460    };
461
462    const char* exp_errors[] = {
463        "4: The value for 'X-foo' cannot be empty",
464        NULL
465    };
466
467    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
468}
469
470ATF_TEST_CASE_WITHOUT_HEAD(tp_59);
471ATF_TEST_CASE_BODY(tp_59)
472{
473    const char* input =
474        "Content-Type: application/X-atf-tp; version=\"1\"\n"
475        "\n"
476        "\n"
477        "ident: test\n"
478        "timeout: 300\n"
479    ;
480
481    const char* exp_calls[] = {
482        NULL
483    };
484
485    const char* exp_errors[] = {
486        "3: Unexpected token `<<NEWLINE>>'; expected property name",
487        NULL
488    };
489
490    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
491}
492
493ATF_TEST_CASE_WITHOUT_HEAD(tp_60);
494ATF_TEST_CASE_BODY(tp_60)
495{
496    const char* input =
497        "Content-Type: application/X-atf-tp; version=\"1\"\n"
498        "\n"
499        "ident: test\n"
500        "require.memory: 12345D\n"
501    ;
502
503    const char* exp_calls[] = {
504        NULL
505    };
506
507    const char* exp_errors[] = {
508        "4: The require.memory property requires an integer value representing"
509        " an amount of bytes",
510        NULL
511    };
512
513    do_parser_test< tp_reader >(input, exp_calls, exp_errors);
514}
515
516// -------------------------------------------------------------------------
517// Tests for the "tps" writer.
518// -------------------------------------------------------------------------
519
520ATF_TEST_CASE(atf_tps_writer);
521ATF_TEST_CASE_HEAD(atf_tps_writer)
522{
523    set_md_var("descr", "Verifies the application/X-atf-tps writer");
524}
525ATF_TEST_CASE_BODY(atf_tps_writer)
526{
527    std::ostringstream expss;
528    std::ostringstream ss;
529    const char *ts_regex = "[0-9]+\\.[0-9]{1,6}, ";
530
531#define RESET \
532    expss.str(""); \
533    ss.str("")
534
535#define CHECK \
536    check_match(*this, ss.str(), expss.str())
537
538    {
539        RESET;
540
541        impl::atf_tps_writer w(ss);
542        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
543        CHECK;
544    }
545
546    {
547        RESET;
548
549        impl::atf_tps_writer w(ss);
550        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
551        CHECK;
552
553        w.info("foo", "bar");
554        expss << "info: foo, bar\n";
555        CHECK;
556
557        w.info("baz", "second info");
558        expss << "info: baz, second info\n";
559        CHECK;
560    }
561
562    {
563        RESET;
564
565        impl::atf_tps_writer w(ss);
566        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
567        CHECK;
568
569        w.ntps(0);
570        expss << "tps-count: 0\n";
571        CHECK;
572    }
573
574    {
575        RESET;
576
577        impl::atf_tps_writer w(ss);
578        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
579        CHECK;
580
581        w.ntps(123);
582        expss << "tps-count: 123\n";
583        CHECK;
584    }
585
586    {
587        RESET;
588
589        impl::atf_tps_writer w(ss);
590        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
591        CHECK;
592
593        w.ntps(2);
594        expss << "tps-count: 2\n";
595        CHECK;
596
597        w.start_tp("foo", 0);
598        expss << "tp-start: " << ts_regex << "foo, 0\n";
599        CHECK;
600
601        w.end_tp("");
602        expss << "tp-end: " << ts_regex << "foo\n";
603        CHECK;
604
605        w.start_tp("bar", 0);
606        expss << "tp-start: " << ts_regex << "bar, 0\n";
607        CHECK;
608
609        w.end_tp("failed program");
610        expss << "tp-end: " << ts_regex << "bar, failed program\n";
611        CHECK;
612    }
613
614    {
615        RESET;
616
617        impl::atf_tps_writer w(ss);
618        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
619        CHECK;
620
621        w.ntps(1);
622        expss << "tps-count: 1\n";
623        CHECK;
624
625        w.start_tp("foo", 1);
626        expss << "tp-start: " << ts_regex << "foo, 1\n";
627        CHECK;
628
629        w.start_tc("brokentc");
630        expss << "tc-start: " << ts_regex << "brokentc\n";
631        CHECK;
632
633        w.end_tp("aborted");
634        expss << "tp-end: " << ts_regex << "foo, aborted\n";
635        CHECK;
636    }
637
638    {
639        RESET;
640
641        impl::atf_tps_writer w(ss);
642        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
643        CHECK;
644
645        w.ntps(1);
646        expss << "tps-count: 1\n";
647        CHECK;
648
649        w.start_tp("thetp", 3);
650        expss << "tp-start: " << ts_regex << "thetp, 3\n";
651        CHECK;
652
653        w.start_tc("passtc");
654        expss << "tc-start: " << ts_regex << "passtc\n";
655        CHECK;
656
657        w.end_tc("passed", "");
658        expss << "tc-end: " << ts_regex << "passtc, passed\n";
659        CHECK;
660
661        w.start_tc("failtc");
662        expss << "tc-start: " << ts_regex << "failtc\n";
663        CHECK;
664
665        w.end_tc("failed", "The reason");
666        expss << "tc-end: " << ts_regex << "failtc, failed, The reason\n";
667        CHECK;
668
669        w.start_tc("skiptc");
670        expss << "tc-start: " << ts_regex << "skiptc\n";
671        CHECK;
672
673        w.end_tc("skipped", "The reason");
674        expss << "tc-end: " << ts_regex << "skiptc, skipped, The reason\n";
675        CHECK;
676
677        w.end_tp("");
678        expss << "tp-end: " << ts_regex << "thetp\n";
679        CHECK;
680    }
681
682    {
683        RESET;
684
685        impl::atf_tps_writer w(ss);
686        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
687        CHECK;
688
689        w.ntps(1);
690        expss << "tps-count: 1\n";
691        CHECK;
692
693        w.start_tp("thetp", 1);
694        expss << "tp-start: " << ts_regex << "thetp, 1\n";
695        CHECK;
696
697        w.start_tc("thetc");
698        expss << "tc-start: " << ts_regex << "thetc\n";
699        CHECK;
700
701        w.stdout_tc("a line");
702        expss << "tc-so:a line\n";
703        CHECK;
704
705        w.stdout_tc("another line");
706        expss << "tc-so:another line\n";
707        CHECK;
708
709        w.stderr_tc("an error message");
710        expss << "tc-se:an error message\n";
711        CHECK;
712
713        w.end_tc("passed", "");
714        expss << "tc-end: " << ts_regex << "thetc, passed\n";
715        CHECK;
716
717        w.end_tp("");
718        expss << "tp-end: " << ts_regex << "thetp\n";
719        CHECK;
720    }
721
722    {
723        RESET;
724
725        impl::atf_tps_writer w(ss);
726        expss << "Content-Type: application/X-atf-tps; version=\"3\"\n\n";
727        CHECK;
728
729        w.ntps(1);
730        expss << "tps-count: 1\n";
731        CHECK;
732
733        w.start_tp("thetp", 0);
734        expss << "tp-start: " << ts_regex << "thetp, 0\n";
735        CHECK;
736
737        w.end_tp("");
738        expss << "tp-end: " << ts_regex << "thetp\n";
739        CHECK;
740
741        w.info("foo", "bar");
742        expss << "info: foo, bar\n";
743        CHECK;
744
745        w.info("baz", "second value");
746        expss << "info: baz, second value\n";
747        CHECK;
748    }
749
750#undef CHECK
751#undef RESET
752}
753
754// -------------------------------------------------------------------------
755// Tests for the free functions.
756// -------------------------------------------------------------------------
757
758ATF_TEST_CASE(get_metadata_bad);
759ATF_TEST_CASE_HEAD(get_metadata_bad) {}
760ATF_TEST_CASE_BODY(get_metadata_bad) {
761    const atf::fs::path executable = get_helper(*this, "bad_metadata_helper");
762    ATF_REQUIRE_THROW(atf::parser::parse_errors,
763                    impl::get_metadata(executable, vars_map()));
764}
765
766ATF_TEST_CASE(get_metadata_zero_tcs);
767ATF_TEST_CASE_HEAD(get_metadata_zero_tcs) {}
768ATF_TEST_CASE_BODY(get_metadata_zero_tcs) {
769    const atf::fs::path executable = get_helper(*this, "zero_tcs_helper");
770    ATF_REQUIRE_THROW(atf::parser::parse_errors,
771                    impl::get_metadata(executable, vars_map()));
772}
773
774ATF_TEST_CASE(get_metadata_several_tcs);
775ATF_TEST_CASE_HEAD(get_metadata_several_tcs) {}
776ATF_TEST_CASE_BODY(get_metadata_several_tcs) {
777    const atf::fs::path executable = get_helper(*this, "several_tcs_helper");
778    const impl::metadata md = impl::get_metadata(executable, vars_map());
779    ATF_REQUIRE_EQ(3, md.test_cases.size());
780
781    {
782        const impl::test_cases_map::const_iterator iter =
783            md.test_cases.find("first");
784        ATF_REQUIRE(iter != md.test_cases.end());
785
786        ATF_REQUIRE_EQ(4, (*iter).second.size());
787        check_property((*iter).second, "descr", "Description 1");
788        check_property((*iter).second, "has.cleanup", "false");
789        check_property((*iter).second, "ident", "first");
790        check_property((*iter).second, "timeout", "300");
791    }
792
793    {
794        const impl::test_cases_map::const_iterator iter =
795            md.test_cases.find("second");
796        ATF_REQUIRE(iter != md.test_cases.end());
797
798        ATF_REQUIRE_EQ(5, (*iter).second.size());
799        check_property((*iter).second, "descr", "Description 2");
800        check_property((*iter).second, "has.cleanup", "true");
801        check_property((*iter).second, "ident", "second");
802        check_property((*iter).second, "timeout", "500");
803        check_property((*iter).second, "X-property", "Custom property");
804    }
805
806    {
807        const impl::test_cases_map::const_iterator iter =
808            md.test_cases.find("third");
809        ATF_REQUIRE(iter != md.test_cases.end());
810
811        ATF_REQUIRE_EQ(3, (*iter).second.size());
812        check_property((*iter).second, "has.cleanup", "false");
813        check_property((*iter).second, "ident", "third");
814        check_property((*iter).second, "timeout", "300");
815    }
816}
817
818ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_death);
819ATF_TEST_CASE_BODY(parse_test_case_result_expected_death) {
820    check_result("expected_death", -1, "foo bar",
821                 detail::parse_test_case_result("expected_death: foo bar"));
822
823    ATF_REQUIRE_THROW(std::runtime_error,
824                    detail::parse_test_case_result("expected_death"));
825    ATF_REQUIRE_THROW(std::runtime_error,
826                    detail::parse_test_case_result("expected_death(3): foo"));
827}
828
829ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_exit);
830ATF_TEST_CASE_BODY(parse_test_case_result_expected_exit) {
831    check_result("expected_exit", -1, "foo bar",
832                 detail::parse_test_case_result("expected_exit: foo bar"));
833    check_result("expected_exit", -1, "foo bar",
834                 detail::parse_test_case_result("expected_exit(): foo bar"));
835    check_result("expected_exit", 5, "foo bar",
836                 detail::parse_test_case_result("expected_exit(5): foo bar"));
837
838    ATF_REQUIRE_THROW(std::runtime_error,
839                    detail::parse_test_case_result("expected_exit"));
840    ATF_REQUIRE_THROW(std::runtime_error,
841                    detail::parse_test_case_result("expected_exit("));
842}
843
844ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_failure);
845ATF_TEST_CASE_BODY(parse_test_case_result_expected_failure) {
846    check_result("expected_failure", -1, "foo bar",
847                 detail::parse_test_case_result("expected_failure: foo bar"));
848
849    ATF_REQUIRE_THROW(std::runtime_error,
850                    detail::parse_test_case_result("expected_failure"));
851    ATF_REQUIRE_THROW(std::runtime_error,
852                    detail::parse_test_case_result("expected_failure(3): foo"));
853}
854
855ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_signal);
856ATF_TEST_CASE_BODY(parse_test_case_result_expected_signal) {
857    check_result("expected_signal", -1, "foo bar",
858                 detail::parse_test_case_result("expected_signal: foo bar"));
859    check_result("expected_signal", -1, "foo bar",
860                 detail::parse_test_case_result("expected_signal(): foo bar"));
861    check_result("expected_signal", 5, "foo bar",
862                 detail::parse_test_case_result("expected_signal(5): foo bar"));
863
864    ATF_REQUIRE_THROW(std::runtime_error,
865                    detail::parse_test_case_result("expected_signal"));
866    ATF_REQUIRE_THROW(std::runtime_error,
867                    detail::parse_test_case_result("expected_signal("));
868}
869
870ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_timeout);
871ATF_TEST_CASE_BODY(parse_test_case_result_expected_timeout) {
872    check_result("expected_timeout", -1, "foo bar",
873                 detail::parse_test_case_result("expected_timeout: foo bar"));
874
875    ATF_REQUIRE_THROW(std::runtime_error,
876                    detail::parse_test_case_result("expected_timeout"));
877    ATF_REQUIRE_THROW(std::runtime_error,
878                    detail::parse_test_case_result("expected_timeout(3): foo"));
879}
880
881ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_failed);
882ATF_TEST_CASE_BODY(parse_test_case_result_failed) {
883    check_result("failed", -1, "foo bar",
884                 detail::parse_test_case_result("failed: foo bar"));
885
886    ATF_REQUIRE_THROW(std::runtime_error,
887                    detail::parse_test_case_result("failed"));
888    ATF_REQUIRE_THROW(std::runtime_error,
889                    detail::parse_test_case_result("failed(3): foo"));
890}
891
892ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_passed);
893ATF_TEST_CASE_BODY(parse_test_case_result_passed) {
894    check_result("passed", -1, "",
895                 detail::parse_test_case_result("passed"));
896
897    ATF_REQUIRE_THROW(std::runtime_error,
898                    detail::parse_test_case_result("passed: foo"));
899    ATF_REQUIRE_THROW(std::runtime_error,
900                    detail::parse_test_case_result("passed(3): foo"));
901}
902
903ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_skipped);
904ATF_TEST_CASE_BODY(parse_test_case_result_skipped) {
905    check_result("skipped", -1, "foo bar",
906                 detail::parse_test_case_result("skipped: foo bar"));
907
908    ATF_REQUIRE_THROW(std::runtime_error,
909                    detail::parse_test_case_result("skipped"));
910    ATF_REQUIRE_THROW(std::runtime_error,
911                    detail::parse_test_case_result("skipped(3): foo"));
912}
913
914ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_unknown);
915ATF_TEST_CASE_BODY(parse_test_case_result_unknown) {
916    ATF_REQUIRE_THROW(std::runtime_error,
917                    detail::parse_test_case_result("foo"));
918    ATF_REQUIRE_THROW(std::runtime_error,
919                    detail::parse_test_case_result("bar: foo"));
920    ATF_REQUIRE_THROW(std::runtime_error,
921                    detail::parse_test_case_result("baz: foo"));
922}
923
924ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_failed);
925ATF_TEST_CASE_BODY(read_test_case_result_failed) {
926    write_test_case_result("resfile", "failed: foo bar\n");
927    const impl::test_case_result tcr = impl::read_test_case_result(
928        atf::fs::path("resfile"));
929    ATF_REQUIRE_EQ("failed", tcr.state());
930    ATF_REQUIRE_EQ("foo bar", tcr.reason());
931}
932
933ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_skipped);
934ATF_TEST_CASE_BODY(read_test_case_result_skipped) {
935    write_test_case_result("resfile", "skipped: baz bar\n");
936    const impl::test_case_result tcr = impl::read_test_case_result(
937        atf::fs::path("resfile"));
938    ATF_REQUIRE_EQ("skipped", tcr.state());
939    ATF_REQUIRE_EQ("baz bar", tcr.reason());
940}
941
942
943ATF_TEST_CASE(read_test_case_result_no_file);
944ATF_TEST_CASE_HEAD(read_test_case_result_no_file) {}
945ATF_TEST_CASE_BODY(read_test_case_result_no_file) {
946    ATF_REQUIRE_THROW(std::runtime_error,
947                    impl::read_test_case_result(atf::fs::path("resfile")));
948}
949
950ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_empty_file);
951ATF_TEST_CASE_BODY(read_test_case_result_empty_file) {
952    write_test_case_result("resfile", "");
953    ATF_REQUIRE_THROW(std::runtime_error,
954                    impl::read_test_case_result(atf::fs::path("resfile")));
955}
956
957ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_invalid);
958ATF_TEST_CASE_BODY(read_test_case_result_invalid) {
959    write_test_case_result("resfile", "passed: hello\n");
960    ATF_REQUIRE_THROW(std::runtime_error,
961                    impl::read_test_case_result(atf::fs::path("resfile")));
962}
963
964ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_multiline);
965ATF_TEST_CASE_BODY(read_test_case_result_multiline) {
966    write_test_case_result("resfile", "skipped: foo\nbar\n");
967    const impl::test_case_result tcr = impl::read_test_case_result(
968        atf::fs::path("resfile"));
969    ATF_REQUIRE_EQ("skipped", tcr.state());
970    ATF_REQUIRE_EQ("foo<<NEWLINE UNEXPECTED>>bar", tcr.reason());
971}
972
973// -------------------------------------------------------------------------
974// Main.
975// -------------------------------------------------------------------------
976
977ATF_INIT_TEST_CASES(tcs)
978{
979    ATF_ADD_TEST_CASE(tcs, tp_1);
980    ATF_ADD_TEST_CASE(tcs, tp_2);
981    ATF_ADD_TEST_CASE(tcs, tp_3);
982    ATF_ADD_TEST_CASE(tcs, tp_4);
983    ATF_ADD_TEST_CASE(tcs, tp_50);
984    ATF_ADD_TEST_CASE(tcs, tp_51);
985    ATF_ADD_TEST_CASE(tcs, tp_52);
986    ATF_ADD_TEST_CASE(tcs, tp_53);
987    ATF_ADD_TEST_CASE(tcs, tp_54);
988    ATF_ADD_TEST_CASE(tcs, tp_55);
989    ATF_ADD_TEST_CASE(tcs, tp_56);
990    ATF_ADD_TEST_CASE(tcs, tp_57);
991    ATF_ADD_TEST_CASE(tcs, tp_58);
992    ATF_ADD_TEST_CASE(tcs, tp_59);
993    ATF_ADD_TEST_CASE(tcs, tp_60);
994
995    ATF_ADD_TEST_CASE(tcs, atf_tps_writer);
996
997    ATF_ADD_TEST_CASE(tcs, get_metadata_bad);
998    ATF_ADD_TEST_CASE(tcs, get_metadata_zero_tcs);
999    ATF_ADD_TEST_CASE(tcs, get_metadata_several_tcs);
1000
1001    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_death);
1002    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_exit);
1003    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_failure);
1004    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_signal);
1005    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_expected_timeout);
1006    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_failed);
1007    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_passed);
1008    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_skipped);
1009    ATF_ADD_TEST_CASE(tcs, parse_test_case_result_unknown);
1010
1011    ATF_ADD_TEST_CASE(tcs, read_test_case_result_failed);
1012    ATF_ADD_TEST_CASE(tcs, read_test_case_result_skipped);
1013    ATF_ADD_TEST_CASE(tcs, read_test_case_result_no_file);
1014    ATF_ADD_TEST_CASE(tcs, read_test_case_result_empty_file);
1015    ATF_ADD_TEST_CASE(tcs, read_test_case_result_multiline);
1016    ATF_ADD_TEST_CASE(tcs, read_test_case_result_invalid);
1017
1018    // TODO: Add tests for run_test_case once all the missing functionality
1019    // is implemented.
1020}
1021