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