// This is core/testlib/testlib_test.h
#ifndef testlib_test_h_
#define testlib_test_h_
//:
// \file
// \brief Testing software
// \author Tim Cootes
// \verbatim
//  Modifications
//   Apr 2002, Amitha Perera: Copied from vil_test and moved into testlib in an
//                  attempt to consolidate all the repeated test functionality.
//   Sep.2004, Peter Vanroose: added testlib_test_assert_near_relative().
// \endverbatim

#include <string>
#include <complex>

//: initialise test counters, check test name 'name' exists
void
testlib_test_start(const char * name = nullptr);
//: increment number of tests, then output msg
void
testlib_test_begin(const char * msg);
//: increment success/failure counters
void
testlib_test_perform(bool success);
//: output summary of tests performed
int
testlib_test_summary();

//: output msg, then perform test in expr
void
testlib_test_assert(const std::string & msg, bool expr);
//: output msg, then perform test to see if expr is within tol of target
void
testlib_test_assert_near(const std::string & msg, double expr, double target = 0, double tol = 1e-12);
//: output msg, then perform test to see if expr is within tol of target
void
testlib_test_assert_near(const std::string & msg,
                         std::complex<double> expr,
                         std::complex<double> target,
                         double tol = 1e-12);
//: output msg, then test to see if expr is within relative tol of target
void
testlib_test_assert_near_relative(const std::string & msg, double expr, double target = 0, double tol = 1e-12);
//: output msg, then test to see if expr is within relative tol of target
void
testlib_test_assert_near_relative(const std::string & msg,
                                  std::complex<double> expr,
                                  std::complex<double> target,
                                  double tol = 1e-12);
//: output msg, then perform test to see if expr is not within tol of target
void
testlib_test_assert_far(const std::string & msg, double expr, double target = 0, double tol = 1e-12);
//: output msg, then perform test to see if expr is not within tol of target
void
testlib_test_assert_far(const std::string & msg,
                        std::complex<double> expr,
                        std::complex<double> target,
                        double tol = 1e-12);
//: output msg, then perform test to see if expr is equal to target
void
testlib_test_assert_equal(const std::string & msg, long expr, long target);

#define Assert testlib_test_assert
#define AssertNear testlib_test_assert_near
#define AssertFar testlib_test_assert_far

//: initialise test
#define START(s) testlib_test_start(s)

//: TEST function, s is message, test to see if p==v
#define TEST(s, p, v)                 \
  do                                  \
  {                                   \
    testlib_test_begin(s);            \
    testlib_test_perform((p) == (v)); \
  } while (false)

//: TEST function, s is message, test to see if p==v for integral values
#define TEST_EQUAL(s, p, v)              \
  do                                     \
  {                                      \
    testlib_test_begin(s);               \
    testlib_test_assert_equal("", p, v); \
  } while (false)

//: TEST function, s is message, test to see if p is close to v, tolerance t
#define TEST_NEAR(s, p, v, t)              \
  do                                       \
  {                                        \
    testlib_test_begin(s);                 \
    testlib_test_assert_near("", p, v, t); \
  } while (false)

//: TEST function, message s, test to see if (p-v)/p is small compared to t
#define TEST_NEAR_REL(s, p, v, t)                   \
  do                                                \
  {                                                 \
    testlib_test_begin(s);                          \
    testlib_test_assert_near_relative("", p, v, t); \
  } while (false)

//: TEST function, s is message, test to see if p is far from v, tolerance t
#define TEST_FAR(s, p, v, t)              \
  do                                      \
  {                                       \
    testlib_test_begin(s);                \
    testlib_test_assert_far("", p, v, t); \
  } while (false)

//: run x, s is message, then test to see if p==v
#define TEST_RUN(s, x, p, v)          \
  do                                  \
  {                                   \
    testlib_test_begin(s);            \
    x;                                \
    testlib_test_perform((p) == (v)); \
  } while (false)

//: Summarise test
#define SUMMARY() return testlib_test_summary()

//: Run a singleton test function
#define RUN_TEST_FUNC(x)  \
  testlib_test_start(#x); \
  x();                    \
  return testlib_test_summary()

//: Declare the main function.
#define MAIN(testname) int testname##_main(int, char *[])

//: Declare the main function with parameter passing.
#define MAIN_ARGS(testname) int testname##_main(int argc, char * argv[])

//: A simplified version of the main test, just in one line.
// Avoids compiler warnings about "unused argc and argv".
#define TESTMAIN(testname)           \
  int testname##_main(int, char *[]) \
  {                                  \
    START(#testname);                \
    testname();                      \
    SUMMARY();                       \
  }

//: A simplified version of the main test, just in one line.
// This (new) variant is to be used with the (new) CMake GENERATE_TEST_DRIVER()
#define TEST_MAIN(testname)   \
  int testname(int, char *[]) \
  {                           \
    START(#testname);         \
    testname();               \
    SUMMARY();                \
  }

//: A simplified version of the main test, with parameter passing.
#define TESTMAIN_ARGS(testname)                \
  int testname##_main(int argc, char * argv[]) \
  {                                            \
    START(#testname);                          \
    testname(argc, argv);                      \
    SUMMARY();                                 \
  }

//: A simplified version of the main test, with parameter passing.
// This (new) variant is to be used with the (new) CMake GENERATE_TEST_DRIVER()
#define TEST_MAIN_ARGS(testname)        \
  int testname(int argc, char * argv[]) \
  {                                     \
    START(#testname);                   \
    testname(argc, argv);               \
    SUMMARY();                          \
  }

//: Another simplified main test.  To be used in a standalone executable.
#undef TESTLIB_DEFINE_MAIN
#define TESTLIB_DEFINE_MAIN(testname) \
  int main()                          \
  {                                   \
    START(#testname);                 \
    testname();                       \
    return testlib_test_summary();    \
  }

//: A simplified main test with parameter passing.  To be used in a standalone executable.
#undef TESTLIB_DEFINE_MAIN_ARGS
#define TESTLIB_DEFINE_MAIN_ARGS(testname) \
  int main(int argc, char * argv[])        \
  {                                        \
    START(#testname);                      \
    testname(argc, argv);                  \
    SUMMARY();                             \
  }

#endif // testlib_test_h_
