Home | History | Annotate | Line # | Download | only in tools
test_program_test.cpp revision 1.1.1.1.4.2
      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
     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
     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
     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
     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
     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
    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
    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 
    145 public:
    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 
    160 ATF_TEST_CASE_WITHOUT_HEAD(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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    524 ATF_TEST_CASE_HEAD(atf_tps_writer)
    525 {
    526     set_md_var("descr", "Verifies the application/X-atf-tps writer");
    527 }
    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);
    762 ATF_TEST_CASE_HEAD(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);
    770 ATF_TEST_CASE_HEAD(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);
    778 ATF_TEST_CASE_HEAD(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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    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);
    947 ATF_TEST_CASE_HEAD(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);
    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);
    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);
    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 
    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