]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/atf/atf-run/test_program_test.cpp
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / contrib / atf / atf-run / test_program_test.cpp
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
41 namespace impl = atf::atf_run;
42 namespace detail = atf::atf_run::detail;
43
44 using atf::tests::vars_map;
45
46 // -------------------------------------------------------------------------
47 // Auxiliary functions.
48 // -------------------------------------------------------------------------
49
50 static
51 atf::fs::path
52 get_helper(const atf::tests::tc& tc, const char* name)
53 {
54     return atf::fs::path(tc.get_config_var("srcdir")) / name;
55 }
56
57 static
58 void
59 check_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
66 static void
67 check_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
75 static
76 void
77 write_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
85 static
86 void
87 print_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.
99 static
100 void
101 check_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
120 class 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
142 public:
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
157 ATF_TEST_CASE_WITHOUT_HEAD(tp_1);
158 ATF_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
185 ATF_TEST_CASE_WITHOUT_HEAD(tp_2);
186 ATF_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
219 ATF_TEST_CASE_WITHOUT_HEAD(tp_3);
220 ATF_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
251 ATF_TEST_CASE_WITHOUT_HEAD(tp_4);
252 ATF_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
274 ATF_TEST_CASE_WITHOUT_HEAD(tp_50);
275 ATF_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
294 ATF_TEST_CASE_WITHOUT_HEAD(tp_51);
295 ATF_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
317 ATF_TEST_CASE_WITHOUT_HEAD(tp_52);
318 ATF_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
340 ATF_TEST_CASE_WITHOUT_HEAD(tp_53);
341 ATF_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
362 ATF_TEST_CASE_WITHOUT_HEAD(tp_54);
363 ATF_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
383 ATF_TEST_CASE_WITHOUT_HEAD(tp_55);
384 ATF_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
404 ATF_TEST_CASE_WITHOUT_HEAD(tp_56);
405 ATF_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
426 ATF_TEST_CASE_WITHOUT_HEAD(tp_57);
427 ATF_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
448 ATF_TEST_CASE_WITHOUT_HEAD(tp_58);
449 ATF_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
470 ATF_TEST_CASE_WITHOUT_HEAD(tp_59);
471 ATF_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
493 ATF_TEST_CASE_WITHOUT_HEAD(tp_60);
494 ATF_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
520 ATF_TEST_CASE(atf_tps_writer);
521 ATF_TEST_CASE_HEAD(atf_tps_writer)
522 {
523     set_md_var("descr", "Verifies the application/X-atf-tps writer");
524 }
525 ATF_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
758 ATF_TEST_CASE(get_metadata_bad);
759 ATF_TEST_CASE_HEAD(get_metadata_bad) {}
760 ATF_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
766 ATF_TEST_CASE(get_metadata_zero_tcs);
767 ATF_TEST_CASE_HEAD(get_metadata_zero_tcs) {}
768 ATF_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
774 ATF_TEST_CASE(get_metadata_several_tcs);
775 ATF_TEST_CASE_HEAD(get_metadata_several_tcs) {}
776 ATF_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
818 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_death);
819 ATF_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
829 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_exit);
830 ATF_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
844 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_failure);
845 ATF_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
855 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_signal);
856 ATF_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
870 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_timeout);
871 ATF_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
881 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_failed);
882 ATF_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
892 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_passed);
893 ATF_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
903 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_skipped);
904 ATF_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
914 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_unknown);
915 ATF_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
924 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_failed);
925 ATF_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
933 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_skipped);
934 ATF_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
943 ATF_TEST_CASE(read_test_case_result_no_file);
944 ATF_TEST_CASE_HEAD(read_test_case_result_no_file) {}
945 ATF_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
950 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_empty_file);
951 ATF_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
957 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_invalid);
958 ATF_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
964 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_multiline);
965 ATF_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
977 ATF_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 }