/// Guards

#ifndef GLTEST_HPP_
#define GLTEST_HPP_


/// Includes

#include <string>
#include <vector>

// #include <glbackend.hpp>
class GLBackend;


/// Struct definition

struct GLTest_
{
    std::string   title;
    int           width;
    int           height;
    int           version_major;
    int           version_minor;
    void        (*func)(GLBackend & backend);
};


/// Function forward declarations

std::vector<GLTest_> & gltests_();


/// Macros

#define GLTEST(TITLE, WIDTH, HEIGHT, VERSION_MAJOR, VERSION_MINOR) \
    void static gltest_func_##TITLE(GLBackend & backend); \
    auto static gltest_init_##TITLE = ( \
        gltests_().push_back({ \
            #TITLE, \
            WIDTH, \
            HEIGHT, \
            VERSION_MAJOR, \
            VERSION_MINOR, \
            gltest_func_##TITLE \
        }), \
        0 \
    ); \
    void static gltest_func_##TITLE(GLBackend & backend)


#define GLTEST_EXPECT_VALUE(VALUE, ...) \
    { \
        auto gltest_value_      = VALUE; \
        auto gltest_expr_value_ = __VA_ARGS__; \
        auto gltest_error_      = std::string{} + \
            ">>> Expression:\n" + \
            #__VA_ARGS__ + "\n" + \
            ">>> Expected value:\n" + \
            #VALUE + " = " + std::to_string(gltest_value_) + "\n" + \
            ">>> Got:"; \
        if (gltest_expr_value_ != gltest_value_) \
            throw std::runtime_error{std::string{} + \
                gltest_error_ + "\n" + \
                std::to_string(gltest_expr_value_) \
            }; \
    }


#define GLTEST_EXPECT_EXCEPTION(PREFIX, WHAT, ...) \
    { \
        auto gltest_prefix_    = PREFIX; \
        auto gltest_expr_what_ = std::string{}; \
        auto gltest_what_      = WHAT; \
        try \
        { \
            __VA_ARGS__; \
        } \
        catch (std::exception const & gltest_exception_) \
        { \
            gltest_expr_what_ = gltest_exception_.what(); \
        } \
        auto gltest_error_ = std::string{} + \
            ">>> Expression:\n" + \
            #__VA_ARGS__ + "\n" + \
            ">>> Expected exception" + \
                (gltest_prefix_ ? " prefix" : "") + ":\n" + \
            gltest_what_ + "\n" + \
            ">>> Got:"; \
        if (gltest_expr_what_.empty()) \
            throw std::runtime_error{std::string{} + \
                gltest_error_ + " none." \
            }; \
        if (gltest_prefix_ \
            ? (gltest_expr_what_.rfind(gltest_what_, 0) \
                == gltest_expr_what_.npos \
            ) \
            : (gltest_expr_what_ != gltest_what_) \
        ) \
            throw std::runtime_error{std::string{} + \
                gltest_error_ + "\n" + \
                gltest_expr_what_ \
            }; \
    }


/// Guards

#endif