xref: /minix3/external/bsd/atf/dist/tools/test_program_test.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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 
40 namespace impl = tools::test_program;
41 namespace detail = tools::test_program::detail;
42 
43 // -------------------------------------------------------------------------
44 // Auxiliary functions.
45 // -------------------------------------------------------------------------
46 
47 namespace {
48 
49 typedef std::map< std::string, std::string > vars_map;
50 
51 static
52 tools::fs::path
get_helper(const atf::tests::tc & tc,const char * name)53 get_helper(const atf::tests::tc& tc, const char* name)
54 {
55     return tools::fs::path(tc.get_config_var("srcdir")) / name;
56 }
57 
58 static
59 void
check_property(const vars_map & props,const char * name,const char * value)60 check_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 
67 static void
check_result(const char * exp_state,const int exp_value,const char * exp_reason,const impl::test_case_result & tcr)68 check_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 
76 static
77 void
write_test_case_result(const char * results_path,const std::string & contents)78 write_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 
86 static
87 void
print_indented(const std::string & str)88 print_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.
100 static
101 void
check_match(const atf::tests::tc & tc,const std::string & str,const std::string & exp)102 check_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 
123 class tp_reader : protected detail::atf_tp_reader {
124     void
got_tc(const std::string & ident,const std::map<std::string,std::string> & md)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
got_eof(void)140     got_eof(void)
141     {
142         m_calls.push_back("got_eof()");
143     }
144 
145 public:
tp_reader(std::istream & is)146     tp_reader(std::istream& is) :
147         detail::atf_tp_reader(is)
148     {
149     }
150 
151     void
read(void)152     read(void)
153     {
154         atf_tp_reader::read();
155     }
156 
157     std::vector< std::string > m_calls;
158 };
159 
160 ATF_TEST_CASE_WITHOUT_HEAD(tp_1);
ATF_TEST_CASE_BODY(tp_1)161 ATF_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 
188 ATF_TEST_CASE_WITHOUT_HEAD(tp_2);
ATF_TEST_CASE_BODY(tp_2)189 ATF_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 
222 ATF_TEST_CASE_WITHOUT_HEAD(tp_3);
ATF_TEST_CASE_BODY(tp_3)223 ATF_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 
254 ATF_TEST_CASE_WITHOUT_HEAD(tp_4);
ATF_TEST_CASE_BODY(tp_4)255 ATF_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 
277 ATF_TEST_CASE_WITHOUT_HEAD(tp_50);
ATF_TEST_CASE_BODY(tp_50)278 ATF_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 
297 ATF_TEST_CASE_WITHOUT_HEAD(tp_51);
ATF_TEST_CASE_BODY(tp_51)298 ATF_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 
320 ATF_TEST_CASE_WITHOUT_HEAD(tp_52);
ATF_TEST_CASE_BODY(tp_52)321 ATF_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 
343 ATF_TEST_CASE_WITHOUT_HEAD(tp_53);
ATF_TEST_CASE_BODY(tp_53)344 ATF_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 
365 ATF_TEST_CASE_WITHOUT_HEAD(tp_54);
ATF_TEST_CASE_BODY(tp_54)366 ATF_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 
386 ATF_TEST_CASE_WITHOUT_HEAD(tp_55);
ATF_TEST_CASE_BODY(tp_55)387 ATF_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 
407 ATF_TEST_CASE_WITHOUT_HEAD(tp_56);
ATF_TEST_CASE_BODY(tp_56)408 ATF_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 
429 ATF_TEST_CASE_WITHOUT_HEAD(tp_57);
ATF_TEST_CASE_BODY(tp_57)430 ATF_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 
451 ATF_TEST_CASE_WITHOUT_HEAD(tp_58);
ATF_TEST_CASE_BODY(tp_58)452 ATF_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 
473 ATF_TEST_CASE_WITHOUT_HEAD(tp_59);
ATF_TEST_CASE_BODY(tp_59)474 ATF_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 
496 ATF_TEST_CASE_WITHOUT_HEAD(tp_60);
ATF_TEST_CASE_BODY(tp_60)497 ATF_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 
523 ATF_TEST_CASE(atf_tps_writer);
ATF_TEST_CASE_HEAD(atf_tps_writer)524 ATF_TEST_CASE_HEAD(atf_tps_writer)
525 {
526     set_md_var("descr", "Verifies the application/X-atf-tps writer");
527 }
ATF_TEST_CASE_BODY(atf_tps_writer)528 ATF_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 
761 ATF_TEST_CASE(get_metadata_bad);
ATF_TEST_CASE_HEAD(get_metadata_bad)762 ATF_TEST_CASE_HEAD(get_metadata_bad) {}
ATF_TEST_CASE_BODY(get_metadata_bad)763 ATF_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 
769 ATF_TEST_CASE(get_metadata_zero_tcs);
ATF_TEST_CASE_HEAD(get_metadata_zero_tcs)770 ATF_TEST_CASE_HEAD(get_metadata_zero_tcs) {}
ATF_TEST_CASE_BODY(get_metadata_zero_tcs)771 ATF_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 
777 ATF_TEST_CASE(get_metadata_several_tcs);
ATF_TEST_CASE_HEAD(get_metadata_several_tcs)778 ATF_TEST_CASE_HEAD(get_metadata_several_tcs) {}
ATF_TEST_CASE_BODY(get_metadata_several_tcs)779 ATF_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 
821 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_death);
ATF_TEST_CASE_BODY(parse_test_case_result_expected_death)822 ATF_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 
832 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_exit);
ATF_TEST_CASE_BODY(parse_test_case_result_expected_exit)833 ATF_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 
847 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_failure);
ATF_TEST_CASE_BODY(parse_test_case_result_expected_failure)848 ATF_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 
858 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_signal);
ATF_TEST_CASE_BODY(parse_test_case_result_expected_signal)859 ATF_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 
873 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_expected_timeout);
ATF_TEST_CASE_BODY(parse_test_case_result_expected_timeout)874 ATF_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 
884 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_failed);
ATF_TEST_CASE_BODY(parse_test_case_result_failed)885 ATF_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 
895 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_passed);
ATF_TEST_CASE_BODY(parse_test_case_result_passed)896 ATF_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 
906 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_skipped);
ATF_TEST_CASE_BODY(parse_test_case_result_skipped)907 ATF_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 
917 ATF_TEST_CASE_WITHOUT_HEAD(parse_test_case_result_unknown);
ATF_TEST_CASE_BODY(parse_test_case_result_unknown)918 ATF_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 
927 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_failed);
ATF_TEST_CASE_BODY(read_test_case_result_failed)928 ATF_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 
936 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_skipped);
ATF_TEST_CASE_BODY(read_test_case_result_skipped)937 ATF_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 
946 ATF_TEST_CASE(read_test_case_result_no_file);
ATF_TEST_CASE_HEAD(read_test_case_result_no_file)947 ATF_TEST_CASE_HEAD(read_test_case_result_no_file) {}
ATF_TEST_CASE_BODY(read_test_case_result_no_file)948 ATF_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 
953 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_empty_file);
ATF_TEST_CASE_BODY(read_test_case_result_empty_file)954 ATF_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 
960 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_invalid);
ATF_TEST_CASE_BODY(read_test_case_result_invalid)961 ATF_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 
967 ATF_TEST_CASE_WITHOUT_HEAD(read_test_case_result_multiline);
ATF_TEST_CASE_BODY(read_test_case_result_multiline)968 ATF_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 
ATF_INIT_TEST_CASES(tcs)980 ATF_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