// This is a part of the VSCppUnit C++ Unit Testing Framework. // Copyright (C) Microsoft Corporation // All rights reserved. // // This file defines the verification entities of the framework. #pragma once #ifndef MS_CPP_UNITTESTFRAMEWORK_ASSERT #define MS_CPP_UNITTESTFRAMEWORK_ASSERT #include #include "CppUnitTestCommon.h" #include #include #include // This macro can be used to retrieve line information. // It can be passed to Assert methods to retrieve the line information. // It can be useful if you are running your test cases without .pdb files // (for example if you are running tests remotely), // because without .pdb files, the stack trace cannot retrieve // method names, filenames or line numbers. #define LINE_INFO() std::unique_ptr(new Microsoft::VisualStudio::CppUnitTestFramework::__LineInfo(__WFILE__, __FUNCTION__, __LINE__)).get() // Exception code for assertion failure: #define ERROR_ASSERT_FAILED 0xE3530001 #define DEFAULT_IGNORECASE false // Below macros are used to create appropriate message for // AreEqual, AreSame, AreNotEqual and AreNotSame asserts. #define RETURN_WIDE_STRING(inputValue) std::wstringstream _s; _s << inputValue; return _s.str() #define EQUALS_MESSAGE(expected, actual, message) reinterpret_cast(GetAssertMessage(true, ToString(expected), ToString(actual), message).c_str()) #define NOT_EQUALS_MESSAGE(notExpected, actual, message) reinterpret_cast(GetAssertMessage(false, ToString(notExpected), ToString(actual), message).c_str()) #ifdef __cplusplus_winrt #define EQUALS_MESSAGE_WINRT(expected, actual, message) reinterpret_cast(GetAssertMessage(true, ToWideString(expected), ToWideString(actual), nullptr == message ? NULL : message->Data()).c_str()) #define NOT_EQUALS_MESSAGE_WINRT(expected, actual, message) reinterpret_cast(GetAssertMessage(false, ToWideString(expected), ToWideString(actual), nullptr == message ? NULL : message->Data()).c_str()) #endif namespace Microsoft{ namespace VisualStudio {namespace CppUnitTestFramework { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // __LineInfo struct __LineInfo { __LineInfo(const wchar_t* pszFileName, const char* pszFuncName, int lineNumber) :pszFile(pszFileName), pszFunc(reinterpret_cast(pszFuncName)), line(lineNumber) { } const wchar_t* pszFile; const unsigned char* pszFunc; int line; }; // User should provide a specialization of below ToString() template to use equality asserts in test code. // std::wstring ToString(const Q& q) is used for converting type Q in user readable std::wstring value. // Converted value is emitted in Assert failure message. Specialization for basic types has been provided below. template constexpr bool dependent_false = false; template static std::wstring ToString(const Q& q) { static_assert(dependent_false, "Test writer must define specialization of ToString for your class " __FUNCSIG__ "."); } template static std::wstring ToString(const Q* q) { static_assert(dependent_false, "Test writer must define specialization of ToString for your class " __FUNCSIG__ "."); } template static std::wstring ToString(Q* q) { static_assert(dependent_false, "Test writer must define specialization of ToString for your class " __FUNCSIG__ "."); } // ToString() template specialization for basic types. template<> inline std::wstring ToString (const bool& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const int& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const long& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const long long& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const short& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const char& t) { RETURN_WIDE_STRING(t); } #ifdef _NATIVE_WCHAR_T_DEFINED template<> inline std::wstring ToString (const wchar_t& t) { RETURN_WIDE_STRING(t); } #endif template<> inline std::wstring ToString (const signed char& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned int& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned long& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned long long& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned short& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned char& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const std::string& t) { RETURN_WIDE_STRING(t.c_str()) ; } template<> inline std::wstring ToString (const std::wstring& t) { return t; } #if _HAS_CXX17 template<> inline std::wstring ToString (const std::wstring_view& t) { auto wstr = std::wstring{ t }; return wstr; } template<> inline std::wstring ToString (const std::string_view& t) { auto str = std::string{ t }; RETURN_WIDE_STRING(str.c_str()); } #endif template<> inline std::wstring ToString (const double& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const float& t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const bool* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const int* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const long long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const short* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const signed char* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned int* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned long long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const unsigned char* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const char* t) { if (NULL == t) return std::wstring(L"(NULL)"); RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const wchar_t* t) { if (NULL == t) return std::wstring(L"(NULL)");RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (const double* t) { RETURN_WIDE_STRING(t);} template<> inline std::wstring ToString (const float* t) { RETURN_WIDE_STRING(t);} template<> inline std::wstring ToString (const void* t) { RETURN_WIDE_STRING(t);} template<> inline std::wstring ToString (bool* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (int* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (long long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (short* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (signed char* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (unsigned int* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (unsigned long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (unsigned long long* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (unsigned char* t) { RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (char* t) { if (NULL == t) return std::wstring(L"(NULL)"); RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (wchar_t* t) { if (NULL == t) return std::wstring(L"(NULL)");RETURN_WIDE_STRING(t); } template<> inline std::wstring ToString (double* t) { RETURN_WIDE_STRING(t);} template<> inline std::wstring ToString (float* t) { RETURN_WIDE_STRING(t);} template<> inline std::wstring ToString (void* t) { RETURN_WIDE_STRING(t);} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Assert class Assert { public: // Verify that two objects are equal (excluded only for first-dimension char arrays so they bind to char* overloads). template::value && std::is_same::type, char>::value), int>::type = 0> static void AreEqual(const T& expected, const T& actual, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(expected == actual, EQUALS_MESSAGE(expected, actual, message), pLineInfo); } // double equality comparison: static void AreEqual(double expected, double actual, double tolerance, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { double diff = expected - actual; FailOnCondition(fabs(diff) <= fabs(tolerance), EQUALS_MESSAGE(expected, actual, message), pLineInfo); } // float equality comparison: static void AreEqual(float expected, float actual, float tolerance, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { float diff = expected - actual; FailOnCondition(fabs(diff) <= fabs(tolerance), EQUALS_MESSAGE(expected, actual, message), pLineInfo); } // char* string equality comparison: static void AreEqual(const char* expected, const char* actual, const char* message, const __LineInfo* pLineInfo = NULL) { AreEqual(expected, actual, DEFAULT_IGNORECASE, ToString(message).c_str(), pLineInfo); } // char* string equality comparison: static void AreEqual(const char* expected, const char* actual, const wchar_t* message, const __LineInfo* pLineInfo = NULL) { AreEqual(expected, actual, DEFAULT_IGNORECASE, message, pLineInfo); } // char* string equality comparison: static void AreEqual(const char* expected, const char* actual, bool ignoreCase = false, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(CppUnitStrCmpA(expected, actual, ignoreCase), EQUALS_MESSAGE(expected, actual, message), pLineInfo); } // wchar_t* string equality comparison: static void AreEqual(const wchar_t* expected, const wchar_t* actual, const char* message, const __LineInfo* pLineInfo = NULL) { AreEqual(expected, actual, DEFAULT_IGNORECASE, ToString(message).c_str(), pLineInfo); } // wchar_t* string equality comparison: static void AreEqual(const wchar_t* expected, const wchar_t* actual, const wchar_t* message, const __LineInfo* pLineInfo = NULL) { AreEqual(expected, actual, DEFAULT_IGNORECASE, message, pLineInfo); } // wchar_t* string equality comparison: static void AreEqual(const wchar_t* expected, const wchar_t* actual, bool ignoreCase = false, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(CppUnitStrCmpW(reinterpret_cast(expected), reinterpret_cast(actual), ignoreCase), EQUALS_MESSAGE(expected, actual, message), pLineInfo); } // Verify that two references refer to the same object instance (identity): template static void AreSame(const T& expected, const T& actual, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(&expected == &actual, EQUALS_MESSAGE(expected, actual, message), pLineInfo); } // Generic AreNotEqual comparison: template static void AreNotEqual(const T& notExpected, const T& actual, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(!(notExpected == actual), NOT_EQUALS_MESSAGE(notExpected, actual, message), pLineInfo); } // double AreNotEqual comparison: static void AreNotEqual(double notExpected, double actual, double tolerance, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { double diff = notExpected - actual; FailOnCondition(fabs(diff) > fabs(tolerance), NOT_EQUALS_MESSAGE(notExpected, actual, message), pLineInfo); } // float AreNotEqual comparison: static void AreNotEqual(float notExpected, float actual, float tolerance, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { float diff = notExpected - actual; FailOnCondition(fabs(diff) > fabs(tolerance), NOT_EQUALS_MESSAGE(notExpected, actual, message), pLineInfo); } // char* string AreNotEqual comparison with char* message: static void AreNotEqual(const char* notExpected, const char* actual, const char* message, const __LineInfo* pLineInfo = NULL) { AreNotEqual(notExpected, actual, DEFAULT_IGNORECASE, ToString(message).c_str(), pLineInfo); } // char* string AreNotEqual comparison with wchar_t* message: static void AreNotEqual(const char* notExpected, const char* actual, const wchar_t* message, const __LineInfo* pLineInfo = NULL) { AreNotEqual(notExpected, actual, DEFAULT_IGNORECASE, message, pLineInfo); } // char* string AreNotEqual comparison: static void AreNotEqual(const char* notExpected, const char* actual, bool ignoreCase = false, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(!CppUnitStrCmpA(notExpected, actual, ignoreCase), NOT_EQUALS_MESSAGE(notExpected, actual, message), pLineInfo); } // wchar_t* string AreNotEqual comparison with char* message: static void AreNotEqual(const wchar_t* notExpected, const wchar_t* actual, const char* message, const __LineInfo* pLineInfo = NULL) { AreNotEqual(notExpected, actual, DEFAULT_IGNORECASE, ToString(message).c_str(), pLineInfo); } // wchar_t* string AreNotEqual comparison with wchar_t* message: static void AreNotEqual(const wchar_t* notExpected, const wchar_t* actual, const wchar_t* message, const __LineInfo* pLineInfo = NULL) { AreNotEqual(notExpected, actual, DEFAULT_IGNORECASE, message, pLineInfo); } // wchar_t* string AreNotEqual comparison: static void AreNotEqual(const wchar_t* notExpected, const wchar_t* actual, bool ignoreCase = false, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(!CppUnitStrCmpW(reinterpret_cast(notExpected), reinterpret_cast(actual), ignoreCase), NOT_EQUALS_MESSAGE(notExpected, actual, message), pLineInfo); } // Verify that two references do not refer to the same object instance (identity): template static void AreNotSame(const T& notExpected, const T& actual, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(!(¬Expected == &actual), NOT_EQUALS_MESSAGE(notExpected, actual, message), pLineInfo); } // Verify that a pointer is NULL: template _When_(actual != NULL, _Analysis_noreturn_) static void IsNull(const T* actual,const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(actual == NULL, reinterpret_cast(message), pLineInfo); } // Verify that a pointer is not NULL: template _When_(actual == NULL, _Analysis_noreturn_) static void IsNotNull(const T* actual, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(!(actual == NULL), reinterpret_cast(message), pLineInfo); } // Verify that a condition is true: static void IsTrue(bool condition, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(condition, reinterpret_cast(message), pLineInfo); } // Verify that a conditon is false: static void IsFalse(bool condition, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(!condition, reinterpret_cast(message), pLineInfo); } // Force the test case result to be Failed: static void __declspec(noreturn) Fail(const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailImpl(reinterpret_cast(message), pLineInfo); } #ifdef __cplusplus_winrt // General equal comparison for WinRT pointers. template static void AreEqual(T^ expected, T^ actual, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { bool condition = false; if(expected != nullptr && actual != nullptr) { condition = expected->Equals(actual); } else if(expected == nullptr && actual == nullptr) { condition = true; } FailOnCondition(condition, EQUALS_MESSAGE_WINRT(expected, actual, message), pLineInfo); } // Platform::String^ string equality comparison. static void AreEqual(Platform::String^ expected, Platform::String^ actual, char* message, const __LineInfo* pLineInfo = nullptr) { AreEqual(expected, actual, DEFAULT_IGNORECASE, ref new Platform::String(ToString(message).c_str()), pLineInfo); } // Platform::String^ string equality comparison. static void AreEqual(Platform::String^ expected, Platform::String^ actual, wchar_t* message, const __LineInfo* pLineInfo = nullptr) { AreEqual(expected, actual, DEFAULT_IGNORECASE, ref new Platform::String(message), pLineInfo); } // Platform::String^ string equality comparison. static void AreEqual(Platform::String^ expected, Platform::String^ actual, Platform::String^ message, const __LineInfo* pLineInfo = nullptr) { AreEqual(expected, actual, DEFAULT_IGNORECASE, message, pLineInfo); } // Platform::String^ string equality comparison. static void AreEqual(Platform::String^ expected, Platform::String^ actual, bool ignoreCase = false, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { FailOnCondition(CppUnitStrCmpW(UnboxString(expected), UnboxString(actual), ignoreCase), EQUALS_MESSAGE_WINRT(expected, actual, message), pLineInfo); } // Used to check if two WinRT references are referecing the same object. // Be noted not to use this one to check if 2 objects are equals. template static void AreSame(T% expected, T% actual, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { FailOnCondition(%expected == %actual, EQUALS_MESSAGE_WINRT(%expected, %actual, message), pLineInfo); } // General AreNotEqual comparison for WinRT pointers. template static void AreNotEqual(T^ notExpected, T^ actual, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { bool condition = true; if(notExpected != nullptr && actual != nullptr) { condition = !notExpected->Equals(actual); } else if(notExpected == nullptr && actual == nullptr) { condition = false; } FailOnCondition(condition, NOT_EQUALS_MESSAGE_WINRT(notExpected, actual, message), pLineInfo); } // Platform::String^ string equality comparison. static void AreNotEqual(Platform::String^ expected, Platform::String^ actual, char* message, const __LineInfo* pLineInfo = nullptr) { AreNotEqual(expected, actual, DEFAULT_IGNORECASE, ref new Platform::String(ToString(message).c_str()), pLineInfo); } // Platform::String^ string equality comparison. static void AreNotEqual(Platform::String^ expected, Platform::String^ actual, wchar_t* message, const __LineInfo* pLineInfo = nullptr) { AreNotEqual(expected, actual, DEFAULT_IGNORECASE, ref new Platform::String(message), pLineInfo); } // Platform::String^ string equality comparison. static void AreNotEqual(Platform::String^ expected, Platform::String^ actual, Platform::String^ message, const __LineInfo* pLineInfo = nullptr) { AreNotEqual(expected, actual, DEFAULT_IGNORECASE, message, pLineInfo); } // Platform::String^ string AreNotEqual comparison: static void AreNotEqual(Platform::String^ notExpected, Platform::String^ actual, bool ignoreCase = false, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { FailOnCondition(!CppUnitStrCmpW(UnboxString(notExpected), UnboxString(actual), ignoreCase), NOT_EQUALS_MESSAGE_WINRT(notExpected, actual, message), pLineInfo); } // Used to check if two WinRT references are not referencing the same object. // Be noted not to use it to do AreNotEqual comparsion for 2 objects. template static void AreNotSame(T% notExpected, T% actual, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { FailOnCondition(!(%notExpected == %actual), NOT_EQUALS_MESSAGE_WINRT(%notExpected, %actual, message), pLineInfo); } // Check if a WinRT pointer is nullptr. template _When_(actual != nullptr, _Analysis_noreturn_) static void IsNull(T^ actual, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { FailOnCondition(actual == nullptr, UnboxString(message), pLineInfo); } // Check if a WinRT pointer is not nullptr template _When_(actual == nullptr, _Analysis_noreturn_) static void IsNotNull(T^ actual, Platform::String^ message = nullptr, const __LineInfo* pLineInfo = nullptr) { FailOnCondition(!(actual == nullptr), UnboxString(message), pLineInfo); } #endif #ifdef _CPPUNWIND // Verify that a function raises an exception: template static void ExpectException(_FUNCTOR functor, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { try { functor(); } catch(_EXPECTEDEXCEPTION) { return; } catch(...) { Internal_SetExpectedExceptionMessage(reinterpret_cast(message)); throw; } Assert::Fail(message, pLineInfo); } template static void ExpectException(_RETURNTYPE (*func)(), const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL) { FailOnCondition(func != NULL, reinterpret_cast(message), pLineInfo); try { func(); } catch(_EXPECTEDEXCEPTION) { return; } catch(...) { Internal_SetExpectedExceptionMessage(reinterpret_cast(message)); throw; } Assert::Fail(message, pLineInfo); } #endif #ifndef __INTELLISENSE__ public: __declspec(dllexport) static unsigned short* __stdcall Internal_GetExpectedExceptionMessage(); __declspec(dllexport) static void __stdcall Internal_SetExpectedExceptionMessage(const unsigned short *message); #endif private: __declspec(dllexport) static void __stdcall FailOnCondition(bool condition, const unsigned short* message, const __LineInfo* pLineInfo); __declspec(dllexport) static bool __stdcall CppUnitStrCmpA(const char* str1, const char* str2, bool ignoreCase); __declspec(dllexport) static bool __stdcall CppUnitStrCmpW(const unsigned short* str1, const unsigned short* str2, bool ignoreCase); __declspec(dllexport) static void __stdcall FailImpl(const unsigned short* message, const __LineInfo* pLineInfo); __declspec(dllexport) static void __stdcall GetAssertMessage(bool equality, const unsigned short *expected, const unsigned short *actual, const unsigned short *userMessage, unsigned short* assertMessageBuffer, size_t bufferSize); // return a formated message for equality based asserts. static std::wstring GetAssertMessage(bool equality, const std::wstring& expected, const std::wstring& actual, const wchar_t *message) { wchar_t assertMessage[MS_CPP_UNITTESTFRAMEWORK_MAX_BUF_LENGTH]; memset(assertMessage, 0, MS_CPP_UNITTESTFRAMEWORK_MAX_BUF_LENGTH * sizeof(wchar_t)); const unsigned short* expectedPtr = reinterpret_cast(expected.c_str()); const unsigned short* actualPtr = reinterpret_cast(actual.c_str()); const unsigned short* messagePtr = reinterpret_cast(message); unsigned short *assertMessagePtr = reinterpret_cast(assertMessage); GetAssertMessage(equality, expectedPtr, actualPtr, messagePtr, assertMessagePtr, MS_CPP_UNITTESTFRAMEWORK_MAX_BUF_LENGTH); return std::wstring(assertMessage); } #ifdef __cplusplus_winrt private: static const unsigned short* UnboxString(Platform::String^ str) { if(str == nullptr) return nullptr; return reinterpret_cast(str->Data()); } template static std::wstring ToWideString(T^ value) { if (nullptr == value) { return std::wstring(L"(NULL)"); } return std::wstring(value->ToString()->Data()); } #endif }; }}} #endif /*MS_CPP_UNITTESTFRAMEWORK_ASSERT*/