/** * @file unitst.h * @brief c++用の 簡易な 単体テスト 処理. * @date 2004-2010 * @author tenk* (Masashi KITAMURA) * @note * - もともと D言語の unittest に触発されて作った代物. * - int=32,long long=64 環境前提 * - 使い方.<br> * コンパイラのオプション等で予め USE_UNITSTを定義. * テストしたい class Foo がある状況で, * <pre> * class Foo { * .... * }; * UNITTEST(Foo_Test) { * Foo* foo = new Foo(); * UNITST_ASSERT_PTR(foo); * .... * }; * </pre> * のようにして、各種テストを行うルーチン記述. * プログラム起動時(main,WinMain付近)の必要最小限の初期化の後で、<br> * UNITST_RUN_ALL(); <br> * を呼ぶと各テストを実行。 * - 登録できるテストルーチンの数は適当に512に設定. * 予め UNITST_MAX に値を設定すればその値を最大数にする. * - エラー無時に経過ログ出力をなくしたい場合は、USE_UNITSTの変わりに * USE_UNITST_NOLOG を定義すること. * - 例外関係を使わない場合は予め * UNUSE_UNITST_THROW を定義. * ただし ASSERT系failedでは、継続できずその場でexit(1)終了になる. * - USE_UNITST_STRSTREAM を定義すれば UNITST_EQ,NE,LT,LE,GT,GE,LIMIT * で strstream を使い、基本型以外の変数内容も表示. * - (vc以外の)コンパイラ・バージョンチェックは適当. * - Public Domain Software */ #ifndef UNITST_H #define UNITST_H #ifndef __cplusplus // Cの時は使えない. が、なるべくエラーにせず無視する #undef USE_UNITST #undef USE_UNITST_NOLOG #endif #if defined USE_UNITST_NOLOG && !(defined USE_UNITST) #define USE_UNITST USE_UNITST_NOLOG #endif #define UNITTEST(T) UNITST_TEST(T) // 旧処理互換. #ifndef USE_UNITST // ######################################################## // テストしないとき. // ############################################################################ #define UNITST_RUN_ALL() // mainやWinMain等の初っ端に呼び出すの想定. #define UNITST_ADD_FUNC(F) #ifdef __cplusplus #define UNITST_TEST(T) template<typename DMY> void uniTtesT_dmy_##T() #define UNITST_FRIEND(T) friend class T // 無作法だが、念のためのもの. #else #define UNITST_TEST(T) static inline void uniTtesT_dmy_##T() #endif #define UNITST_STATIC_ASSERT(cc) #define UNITST_ABORT() #define UNITST_PRINTF(x) #define UNITST_IS_RAM_PTR(p) (1) #define UNITST_RETURN() #define UNITST_ADD_FAILUSE() #define UNITST_FAIL() #define UNITST_ASSERT(b) #define UNITST_ASSERT_PTR(a) #define UNITST_ASSERT_PTR0(a) #define UNITST_ASSERT_MSGF(b, msg) #define UNITST_ASSERT_MSG(b, m) #define UNITST_ASSERT_THROW(exp,E) #define UNITST_ASSERT_ANY_THROW(e) #define UNITST_ASSERT_NO_THROW(e) #define UNITST_CHECK(b) #define UNITST_CHECK_PTR(a) #define UNITST_CHECK_PTR0(a) #define UNITST_CHECK_MSGF(b, msg) #define UNITST_CHECK_MSG(b, m) #define UNITST_CHECK_THROW(exp, E) #define UNITST_CHECK_ANY_THROW(exp) #define UNITST_CHECK_NO_THROW(exp) #define UNITST_LIMIT(a, mi, ma) #define UNITST_EQ(a, b) #define UNITST_NE(a, b) #define UNITST_LT(a, b) #define UNITST_LE(a, b) #define UNITST_GT(a, b) #define UNITST_GE(a, b) #define UNITST_LIM_BOOL(a) #define UNITST_LIM_PTR(a, mi, ma) #define UNITST_EQ_DELTA_F(a,b,d) #define UNITST_EQ_DELTA_D(a,b,d) #define UNITST_EQ_STR(a,b) #define UNITST_EQ_STRN(a,b,n) #define UNITST_EQ_STRI(a,b) #define UNITST_EQ_STRNI(a,b,n) #define UNITST_EQ_WSTR(a,b) #define UNITST_EQ_WSTRN(a,b,n) #define UNITST_EQ_WSTRI(a,b) #define UNITST_EQ_WSTRNI(a,b,n) #define UNITST_EQ_STRING(a,b) #define UNITST_EQ_CSTRING(a,b) #define UNITST_EQ_MEM(a, b, l) #define UNITST_NE_MEM(a, b, l) #define UNITST_EQ_CLCTN(a,a2,b) #else // #################################################################### // テストするとき // ############################################################################ #include <stddef.h> #include <string.h> #include <stdlib.h> #ifdef USE_UNITST_STRSTREAM #include <strstream> #endif // ============================================================ // 登録できるテスト(ルーチン)の最大数の設定. #ifdef UNITST_MAX // 予めUNITST_MAXが設定済みならそれを、 #else // 違った場合はここの値(512)を #define UNITST_MAX 512 ///< UNITTESTの最大数. #endif // ============================================================ // 簡易なデバッグ専用サブルーチン や コンパイラの辻褄あわせ. #define UNITST_STR_CAT(a,b) UNITST_STR_CAT_2(a,b) #define UNITST_STR_CAT_2(a,b) a##b #ifdef DBG_H // ---------------------------------------- // dbg.h を使っている場合はそちらに乗っかる #define UNITST_STATIC_ASSERT(cc) DBG_STATIC_ASSERT(cc) #define UNITST_ABORT() ERR_ABORT() #define UNITST_PRINTF(x) ERR_PRINTF(x) #define UNITST_IS_RAM_PTR(p) ERR_IS_RAM_PTR(p) #else // ---------------------------------------- #include <stdio.h> #include <stdarg.h> #if defined _MSC_VER #define UNITST_STATIC_ASSERT(cc) struct UNITST_STR_CAT(STATIC_ASSERT_CHECK_ST,__LINE__) { char dmy[2*((cc)!=0) - 1];}; \ enum { UNITST_STR_CAT(STATIC_ASSERT_CHECK,__LINE__) = sizeof( UNITST_STR_CAT(STATIC_ASSERT_CHECK_ST,__LINE__) ) } #else #define UNITST_STATIC_ASSERT(cc) typedef char UNITST_STR_CAT(STATIC_ASSERT_CHECK__LINE_,__LINE__)[(cc)? 1/*OK*/ : -1/*ERROR*/] #endif #if defined UNITST_ABORT // 定義済みなら、再定義しない. #elif defined _WINDOWS // GUIアプリの時 #define UNITST_ABORT() _CrtDbgBreak() #else // コマンドライン・アプリのとき. #define UNITST_ABORT() exit(1) // ((*(char*)0) = 0) #endif #if defined UNITST_PRINTF // 定義済みなら再定義しない. #elif defined _WINDOWS // GUIアプリの時 #define UNITST_PRINTF(x) unitst_printf x inline void unitst_printf(const char* f, ...) { char b[0x4000];va_list a;va_start(a,f);_vsnprintf(b,sizeof b,f,a); va_end(a); OutputDebugString(b); } #else // コマンドライン・アプリのとき. #define UNITST_PRINTF(x) unitst_printf x inline void unitst_printf(const char* f, ...) { va_list a; va_start(a,f); vfprintf(stderr,f,a); va_end(a); } #endif #if defined UNITST_IS_RAM_PTR // 定義済みなら再定義しない. #elif (defined _WIN64) || (defined __WORDSIZE && __WORDSIZE == 64) || (defined _M_AMD64) #define UNITST_IS_RAM_PTR(p) ((size_t)(ptrdiff_t)(p) >= 0x10000 && (size_t)(ptrdiff_t)(p) <= 0xFFFFFFFF00000000LL) #elif defined _WIN32 #define UNITST_IS_RAM_PTR(p) ((size_t)(ptrdiff_t)(p) >= 0x10000 && (size_t)(ptrdiff_t)(p) <= 0xFFFF0000) #else inline bool UNITST_is_ram_ptr(const char* p) { return (sizeof(void*) >= 4) ? ((p >= (char*)(ptrdiff_t)0x1000 && p <= (char*)((ptrdiff_t)-0x1000))) : (p != 0) ; } #define UNITST_IS_RAM_PTR(p) UNITST_is_ram_ptr((const char*)p) #endif #endif // ---------------------------------------- // ============================================================================ // このヘッダ内のみで使う関数やマクロ #ifdef _WIN32 #define UNITST_LONGLONG __int64 #define UNITST_ULONGLONG unsigned __int64 #define UNITST_snprintf _snprintf #else #define UNITST_LONGLONG long long #define UNITST_ULONGLONG unsigned long long #define UNITST_snprintf snprintf #endif #define UNITST_toSsz 64 // 数値文字列化用の処理 inline char* UNITST_toS(char buf[], const char* s) { UNITST_snprintf(buf, UNITST_toSsz, "%s" , s); return buf; } inline char* UNITST_toS(char buf[], const wchar_t* s) { UNITST_snprintf(buf, UNITST_toSsz, "%ls", s); return buf; } #if 0 inline char* UNITST_toS(char buf[], char c) { UNITST_snprintf(buf, UNITST_toSsz, "%c" , c); return buf; } inline char* UNITST_toS(char buf[], wchar_t c) { UNITST_snprintf(buf, UNITST_toSsz, "%lc", c); return buf; } inline char* UNITST_toS(char buf[], signed char v) { UNITST_snprintf(buf, UNITST_toSsz, "%d(%#x)", v,v); return buf; } inline char* UNITST_toS(char buf[], unsigned char v) { UNITST_snprintf(buf, UNITST_toSsz, "%d(%#x)", v,v); return buf; } inline char* UNITST_toS(char buf[], short v) { UNITST_snprintf(buf, UNITST_toSsz, "%d(%#x)", v,v); return buf; } inline char* UNITST_toS(char buf[], unsigned short v) { UNITST_snprintf(buf, UNITST_toSsz, "%u(%#x)", v,v); return buf; } #endif inline char* UNITST_toS(char buf[], int v) { UNITST_snprintf(buf, UNITST_toSsz, "%d(%#x)", v,v); return buf; } inline char* UNITST_toS(char buf[], unsigned v) { UNITST_snprintf(buf, UNITST_toSsz, "%u(%#x)", v,v); return buf; } inline char* UNITST_toS(char buf[], long v) { UNITST_snprintf(buf, UNITST_toSsz, "%ld(%#lx)",v,v); return buf; } inline char* UNITST_toS(char buf[], unsigned long v) { UNITST_snprintf(buf, UNITST_toSsz, "%lu(%#lx)",v,v); return buf; } inline char* UNITST_toS(char buf[], float v) { UNITST_snprintf(buf, UNITST_toSsz, "%g" , double(v)); return buf;} inline char* UNITST_toS(char buf[], double v) { UNITST_snprintf(buf, UNITST_toSsz, "%g" , v); return buf; } inline char* UNITST_toS(char buf[], long double v) { UNITST_snprintf(buf, UNITST_toSsz, "%Lg", v); return buf; } inline char* UNITST_toS(char buf[], UNITST_LONGLONG v) { if (v >= -(UNITST_LONGLONG)(2147483648) && v <= (UNITST_LONGLONG)(2147483647)) UNITST_snprintf(buf, UNITST_toSsz, "%d(%#x)", int(v), unsigned(v) ); else UNITST_snprintf(buf, UNITST_toSsz, "0X%x%08x", unsigned(v >> 32), unsigned(v) ); return buf; } inline char* UNITST_toS(char buf[], UNITST_ULONGLONG v) { if (v <= (UNITST_ULONGLONG)0xffffffff) UNITST_snprintf(buf, UNITST_toSsz, "%u(%#x)", unsigned(v), unsigned(v) ); else UNITST_snprintf(buf, UNITST_toSsz, "0x%x%08x", unsigned(v >> 32), unsigned(v) ); return buf; } #ifdef USE_UNITST_STRSTREAM template<class T> inline char* UNITST_toS(char buf[], const T& t) { std::strstream s(buf,UNITST_toSsz); s << t << std::ends; return buf; } #else template<class T> inline char* UNITST_toS(char buf[], const T&) { buf[0] = 0; return buf; } #endif /// 範囲チェックでのエラー表示処理. inline int UNITST_lim_pri( const char* fname, unsigned line, const char* a , const char* a2, const char* mi , const char* mi2, const char* ma , const char* ma2) { char buf[ UNITST_toSsz * 3 ]; buf[0] = 0; if (mi2[0] || ma2[0]) UNITST_snprintf(buf, sizeof buf, "(%s .. %s)", mi2, ma2); UNITST_PRINTF(("%s (%d): %s%s%s, Out of range[%s .. %s] %s\n" , fname, line , a, a2[0] ? "=" : "", a2 , mi, ma , buf )); return 1; } /// 範囲チェックでのエラー表示マクロ. #define UNITST_limit(a, mi, ma) do { \ if (UNITST_NOT((mi) <= (a) && (a) <= (ma))) { \ char a2[UNITST_toSsz], mi2[UNITST_toSsz], ma2[UNITST_toSsz]; \ UNITST_lim_pri(__FILE__, __LINE__ \ , #a, UNITST_toS(a2 ,a) \ , #mi, UNITST_toS(mi2,mi) \ , #ma, UNITST_toS(ma2,ma)); \ } \ } while(0) /// 比較でのエラー表示処理. inline int UNITST_cmp_pri( const char* fname, unsigned line, const char* a , const char* a2, const char* cc , const char* b , const char* b2) { UNITST_PRINTF(("%s (%d): [%s%s%s] %s [%s%s%s] failed.\n" , fname, line , a, a2[0] ? ":" : "", a2 , cc , b, b2[0] ? ":" : "", b2 )); return 1; } /// 比較でのエラー表示マクロ. #define UNITST_cmp(a, cc, b) do { \ if (UNITST_NOT((a) cc (b))) { \ char as[UNITST_toSsz], bs[UNITST_toSsz]; \ UNITST_cmp_pri(__FILE__, __LINE__ \ , #a, UNITST_toS(as,a), #cc, #b, UNITST_toS(bs,b)); \ } \ } while(0) // UNITST_EQ_STRING(a,b) で std::stringと"文字列"の比較結果表示用. template<class S> inline typename S::const_pointer UNITST_string2c_str(const S& s) { return s.c_str();} inline const char* UNITST_string2c_str(const char* s) { return s; } inline const wchar_t* UNITST_string2c_str(const wchar_t* s) { return s; } // =========================================================================== // テスト登録マクロ. /// 登録してあるテストルーチンの実行. #define UNITST_RUN_ALL() UNItTeST_<>::runAll() /// 単体テストルーチンを記述するためのマクロ. (D言語を多少意識) #define UNITST_TEST(T) \ class T { \ static void unittest(); \ public: \ T() { \ UNItTeST_<>::add(&unittest, #T); \ } \ }; \ static T uniTtEst_##T; \ void T::unittest() /// テストルーチンの関数を指定して登録するマクロ. #define UNITST_ADD_FUNC(F) \ struct CUniTst_##F { \ CUniTst_##F() { \ UNItTeST_<>::add(F, #F); \ } \ }; \ static CUniTst_##F uniTtEst_##F /// テスト対象クラスの中身を弄りたい場合に、対象クラス内に記述. /// こんなことすると単体テストでなくなっちゃうけれど. #define UNITST_FRIEND(T) friend class T // ============================================================ /// テストをfailで途中抜けする時の判別用. struct UNITST_Fail_Exception { }; // ============================================================ /// ユニットテストの管理クラス template<int NN = UNITST_MAX> class UNItTeST_ { public: static void add(void (*fnc)(), const char* name); static void runAll(); static bool cc(bool b) { ++cur_->total_; cur_->errs_ += !b; return b; } private: //static void (*tests_[NN])(); // 関数へのポインタだとvcが落ちる... struct Test1 { void (*func_)(); ///< テスト関数. const char* name_; ///< テスト名. unsigned total_; ///< チェック項目の数. unsigned errs_; ///< 失敗したチェックの数. }; static Test1 tests_[NN]; ///< 1つのテストの情報. static unsigned testSize_; ///< テストの数. static Test1* cur_; ///< 現在処理中のテスト. }; template<int NN> typename UNItTeST_<NN>::Test1 UNItTeST_<NN>::tests_[NN]; template<int NN> unsigned UNItTeST_<NN>::testSize_ = 0; template<int NN> typename UNItTeST_<NN>::Test1* UNItTeST_<NN>::cur_ = &UNItTeST_<NN>::tests_[NN-1]; /** テストルーチンの登録. */ template<int NN> void UNItTeST_<NN>::add(void (*fnc)(), const char* name) { if (testSize_ < NN) { #if 1 for (unsigned i = 0; i < testSize_; ++i) { Test1& f1 = tests_[i]; if (f1.func_ == fnc || strcmp(f1.name_, name) == 0) { UNITST_PRINTF(("[UNITST] %s is already registered.\n", name)); return; } } #endif Test1& t = tests_[testSize_++]; t.func_ = fnc; t.name_ = name; t.total_ = 0; t.errs_ = 0; } else { UNITST_PRINTF(("too many UNITST.(%d)\n", NN)); UNITST_ABORT(); } } /** 登録してあるテストルーチンの実行. */ template<int NN> void UNItTeST_<NN>::runAll() { unsigned failed = 0; #ifndef USE_UNITST_NOLOG UNITST_PRINTF(("### UNITST: %4d tests (%s %s) ###\n", testSize_, __DATE__, __TIME__)); #endif for (unsigned i = 0; i < testSize_; i++) { cur_ = &tests_[i]; const char* name = cur_->name_; #ifndef USE_UNITST_NOLOG UNITST_PRINTF(("[test] %s\n", name)); #endif #ifdef UNUSE_UNITST_THROW cur_->func_(); #else try { cur_->func_(); } catch (UNITST_Fail_Exception) { ++cur_->errs_, ++cur_->total_; } catch (...) { ++cur_->errs_, ++cur_->total_; UNITST_PRINTF(("\tERROR: %s threw something.\n", name)); } #endif if (cur_->errs_) { ++failed; UNITST_PRINTF(("<FAILED> %s (error:%d/%d)\n", name, cur_->errs_, cur_->total_)); } #ifndef USE_UNITST_NOLOG else { UNITST_PRINTF((" (ok) %s\n", name)); } #endif } if (failed) { UNITST_PRINTF(("=== %d tests, %d failed\n\n", testSize_, failed)); UNITST_ABORT(); } #ifndef USE_UNITST_NOLOG else { UNITST_PRINTF(("=== %d tests ok\n\n", testSize_)); } #endif } #define UNITST_CHECK_COUNT(b) (UNItTeST_<>::cc(b)) ///< 条件が成立していたらtrueを返す. #define UNITST_NOT(b) (!UNItTeST_<>::cc(b)) ///< 条件が成立してなかったらtrueを返す. // ============================================================================ // ============================================================================ // UNITTEST(T) 中に記述する、チェック用のマクロ. // ============================================================================ #ifndef UNUSE_UNITST_THROW // 例外処理がありのとき. #define UNITST_RETURN() (throw UNITST_Fail_Exception()) ///< このテストを中断する.(次のテストへ) #else // 例外処理が無しのとき. #define UNITST_RETURN() UNITST_ABORT() ///< テストを中断する #endif #define UNITST_ADD_FAILUSE() UNITST_CHECK_COUNT(0) #define UNITST_FAIL() do {UNITST_PRINTF(("%s (%d): fail.\n",__FILE__,__LINE__));UNITST_RETURN();}while(0) // UNITST_ASSERT系: 条件チェックし、偽ならメッセージ出力して、そのテストを中断. #define UNITST_ASSERT(b) do {if (UNITST_NOT(b)) { UNITST_PRINTF(("%s (%d): [%s] failed.\n", __FILE__, __LINE__, #b)); UNITST_RETURN();} } while (0) #define UNITST_ASSERT_PTR(a) do {if (UNITST_NOT(UNITST_IS_RAM_PTR(a))) { UNITST_PRINTF(("%s (%d): %s(%p) is bad pointer.\n", __FILE__, __LINE__, #a, (a))); UNITST_RETURN();} } while (0) #define UNITST_ASSERT_PTR0(a) do {if (UNITST_NOT(UNITST_IS_RAM_PTR(a) || !(a))) { UNITST_PRINTF(("%s (%d): %s(%p) is bad pointer.\n", __FILE__,__LINE__,#a,(a))); UNITST_RETURN();} } while (0) #define UNITST_ASSERT_MSGF(b, msg) do {if (UNITST_NOT(b)) { UNITST_PRINTF(("%s (%d): [%s] failed. ", __FILE__, __LINE__, #b)); UNITST_PRINTF(msg); UNITST_RETURN();} } while (0) #if __STDC_VERSION__ >= 199901L || (_MSC_VER >= 1400) || (__GNUC__ >= 3) || (__BORLANDC__ >= 0x580) || (__WATCOMC__ >= 1260) //|| (__SC__ >= 850) #define UNITST_ASSERT_MSG(b, ...) do {if (UNITST_NOT(b)) { UNITST_PRINTF(("%s (%d): [%s] failed. ", __FILE__, __LINE__, #b)); UNITST_PRINTF((__VA_ARGS__)); UNITST_RETURN(); } } while (0) #else #define UNITST_ASSERT_MSG(b, m) do {if (UNITST_NOT(b)) { UNITST_PRINTF(("%s (%d): [%s] failed. ", __FILE__, __LINE__, #b)); UNITST_PRINTF(("%s", m)); UNITST_RETURN(); } } while (0) #endif #ifndef UNUSE_UNITST_THROW // 例外処理がありのとき. #define UNITST_ASSERT_THROW(exp,E) do { bool f=0;f; try { exp; } catch (E) { f=1; } catch (...) {} if (UNITST_NOT(f)) { UNITST_PRINTF(("%s (%d): (%s) threw not %s.\n", __FILE__, __LINE__, #exp, #E)); UNITST_RETURN();} } while (0) #define UNITST_ASSERT_ANY_THROW(e) do { bool f=0;f; try { e; } catch (...) { f=1; } if (UNITST_NOT(f)) { UNITST_PRINTF(("%s (%d): (%s) threw not...\n", __FILE__, __LINE__, #e)); UNITST_RETURN();} } while (0) #define UNITST_ASSERT_NO_THROW(e) do { try { e; } catch (...) { UNITST_PRINTF(("%s (%d): (%s) threw something.\n", __FILE__, __LINE__, #e)); UNITST_RETURN();} } while (0) #else // 例外処理が無しのとき. #define UNITST_ASSERT_THROW(exp, E) #define UNITST_ASSERT_ANY_THROW(e) #define UNITST_ASSERT_NO_THROW(e) #endif // UNITST_CHECK系: 条件チェックし、偽ならメッセージ出力. テスト自体は継続. #define UNITST_CHECK(b) do {if (UNITST_NOT(b)) UNITST_PRINTF(("%s (%d): [%s] failed.\n", __FILE__, __LINE__, #b)); } while (0) #define UNITST_CHECK_PTR(a) do {if (UNITST_NOT(UNITST_IS_RAM_PTR(a))) UNITST_PRINTF(("%s (%d): %s(%p) is bad pointer.\n", __FILE__, __LINE__, #a, (a))); } while (0) #define UNITST_CHECK_PTR0(a) do {if (UNITST_NOT(UNITST_IS_RAM_PTR(a) || (a) == 0)) UNITST_PRINTF(("%s (%d): %s(%p) is bad pointer.\n", __FILE__, __LINE__, #a, (a))); } while (0) #define UNITST_CHECK_MSGF(b, msg) do {if (UNITST_NOT(b)) { UNITST_PRINTF(("%s (%d): [%s] failed. ", __FILE__, __LINE__, #b)); UNITST_PRINTF(msg); } } while (0) #if __STDC_VERSION__ >= 199901L || (_MSC_VER >= 1400) || (__GNUC__ >= 3) || (__BORLANDC__ >= 0x580) || (__WATCOMC__ >= 1260) //|| (__SC__ >= 850) #define UNITST_CHECK_MSG(b, ...) do {if (UNITST_NOT(b)) { UNITST_PRINTF(("%s (%d): [%s] failed. ", __FILE__, __LINE__, #b)); UNITST_PRINTF((__VA_ARGS__)); } } while (0) #else #define UNITST_CHECK_MSG(b, m) do {if (UNITST_NOT(b)) { UNITST_PRINTF(("%s (%d): [%s] failed. ", __FILE__, __LINE__, #b)); UNITST_PRINTF(("%s", m)); } } while (0) #endif #ifndef UNUSE_UNITST_THROW // 例外処理がありのとき. #define UNITST_CHECK_THROW(exp, E) do { bool f=0;f; try { exp; } catch (E) { f=1; } catch (...) {} if (UNITST_NOT(f)) UNITST_PRINTF(("%s (%d): (%s) threw not %s.\n", __FILE__, __LINE__, #exp, #E)); } while (0) #define UNITST_CHECK_ANY_THROW(exp) do { bool f=0;f; try { exp; } catch (...) { f=1; } if (UNITST_NOT(f)) UNITST_PRINTF(("%s (%d): (%s) threw not...\n", __FILE__, __LINE__, #exp)); } while (0) #define UNITST_CHECK_NO_THROW(exp) do { try { exp; } catch (...) { UNITST_PRINTF(("%s (%d): (%s) threw something.\n", __FILE__, __LINE__, #exp)); } } while (0) #else // 例外処理が無しのとき. #define UNITST_CHECK_THROW(exp, E) #define UNITST_CHECK_ANY_THROW(exp) #define UNITST_CHECK_NO_THROW(exp) #endif // 変数の範囲チェック. 範囲外ならメッセージ表示. (処理は継続) // a,b の関係をチェック. 満たしていない場合メッセージ表示. (処理は継続) #define UNITST_LIMIT(a, mi, ma) UNITST_limit(a, mi, ma) #define UNITST_EQ(a, b) UNITST_cmp(a, == , b) #define UNITST_NE(a, b) UNITST_cmp(a, != , b) #define UNITST_LT(a, b) UNITST_cmp(a, < , b) #define UNITST_LE(a, b) UNITST_cmp(a, <= , b) #define UNITST_GT(a, b) UNITST_cmp(a, > , b) #define UNITST_GE(a, b) UNITST_cmp(a, >= , b) #define UNITST_LIM_BOOL(a) UNITST_limit(a, 0, 1) #define UNITST_LIM_PTR(a, mi, ma) do {if (UNITST_NOT((char*)(mi) <=(char*)(a) && (char*)(a) <=(char*)(ma))) UNITST_PRINTF(("%s (%d): %s=%#p, Out of range[%p..%p]\n",__FILE__, __LINE__, #a, (a), (mi), (ma) ));} while(0) #define UNITST_EQ_MEM(a, b, l) do {const void* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_|| (A_&&B_&& memcmp( A_,B_,(l)) == 0))) UNITST_PRINTF(("%s (%d): [%s] == [%s](%dbytes) failed.\n", __FILE__, __LINE__, #a, #b, (l))); } while (0) #define UNITST_NE_MEM(a, b, l) do {const void* A_=(a),*B_=(b); if (UNITST_NOT(A_!=B_&& (!A_||!B_|| memcmp( A_,B_,(l))))) UNITST_PRINTF(("%s (%d): [%s] != [%s](%dbytes) failed.\n", __FILE__, __LINE__, #a, #b, (l))); } while (0) #define UNITST_EQ_CLCTN(a,a2,b) do {if (UNITST_NOT(std::equal(a,a2,b) )) UNITST_PRINTF(("%s (%d): {%s,%s} == {%s,...} failed.\n", __FILE__, __LINE__, #a, #a2, #b)); } while (0) #define UNITST_EQ_DELTA_F(a,b,d) do {const float *aa=&(a);aa; if (UNITST_NOT((a) >= (b)-(d) && (a) <= (b)+(d))) UNITST_PRINTF(("%s (%d): [%s:%g] == [%s:%g] failed.\n", __FILE__, __LINE__, #a, (double)(a), #b, (double)(b) )); } while (0) #define UNITST_EQ_DELTA_D(a,b,d) do {const double *aa=&(a);aa; if (UNITST_NOT((a) >= (b)-(d) && (a) <= (b)+(d))) UNITST_PRINTF(("%s (%d): [%s:%g] == [%s:%g] failed.\n", __FILE__, __LINE__, #a, (double)(a), #b, (double)(b) )); } while (0) #define UNITST_EQ_STR(a,b) do {const char* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !strcmp (A_,B_ )))) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_ )); } while (0) #define UNITST_EQ_STRN(a,b,n) do {const char* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !strncmp (A_,B_,(n))))) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] len=%d failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_,(n))); } while (0) #define UNITST_EQ_WSTR(a,b) do {const wchar_t* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !wcscmp (A_,B_ )))) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_ )); } while (0) #define UNITST_EQ_WSTRN(a,b,n) do {const wchar_t* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !wcsncmp (A_,B_,(n))))) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] len=%d failed.\n",__FILE__,__LINE__,#a,A_,#b,B_,(n))); } while (0) #if defined _WIN32 #define UNITST_EQ_STRI(a,b) do {const char* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !stricmp (A_,B_ )))) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_ )); } while (0) #define UNITST_EQ_STRNI(a,b,n) do {const char* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !strnicmp (A_,B_,(n))))) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] len=%d failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_,(n))); } while (0) #define UNITST_EQ_WSTRI(a,b) do {const wchar_t* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !_wcsicmp (A_,B_ )))) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_ )); } while (0) #define UNITST_EQ_WSTRNI(a,b,n) do {const wchar_t* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !_wcsnicmp (A_,B_,(n))))) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] len=%d failed.\n",__FILE__,__LINE__,#a,A_,#b,B_,(n))); } while (0) #else #define UNITST_EQ_STRI(a,b) do {const char* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !strcasecmp (A_,B_ )))) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_ )); } while (0) #define UNITST_EQ_STRNI(a,b,n) do {const char* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !strncasecmp(A_,B_,(n))))) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] len=%d failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_,(n))); } while (0) #define UNITST_EQ_WSTRI(a,b) do {const wchar_t* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !wcscasecmp (A_,B_ )))) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] failed.\n" ,__FILE__,__LINE__,#a,A_,#b,B_ )); } while (0) #define UNITST_EQ_WSTRNI(a,b,n) do {const wchar_t* A_=(a),*B_=(b); if (UNITST_NOT(A_==B_||(A_&&B_&& !wcsncasecmp(A_,B_,(n))))) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] len=%d failed.\n",__FILE__,__LINE__,#a,A_,#b,B_,(n))); } while (0) #endif #define UNITST_EQ_STRING(a,b) do { if (UNITST_NOT(a == b)) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] failed.\n",__FILE__,__LINE__,#a,UNITST_string2c_str(a),#b,UNITST_string2c_str(b))); } while (0) #define UNITST_EQ_WSTRING(a,b) do { if (UNITST_NOT(a == b)) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] failed.\n",__FILE__,__LINE__,#a,UNITST_string2c_str(a),#b,UNITST_string2c_str(b))); } while (0) #ifdef UNICODE #define UNITST_EQ_CSTRING(a,b) do { if (UNITST_NOT(CString(a) == CString(b))) UNITST_PRINTF(("%s (%d): [%s:%ls] == [%s:%ls] failed.\n",__FILE__,__LINE__,#a,LPCTSTR(a),#b,LPCTSTR(b))); } while (0) #else #define UNITST_EQ_CSTRING(a,b) do { if (UNITST_NOT(CString(a) == CString(b))) UNITST_PRINTF(("%s (%d): [%s:%s] == [%s:%s] failed.\n",__FILE__,__LINE__,#a,LPCTSTR(a),#b,LPCTSTR(b))); } while (0) #endif #endif // #################################################################### // ############################################################################ // ============================================================================ // TCHAR 対応. #ifdef UNICODE #define UNITST_EQ_TSTR(a,b) UNITST_EQ_WSTR(a,b) #define UNITST_EQ_TSTRI(a,b) UNITST_EQ_WSTRI(a,b) #define UNITST_EQ_TSTRN(a,b,n) UNITST_EQ_WSTRN(a,b,n) #define UNITST_EQ_TSTRNI(a,b,n) UNITST_EQ_WSTRNI(a,b,n) #else #define UNITST_EQ_TSTR(a,b) UNITST_EQ_STR(a,b) #define UNITST_EQ_TSTRI(a,b) UNITST_EQ_STRI(a,b) #define UNITST_EQ_TSTRN(a,b,n) UNITST_EQ_STRN(a,b,n) #define UNITST_EQ_TSTRNI(a,b,n) UNITST_EQ_STRNI(a,b,n) #endif // ============================================================================ // 旧バージョン・互換. #define UNITST_LIM_I(a, mi, ma) UNITST_LIMIT(a, mi, ma) #define UNITST_LIM_LL(a, mi, ma) UNITST_LIMIT(a, mi, ma) #define UNITST_LIM_F(a, mi, ma) UNITST_LIMIT(a, mi, ma) #define UNITST_LIM_D(a, mi, ma) UNITST_LIMIT(a, mi, ma) #define UNITST_LIM_LD(a, mi, ma) UNITST_LIMIT(a, mi, ma) #define UNITST_EQ_I(a, b) UNITST_EQ(a, b) #define UNITST_NE_I(a, b) UNITST_NE(a, b) #define UNITST_LT_I(a, b) UNITST_LT(a, b) #define UNITST_LE_I(a, b) UNITST_LE(a, b) #define UNITST_GT_I(a, b) UNITST_GT(a, b) #define UNITST_GE_I(a, b) UNITST_GE(a, b) #define UNITST_EQ_LL(a, b) UNITST_EQ(a, b) #define UNITST_NE_LL(a, b) UNITST_NE(a, b) #define UNITST_LT_LL(a, b) UNITST_LT(a, b) #define UNITST_LE_LL(a, b) UNITST_LE(a, b) #define UNITST_GT_LL(a, b) UNITST_GT(a, b) #define UNITST_GE_LL(a, b) UNITST_GE(a, b) #define UNITST_EQ_F(a, b) UNITST_EQ(a, b) #define UNITST_NE_F(a, b) UNITST_NE(a, b) #define UNITST_LT_F(a, b) UNITST_LT(a, b) #define UNITST_LE_F(a, b) UNITST_LE(a, b) #define UNITST_GT_F(a, b) UNITST_GT(a, b) #define UNITST_GE_F(a, b) UNITST_GE(a, b) #define UNITST_EQ_D(a, b) UNITST_EQ(a, b) #define UNITST_NE_D(a, b) UNITST_NE(a, b) #define UNITST_LT_D(a, b) UNITST_LT(a, b) #define UNITST_LE_D(a, b) UNITST_LE(a, b) #define UNITST_GT_D(a, b) UNITST_GT(a, b) #define UNITST_GE_D(a, b) UNITST_GE(a, b) #define UNITST_EQ_LD(a, b) UNITST_EQ(a, b) #define UNITST_NE_LD(a, b) UNITST_NE(a, b) #define UNITST_LT_LD(a, b) UNITST_LT(a, b) #define UNITST_LE_LD(a, b) UNITST_LE(a, b) #define UNITST_GT_LD(a, b) UNITST_GT(a, b) #define UNITST_GE_LD(a, b) UNITST_GE(a, b) #endif // UNITST_H