f99aq8ove's blog

TAP on C++

tag: C++ and tap
23 June 2008

このエントリは 2008-06-23 に書かれました。 内容が古くなっていたり、もはや正しくないこともありますので、十分検証を行ってください。

Test Anything Protocol - TAP ですが、なんとなく C++ で実装してみました。

tap.hpp

#ifndef TAP_HPP_526c07e9e0a11dc15e7838c85f7e46780782392d
#define TAP_HPP_526c07e9e0a11dc15e7838c85f7e46780782392d

#include <string>
#include <iostream>

namespace tap {
    size_t tests__ = 0;
    size_t numof_tested__ = 0;

    void tests(size_t n) {
        tests__ = n;
        std::cout << "1.." << n << std::endl;
    }

    void ok_notok__(bool is_ok, const std::string& name) {
        std::cout << (is_ok ? "ok " : "not ok ") << ++numof_tested__ << " - " << name << std::endl;
    }

    template <typename T, typename U> void is__(const std::string& file, size_t line,
            T got, U expected, const std::string& name = "") {
        if (got != expected) {
            ok_notok__(false, name);
            std::cerr
                << "#   Failed test '" << name << "'\n"
                << "#   at " << file << " line " << line << ".\n"
                << "#          got: '" << got << "'\n"
                << "#     expected: '" << expected << "'" << std::endl;
        } else {
            ok_notok__(true, name);
        }
    }

    template <typename T, typename U> void isnt__(const std::string& file, size_t line,
            T got, U expected, const std::string& name = "") {
        if (got == expected) {
            ok_notok__(false, name);
            std::cerr
                << "#   Failed test '" << name << "'\n"
                << "#   at " << file << " line " << line << ".\n"
                << "#     '" << got << "'\n"
                << "#         ne\n"
                << "#     '" << expected << "'" << std::endl;
        } else {
            ok_notok__(true, name);
        }
    }

    void fail__(const std::string& file, size_t line, const std::string& name) {
        ok_notok__(false, name);
        std::cerr
            << "#   Failed test '" << name << "'\n"
            << "#   at " << file << " line " << line << std::endl;
    }

    void diag__(const std::string& d) {
        std::cerr << "# " << d << std::endl;
    }
}

#define is(g, e, n) tap::is__(__FILE__, __LINE__, (g), (e), (n))
#define isnt(g, e, n) tap::isnt__(__FILE__, __LINE__, (g), (e), (n))
#define fail(n) tap::fail__(__FILE__, __LINE__, (n))
#define diag(d) tap::diag__((d))

#endif

こんな風に使います。

#include "tap.hpp"

#include <iostream>
#include <string>

using namespace std;

int main(void) {
    tap::tests(6);
    is(1, 3, "hoge");
    string hoge = "hoge";
    string geho = "hoge";
    isnt(hoge, geho, "hoge");
    isnt(0, 0, "hoge");
    fail("asdf");
    is(0, 0, "asf");
    diag("asdf");
    return 0;
}

実行すると…。

% g++ -Wall -Wextra test.cpp && ./a.out
1..6
not ok 1 - hoge
#   Failed test 'hoge'
#   at test.cpp line 10.
#          got: '1'
#     expected: '3'
not ok 2 - hoge
#   Failed test 'hoge'
#   at test.cpp line 13.
#     'hoge'
#         ne
#     'hoge'
not ok 3 - hoge
#   Failed test 'hoge'
#   at test.cpp line 14.
#     '0'
#         ne
#     '0'
not ok 4 - asdf
#   Failed test 'asdf'
#   at test.cpp line 15
ok 5 - asf
# asdf

a.t を用意して…。

#!/bin/sh
./a.out
% prove -v ./a.t
./a......
1..6
not ok 1 - hoge
not ok 2 - hoge
not ok 3 - hoge
not ok 4 - asdf
ok 5 - asf
#   Failed test 'hoge'
#   at test.cpp line 10.
#          got: '1'
#     expected: '3'
#   Failed test 'hoge'
#   at test.cpp line 13.
#     'hoge'
#         ne
#     'hoge'
#   Failed test 'hoge'
#   at test.cpp line 14.
#     '0'
#         ne
#     '0'
#   Failed test 'asdf'
#   at test.cpp line 15
# asdf
 Failed 5/6 subtests

Test Summary Report
-------------------
./a.t (Wstat: 0 Tests: 5 Failed: 4)
  Failed tests:  1-4
  Parse errors: Bad plan.  You planned 6 tests but ran 5.
Files=1, Tests=5,  0 wallclock secs ( 0.03 usr +  0.01 sys =  0.04 CPU)
Result: FAIL
[1]    3716 exit 1     prove -v ./a.t

こうなる。

freeHG にあげときました。BSL1.0 です。utils: Manifest

テストに失敗したときの戻り値を…には、まだ対応していません。

Related Posts