/********************************************************
 *  ██████╗  ██████╗████████╗██╗
 * ██╔════╝ ██╔════╝╚══██╔══╝██║
 * ██║  ███╗██║        ██║   ██║
 * ██║   ██║██║        ██║   ██║
 * ╚██████╔╝╚██████╗   ██║   ███████╗
 *  ╚═════╝  ╚═════╝   ╚═╝   ╚══════╝
 * Geophysical Computational Tools & Library (GCTL)
 *
 * Copyright (c) 2023  Yi Zhang (yizhang-geo@zju.edu.cn)
 *
 * GCTL is distributed under a dual licensing scheme. You can redistribute 
 * it and/or modify it under the terms of the GNU Lesser General Public 
 * License as published by the Free Software Foundation, either version 2 
 * of the License, or (at your option) any later version. You should have 
 * received a copy of the GNU Lesser General Public License along with this 
 * program. If not, see <http://www.gnu.org/licenses/>.
 * 
 * If the terms and conditions of the LGPL v.2. would prevent you from using 
 * the GCTL, please consider the option to obtain a commercial license for a 
 * fee. These licenses are offered by the GCTL's original author. As a rule, 
 * licenses are provided "as-is", unlimited in time for a one time fee. Please 
 * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget 
 * to include some description of your company and the realm of its activities. 
 * Also add information on how to contact you by electronic and paper mail.
 ******************************************************/

#ifndef _GCTL_ASSESS_H
#define _GCTL_ASSESS_H

#include <iostream>
#include <string>
#include <cmath>
#include <ctime>
#include <chrono>

/* Basic assess. If fails, returns msg. If passes, returns 0 */
#define GCTL_Assess(test, msg) \
    do { if (!(test)) return msg; return "NULL";} while (0)

/* Assess if val equals expect within a certain precision prec */
#define GCTL_AssessAlmostEqual(val, expect, prec, msg) \
    do { if(!(val <= expect + prec && val >= expect - prec)) return msg; return "NULL";} while (0)

/* Assess if val equals expect within a certain precision precision given in % */
#define GCTL_AssessAlmostEqualRel(val, expect, prec, msg) \
    do { if(fabs(val - expect) > 0.01*prec*fabs(expect)) return msg; return "NULL";} while (0)

namespace gctl
{
    /**
     * @brief      函数功能测试与评估工具
     * 
     * 此类型可以通过运行特定接口函数以评估函数内操作的有效性或者正确性。用户需定义待测试的函数内容，
     * 然后调用run_test()函数来进行测试，并通过summary()函数显示累积的测试信息。
     */
    class assess
    {
    public:
        /**
         * @brief      构造函数
         */
        assess();
        /**
         * @brief      析构函数
         */
        virtual ~assess();
        /**
         * @brief      清空测试计数并重置计时
         */
        void clear();
        /**
         * @brief      测试函数的接口
         * 
         * 若测试内容通过则此函数应返回NULL,否则应返回错误信息或代码
         * 
         * @return     返回的错误信息或代码
         */
        typedef std::string (*test_func_ptr)(void);
        /**
         * @brief      运行测试函数
         *
         * @param[in]  f_ptr    待运行的函数指针
         * @param[in]  verbose  关于此次测试的说明信息
         *
         * @return     测试成功返回0，否则返回1
         */
        int run_test(test_func_ptr f_ptr, std::string verbose);
        /**
         * @brief      输出所有测试的统计信息，包括总的测试数，成功数，失败数与所用时间
         *
         * @return     无失败测试返回假，否则返回真
         */
        bool summary();
    protected:
        int tests_run, tests_passed, tests_failed;
        std::chrono::system_clock::time_point start_t;
    };
};

#endif // _GCTL_ASSESS_H