From 505e694347c22d6d98ffa97ddd0230c4c22a5476 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 16 Nov 2019 17:01:57 +0100 Subject: [PATCH 1/4] Get rid of useless VarArgTestCase test fixture We don't need it any more, just define individual tests as independent test cases. This required using some other pointer instead of "this" in one of the tests, but it doesn't really matter which pointer we use there anyhow. No real changes. --- tests/strings/vararg.cpp | 67 +++++++--------------------------------- 1 file changed, 12 insertions(+), 55 deletions(-) diff --git a/tests/strings/vararg.cpp b/tests/strings/vararg.cpp index 413cb2e4c6..747a75e0b8 100644 --- a/tests/strings/vararg.cpp +++ b/tests/strings/vararg.cpp @@ -24,53 +24,10 @@ #include "wx/string.h" // ---------------------------------------------------------------------------- -// test class +// tests themselves // ---------------------------------------------------------------------------- -class VarArgTestCase : public CppUnit::TestCase -{ -public: - VarArgTestCase() {} - -private: - CPPUNIT_TEST_SUITE( VarArgTestCase ); - CPPUNIT_TEST( StringPrintf ); - CPPUNIT_TEST( CharPrintf ); - CPPUNIT_TEST( SizetPrintf ); -#if wxUSE_STD_STRING - CPPUNIT_TEST( StdString ); -#endif -#if wxUSE_LONGLONG - CPPUNIT_TEST( LongLongPrintf ); -#endif - CPPUNIT_TEST( Sscanf ); - CPPUNIT_TEST( RepeatedPrintf ); - CPPUNIT_TEST( ArgsValidation ); - CPPUNIT_TEST_SUITE_END(); - - void StringPrintf(); - void CharPrintf(); - void SizetPrintf(); -#if wxUSE_STD_STRING - void StdString(); -#endif -#if wxUSE_LONGLONG - void LongLongPrintf(); -#endif - void Sscanf(); - void RepeatedPrintf(); - void ArgsValidation(); - - wxDECLARE_NO_COPY_CLASS(VarArgTestCase); -}; - -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( VarArgTestCase ); - -// also include in its own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( VarArgTestCase, "VarArgTestCase" ); - -void VarArgTestCase::StringPrintf() +TEST_CASE("StringPrintf", "[wxString][Printf][vararg]") { wxString s, s2; @@ -113,7 +70,7 @@ void VarArgTestCase::StringPrintf() wxCLANG_WARNING_RESTORE(c++11-compat-deprecated-writable-strings) } -void VarArgTestCase::CharPrintf() +TEST_CASE("CharPrintf", "[wxString][Printf][vararg]") { wxString foo("foo"); wxString s; @@ -151,7 +108,7 @@ void VarArgTestCase::CharPrintf() CPPUNIT_ASSERT_EQUAL( "value is 240 (int)", s ); } -void VarArgTestCase::SizetPrintf() +TEST_CASE("SizetPrintf", "[wxString][Printf][vararg]") { size_t i = 1; ssize_t j = -2; @@ -170,7 +127,7 @@ void VarArgTestCase::SizetPrintf() } #if wxUSE_STD_STRING -void VarArgTestCase::StdString() +TEST_CASE("StdString", "[wxString][Printf][vararg]") { // test passing std::[w]string wxString s; @@ -187,7 +144,7 @@ void VarArgTestCase::StdString() #endif // wxUSE_STD_STRING #if wxUSE_LONGLONG -void VarArgTestCase::LongLongPrintf() +TEST_CASE("LongLongPrintf", "[wxString][Printf][vararg]") { const char * const llfmt = "%" wxLongLongFmtSpec "d"; @@ -198,7 +155,7 @@ void VarArgTestCase::LongLongPrintf() } #endif // wxUSE_LONGLONG -void VarArgTestCase::Sscanf() +TEST_CASE("Sscanf", "[wxSscanf][vararg]") { int i = 0; char str[20]; @@ -223,7 +180,7 @@ void VarArgTestCase::Sscanf() #endif } -void VarArgTestCase::RepeatedPrintf() +TEST_CASE("RepeatedPrintf", "[wxString][Printf][vararg]") { wxCharBuffer buffer(2); char *p = buffer.data(); @@ -239,10 +196,10 @@ void VarArgTestCase::RepeatedPrintf() CPPUNIT_ASSERT_EQUAL("buffer hi, len 2", s); } -void VarArgTestCase::ArgsValidation() +TEST_CASE("ArgsValidation", "[wxString][vararg][error]") { - void *ptr = this; int written; + void *ptr = &written; short int swritten; // these are valid: @@ -283,7 +240,7 @@ void VarArgTestCase::ArgsValidation() // but these are not: WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("%i", "foo") ); - WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("%s", (void*)this) ); + WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("%s", (void*)&written) ); WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("%d", ptr) ); // we don't check wxNO_PRINTF_PERCENT_N here as these expressions should @@ -306,7 +263,7 @@ void VarArgTestCase::ArgsValidation() wxString::Format("%c", wxChar(80) + wxChar(1)); // check size_t handling - size_t len = sizeof(*this); + size_t len = sizeof(ptr); #ifdef __WINDOWS__ wxString::Format("%Iu", len); #else From b690caba847aeaf90992fadae27cf633e0224f96 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 16 Nov 2019 17:05:06 +0100 Subject: [PATCH 2/4] Replace CPPUNIT_XXX macros with CHECKs This results in better error messages and also allows the test to continue executing even if a check fails. --- tests/strings/vararg.cpp | 62 ++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/tests/strings/vararg.cpp b/tests/strings/vararg.cpp index 747a75e0b8..cdc2af4530 100644 --- a/tests/strings/vararg.cpp +++ b/tests/strings/vararg.cpp @@ -33,29 +33,29 @@ TEST_CASE("StringPrintf", "[wxString][Printf][vararg]") // test passing literals: s.Printf("%s %i", "foo", 42); - CPPUNIT_ASSERT( s == "foo 42" ); + CHECK( s == "foo 42" ); s.Printf("%s %s %i", wxT("bar"), "=", 11); // test passing c_str(): - CPPUNIT_ASSERT( s == "bar = 11" ); + CHECK( s == "bar = 11" ); s2.Printf("(%s)", s.c_str()); - CPPUNIT_ASSERT( s2 == "(bar = 11)" ); + CHECK( s2 == "(bar = 11)" ); s2.Printf(wxT("[%s](%s)"), s.c_str(), "str"); - CPPUNIT_ASSERT( s2 == "[bar = 11](str)" ); + CHECK( s2 == "[bar = 11](str)" ); s2.Printf("%s mailbox", wxString("Opening").c_str()); - CPPUNIT_ASSERT( s2 == "Opening mailbox" ); + CHECK( s2 == "Opening mailbox" ); // test passing wxString directly: s2.Printf(wxT("[%s](%s)"), s, "str"); - CPPUNIT_ASSERT( s2 == "[bar = 11](str)" ); + CHECK( s2 == "[bar = 11](str)" ); // test passing wxCharBufferType: s = "FooBar"; s2.Printf(wxT("(%s)"), s.mb_str()); - CPPUNIT_ASSERT( s2 == "(FooBar)" ); + CHECK( s2 == "(FooBar)" ); s2.Printf(wxT("value=%s;"), s.wc_str()); - CPPUNIT_ASSERT( s2 == "value=FooBar;" ); + CHECK( s2 == "value=FooBar;" ); // this tests correct passing of wxCStrData constructed from string // literal (and we disable the warnings related to the use of a literal @@ -77,16 +77,16 @@ TEST_CASE("CharPrintf", "[wxString][Printf][vararg]") // test using wchar_t: s.Printf("char=%c", L'c'); - CPPUNIT_ASSERT_EQUAL( "char=c", s ); + CHECK( s == "char=c" ); // test wxUniCharRef: s.Printf("string[1] is %c", foo[1]); - CPPUNIT_ASSERT_EQUAL( "string[1] is o", s ); + CHECK( s == "string[1] is o" ); // test char char c = 'z'; s.Printf("%c to %c", 'a', c); - CPPUNIT_ASSERT_EQUAL( "a to z", s ); + CHECK( s == "a to z" ); // test char used as integer: #ifdef _MSC_VER @@ -100,12 +100,12 @@ TEST_CASE("CharPrintf", "[wxString][Printf][vararg]") #endif #ifndef __CHAR_UNSIGNED__ s.Printf("value is %i (int)", c); - CPPUNIT_ASSERT_EQUAL( wxString("value is -16 (int)"), s ); + CHECK( s == wxString("value is -16 (int)") ); #endif unsigned char u = 240; s.Printf("value is %i (int)", u); - CPPUNIT_ASSERT_EQUAL( "value is 240 (int)", s ); + CHECK( s == "value is 240 (int)" ); } TEST_CASE("SizetPrintf", "[wxString][Printf][vararg]") @@ -113,17 +113,11 @@ TEST_CASE("SizetPrintf", "[wxString][Printf][vararg]") size_t i = 1; ssize_t j = -2; - CPPUNIT_ASSERT_EQUAL - ( - "size_t=1 ssize_t=-2", - wxString::Format("size_t=%zu ssize_t=%zd", i, j) - ); + CHECK( wxString::Format("size_t=%zu ssize_t=%zd", i, j) + == "size_t=1 ssize_t=-2" ); - CPPUNIT_ASSERT_EQUAL - ( - "size_t=0xA0", - wxString::Format("size_t=0x%zX", static_cast(160)) - ); + CHECK( wxString::Format("size_t=0x%zX", static_cast(160)) + == "size_t=0xA0" ); } #if wxUSE_STD_STRING @@ -136,10 +130,10 @@ TEST_CASE("StdString", "[wxString][Printf][vararg]") std::string wc("widechar"); s.Printf("string %s(%i).", mb, 1); - CPPUNIT_ASSERT_EQUAL( "string multi-byte(1).", s ); + CHECK( s == "string multi-byte(1)." ); s.Printf("string %s(%i).", wc, 2); - CPPUNIT_ASSERT_EQUAL( "string widechar(2).", s ); + CHECK( s == "string widechar(2)." ); } #endif // wxUSE_STD_STRING @@ -148,10 +142,10 @@ TEST_CASE("LongLongPrintf", "[wxString][Printf][vararg]") { const char * const llfmt = "%" wxLongLongFmtSpec "d"; - CPPUNIT_ASSERT_EQUAL( "17", wxString::Format(llfmt, wxLL(17)) ); + CHECK( wxString::Format(llfmt, wxLL(17)) == "17" ); wxLongLong ll = 1234567890; - CPPUNIT_ASSERT_EQUAL( "1234567890", wxString::Format(llfmt, ll) ); + CHECK( wxString::Format(llfmt, ll) == "1234567890" ); } #endif // wxUSE_LONGLONG @@ -163,8 +157,8 @@ TEST_CASE("Sscanf", "[wxSscanf][vararg]") wxString input("42 test"); wxSscanf(input, "%d %s", &i, &str); - CPPUNIT_ASSERT( i == 42 ); - CPPUNIT_ASSERT( wxString(str) == "test" ); + CHECK( i == 42 ); + CHECK( wxString(str) == "test" ); #if !(defined(__MINGW32__) && \ defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO == 1) @@ -175,8 +169,8 @@ TEST_CASE("Sscanf", "[wxSscanf][vararg]") i = 0; wxSscanf(input, L"%d %s", &i, &wstr); - CPPUNIT_ASSERT( i == 42 ); - CPPUNIT_ASSERT( wxString(wstr) == "test" ); + CHECK( i == 42 ); + CHECK( wxString(wstr) == "test" ); #endif } @@ -190,10 +184,10 @@ TEST_CASE("RepeatedPrintf", "[wxString][Printf][vararg]") wxString s; s = wxString::Format("buffer %s, len %d", buffer, (int)wxStrlen(buffer)); - CPPUNIT_ASSERT_EQUAL("buffer hi, len 2", s); + CHECK( s == "buffer hi, len 2" ); s = wxString::Format("buffer %s, len %d", buffer, (int)wxStrlen(buffer)); - CPPUNIT_ASSERT_EQUAL("buffer hi, len 2", s); + CHECK( s == "buffer hi, len 2" ); } TEST_CASE("ArgsValidation", "[wxString][vararg][error]") @@ -235,7 +229,7 @@ TEST_CASE("ArgsValidation", "[wxString][vararg][error]") #ifndef wxNO_PRINTF_PERCENT_N wxString::Format("foo%i%n", 42, &written); - CPPUNIT_ASSERT_EQUAL( 5, written ); + CHECK( written == 5 ); #endif // but these are not: From 8005c5961543796c20bd9b940afcdaa4c8423adf Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 17 Nov 2019 18:26:26 +0100 Subject: [PATCH 3/4] Stop truncating all wxString::Printf() arguments to 65535 chars There is absolutely no good reason to do it and it resulted in silently truncating all the string formatted using "%s" to their first 65535 characters when using our wxPrintf() implementation. Closes #18586. --- include/wx/private/wxprintf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/wx/private/wxprintf.h b/include/wx/private/wxprintf.h index 5854d894d7..40ba87eef0 100644 --- a/include/wx/private/wxprintf.h +++ b/include/wx/private/wxprintf.h @@ -19,6 +19,7 @@ #include "wx/log.h" #include "wx/utils.h" +#include #include // prefer snprintf over sprintf @@ -189,7 +190,7 @@ template void wxPrintfConvSpec::Init() { m_nMinWidth = 0; - m_nMaxWidth = 0xFFFF; + m_nMaxWidth = INT_MAX; m_pos = 0; m_bAlignLeft = false; m_pArgPos = m_pArgEnd = NULL; From 8cba51978e30a7aa9663e724313a8a0a12b27784 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 16 Nov 2019 17:08:15 +0100 Subject: [PATCH 4/4] Add a check for using wxString::Format() with a very long string This used to fail until it was fixed in the previous commit. See #18586. --- tests/strings/vararg.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/strings/vararg.cpp b/tests/strings/vararg.cpp index cdc2af4530..237a0b6823 100644 --- a/tests/strings/vararg.cpp +++ b/tests/strings/vararg.cpp @@ -264,3 +264,16 @@ TEST_CASE("ArgsValidation", "[wxString][vararg][error]") wxString::Format("%zu", len); #endif } + +TEST_CASE("VeryLongArg", "[wxString][Format][vararg]") +{ + const size_t LENGTH = 70000; + wxString veryLongString('.', LENGTH); + REQUIRE( veryLongString.length() == LENGTH ); + + const wxString s = wxString::Format("%s", veryLongString); + + // Check the length first to avoid very long output if this fails. + REQUIRE( s.length() == LENGTH ); + CHECK( s == veryLongString ); +}