From dcf5a2667f8abe86c826ff9c6e4098466a683c22 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Thu, 22 Jan 2015 20:30:05 +0000 Subject: [PATCH] CLogger: Use cppformat instead of sys_vswprintf. sys_vswprintf relies on platform-specific printf implementations, which vary widely between platforms (in handling of truncation, return values, use of %s/%S/%hs/%ls for mixing char and wchar_t strings, etc) and are therefore a pain. Use cppformat's fmt::sprintf instead, which has very similar syntax to sprintf but is more C++ish and is portable. Also, wchar_t is stupid, so use char* strings (which are expected to be UTF-8) in CLogger. This creates a bit of a pain with changing all callers to convert to char* strings, but that's their fault for not using UTF-8 already. Refs #3011. This was SVN commit r16182. --- build/premake/premake4.lua | 3 +- source/graphics/TextRenderer.cpp | 8 ++ source/graphics/TextRenderer.h | 7 ++ source/graphics/tests/test_MeshManager.h | 4 +- source/lib/self_test.h | 3 + source/ps/CLogger.cpp | 118 ++++-------------- source/ps/CLogger.h | 29 ++--- source/ps/XML/tests/test_RelaxNG.h | 6 +- source/ps/tests/test_CLogger.h | 65 +--------- .../tests/test_ScriptInterface.h | 10 +- .../simulation2/tests/test_ComponentManager.h | 6 +- source/test_setup.cpp | 5 + 12 files changed, 81 insertions(+), 183 deletions(-) diff --git a/build/premake/premake4.lua b/build/premake/premake4.lua index 8bf879c543..80522f8866 100644 --- a/build/premake/premake4.lua +++ b/build/premake/premake4.lua @@ -711,7 +711,8 @@ function setup_all_libs () "maths", "maths/scripting", "i18n", - "i18n/scripting" + "i18n/scripting", + "third_party/cppformat", } extern_libs = { "spidermonkey", diff --git a/source/graphics/TextRenderer.cpp b/source/graphics/TextRenderer.cpp index 3149ed69fb..ae5ac69849 100644 --- a/source/graphics/TextRenderer.cpp +++ b/source/graphics/TextRenderer.cpp @@ -144,6 +144,14 @@ void CTextRenderer::Put(float x, float y, const wchar_t* buf) PutString(x, y, new std::wstring(buf), true); } +void CTextRenderer::Put(float x, float y, const char* buf) +{ + if (buf[0] == 0) + return; // empty string; don't bother storing + + PutString(x, y, new std::wstring(wstring_from_utf8(buf)), true); +} + void CTextRenderer::Put(float x, float y, const std::wstring* buf) { if (buf->empty()) diff --git a/source/graphics/TextRenderer.h b/source/graphics/TextRenderer.h index ac4d3b1d83..0c096f99dc 100644 --- a/source/graphics/TextRenderer.h +++ b/source/graphics/TextRenderer.h @@ -88,6 +88,13 @@ public: */ void Put(float x, float y, const wchar_t* buf); + /** + * Print text at (x,y) under the current transform. + * Does not alter the current transform. + * @p buf must be a UTF-8 string. + */ + void Put(float x, float y, const char* buf); + /** * Print text at (x,y) under the current transform. * Does not alter the current transform. diff --git a/source/graphics/tests/test_MeshManager.h b/source/graphics/tests/test_MeshManager.h index 4e59ba1cb3..a35d3b3f32 100644 --- a/source/graphics/tests/test_MeshManager.h +++ b/source/graphics/tests/test_MeshManager.h @@ -190,7 +190,7 @@ public: CModelDefPtr modeldef = meshManager->GetMesh(testDAE); TS_ASSERT(! modeldef); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"parser error"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "parser error"); } void test_invalid_dae() @@ -205,7 +205,7 @@ public: CModelDefPtr modeldef = meshManager->GetMesh(testDAE); TS_ASSERT(! modeldef); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"parser error"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "parser error"); } void test_load_nonexistent_pmd() diff --git a/source/lib/self_test.h b/source/lib/self_test.h index 27e3870bbc..4b68be034d 100644 --- a/source/lib/self_test.h +++ b/source/lib/self_test.h @@ -269,7 +269,10 @@ namespace CxxTest #define TS_ASSERT_PATH_EQUALS(path1, path2) TS_ASSERT_EQUALS((path1).string(), (path2).string()) #define TSM_ASSERT_PATH_EQUALS(m, path1, path2) TSM_ASSERT_EQUALS(m, (path1).string(), (path2).string()) +bool ts_str_contains(const std::string& str1, const std::string& str2); // defined in test_setup.cpp bool ts_str_contains(const std::wstring& str1, const std::wstring& str2); // defined in test_setup.cpp +#define TS_ASSERT_STR_CONTAINS(str1, str2) TSM_ASSERT(str1, ts_str_contains(str1, str2)) +#define TS_ASSERT_STR_NOT_CONTAINS(str1, str2) TSM_ASSERT(str1, !ts_str_contains(str1, str2)) #define TS_ASSERT_WSTR_CONTAINS(str1, str2) TSM_ASSERT(str1, ts_str_contains(str1, str2)) #define TS_ASSERT_WSTR_NOT_CONTAINS(str1, str2) TSM_ASSERT(str1, !ts_str_contains(str1, str2)) diff --git a/source/ps/CLogger.cpp b/source/ps/CLogger.cpp index 1a68943e6d..16c8ff03bd 100644 --- a/source/ps/CLogger.cpp +++ b/source/ps/CLogger.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2015 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -140,16 +140,15 @@ CLogger::~CLogger() } } -static std::string ToHTML(const wchar_t* message) +static std::string ToHTML(const char* message) { - Status err; - std::string cmessage = utf8_from_wstring(message, &err); + std::string cmessage = message; boost::algorithm::replace_all(cmessage, "&", "&"); boost::algorithm::replace_all(cmessage, "<", "<"); return cmessage; } -void CLogger::WriteMessage(const wchar_t* message, bool doRender = false) +void CLogger::WriteMessage(const char* message, bool doRender = false) { std::string cmessage = ToHTML(message); @@ -157,20 +156,20 @@ void CLogger::WriteMessage(const wchar_t* message, bool doRender = false) ++m_NumberOfMessages; // if (m_UseDebugPrintf) -// debug_printf(L"MESSAGE: %ls\n", message); +// debug_printf(L"MESSAGE: %hs\n", message); *m_MainLog << "

" << cmessage << "

\n"; m_MainLog->flush(); if (doRender) { - if (g_Console) g_Console->InsertMessage(L"INFO: %ls", message); + if (g_Console) g_Console->InsertMessage(L"INFO: %hs", message); PushRenderMessage(Normal, message); } } -void CLogger::WriteError(const wchar_t* message) +void CLogger::WriteError(const char* message) { std::string cmessage = ToHTML(message); @@ -178,9 +177,9 @@ void CLogger::WriteError(const wchar_t* message) ++m_NumberOfErrors; if (m_UseDebugPrintf) - debug_printf(L"ERROR: %ls\n", message); + debug_printf(L"ERROR: %hs\n", message); - if (g_Console) g_Console->InsertMessage(L"ERROR: %ls", message); + if (g_Console) g_Console->InsertMessage(L"ERROR: %hs", message); *m_InterestingLog << "

ERROR: " << cmessage << "

\n"; m_InterestingLog->flush(); @@ -190,7 +189,7 @@ void CLogger::WriteError(const wchar_t* message) PushRenderMessage(Error, message); } -void CLogger::WriteWarning(const wchar_t* message) +void CLogger::WriteWarning(const char* message) { std::string cmessage = ToHTML(message); @@ -198,9 +197,9 @@ void CLogger::WriteWarning(const wchar_t* message) ++m_NumberOfWarnings; if (m_UseDebugPrintf) - debug_printf(L"WARNING: %ls\n", message); + debug_printf(L"WARNING: %hs\n", message); - if (g_Console) g_Console->InsertMessage(L"WARNING: %ls", message); + if (g_Console) g_Console->InsertMessage(L"WARNING: %hs", message); *m_InterestingLog << "

WARNING: " << cmessage << "

\n"; m_InterestingLog->flush(); @@ -210,70 +209,6 @@ void CLogger::WriteWarning(const wchar_t* message) PushRenderMessage(Warning, message); } -void CLogger::LogMessage(const wchar_t* fmt, ...) -{ - va_list argp; - wchar_t buffer[BUFFER_SIZE] = {0}; - - va_start(argp, fmt); - if (sys_vswprintf(buffer, ARRAY_SIZE(buffer), fmt, argp) == -1) - { - // Buffer too small - ensure the string is nicely terminated - wcscpy_s(buffer+ARRAY_SIZE(buffer)-4, 4, L"..."); - } - va_end(argp); - - WriteMessage(buffer); -} - -void CLogger::LogMessageRender(const wchar_t* fmt, ...) -{ - va_list argp; - wchar_t buffer[BUFFER_SIZE] = {0}; - - va_start(argp, fmt); - if (sys_vswprintf(buffer, ARRAY_SIZE(buffer), fmt, argp) == -1) - { - // Buffer too small - ensure the string is nicely terminated - wcscpy_s(buffer+ARRAY_SIZE(buffer)-4, 4, L"..."); - } - va_end(argp); - - WriteMessage(buffer, true); -} - -void CLogger::LogWarning(const wchar_t* fmt, ...) -{ - va_list argp; - wchar_t buffer[BUFFER_SIZE] = {0}; - - va_start(argp, fmt); - if (sys_vswprintf(buffer, ARRAY_SIZE(buffer), fmt, argp) == -1) - { - // Buffer too small - ensure the string is nicely terminated - wcscpy_s(buffer+ARRAY_SIZE(buffer)-4, 4, L"..."); - } - va_end(argp); - - WriteWarning(buffer); -} - -void CLogger::LogError(const wchar_t* fmt, ...) -{ - va_list argp; - wchar_t buffer[BUFFER_SIZE] = {0}; - - va_start(argp, fmt); - if (sys_vswprintf(buffer, ARRAY_SIZE(buffer), fmt, argp) == -1) - { - // Buffer too small - ensure the string is nicely terminated - wcscpy_s(buffer+ARRAY_SIZE(buffer)-4, 4, L"..."); - } - va_end(argp); - - WriteError(buffer); -} - void CLogger::Render() { PROFILE3_GPU("logger"); @@ -300,26 +235,26 @@ void CLogger::Render() for (std::deque::iterator it = m_RenderMessages.begin(); it != m_RenderMessages.end(); ++it) { - const wchar_t* type; + const char* type; if (it->method == Normal) { - type = L"info"; + type = "info"; textRenderer.Color(0.0f, 0.8f, 0.0f); } else if (it->method == Warning) { - type = L"warning"; + type = "warning"; textRenderer.Color(1.0f, 1.0f, 0.0f); } else { - type = L"error"; + type = "error"; textRenderer.Color(1.0f, 0.0f, 0.0f); } CMatrix3D savedTransform = textRenderer.GetTransform(); - textRenderer.PrintfAdvance(L"[%8.3f] %ls: ", it->time, type); + textRenderer.PrintfAdvance(L"[%8.3f] %hs: ", it->time, type); // Display the actual message in white so it's more readable textRenderer.Color(1.0f, 1.0f, 1.0f); textRenderer.Put(0.0f, 0.0f, it->message.c_str()); @@ -334,26 +269,26 @@ void CLogger::Render() textTech->EndPass(); } -void CLogger::PushRenderMessage(ELogMethod method, const wchar_t* message) +void CLogger::PushRenderMessage(ELogMethod method, const char* message) { double now = timer_Time(); // Add each message line separately - const wchar_t* pos = message; - const wchar_t* eol; - while ((eol = wcschr(pos, L'\n')) != NULL) + const char* pos = message; + const char* eol; + while ((eol = strchr(pos, '\n')) != NULL) { if (eol != pos) { - RenderedMessage r = { method, now, std::wstring(pos, eol) }; + RenderedMessage r = { method, now, std::string(pos, eol) }; m_RenderMessages.push_back(r); } pos = eol + 1; } // Add the last line, if we didn't end on a \n - if (*pos != L'\0') + if (*pos != '\0') { - RenderedMessage r = { method, now, std::wstring(pos) }; + RenderedMessage r = { method, now, std::string(pos) }; m_RenderMessages.push_back(r); } } @@ -398,10 +333,9 @@ TestLogger::~TestLogger() g_Logger = m_OldLogger; } -std::wstring TestLogger::GetOutput() +std::string TestLogger::GetOutput() { - Status err; - return wstring_from_utf8(m_Stream.str(), &err); + return m_Stream.str(); } TestStdoutLogger::TestStdoutLogger() diff --git a/source/ps/CLogger.h b/source/ps/CLogger.h index 78e9ad8f1f..ba239767c4 100644 --- a/source/ps/CLogger.h +++ b/source/ps/CLogger.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2015 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,15 +24,16 @@ #include #include "ps/ThreadUtil.h" +#include "third_party/cppformat/format.h" class CLogger; extern CLogger* g_Logger; -#define LOGMESSAGE g_Logger->LogMessage -#define LOGMESSAGERENDER g_Logger->LogMessageRender -#define LOGWARNING g_Logger->LogWarning -#define LOGERROR g_Logger->LogError +#define LOGMESSAGE(...) g_Logger->WriteMessage(fmt::sprintf(__VA_ARGS__).c_str(), false) +#define LOGMESSAGERENDER(...) g_Logger->WriteMessage(fmt::sprintf(__VA_ARGS__).c_str(), true) +#define LOGWARNING(...) g_Logger->WriteWarning(fmt::sprintf(__VA_ARGS__).c_str()) +#define LOGERROR(...) g_Logger->WriteError (fmt::sprintf(__VA_ARGS__).c_str()) /** * Error/warning/message logging class. @@ -64,23 +65,17 @@ public: // Functions to write different message types (Errors and warnings are placed // both in mainLog and intrestingLog.) - void WriteMessage(const wchar_t* message, bool doRender); - void WriteError (const wchar_t* message); - void WriteWarning(const wchar_t* message); + void WriteMessage(const char* message, bool doRender); + void WriteError (const char* message); + void WriteWarning(const char* message); - // Functions to write a message, warning or error to file. - void LogMessage(const wchar_t* fmt, ...) WPRINTF_ARGS(2); - void LogMessageRender(const wchar_t* fmt, ...) WPRINTF_ARGS(2); - void LogWarning(const wchar_t* fmt, ...) WPRINTF_ARGS(2); - void LogError(const wchar_t* fmt, ...) WPRINTF_ARGS(2); - // Render recent log messages onto the screen void Render(); private: void Init(); - void PushRenderMessage(ELogMethod method, const wchar_t* message); + void PushRenderMessage(ELogMethod method, const char* message); // Delete old timed-out entries from the list of text to render void CleanupRenderQueue(); @@ -104,7 +99,7 @@ private: { ELogMethod method; double time; - std::wstring message; + std::string message; }; std::deque m_RenderMessages; double m_RenderLastEraseTime; @@ -123,7 +118,7 @@ class TestLogger public: TestLogger(); ~TestLogger(); - std::wstring GetOutput(); + std::string GetOutput(); private: CLogger* m_OldLogger; std::stringstream m_Stream; diff --git a/source/ps/XML/tests/test_RelaxNG.h b/source/ps/XML/tests/test_RelaxNG.h index 0cb11c69d3..3b1098672c 100644 --- a/source/ps/XML/tests/test_RelaxNG.h +++ b/source/ps/XML/tests/test_RelaxNG.h @@ -44,13 +44,13 @@ public: { TestLogger logger; TS_ASSERT(!v.Validate(L"doc", L"")); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"Parse error: doc:1: Expecting element test, got bogus"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "Parse error: doc:1: Expecting element test, got bogus"); } { TestLogger logger; TS_ASSERT(!v.Validate(L"doc", L"bogus")); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"RelaxNGValidator: Failed to parse document"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "RelaxNGValidator: Failed to parse document"); } TS_ASSERT(v.Validate(L"doc", L"")); @@ -82,7 +82,7 @@ public: TestLogger logger; TS_ASSERT(!v.LoadGrammar("whoops")); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"RelaxNGValidator: Failed to compile schema"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "RelaxNGValidator: Failed to compile schema"); TS_ASSERT(!v.Validate(L"doc", L"")); } diff --git a/source/ps/tests/test_CLogger.h b/source/ps/tests/test_CLogger.h index 285abd6d64..7b7623e1c4 100644 --- a/source/ps/tests/test_CLogger.h +++ b/source/ps/tests/test_CLogger.h @@ -24,8 +24,8 @@ class TestCLogger : public CxxTest::TestSuite public: void test_basic() { - logger->LogMessage(L"Test 1"); - logger->LogMessage(L"Test 2"); + logger->WriteMessage("Test 1", false); + logger->WriteMessage("Test 2", false); ParseOutput(); @@ -34,65 +34,10 @@ public: TS_ASSERT_EQUALS(lines[1], "Test 2"); } - void test_overflow() - { - const int buflen = 1024; - - std::string msg0 (buflen-2, '*'); - std::string msg1 (buflen-1, '*'); - std::string msg2 (buflen, '*'); - std::string msg3 (buflen+1, '*'); - - std::string clipped (buflen-4, '*'); - clipped += "..."; - - logger->LogMessage(L"%hs", msg0.c_str()); - logger->LogMessage(L"%hs", msg1.c_str()); - logger->LogMessage(L"%hs", msg2.c_str()); - logger->LogMessage(L"%hs", msg3.c_str()); - - logger->LogMessageRender(L"%hs", msg0.c_str()); - logger->LogMessageRender(L"%hs", msg1.c_str()); - logger->LogMessageRender(L"%hs", msg2.c_str()); - logger->LogMessageRender(L"%hs", msg3.c_str()); - - logger->LogWarning(L"%hs", msg0.c_str()); - logger->LogWarning(L"%hs", msg1.c_str()); - logger->LogWarning(L"%hs", msg2.c_str()); - logger->LogWarning(L"%hs", msg3.c_str()); - - logger->LogError(L"%hs", msg0.c_str()); - logger->LogError(L"%hs", msg1.c_str()); - logger->LogError(L"%hs", msg2.c_str()); - logger->LogError(L"%hs", msg3.c_str()); - - ParseOutput(); - - TS_ASSERT_EQUALS((int)lines.size(), 4*4); - TS_ASSERT_EQUALS(lines[0], msg0); - TS_ASSERT_EQUALS(lines[1], msg1); - TS_ASSERT_EQUALS(lines[2], clipped); - TS_ASSERT_EQUALS(lines[3], clipped); - - TS_ASSERT_EQUALS(lines[4], msg0); - TS_ASSERT_EQUALS(lines[5], msg1); - TS_ASSERT_EQUALS(lines[6], clipped); - TS_ASSERT_EQUALS(lines[7], clipped); - - TS_ASSERT_EQUALS(lines[8], "WARNING: "+msg0); - TS_ASSERT_EQUALS(lines[9], "WARNING: "+msg1); - TS_ASSERT_EQUALS(lines[10], "WARNING: "+clipped); - TS_ASSERT_EQUALS(lines[11], "WARNING: "+clipped); - - TS_ASSERT_EQUALS(lines[12], "ERROR: "+msg0); - TS_ASSERT_EQUALS(lines[13], "ERROR: "+msg1); - TS_ASSERT_EQUALS(lines[14], "ERROR: "+clipped); - TS_ASSERT_EQUALS(lines[15], "ERROR: "+clipped); - } - void test_unicode() { - logger->LogMessage(L"%lc %lc", 226, 295); + wchar_t str[] = { 226, 32, 295, 0 }; + logger->WriteMessage(utf8_from_wstring(str).c_str(), false); ParseOutput(); @@ -102,7 +47,7 @@ public: void test_html() { - logger->LogMessage(L"Testc"); + logger->WriteMessage("Testc", false); ParseOutput(); diff --git a/source/scriptinterface/tests/test_ScriptInterface.h b/source/scriptinterface/tests/test_ScriptInterface.h index 3089ea6af2..e966ee4a4f 100644 --- a/source/scriptinterface/tests/test_ScriptInterface.h +++ b/source/scriptinterface/tests/test_ScriptInterface.h @@ -31,8 +31,8 @@ public: ScriptInterface script("Test", "Test", g_ScriptRuntime); TestLogger logger; TS_ASSERT(script.LoadScript(L"test.js", "var x = 1+1;")); - TS_ASSERT_WSTR_NOT_CONTAINS(logger.GetOutput(), L"JavaScript error"); - TS_ASSERT_WSTR_NOT_CONTAINS(logger.GetOutput(), L"JavaScript warning"); + TS_ASSERT_STR_NOT_CONTAINS(logger.GetOutput(), "JavaScript error"); + TS_ASSERT_STR_NOT_CONTAINS(logger.GetOutput(), "JavaScript warning"); } void test_loadscript_error() @@ -40,7 +40,7 @@ public: ScriptInterface script("Test", "Test", g_ScriptRuntime); TestLogger logger; TS_ASSERT(!script.LoadScript(L"test.js", "1+")); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"JavaScript error: test.js line 1\nSyntaxError: syntax error"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: syntax error"); } void test_loadscript_strict_warning() @@ -49,7 +49,7 @@ public: TestLogger logger; // in strict mode, this inside a function doesn't point to the global object TS_ASSERT(script.LoadScript(L"test.js", "var isStrict = (function() { return !this; })();warn('isStrict is '+isStrict);")); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"WARNING: isStrict is true"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "WARNING: isStrict is true"); } void test_loadscript_strict_error() @@ -57,7 +57,7 @@ public: ScriptInterface script("Test", "Test", g_ScriptRuntime); TestLogger logger; TS_ASSERT(!script.LoadScript(L"test.js", "with(1){}")); - TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements"); } void test_clone_basic() diff --git a/source/simulation2/tests/test_ComponentManager.h b/source/simulation2/tests/test_ComponentManager.h index c84fe34208..9c92b4bb5b 100644 --- a/source/simulation2/tests/test_ComponentManager.h +++ b/source/simulation2/tests/test_ComponentManager.h @@ -109,13 +109,13 @@ public: { TestLogger log; TS_ASSERT(! man.AddComponent(hnd1, 12345, noParam)); - TS_ASSERT_WSTR_CONTAINS(log.GetOutput(), L"ERROR: Invalid component id 12345"); + TS_ASSERT_STR_CONTAINS(log.GetOutput(), "ERROR: Invalid component id 12345"); } { TestLogger log; TS_ASSERT(! man.AddComponent(hnd1, CID_Test1B, noParam)); - TS_ASSERT_WSTR_CONTAINS(log.GetOutput(), L"ERROR: Multiple components for interface "); + TS_ASSERT_STR_CONTAINS(log.GetOutput(), "ERROR: Multiple components for interface "); } } @@ -347,7 +347,7 @@ public: // In SpiderMonkey 1.6, JS_ReportError calls the error reporter even if it's inside // a try{} in the script; in recent versions (not sure when it changed) it doesn't // so the error here won't get reported. - TS_ASSERT_WSTR_NOT_CONTAINS(log.GetOutput(), L"ERROR: JavaScript error: simulation/components/error.js line 4\nInvalid interface id"); + TS_ASSERT_STR_NOT_CONTAINS(log.GetOutput(), "ERROR: JavaScript error: simulation/components/error.js line 4\nInvalid interface id"); } } diff --git a/source/test_setup.cpp b/source/test_setup.cpp index 448a650df9..c75f43a4f0 100644 --- a/source/test_setup.cpp +++ b/source/test_setup.cpp @@ -100,6 +100,11 @@ static MiscSetup miscSetup; // Definition of functions from lib/self_test.h +bool ts_str_contains(const std::string& str1, const std::string& str2) +{ + return str1.find(str2) != str1.npos; +} + bool ts_str_contains(const std::wstring& str1, const std::wstring& str2) { return str1.find(str2) != str1.npos;