testrunner.hpp

Back to Unit testing

pastel/sys/testing/

#ifndef PASTELSYS_TESTRUNNER_HPP
#define PASTELSYS_TESTRUNNER_HPP

#include "pastel/sys/testing/testrunner.h"
#include "pastel/sys/ensure.h"
#include "pastel/sys/logging/log.h"
#include "pastel/sys/string.h"

#include <vector>
#include <iostream>
#include <string>

namespace Pastel
{

    inline TestRunner::TestRunner()
        : functionSet_()
        , name_("Unnamed")
    {
    }

    inline TestRunner::TestRunner(const std::string& name)
        : functionSet_()
        , name_(name)
    {
    }

    inline void TestRunner::add(
        const std::string& key,
        Function function)
    {
        functionSet_.insert(std::make_pair(key, function));
    }

    inline void TestRunner::run() const
    {
        std::cout << "Testing " << name_ << "..."
            << std::endl << std::endl;

        ConstIterator iter(functionSet_.begin());
        ConstIterator iterEnd(functionSet_.end());
        while (iter != iterEnd)
        {
            run(iter);
            ++iter;
        }

        //std::cout << name_ << " testing complete."
        // << std::endl << std::endl;
    }

    inline void TestRunner::run(
        const ConstIterator& iter) const
    {
        if (iter == functionSet_.end())
        {
            return;
        }

        std::cout << iter->first << std::endl;

        Function function = iter->second;
        if (function)
        {
            try
            {
                function();
            }
            catch(const InvariantFailure&)
            {
                std::cout << "An invariant failure occurred while running the test " 
                    << iter->first << "."
                    << std::endl;
            }
            catch(...)
            {
                std::cout << "An exception was thrown while running the test " 
                    << iter->first << "."
                    << std::endl;
                throw;
            };
        }
    }

    inline bool TestRunner::run(
        const std::string& key) const
    {
        bool result = false;

        ConstIterator iter(functionSet_.find(key));
        if (iter != functionSet_.end())
        {
            run(iter);
            result = true;
        }

        return result;
    }

    inline bool TestRunner::runPrefix(
        const std::string& key) const
    {
        bool result = false;

        ConstIterator iter(functionSet_.begin());
        while (iter != functionSet_.end())
        {
            if (iter->first.substr(0, key.size()) == key)
            {
                run(iter);
                result = true;
            }

            ++iter;
        }

        return result;
    }

    inline void TestRunner::clear()
    {
        functionSet_.clear();
    }

    inline void TestRunner::help() const
    {
        std::cout << name_ << " test suite" << std::endl;
        std::cout << std::endl;
        std::cout << "'quit' to quit." << std::endl;
        std::cout << "'help' to print this text." << std::endl;
        std::cout << "'all' to run all tests." << std::endl;
        std::cout << "'prefix' to add a prefix to typed names." << std::endl;
        std::cout << "'' to list available tests." << std::endl;
        std::cout << "Specifying a name runs all the tests that have that name as a prefix." << std::endl;
    }

    inline void TestRunner::console() const
    {
        help();

        std::string prefix;

        bool quit = false;
        while (!quit)
        {
            std::cout << prefix << "> ";
            std::string input;
            std::getline(std::cin, input);

            if (!std::cin)
            {
                break;
            }

            std::string trimmedInput(trim(input));
            if (trimmedInput == "quit")
            {
                break;
            }
            else if (trimmedInput == "all")
            {
                runPrefix(prefix);
            }
            else if (trimmedInput == "help")
            {
                help();
            }
            else if (trimmedInput.substr(0, 6) == "prefix")
            {
                prefix = trim(trimmedInput.substr(6));
            }
            else if (trimmedInput.empty())
            {
                printTests();
            }
            else
            {
                bool result = runPrefix(prefix + trimmedInput);
                if (!result)
                {
                    std::cout << "No such keyword or test(s) found." << std::endl;
                }
            }
        }
    }

    inline void TestRunner::printTests() const
    {
        ConstIterator iter(functionSet_.begin());
        ConstIterator iterEnd(functionSet_.end());
        while (iter != iterEnd)
        {
            std::cout << iter->first << std::endl;

            ++iter;
        }
    }

}

#endif