#define BOOST_NOWIDE_LIB_TEST_H_INCLUDED
#include <cstdlib>
+#include <iomanip>
#include <iostream>
+#include <limits>
#include <sstream>
#include <stdexcept>
+#include <string>
#if defined(_MSC_VER) && defined(_CPPLIB_VER) && defined(_DEBUG)
#include <crtdbg.h>
namespace boost {
namespace nowide {
- struct test_monitor
- {
- test_monitor()
+ namespace test {
+ struct test_error : std::runtime_error
+ {
+ using std::runtime_error::runtime_error;
+ };
+ struct test_monitor
{
+ test_monitor()
+ {
#if defined(_MSC_VER) && (_MSC_VER > 1310)
- // disable message boxes on assert(), abort()
- ::_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+ // disable message boxes on assert(), abort()
+ ::_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#if defined(_MSC_VER) && defined(_CPPLIB_VER) && defined(_DEBUG)
- // disable message boxes on iterator debugging violations
- _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
- _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ // disable message boxes on iterator debugging violations
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
#endif
+ }
+ };
+ inline test_monitor& test_mon()
+ {
+ static test_monitor instance;
+ return instance;
+ }
+ /// Function called when a test failed to be able set a breakpoint for debugging
+ inline void test_failed(const char* expr, const char* file, const int line, const char* function)
+ {
+ std::ostringstream ss;
+ ss << expr << " at " << file << ':' << line << " in " << function;
+ throw test_error(ss.str());
}
- };
-} // namespace nowide
-} // namespace boost
-
-inline boost::nowide::test_monitor& test_mon()
-{
- static boost::nowide::test_monitor instance;
- return instance;
-}
-/// Function called when a test failed to be able set a breakpoint for debugging
-inline void test_failed(const char* expr, const char* file, const int line, const char* function)
-{
- std::ostringstream ss;
- ss << "Error " << expr << " at " << file << ':' << line << " in " << function;
- throw std::runtime_error(ss.str());
-}
+ template<typename T>
+ const T& print_value(const T& value)
+ {
+ return value;
+ }
+ inline std::string print_value(const std::wstring& value)
+ {
+ std::ostringstream ss;
+ const auto defWidth = ss.width();
+ ss << std::hex << std::uppercase << std::setfill('0');
+ for(const wchar_t c : value)
+ {
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
+#endif
+ if(c >= (std::numeric_limits<char>::min)() && c <= (std::numeric_limits<char>::max)())
+ ss << static_cast<char>(c);
+ else
+ ss << "\\" << std::setw(sizeof(wchar_t) * 2) << static_cast<int>(c) << std::setw(defWidth);
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+ }
+ return ss.str();
+ }
-template<typename T, typename U>
-inline void test_equal_impl(const T& lhs, const U& rhs, const char* file, const int line, const char* function)
-{
- if(lhs == rhs)
- return;
- std::ostringstream ss;
- ss << "[" << lhs << "!=" << rhs << "]";
- test_failed(ss.str().c_str(), file, line, function);
-}
+ template<typename T, typename U>
+ void test_equal_impl(const T& lhs, const U& rhs, const char* file, const int line, const char* function)
+ {
+ if(lhs == rhs)
+ return;
+ std::ostringstream ss;
+ ss << "[" << print_value(lhs) << "!=" << print_value(rhs) << "]";
+ test_failed(ss.str().c_str(), file, line, function);
+ }
+ } // namespace test
+} // namespace nowide
+} // namespace boost
#ifdef _MSC_VER
#define DISABLE_CONST_EXPR_DETECTED __pragma(warning(push)) __pragma(warning(disable : 4127))
#define TEST(x) \
do \
{ \
+ using namespace boost::nowide::test; \
test_mon(); \
if(x) \
break; \
#define TEST_EQ(lhs, rhs) \
do \
{ \
+ using namespace boost::nowide::test; \
test_mon(); \
test_equal_impl((lhs), (rhs), __FILE__, __LINE__, __FUNCTION__); \
break; \
DISABLE_CONST_EXPR_DETECTED \
} while(0) DISABLE_CONST_EXPR_DETECTED_POP
+#define TEST_THROW(expr, error) \
+ do \
+ { \
+ test_mon(); \
+ try \
+ { \
+ expr; \
+ test_failed(#error " not thrown", __FILE__, __LINE__, __FUNCTION__); \
+ } catch(const error&) \
+ { /* OK */ \
+ } \
+ break; \
+ DISABLE_CONST_EXPR_DETECTED \
+ } while(0) DISABLE_CONST_EXPR_DETECTED_POP
+
#ifndef BOOST_NOWIDE_TEST_NO_MAIN
// Tests should implement this
void test_main(int argc, char** argv, char** env);
{
try
{
+#ifdef _MSC_VER
+ std::cout << "MSVC version " << _MSC_VER << std::endl;
+#endif
test_main(argc, argv, env);
+ } catch(const boost::nowide::test::test_error& e)
+ {
+ std::cerr << "Failed test assertion: " << e.what() << std::endl;
+ return 1;
} catch(const std::exception& e)
{
- std::cerr << "Failed " << e.what() << std::endl;
+ std::cerr << "Failed with unexpected exception: " << e.what() << std::endl;
return 1;
}
return 0;