# ifndef CPPAD_UTILITY_TEST_BOOLOFVOID_HPP
# define CPPAD_UTILITY_TEST_BOOLOFVOID_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell

CppAD is distributed under the terms of the
             Eclipse Public License Version 2.0.

This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
      GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*
$begin test_boolofvoid$$
$spell
    boolofvoid
    const
    std
    bool
    ipopt
    cpp
    cppad
    hpp
$$

$section Object that Runs a Group of Tests$$

$head Syntax$$
$codei%# include <cppad/utility/test_boolofvoid.hpp>
%$$
$codei%test_boolofvoid %Run%(%group%, %width%)
%$$
$icode%Run%(%test%, %name%)
%$$
$icode%ok% = %Run%.summary(%memory_ok%)%$$

$head Purpose$$
The object $icode Run$$ is used to run a group of tests functions
and report the results on standard output.

$head group$$
The argument has prototype
$codei%
    const std::string& %group%
%$$
It is the name for this group of tests.

$head width$$
The argument has prototype
$codei%
    size_t %width%
%$$
It is the number of columns used to display the name of each test.
It must be greater than the maximum number of characters in a test name.

$head test$$
The argument has prototype
$codei%
    bool %test%(void)
%$$
It is a function that returns true (when the test passes) and false
otherwise.

$head name$$
The argument has prototype
$codei%
    const std::string& %name%
%$$
It is the name for the corresponding $icode test$$.

$head memory_ok$$
The argument has prototype
$codei%
    bool %memory_ok%
%$$
It is false if a memory leak is detected (and true otherwise).

$head ok$$
This is true if all of the tests pass (including the memory leak test),
otherwise it is false.

$head Example$$
See any of the main programs in the example directory; e.g.,
$code example/ipopt_solve.cpp$$.

$end
*/

# include <cppad/core/cppad_assert.hpp>
# include <string>

namespace CppAD { // BEGIN_CPPAD_NAMESPACE

/// One class object is used to run a group of tests
class test_boolofvoid {
private:
    /// name for the group of test this object will run
    const std::string group_;
    /// number of characters used to display the name for each indiviual test
    /// (must be larger than the number of characters in name for each test)
    const size_t      width_;
    /// number of tests that have passed
    size_t            n_ok_;
    /// number of tests that have failed
    size_t            n_error_;

public:
    /// ctor
    test_boolofvoid(const std::string& group, size_t width) :
    group_(group) ,
    width_(width) ,
    n_ok_(0)      ,
    n_error_(0)
    {   std::cout << "Begin test group " << group_ << std::endl; }
    /// destructor
    ~test_boolofvoid(void)
    {   std::cout << "End test group " << group_ << std::endl; }
    /// run one test
    bool operator()(bool test(void), const std::string& name)
    {   CPPAD_ASSERT_KNOWN(
            name.size() < width_ ,
            "test_boolofvoid: name does not have less characters than width"
        );
        std::cout.width( int(width_) );
        std::cout.setf( std::ios_base::left );
        std::cout << name;
        //
        bool ok = test();
        if( ok )
        {   std::cout << "OK" << std::endl;
            n_ok_++;
        }
        else
        {   std::cout << "Error" << std::endl;
            n_error_++;
        }
        return ok;
    }
    /// nuber of tests that passed
    size_t n_ok(void) const
    {   return n_ok_; }
    /// nuber of tests that failed
    size_t n_error(void) const
    {   return n_error_; }
    /// summary
    bool summary(bool memory_ok )
    {
        std::cout.width( int(width_) );
        std::cout.setf( std::ios_base::left );
        std::cout << "memory_leak";
        //
        if( memory_ok  )
        {   std::cout << "OK" << std::endl;
            n_ok_++;
        }
        else
        {   std::cout << "Error" << std::endl;
            n_error_++;
        }
        if( n_error_ == 0 )
            std::cout << "All " << n_ok_ << " tests passed." << std::endl;
        else
            std::cout << n_error_ << " tests failed." << std::endl;
        //
        return n_error_ == 0;
    }
};

} // END_CPPAD_NAMESPACE

# endif
