⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tut_restartable.hpp

📁 VC源码,开源测试工具.有助于VC++的学习与开发
💻 HPP
字号:
#ifndef TUT_RESTARTABLE_H_GUARD#define TUT_RESTARTABLE_H_GUARD#include <tut/tut.hpp>#include <fstream>#include <iostream>#include <stdexcept>/** * Template Unit Tests Framework for C++. * http://tut.dozen.ru * * Optional restartable wrapper for test_runner. Allows to restart test runs * finished due to abnormal test application termination (such as segmentation * fault or math error). * * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com */namespace tut{    namespace util{    /** * Escapes non-alphabetical characters in string. */std::string escape(const std::string& orig){    std::string rc;    std::string::const_iterator i,e;    i = orig.begin();    e = orig.end();    while (i != e)    {        if ((*i >= 'a' && *i <= 'z') ||                (*i >= 'A' && *i <= 'Z') ||                (*i >= '0' && *i <= '9') )        {            rc += *i;        }        else        {            rc += '\\';            rc += ('a'+(((unsigned int)*i) >> 4));            rc += ('a'+(((unsigned int)*i) & 0xF));        }        ++i;    }    return rc;}/** * Un-escapes string. */std::string unescape(const std::string& orig){    std::string rc;    std::string::const_iterator i,e;    i = orig.begin();    e = orig.end();    while (i != e)    {        if (*i != '\\')        {            rc += *i;        }        else        {            ++i;            if (i == e)            {                throw std::invalid_argument("unexpected end of string");            }            unsigned int c1 = *i;            ++i;            if (i == e)            {                throw std::invalid_argument("unexpected end of string");            }            unsigned int c2 = *i;            rc += (((c1 - 'a') << 4) + (c2 - 'a'));        }        ++i;    }    return rc;}/** * Serialize test_result avoiding interfering with operator <<. */void serialize(std::ostream& os, const tut::test_result& tr){    os << escape(tr.group) << std::endl;    os << tr.test << ' ';    switch(tr.result)    {    case test_result::ok:        os << 0;        break;    case test_result::fail:        os << 1;        break;    case test_result::ex:        os << 2;        break;    case test_result::warn:        os << 3;        break;    case test_result::term:        os << 4;        break;    default:        throw std::logic_error("operator << : bad result_type");    }    os << ' ' << escape(tr.message) << std::endl;}/** * deserialization for test_result */void deserialize(std::istream& is, tut::test_result& tr){    std::getline(is,tr.group);    if (is.eof())    {        throw tut::no_more_tests();    }    tr.group = unescape(tr.group);    tr.test = -1;    is >> tr.test;    if (tr.test < 0)    {        throw std::logic_error("operator >> : bad test number");    }    int n = -1;    is >> n;    switch(n)    {    case 0:        tr.result = test_result::ok;        break;    case 1:        tr.result = test_result::fail;        break;    case 2:        tr.result = test_result::ex;        break;    case 3:        tr.result = test_result::warn;        break;    case 4:        tr.result = test_result::term;        break;    default:        throw std::logic_error("operator >> : bad result_type");    }    is.ignore(1); // space    std::getline(is,tr.message);    tr.message = unescape(tr.message);    if (!is.good())    {        throw std::logic_error("malformed test result");    }}};/** * Restartable test runner wrapper. */class restartable_wrapper{    test_runner& runner_;    callback* callback_;    std::string dir_;    std::string log_; // log file: last test being executed    std::string jrn_; // journal file: results of all executed testspublic:    /**     * Default constructor.     * @param dir Directory where to search/put log and journal files     */    restartable_wrapper(const std::string& dir = ".")        : runner_(runner.get()),           callback_(0),           dir_(dir)    {        // dozen: it works, but it would be better to use system path separator        jrn_ = dir_ + '/' + "journal.tut";        log_ = dir_ + '/' + "log.tut";    }    /**     * Stores another group for getting by name.     */    void register_group(const std::string& name, group_base* gr)    {        runner_.register_group(name,gr);    }    /**     * Stores callback object.     */    void set_callback(callback* cb)    {        callback_ = cb;    }    /**     * Returns callback object.     */    callback& get_callback() const    {        return runner_.get_callback();    }    /**     * Returns list of known test groups.     */    groupnames list_groups() const    {        return runner_.list_groups();    }    /**     * Runs all tests in all groups.     */    void run_tests() const    {        // where last run was failed        std::string fail_group;        int fail_test;        read_log_(fail_group,fail_test);        bool fail_group_reached = (fail_group == "");        // iterate over groups        tut::groupnames gn = list_groups();        tut::groupnames::const_iterator gni,gne;        gni = gn.begin();        gne = gn.end();        while (gni != gne)        {            // skip all groups before one that failed            if (!fail_group_reached)            {                if (*gni != fail_group)                {                    ++gni;                    continue;                }                fail_group_reached = true;            }            // first or restarted run            int test = (*gni == fail_group && fail_test >= 0) ? fail_test + 1 : 1;            while(true)            {                // last executed test pos                register_execution_(*gni,test);                try                {                    tut::test_result tr = runner_.run_test(*gni,test);                    register_test_(tr);                }                catch (const tut::beyond_last_test&)                {                    break;                }                catch(const tut::no_such_test&)                {                    // it's ok                }                ++test;            }            ++gni;        }        // show final results to user        invoke_callback_();        // truncate files as mark of successful finish        truncate_();    }private:    /**     * Shows results from journal file.     */    void invoke_callback_() const    {        runner_.set_callback(callback_);        runner_.get_callback().run_started();        std::string current_group;        std::ifstream ijournal(jrn_.c_str());        while (ijournal.good())        {            // read next test result            try            {                tut::test_result tr;                util::deserialize(ijournal,tr);                runner_.get_callback().test_completed(tr);            }            catch (const no_more_tests&)            {                break;            }        }        runner_.get_callback().run_completed();    }    /**     * Register test into journal.     */    void register_test_(const test_result& tr) const    {        std::ofstream ojournal(jrn_.c_str(), std::ios::app);        util::serialize(ojournal, tr);        ojournal << std::flush;        if (!ojournal.good())        {            throw std::runtime_error("unable to register test result in file "                + jrn_);        }    }    /**     * Mark the fact test going to be executed     */    void register_execution_(const std::string& grp, int test) const    {        // last executed test pos        std::ofstream olog(log_.c_str());        olog << util::escape(grp) << std::endl << test << std::endl << std::flush;        if (!olog.good())        {            throw std::runtime_error("unable to register execution in file "                + log_);        }    }    /**     * Truncate tests.     */    void truncate_() const    {        std::ofstream olog(log_.c_str());        std::ofstream ojournal(jrn_.c_str());    }    /**     * Read log file     */    void read_log_(std::string& fail_group, int& fail_test) const    {        // read failure point, if any        std::ifstream ilog(log_.c_str());        std::getline(ilog,fail_group);        fail_group = util::unescape(fail_group);        ilog >> fail_test;        if (!ilog.good())        {            fail_group = "";            fail_test = -1;            truncate_();        }        else        {            // test was terminated...            tut::test_result tr(fail_group, fail_test, "", tut::test_result::term);            register_test_(tr);        }    }};}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -