]> git.stg.codes - stg.git/blobdiff - tests/tut/tut_posix.hpp
Finalize transition to Boost.UnitTest.
[stg.git] / tests / tut / tut_posix.hpp
diff --git a/tests/tut/tut_posix.hpp b/tests/tut/tut_posix.hpp
deleted file mode 100644 (file)
index c7cfe57..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-#ifndef TUT_FORK_H_GUARD
-#define TUT_FORK_H_GUARD
-#include <tut/tut_config.hpp>
-
-#if defined(TUT_USE_POSIX)
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <cstring>
-#include <cstdlib>
-#include <map>
-#include <iterator>
-#include <functional>
-
-#include "tut_result.hpp"
-#include "tut_assert.hpp"
-#include "tut_runner.hpp"
-
-namespace tut
-{
-
-template<typename, int>
-class test_group;
-
-template<typename T>
-class test_object;
-
-class test_group_posix
-{
-private:
-    template<typename, int>
-    friend class test_group;
-
-    template<typename T>
-    void send_result_(const T *obj, const test_result &tr)
-    {
-        if(obj->get_pipe_() == -1)
-        {
-            return;
-        }
-
-        if(tr.result != test_result::ok)
-        {
-            std::ostringstream ss;
-            ss << int(tr.result) << "\n"
-                << tr.group << "\n"
-                << tr.test << "\n"
-                << tr.name << "\n"
-                << tr.exception_typeid << "\n";
-            std::copy( tr.message.begin(), tr.message.end(), std::ostreambuf_iterator<char>(ss.rdbuf()) );
-
-            int size = ss.str().length();
-            int w = write(obj->get_pipe_(), ss.str().c_str(), size);
-            ensure_errno("write() failed", w == size);
-        }
-    }
-
-    virtual ~test_group_posix()
-    {
-    }
-};
-
-template<typename T>
-struct tut_posix
-{
-    pid_t fork()
-    {
-        test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
-        ensure("trying to call 'tut_fork' in ctor of test object", self != NULL);
-
-        return self->fork_();
-    }
-
-    pid_t waitpid(pid_t pid, int *status, int flags = 0)
-    {
-        test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
-        ensure("trying to call 'tut_waitpid' in ctor of test object", self != NULL);
-
-        return self->waitpid_(pid, status, flags);
-    }
-
-    void ensure_child_exit(pid_t pid, int exit_status = 0)
-    {
-        test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
-        ensure("trying to call 'ensure_child_exit' in ctor of test object", self != NULL);
-
-        int status;
-        self->waitpid_(pid, &status);
-
-        self->ensure_child_exit_(status, exit_status);
-    }
-
-
-    void ensure_child_signal(pid_t pid, int signal = SIGTERM)
-    {
-        test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
-        ensure("trying to call 'ensure_child_signal' in ctor of test object", self != NULL);
-
-        int status;
-        self->waitpid_(pid, &status);
-
-        self->ensure_child_signal_(status, signal);
-    }
-
-    std::set<pid_t> get_pids() const
-    {
-        using namespace std;
-
-        const test_object<T> *self = dynamic_cast< const tut::test_object<T>* >(this);
-        ensure("trying to call 'get_pids' in ctor of test object", self != NULL);
-
-        return self->get_pids_();
-    }
-
-    virtual ~tut_posix()
-    {
-    }
-
-};
-
-class test_object_posix
-{
-public:
-    typedef std::map<pid_t, int> pid_map;
-
-    /**
-     * Default constructor
-     */
-    test_object_posix()
-        : pids_(),
-          pipe_(-1)
-    {
-    }
-
-
-    virtual ~test_object_posix()
-    {
-        // we have forked
-        if(pipe_ != -1)
-        {
-            // in child, force exit
-            std::exit(0);
-        }
-
-        if(!pids_.empty())
-        {
-            std::ostringstream ss;
-
-            // in parent, reap children
-            for(std::map<pid_t, int>::iterator i = pids_.begin(); i != pids_.end(); ++i)
-            {
-                try {
-                    kill_child_(i->first);
-                } catch(const rethrown &ex) {
-                    ss << std::endl << "child " << ex.tr.pid << " has thrown an exception: " << ex.what();
-                } catch(const failure &ex) {
-                    ss << std::endl << ex.what();
-                }
-            }
-
-            if(!ss.str().empty())
-            {
-                fail(ss.str().c_str());
-            }
-        }
-    }
-
-private:
-    template<typename T>
-    friend class tut_posix;
-
-    friend class test_group_posix;
-
-    int get_pipe_() const
-    {
-        return pipe_;
-    }
-
-
-    pid_t fork_()
-    {
-        // create pipe
-        int fds[2];
-        ensure_errno("pipe() failed", ::pipe(fds) == 0);
-
-        pid_t pid = ::fork();
-
-        ensure_errno("fork() failed", pid >= 0);
-
-        if(pid != 0)
-        {
-            // in parent, register pid
-            ensure("duplicated child", pids_.insert( std::make_pair(pid, fds[0]) ).second);
-
-            // close writing side
-            close(fds[1]);
-        }
-        else
-        {
-            // in child, shutdown reporter
-            tut::runner.get().clear_callbacks();
-
-            // close reading side
-            close(fds[0]);
-            pipe_ = fds[1];
-        }
-
-        return pid;
-    }
-
-    void kill_child_(pid_t pid)
-    {
-        int status;
-
-        if(waitpid_(pid, &status, WNOHANG) == pid)
-        {
-            ensure_child_exit_(status, 0);
-            return;
-        }
-
-        if(::kill(pid, SIGTERM) != 0)
-        {
-            if(errno == ESRCH)
-            {
-                // no such process
-                return;
-            }
-            else
-            {
-                // cannot kill, we are in trouble
-                std::ostringstream ss;
-                char e[1024];
-                ss << "child " << pid << " could not be killed with SIGTERM, " << strerror_r(errno, e, sizeof(e)) << std::endl;
-                fail(ss.str());
-            }
-        }
-
-        if(waitpid_(pid, &status, WNOHANG) == pid)
-        {
-            // child killed, check signal
-            ensure_child_signal_(status, SIGTERM);
-
-            ensure_equals("child process exists after SIGTERM", ::kill(pid, 0), -1);
-            return;
-        }
-
-        // child seems to be still exiting, give it some time
-        sleep(2);
-
-        if(waitpid_(pid, &status, WNOHANG) != pid)
-        {
-            // child is still running, kill it
-            if(::kill(pid, SIGKILL) != 0)
-            {
-                if(errno == ESRCH)
-                {
-                    // no such process
-                    return;
-                }
-                else
-                {
-                    std::ostringstream ss;
-                    char e[1024];
-                    ss << "child " << pid << " could not be killed with SIGKILL, " << strerror_r(errno, e, sizeof(e)) << std::endl;
-                    fail(ss.str());
-                }
-            }
-
-            ensure_equals("wait after SIGKILL", waitpid_(pid, &status), pid);
-            ensure_child_signal_(status, SIGKILL);
-
-            ensure_equals("child process exists after SIGKILL", ::kill(pid, 0), -1);
-
-            std::ostringstream ss;
-            ss << "child " << pid << " had to be killed with SIGKILL";
-            fail(ss.str());
-        }
-    }
-
-    test_result receive_result_(std::istream &ss, pid_t pid)
-    {
-        test_result tr;
-
-        int type;
-        ss >> type;
-        tr.result = test_result::result_type(type);
-        ss.ignore(1024, '\n');
-
-        std::getline(ss, tr.group);
-        ss >> tr.test;
-        ss.ignore(1024, '\n');
-        std::getline(ss, tr.name);
-        std::getline(ss, tr.exception_typeid);
-        std::copy( std::istreambuf_iterator<char>(ss.rdbuf()),
-                   std::istreambuf_iterator<char>(),
-                   std::back_inserter(tr.message) );
-
-        tr.pid = pid;
-
-        return tr;
-    }
-
-    struct fdclose
-    {
-        fdclose(int fd): fd_(fd) { }
-        ~fdclose()
-        {
-            close(fd_);
-        }
-    private:
-        int fd_;
-    };
-
-    pid_t waitpid_(pid_t pid, int *status, int flags = 0)
-    {
-
-        ensure("trying to wait for unknown pid", pids_.count(pid) > 0);
-
-        pid_t p = ::waitpid(pid, status, flags);
-        if( (flags & WNOHANG) && (p != pid) )
-        {
-            return p;
-        }
-
-        // read child result from pipe
-        fd_set fdset;
-        timeval tv;
-        tv.tv_sec = 0;
-        tv.tv_usec = 0;
-
-        FD_ZERO(&fdset);
-
-        int pipe = pids_[pid];
-        fdclose guard(pipe);
-
-        FD_SET(pipe, &fdset);
-
-        int result = select(pipe+1, &fdset, NULL, NULL, &tv);
-        ensure_errno("sanity check on select() failed", result >= 0);
-
-        if(result > 0)
-        {
-            ensure("sanity check on FD_ISSET() failed", FD_ISSET(pipe, &fdset) );
-
-            std::stringstream ss;
-
-            //TODO: max failure length
-            char buffer[1024];
-            int r = read(pipe, buffer, sizeof(buffer));
-            ensure_errno("sanity check on read() failed", r >= 0);
-
-            if(r > 0)
-            {
-                ss.write(buffer, r);
-                throw rethrown( receive_result_(ss, pid) );
-            }
-        }
-
-        return pid;
-    }
-
-    void ensure_child_exit_(int status, int exit_status)
-    {
-        if(WIFSIGNALED(status))
-        {
-            std::ostringstream ss;
-            ss << "child killed by signal " << WTERMSIG(status)
-                << ": expected exit with code " << exit_status;
-
-            throw failure(ss.str().c_str());
-        }
-
-        if(WIFEXITED(status))
-        {
-            if(WEXITSTATUS(status) != exit_status)
-            {
-                std::ostringstream ss;
-                ss << "child exited, expected '"
-                    << exit_status
-                    << "' actual '"
-                    << WEXITSTATUS(status)
-                    << '\'';
-
-                throw failure(ss.str().c_str());
-            }
-        }
-
-        if(WIFSTOPPED(status))
-        {
-            std::ostringstream ss;
-            ss << "child stopped by signal " << WTERMSIG(status)
-                << ": expected exit with code " << exit_status;
-            throw failure(ss.str().c_str());
-        }
-    }
-
-    void ensure_child_signal_(int status, int signal)
-    {
-        if(WIFSIGNALED(status))
-        {
-            if(WTERMSIG(status) != signal)
-            {
-                std::ostringstream ss;
-                ss << "child killed by signal, expected '"
-                    << signal
-                    << "' actual '"
-                    << WTERMSIG(status)
-                    << '\'';
-                throw failure(ss.str().c_str());
-            }
-        }
-
-        if(WIFEXITED(status))
-        {
-            std::ostringstream ss;
-            ss << "child exited with code " << WEXITSTATUS(status)
-                << ": expected signal " << signal;
-
-            throw failure(ss.str().c_str());
-        }
-
-        if(WIFSTOPPED(status))
-        {
-            std::ostringstream ss;
-            ss << "child stopped by signal " << WTERMSIG(status)
-                << ": expected kill by signal " << signal;
-
-            throw failure(ss.str().c_str());
-        }
-    }
-
-    std::set<pid_t> get_pids_() const
-    {
-        using namespace std;
-
-        set<pid_t> pids;
-        for(pid_map::const_iterator i = pids_.begin(); i != pids_.end(); ++i)
-        {
-            pids.insert( i->first );
-        }
-
-        return pids;
-    }
-
-    pid_map         pids_;
-    int             pipe_;
-};
-
-} // namespace tut
-
-#else
-
-namespace tut
-{
-
-struct test_object_posix
-{
-    virtual ~test_object_posix()
-    {
-    }
-};
-
-struct test_group_posix
-{
-    template<typename T>
-    void send_result_(const T*, const test_result &)
-    {
-    }
-
-    virtual ~test_group_posix()
-    {
-    }
-};
-
-} // namespace tut
-
-#endif
-
-
-#endif
-