initial commit

Signed-off-by: Peter Siegmund <mars3142@noreply.mars3142.dev>
This commit is contained in:
2025-10-31 23:37:30 +01:00
commit bf6b52fd94
9654 changed files with 4035664 additions and 0 deletions

View File

@@ -0,0 +1,280 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/crt.cpp
// Purpose: Test for wx C runtime functions wrappers
// Author: Vaclav Slavik
// Created: 2004-06-03
// Copyright: (c) 2004 Vaclav Slavik
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/textfile.h"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
static const char *strMB = "hello, world";
static const wchar_t *strWC = L"hello, world";
static const wxString strWX("hello, world");
// ----------------------------------------------------------------------------
// tests
// ----------------------------------------------------------------------------
TEST_CASE("CRT::SetGetEnv", "[crt][getenv][setenv]")
{
#define TESTVAR_NAME "WXTESTVAR"
wxString val;
wxSetEnv(TESTVAR_NAME, wxT("value"));
CHECK( wxGetEnv(TESTVAR_NAME, &val) );
CHECK( val == "value" );
CHECK( wxString(wxGetenv(TESTVAR_NAME)) == "value" );
const wxString nonASCII = wxString::FromUTF8("");
wxSetEnv(TESTVAR_NAME, nonASCII);
CHECK( wxGetEnv(TESTVAR_NAME, &val) );
CHECK( val == nonASCII );
// Under MSW the current locale encoding is used for storing the value in
// the ASCII environment block, so we can't expect to get it back unless
// this encoding is UTF-8, which is not the case by default.
#ifndef __WINDOWS__
CHECK( wxString::FromUTF8(wxGetenv(TESTVAR_NAME)) == nonASCII );
#endif
// Wide char wxGetenv() overload does work, under both MSW and Unix.
CHECK( wxGetenv(L"WXTESTVAR") == nonASCII );
CHECK( wxUnsetEnv(TESTVAR_NAME) );
CHECK( !wxGetEnv(TESTVAR_NAME, nullptr) );
CHECK( !wxGetenv(TESTVAR_NAME) );
#undef TESTVAR_NAME
}
TEST_CASE("CRT::Strchr", "[crt][strchr]")
{
// test that searching for a wide character in a narrow string simply
// doesn't find it but doesn't fail with an assert (#11487)
const wxUniChar smiley = *wxString::FromUTF8("").begin();
CHECK( !wxStrchr("hello", smiley) );
// but searching for an explicitly wide character does find it
CHECK( wxStrchr(wxString::FromUTF8(":-) == ☺"),
static_cast<wchar_t>(smiley)) );
}
TEST_CASE("CRT::Strcmp", "[crt][strcmp]")
{
// this code tests if all possible ways of calling wxStrcmp() compile:
const char * const char1 = "first";
const wchar_t * const wchar1 = L"first";
wxString str1("first");
wxCStrData cstr1(str1.c_str());
wxCharBuffer charbuf1(char1);
wxWCharBuffer wcharbuf1(wchar1);
const char * const char2 = "last";
const wchar_t * const wchar2 = L"last";
wxString str2("last");
wxCStrData cstr2(str2.c_str());
wxCharBuffer charbuf2(char2);
wxWCharBuffer wcharbuf2(wchar2);
CHECK( wxStrcmp(char1, char2) < 0 );
CHECK( wxStrcmp(char1, wchar2) < 0 );
CHECK( wxStrcmp(char1, str2) < 0 );
CHECK( wxStrcmp(char1, cstr2) < 0 );
CHECK( wxStrcmp(char1, charbuf2) < 0 );
CHECK( wxStrcmp(char1, wcharbuf2) < 0 );
CHECK( wxStrcmp(wchar1, char2) < 0 );
CHECK( wxStrcmp(wchar1, wchar2) < 0 );
CHECK( wxStrcmp(wchar1, str2) < 0 );
CHECK( wxStrcmp(wchar1, cstr2) < 0 );
CHECK( wxStrcmp(wchar1, charbuf2) < 0 );
CHECK( wxStrcmp(wchar1, wcharbuf2) < 0 );
CHECK( wxStrcmp(str1, char2) < 0 );
CHECK( wxStrcmp(str1, wchar2) < 0 );
CHECK( wxStrcmp(str1, str2) < 0 );
CHECK( wxStrcmp(str1, cstr2) < 0 );
CHECK( wxStrcmp(str1, charbuf2) < 0 );
CHECK( wxStrcmp(str1, wcharbuf2) < 0 );
CHECK( wxStrcmp(cstr1, char2) < 0 );
CHECK( wxStrcmp(cstr1, wchar2) < 0 );
CHECK( wxStrcmp(cstr1, str2) < 0 );
CHECK( wxStrcmp(cstr1, cstr2) < 0 );
CHECK( wxStrcmp(cstr1, charbuf2) < 0 );
CHECK( wxStrcmp(cstr1, wcharbuf2) < 0 );
CHECK( wxStrcmp(charbuf1, char2) < 0 );
CHECK( wxStrcmp(charbuf1, wchar2) < 0 );
CHECK( wxStrcmp(charbuf1, str2) < 0 );
CHECK( wxStrcmp(charbuf1, cstr2) < 0 );
CHECK( wxStrcmp(charbuf1, charbuf2) < 0 );
CHECK( wxStrcmp(charbuf1, wcharbuf2) < 0 );
CHECK( wxStrcmp(wcharbuf1, char2) < 0 );
CHECK( wxStrcmp(wcharbuf1, wchar2) < 0 );
CHECK( wxStrcmp(wcharbuf1, str2) < 0 );
CHECK( wxStrcmp(wcharbuf1, cstr2) < 0 );
CHECK( wxStrcmp(wcharbuf1, charbuf2) < 0 );
CHECK( wxStrcmp(wcharbuf1, wcharbuf2) < 0 );
}
TEST_CASE("CRT::Strspn", "[crt][strspn]")
{
CHECK( wxStrspn(strMB, "xyz") == 0 );
CHECK( wxStrspn(strWC, "xyz") == 0 );
CHECK( wxStrspn(strWX, "xyz") == 0 );
CHECK( wxStrspn(strMB, L"xyz") == 0 );
CHECK( wxStrspn(strWC, L"xyz") == 0 );
CHECK( wxStrspn(strWX, L"xyz") == 0 );
CHECK( wxStrspn(strMB, "hleo") == 5 );
CHECK( wxStrspn(strWC, "hleo") == 5 );
CHECK( wxStrspn(strWX, "hleo") == 5 );
CHECK( wxStrspn(strMB, "ld") == 0 );
CHECK( wxStrspn(strWC, "ld") == 0 );
CHECK( wxStrspn(strWX, "ld") == 0 );
CHECK( wxStrspn(strMB, strWC) == strWX.length() );
CHECK( wxStrspn(strWC, strWX) == strWX.length() );
CHECK( wxStrspn(strWX, strMB) == strWX.length() );
}
TEST_CASE("CRT::Strcspn", "[crt][strcspn]")
{
CHECK( wxStrcspn(strMB, strWX) == 0 );
CHECK( wxStrcspn(strWC, strMB) == 0 );
CHECK( wxStrcspn(strWX, strWC) == 0 );
CHECK( wxStrcspn(strMB, ", ") == 5 );
CHECK( wxStrcspn(strWC, ", ") == 5 );
CHECK( wxStrcspn(strWX, ", ") == 5 );
CHECK( wxStrcspn(strMB, "hel") == 0 );
CHECK( wxStrcspn(strWC, "hel") == 0 );
CHECK( wxStrcspn(strWX, "hel") == 0 );
CHECK( wxStrcspn(strMB, "xy") == strWX.length() );
CHECK( wxStrcspn(strWC, "xy") == strWX.length() );
CHECK( wxStrcspn(strWX, "xy") == strWX.length() );
}
TEST_CASE("CRT::Strpbrk", "[crt][strpbrk]")
{
const wxString s(", ");
CHECK( *wxStrpbrk(strMB, ", ") == ',' );
CHECK( *wxStrpbrk(strWC, L", ") == L',' );
CHECK( *wxStrpbrk(strWX, ", ") == ',' );
CHECK( *wxStrpbrk(strWX, L", ") == L',' );
CHECK( *wxStrpbrk(strMB, s) == ',' );
CHECK( *wxStrpbrk(strWC, s) == L',' );
CHECK( *wxStrpbrk(strWX, s) == ',' );
CHECK( *wxStrpbrk(strWX.c_str(), s) == ',' );
CHECK( *wxStrpbrk(strMB, s.c_str()) == ',' );
CHECK( *wxStrpbrk(strWC, s.c_str()) == L',' );
CHECK( *wxStrpbrk(strWX, s.c_str()) == ',' );
CHECK( *wxStrpbrk(strWX.c_str(), s.c_str()) == ',' );
CHECK( *wxStrpbrk(strMB, s.mb_str()) == ',' );
CHECK( *wxStrpbrk(strWC, s.wc_str()) == L',' );
CHECK( *wxStrpbrk(strWX, s.mb_str()) == ',' );
CHECK( *wxStrpbrk(strWX, s.wc_str()) == L',' );
CHECK( *wxStrpbrk(strWX.c_str(), s.mb_str()) == ',' );
CHECK( *wxStrpbrk(strWX.c_str(), s.wc_str()) == L',' );
CHECK( !wxStrpbrk(strWX, "xyz") );
CHECK( !wxStrpbrk(strWX.c_str(), L"xyz") );
}
TEST_CASE("CRT::Strnlen", "[crt][strnlen]")
{
// other misc tests for wxStrnlen(const char*, size_t)
CHECK( wxStrnlen("", 0) == 0 );
CHECK( wxStrnlen("", 8) == 0 );
CHECK( wxStrnlen("1234", 0) == 0 );
CHECK( wxStrnlen("1234", 2) == 2 );
CHECK( wxStrnlen("1234", 8) == 4 );
CHECK( wxStrnlen("1234567", 8) == 7 );
CHECK( wxStrnlen("12345678", 8) == 8 );
CHECK( wxStrnlen("123456789", 8) == 8 );
CHECK( wxStrnlen("123456789", 12) == 9 );
// other misc tests for wxStrnlen(const wchar_t*, size_t)
CHECK( wxStrnlen(L"", 0) == 0 );
CHECK( wxStrnlen(L"", 8) == 0 );
CHECK( wxStrnlen(L"1234", 0) == 0 );
CHECK( wxStrnlen(L"1234", 2) == 2 );
CHECK( wxStrnlen(L"1234", 8) == 4 );
CHECK( wxStrnlen(L"1234567", 8) == 7 );
CHECK( wxStrnlen(L"12345678", 8) == 8 );
CHECK( wxStrnlen(L"123456789", 8) == 8 );
CHECK( wxStrnlen(L"123456789", 12) == 9 );
// wxStrlen() is only for null-terminated strings:
CHECK( wxStrnlen("1234" "\0" "78", 12) == 4 );
CHECK( wxStrnlen(L"1234" L"\0" L"5678", 12) == 4 );
}
TEST_CASE("CRT::Strtox", "[crt][strtod][strtol]")
{
const wxString s = "123@";
const double d = 123.0;
const long l = 123;
SECTION("char")
{
char* end = nullptr;
CHECK( wxStrtod(s, &end) == d );
REQUIRE( end );
CHECK( *end == '@' );
CHECK( wxStrtol(s, &end, 10) == l );
REQUIRE( end );
CHECK( *end == '@' );
}
SECTION("wchar_t")
{
wchar_t* end = nullptr;
CHECK( wxStrtod(s, &end) == d );
REQUIRE( end );
CHECK( *end == L'@' );
CHECK( wxStrtol(s, &end, 10) == l );
REQUIRE( end );
CHECK( *end == L'@' );
}
SECTION("other")
{
CHECK( wxStrtod(s, 0) == d );
#ifdef wxHAS_NULLPTR_T
CHECK( wxStrtod(s, nullptr) == d );
CHECK( wxStrtol(s, nullptr, 10) == l );
#endif
}
}

View File

@@ -0,0 +1,127 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/hexconv.cpp
// Purpose: wxDecToHex, wxHexToDec unit test
// Author: Artur Wieczorek
// Created: 2017-02-23
// Copyright: (c) 2017 wxWidgets development team
///////////////////////////////////////////////////////////////////////////////
#include "testprec.h"
#include "wx/utils.h"
static void DecToHex1();
static void DecToHex2();
static void DecToHex3();
static void HexToDec1();
static void HexToDec2();
TEST_CASE("HexConvTestCase", "[string][hexconv]")
{
SECTION("DecToHex1") // Conversion to wxString
{
DecToHex1();
}
SECTION("DecToHex2") // Conversion to wxChar string
{
DecToHex2();
}
SECTION("DecToHex3") // Conversion to 2 characters
{
DecToHex3();
}
SECTION("HexToDec1") // Conversion from char string
{
HexToDec1();
}
SECTION("HexToDec2") // Conversion from wxString
{
HexToDec2();
}
}
// ===== Implementation =====
static void DecToHex1()
{
// Conversion to wxString
for ( int i = 0; i < 256; i++ )
{
char szHexStrRef[16];
sprintf(szHexStrRef, "%02X", i);
wxString hexStrRef = wxString(szHexStrRef);
wxString hexStr = wxDecToHex(i);
CHECK(hexStr == hexStrRef);
}
}
static void DecToHex2()
{
// Conversion to wxChar string
for ( int i = 0; i < 256; i++ )
{
char szHexStrRef[16];
sprintf(szHexStrRef, "%02X", i);
wxChar hexStr[4];
memset(hexStr, 0xFF, sizeof(hexStr));
wxChar c3 = hexStr[3]; // This character should remain untouched
wxDecToHex(i, hexStr);
CHECK(hexStr[0] == (wxChar)szHexStrRef[0]);
CHECK(hexStr[1] == (wxChar)szHexStrRef[1]);
CHECK(hexStr[2] == (wxChar)'\0');
CHECK(hexStr[3] == c3);
}
}
static void DecToHex3()
{
// Conversion to 2 characters
for ( int i = 0; i < 256; i++ )
{
char szHexStrRef[16];
sprintf(szHexStrRef, "%02X", i);
char c1 = '\xFF';
char c2 = '\xFF';
wxDecToHex(i, &c1, &c2);
CHECK(c1 == szHexStrRef[0]);
CHECK(c2 == szHexStrRef[1]);
}
}
static void HexToDec1()
{
// Conversion from char string
for ( int i = 0; i < 256; i++ )
{
char szHexStr[16];
sprintf(szHexStr, "%02X", i);
int n = wxHexToDec(szHexStr);
CHECK(n == i);
}
}
static void HexToDec2()
{
// Conversion from wxString
for ( int i = 0; i < 256; i++ )
{
char szHexStr[16];
sprintf(szHexStr, "%02X", i);
wxString hexStr = wxString(szHexStr);
int n = wxHexToDec(hexStr);
CHECK(n == i);
}
}

View File

@@ -0,0 +1,62 @@
//////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/iostream.cpp
// Purpose: unit test of wxString interaction with std::[io]stream
// Author: Vadim Zeitlin
// Created: 2007-10-09
// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwidgets.org>
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifndef WX_PRECOMP
#include "wx/string.h"
#endif // WX_PRECOMP
#if wxUSE_STD_IOSTREAM
#include <sstream>
#define ASSERT_OSTREAM_EQUAL(p, s) CPPUNIT_ASSERT_EQUAL(std::string(p), s.str())
#define ASSERT_WOSTREAM_EQUAL(p, s) CPPUNIT_ASSERT_EQUAL(std::wstring(p), s.str())
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class StringIostreamTestCase : public CppUnit::TestCase
{
public:
StringIostreamTestCase() { }
private:
CPPUNIT_TEST_SUITE( StringIostreamTestCase );
CPPUNIT_TEST( Out );
CPPUNIT_TEST_SUITE_END();
void Out();
};
CPPUNIT_TEST_SUITE_REGISTRATION( StringIostreamTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( StringIostreamTestCase, "StringIostream" );
void StringIostreamTestCase::Out()
{
std::ostringstream s;
s << wxString("hello");
ASSERT_OSTREAM_EQUAL("hello", s);
#if defined(HAVE_WOSTREAM)
std::wostringstream ws;
ws << wxString("bye");
ASSERT_WOSTREAM_EQUAL(L"bye", ws);
#endif
}
#endif // wxUSE_STD_IOSTREAM

View File

@@ -0,0 +1,343 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/numformat.cpp
// Purpose: wxNumberFormatter unit test
// Author: Vadim Zeitlin
// Created: 2011-01-15
// Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#include "wx/numformatter.h"
#include "wx/intl.h"
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
namespace
{
class NumFormatterTestCase
{
public:
NumFormatterTestCase() :
// We need to use a locale with known decimal point and which uses the
// thousands separator for the tests to make sense.
m_locale(wxLANGUAGE_ENGLISH_UK, wxLOCALE_DONT_LOAD_DEFAULT)
{
}
protected:
bool CanRunTest() const { return m_locale.IsOk(); }
private:
wxLocale m_locale;
wxDECLARE_NO_COPY_CLASS(NumFormatterTestCase);
};
// A couple of helpers to avoid writing over long expressions.
wxString ToStringWithoutTrailingZeroes(double val, int precision)
{
return wxNumberFormatter::ToString
(
val,
precision,
wxNumberFormatter::Style_NoTrailingZeroes
);
}
wxString ToStringWithTrailingZeroes(double val, int precision)
{
return wxNumberFormatter::ToString
(
val,
precision,
wxNumberFormatter::Style_None
);
}
} // anonymous namespace
// ----------------------------------------------------------------------------
// tests themselves
// ----------------------------------------------------------------------------
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::LongToString", "[numformatter]")
{
if ( !CanRunTest() )
return;
CHECK( wxNumberFormatter::ToString( 1L) == "1" );
CHECK( wxNumberFormatter::ToString( -1L) == "-1" );
CHECK( wxNumberFormatter::ToString( 12L) == "12" );
CHECK( wxNumberFormatter::ToString( -12L) == "-12" );
CHECK( wxNumberFormatter::ToString( 123L) == "123" );
CHECK( wxNumberFormatter::ToString( -123L) == "-123" );
CHECK( wxNumberFormatter::ToString( 1234L) == "1,234" );
CHECK( wxNumberFormatter::ToString( -1234L) == "-1,234" );
CHECK( wxNumberFormatter::ToString( 12345L) == "12,345" );
CHECK( wxNumberFormatter::ToString( -12345L) == "-12,345" );
CHECK( wxNumberFormatter::ToString( 123456L) == "123,456" );
CHECK( wxNumberFormatter::ToString( -123456L) == "-123,456" );
CHECK( wxNumberFormatter::ToString( 1234567L) == "1,234,567" );
CHECK( wxNumberFormatter::ToString( -1234567L) == "-1,234,567" );
CHECK( wxNumberFormatter::ToString( 12345678L) == "12,345,678" );
CHECK( wxNumberFormatter::ToString( -12345678L) == "-12,345,678" );
CHECK( wxNumberFormatter::ToString( 123456789L) == "123,456,789" );
}
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::LongLongToString", "[numformatter]")
{
if ( !CanRunTest() )
return;
CHECK( wxNumberFormatter::ToString(wxLL( 1)) == "1" );
CHECK( wxNumberFormatter::ToString(wxLL( 12)) == "12" );
CHECK( wxNumberFormatter::ToString(wxLL( 123)) == "123" );
CHECK( wxNumberFormatter::ToString(wxLL( 1234)) == "1,234" );
CHECK( wxNumberFormatter::ToString(wxLL( 12345)) == "12,345" );
CHECK( wxNumberFormatter::ToString(wxLL( 123456)) == "123,456" );
CHECK( wxNumberFormatter::ToString(wxLL( 1234567)) == "1,234,567" );
CHECK( wxNumberFormatter::ToString(wxLL( 12345678)) == "12,345,678" );
CHECK( wxNumberFormatter::ToString(wxLL( 123456789)) == "123,456,789" );
}
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::DoubleToString", "[numformatter]")
{
if ( !CanRunTest() )
return;
CHECK( wxNumberFormatter::ToString( 1., 1) == "1.0" );
CHECK( wxNumberFormatter::ToString( 0.123456, 6) == "0.123456" );
CHECK( wxNumberFormatter::ToString( 1.234567, 6) == "1.234567" );
CHECK( wxNumberFormatter::ToString( 12.34567, 5) == "12.34567" );
CHECK( wxNumberFormatter::ToString( 123.4567, 4) == "123.4567" );
CHECK( wxNumberFormatter::ToString( 1234.56, 2) == "1,234.56" );
CHECK( wxNumberFormatter::ToString( 12345.6, 1) == "12,345.6" );
CHECK( wxNumberFormatter::ToString(123456789.012, 3) == "123,456,789.012" );
CHECK( wxNumberFormatter::ToString( 12345.012, -1) == "12,345" );
CHECK( ToStringWithTrailingZeroes(-123.123, 4) == "-123.1230" );
CHECK( ToStringWithTrailingZeroes( 0.02, 1) == "0.0" );
CHECK( ToStringWithTrailingZeroes( -0.02, 1) == "-0.0" );
}
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::NoTrailingZeroes", "[numformatter]")
{
WX_ASSERT_FAILS_WITH_ASSERT
(
wxNumberFormatter::ToString(123L, wxNumberFormatter::Style_NoTrailingZeroes)
);
if ( !CanRunTest() )
return;
CHECK( ToStringWithTrailingZeroes ( 123., 3) == "123.000" );
CHECK( ToStringWithoutTrailingZeroes( 123., 3) == "123" );
CHECK( ToStringWithoutTrailingZeroes( 123., 9) == "123" );
CHECK( ToStringWithoutTrailingZeroes( 123.456, 3) == "123.456" );
CHECK( ToStringWithTrailingZeroes ( 123.456, 9) == "123.456000000" );
CHECK( ToStringWithoutTrailingZeroes( 123.456, 9) == "123.456" );
CHECK( ToStringWithoutTrailingZeroes( 123.123, 2) == "123.12" );
CHECK( ToStringWithoutTrailingZeroes( 123.123, 0) == "123" );
CHECK( ToStringWithoutTrailingZeroes( -0.000123, 3) == "0" );
CHECK( ToStringWithoutTrailingZeroes( 123., -1) == "123" );
CHECK( ToStringWithoutTrailingZeroes( 1e-120, -1) == "1e-120" );
}
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::LongFromString", "[numformatter]")
{
if ( !CanRunTest() )
return;
WX_ASSERT_FAILS_WITH_ASSERT
(
wxNumberFormatter::FromString("123", static_cast<long *>(nullptr))
);
long l;
CHECK_FALSE( wxNumberFormatter::FromString("", &l) );
CHECK_FALSE( wxNumberFormatter::FromString("foo", &l) );
CHECK_FALSE( wxNumberFormatter::FromString("1.234", &l) );
CHECK_FALSE( wxNumberFormatter::FromString("-", &l) );
CHECK( wxNumberFormatter::FromString("0", &l) );
CHECK( l == 0 );
CHECK( wxNumberFormatter::FromString("123", &l) );
CHECK( l == 123 );
CHECK( wxNumberFormatter::FromString("1234", &l) );
CHECK( l == 1234 );
CHECK( wxNumberFormatter::FromString("1,234", &l) );
CHECK( l == 1234 );
CHECK( wxNumberFormatter::FromString("12,345", &l) );
CHECK( l == 12345 );
CHECK( wxNumberFormatter::FromString("123,456", &l) );
CHECK( l == 123456 );
CHECK( wxNumberFormatter::FromString("1,234,567", &l) );
CHECK( l == 1234567 );
CHECK( wxNumberFormatter::FromString("-123", &l) );
CHECK( l == -123 );
CHECK_FALSE( wxNumberFormatter::FromString("9223372036854775808", &l) );
}
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::LongLongFromString", "[numformatter]")
{
if ( !CanRunTest() )
return;
WX_ASSERT_FAILS_WITH_ASSERT
(
wxNumberFormatter::FromString("123", static_cast<wxLongLong_t *>(nullptr))
);
wxLongLong_t l;
CHECK_FALSE( wxNumberFormatter::FromString("", &l) );
CHECK_FALSE( wxNumberFormatter::FromString("foo", &l) );
CHECK_FALSE( wxNumberFormatter::FromString("1.234", &l) );
// This somehow succeeds with gcc 4.8.4 under Ubuntu and MinGW 5.3, so
// don't use CHECK() for it.
if ( wxNumberFormatter::FromString("-", &l) )
{
WARN("Converting \"-\" to long long unexpectedly succeeded, result: " << l);
}
CHECK( wxNumberFormatter::FromString("0", &l) );
CHECK( l == 0 );
CHECK( wxNumberFormatter::FromString("123", &l) );
CHECK( l == 123 );
CHECK( wxNumberFormatter::FromString("1234", &l) );
CHECK( l == 1234 );
CHECK( wxNumberFormatter::FromString("1,234", &l) );
CHECK( l == 1234 );
CHECK( wxNumberFormatter::FromString("12,345", &l) );
CHECK( l == 12345 );
CHECK( wxNumberFormatter::FromString("123,456", &l) );
CHECK( l == 123456 );
CHECK( wxNumberFormatter::FromString("1,234,567", &l) );
CHECK( l == 1234567 );
CHECK( wxNumberFormatter::FromString("-123", &l) );
CHECK( l == -123 );
CHECK( wxNumberFormatter::FromString("9223372036854775807", &l) );
CHECK( l == wxINT64_MAX );
CHECK_FALSE( wxNumberFormatter::FromString("9223372036854775808", &l) );
}
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::ULongLongFromString", "[numformatter]")
{
if ( !CanRunTest() )
return;
wxULongLong_t u;
CHECK_FALSE( wxNumberFormatter::FromString("", &u) );
CHECK_FALSE( wxNumberFormatter::FromString("bar", &u) );
CHECK_FALSE( wxNumberFormatter::FromString("1.234", &u) );
CHECK_FALSE( wxNumberFormatter::FromString("-2", &u) );
CHECK_FALSE( wxNumberFormatter::FromString("-", &u) );
CHECK( wxNumberFormatter::FromString("0", &u) );
CHECK( u == 0 );
CHECK( wxNumberFormatter::FromString("123", &u) );
CHECK( u == 123 );
CHECK( wxNumberFormatter::FromString("1234", &u) );
CHECK( u == 1234 );
CHECK( wxNumberFormatter::FromString("1,234", &u) );
CHECK( u == 1234 );
CHECK( wxNumberFormatter::FromString("12,345", &u) );
CHECK( u == 12345 );
CHECK( wxNumberFormatter::FromString("123,456", &u) );
CHECK( u == 123456 );
CHECK( wxNumberFormatter::FromString("1,234,567", &u) );
CHECK( u == 1234567 );
CHECK( wxNumberFormatter::FromString("9223372036854775807", &u) );
CHECK( u == static_cast<wxULongLong_t>(wxINT64_MAX) );
CHECK( wxNumberFormatter::FromString("9223372036854775808", &u) );
CHECK( u == static_cast<wxULongLong_t>(wxINT64_MAX) + 1 );
CHECK( wxNumberFormatter::FromString("18446744073709551615", &u) );
CHECK( u == wxUINT64_MAX );
CHECK_FALSE( wxNumberFormatter::FromString("18446744073709551616", &u) );
}
TEST_CASE_METHOD(NumFormatterTestCase, "NumFormatter::DoubleFromString", "[numformatter]")
{
if ( !CanRunTest() )
return;
WX_ASSERT_FAILS_WITH_ASSERT
(
wxNumberFormatter::FromString("123", static_cast<double *>(nullptr))
);
double d;
CHECK_FALSE( wxNumberFormatter::FromString("", &d) );
CHECK_FALSE( wxNumberFormatter::FromString("bar", &d) );
CHECK( wxNumberFormatter::FromString("123", &d) );
CHECK( d == 123. );
CHECK( wxNumberFormatter::FromString("123.456789012", &d) );
CHECK( d == 123.456789012 );
CHECK( wxNumberFormatter::FromString("1,234.56789012", &d) );
CHECK( d == 1234.56789012 );
CHECK( wxNumberFormatter::FromString("12,345.6789012", &d) );
CHECK( d == 12345.6789012 );
CHECK( wxNumberFormatter::FromString("123,456.789012", &d) );
CHECK( d == 123456.789012 );
CHECK( wxNumberFormatter::FromString("1,234,567.89012", &d) );
CHECK( d == 1234567.89012 );
CHECK( wxNumberFormatter::FromString("12,345,678.9012", &d) );
CHECK( d == 12345678.9012 );
CHECK( wxNumberFormatter::FromString("123,456,789.012", &d) );
CHECK( d == 123456789.012 );
CHECK( wxNumberFormatter::FromString("123456789.012", &d) );
CHECK( d == 123456789.012 );
}

View File

@@ -0,0 +1,704 @@
//////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/stdstrings.cpp
// Purpose: wxString unit test
// Author: Vadim Zeitlin, Wlodzimierz ABX Skiba
// Created: 2004-05-07
// Copyright: (c) 2004 Vadim Zeitlin, Wlodzimierz Skiba
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include <algorithm>
TEST_CASE("StdString::Constructors", "[stdstring]")
{
wxString s1(wxT("abcdefgh")),
s2(wxT("abcdefghijklm"), 8),
s3(wxT("abcdefghijklm")),
s4(8, wxT('a'));
wxString s5(s1),
s6(s3, 0, 8),
s7(s3.begin(), s3.begin() + 8);
wxString s8(s1, 4, 8);
CHECK( s1 == wxT("abcdefgh") );
CHECK( s2 == s1 );
CHECK( s4 == wxT("aaaaaaaa") );
CHECK( s5 == wxT("abcdefgh") );
CHECK( s6 == s1 );
CHECK( s7 == s1 );
CHECK( s8 == wxT("efgh") );
const char *pc = s1.c_str();
CHECK( wxString(pc + 1, pc + 4) == "bcd" );
const wchar_t *pw = s2.c_str();
CHECK( wxString(pw, pw + 1) == "a" );
wxString s9(std::move(s1));
CHECK( s9 == wxT("abcdefgh"));
wxString s10(std::move(s3), 8);
CHECK( s10 == wxT("abcdefgh"));
}
TEST_CASE("StdString::Iterators", "[stdstring]")
{
// test compilation of default iterators ctors:
wxString::iterator i1;
wxUnusedVar(i1);
wxString::const_iterator i2;
wxUnusedVar(i2);
wxString::reverse_iterator i3;
wxUnusedVar(i3);
wxString::const_reverse_iterator i4;
wxUnusedVar(i4);
}
TEST_CASE("StdString::IteratorsCmp", "[stdstring]")
{
wxString s("foobar");
wxString::iterator i = s.begin();
wxString::const_iterator ci = s.begin();
CHECK( i == ci );
CHECK( i >= ci );
CHECK( i <= ci );
CHECK( ci == i );
CHECK( ci >= i );
CHECK( ci <= i );
ci++;
CHECK( i != ci );
CHECK( i < ci );
CHECK( !(i > ci) );
CHECK( ci != i );
CHECK( ci > i );
CHECK( !(ci < i) );
}
TEST_CASE("StdString::Append", "[stdstring]")
{
wxString s1, s2, s3, s4, s5, s6, s7, s8;
s1 = s2 = s3 = s4 = s5 = s6 = wxT("abc");
s1.append(wxT("def"));
s2.append(wxT("defgh"), 3);
s3.append(wxString(wxT("abcdef")), 3, 6);
s4.append(s1);
s5.append(3, wxT('a'));
s5.append(2, 'x');
s5.append(1, (unsigned char)'y');
s6.append(s1.begin() + 3, s1.end());
CHECK( s1 == wxT("abcdef") );
CHECK( s2 == wxT("abcdef") );
CHECK( s3 == wxT("abcdef") );
CHECK( s4 == wxT("abcabcdef") );
CHECK( s5 == wxT("abcaaaxxy") );
CHECK( s6 == wxT("abcdef") );
const char *pc = s1.c_str() + 2;
s7.append(pc, pc + 4);
CHECK( s7 == "cdef" );
const wchar_t *pw = s2.c_str() + 2;
s8.append(pw, pw + 4);
CHECK( s8 == "cdef" );
s7 = s8 = wxString(wxT("null\0time"), 9);
s7.append(wxT("def"));
s8.append(wxT("defgh"), 3);
CHECK( s7 == wxString(wxT("null\0timedef"), 12) );
CHECK( s8 == wxString(wxT("null\0timedef"), 12) );
}
TEST_CASE("StdString::Assign", "[stdstring]")
{
wxString s1, s2, s3, s4, s5, s6, s7, s8, s9;
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = wxT("abc");
s1.assign(wxT("def"));
s2.assign(wxT("defgh"), 3);
s3.assign(wxString(wxT("abcdef")), 3, 6);
s4.assign(s1);
s5.assign(3, wxT('a'));
s6.assign(s1.begin() + 1, s1.end());
CHECK( s1 == wxT("def") );
CHECK( s2 == wxT("def") );
CHECK( s3 == wxT("def") );
CHECK( s4 == wxT("def") );
CHECK( s5 == wxT("aaa") );
CHECK( s6 == wxT("ef") );
const char *pc = s1.c_str();
s7.assign(pc, pc + 2);
CHECK( s7 == "de" );
const wchar_t *pw = s1.c_str();
s8.assign(pw + 2, pw + 3);
CHECK( s8 == "f" );
s1.assign(s1, 1, 1);
CHECK( s1 == "e" );
s9.assign(std::move(s2));
CHECK(s9 == wxT("def"));
s2 = wxT("qwerty");
CHECK(s2 == wxT("qwerty"));
// Self-assignment
wxString& s9ref = s9;
s9ref.assign(s9);
CHECK(s9 == wxT("def"));
// Self-move may change the value, but shouldn't crash
// and reassignment should work
s9ref.assign(std::move(s9));
s9 = "qwerty";
CHECK(s9 == wxT("qwerty"));
}
TEST_CASE("StdString::AssignOp", "[stdstring]")
{
wxString s1, s2, s3, s4, s5, s6, s7, s8;
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = wxT("abc");
// operator=
s1 = wxT("def");
CHECK(s1 == wxT("def"));
s2 = s1;
CHECK(s2 == wxT("def"));
const char* pc = s1.c_str();
s3 = pc;
CHECK(s3 == wxT("def"));
const wchar_t* pw = s1.c_str();
s4 = pw;
CHECK(s4 == wxT("def"));
s5 = std::move(s1);
CHECK(s5 == wxT("def"));
s1 = wxT("qwerty");
CHECK(s1 == wxT("qwerty"));
// swap
s6 = wxT("def");
std::swap(s6, s7);
CHECK(s6 == wxT("abc"));
CHECK(s7 == wxT("def"));
swap(s6, s7);
CHECK(s6 == wxT("def"));
CHECK(s7 == wxT("abc"));
s6.swap(s7);
CHECK(s6 == wxT("abc"));
CHECK(s7 == wxT("def"));
// Self-assignment
wxString& s8ref = s8;
s8ref = s8;
CHECK(s8 == wxT("abc"));
// Self-move may change the value, but shouldn't crash
// and reassignment should work
s8ref = std::move(s8);
s8 = "qwerty";
CHECK(s8 == wxT("qwerty"));
// Self-swap
std::swap(s8, s8ref);
CHECK(s8 == wxT("qwerty"));
swap(s8, s8ref);
CHECK(s8 == wxT("qwerty"));
s8.swap(s8ref);
CHECK(s8 == wxT("qwerty"));
}
TEST_CASE("StdString::Compare", "[stdstring]")
{
wxString s1, s2, s3, s4, s5, s6;
s1 = wxT("abcdefgh");
s2 = wxT("abcdefgh");
s3 = wxT("abc");
s4 = wxT("abcdefghi");
s5 = wxT("aaa");
s6 = wxT("zzz");
CHECK( s1.compare(s2) == 0 );
CHECK( s1.compare(s3) > 0 );
CHECK( s1.compare(s4) < 0 );
CHECK( s1.compare(s5) > 0 );
CHECK( s1.compare(s6) < 0 );
CHECK( s1.compare(1, 12, s1) > 0);
CHECK( s1.compare(wxT("abcdefgh")) == 0);
CHECK( s1.compare(1, 7, wxT("bcdefgh")) == 0);
CHECK( s1.compare(1, 7, wxT("bcdefgh"), 7) == 0);
}
TEST_CASE("StdString::Erase", "[stdstring]")
{
wxString s1, s2, s3, s4, s7;
s1 = wxT("abcdefgh");
s2 = wxT("abcdefgh");
s3 = wxT("abc");
s4 = wxT("abcdefghi");
s7 = wxT("zabcdefg");
s1.erase(1, 1);
s2.erase(4, 12);
wxString::iterator it = s3.erase(s3.begin() + 1);
wxString::iterator it2 = s4.erase(s4.begin() + 4, s4.begin() + 6);
wxString::iterator it3 = s7.erase(s7.begin() + 4, s7.begin() + 8);
CHECK( s1 == wxT("acdefgh") );
CHECK( s2 == wxT("abcd") );
CHECK( s3 == wxT("ac") );
CHECK( s4 == wxT("abcdghi") );
CHECK( s7 == wxT("zabc") );
CHECK( *it == wxT('c') );
CHECK( *it2 == wxT('g') );
CHECK( it3 == s7.end() );
}
TEST_CASE("StdString::Find", "[stdstring]")
{
// 0 1 2
// 01234567890123456789012345
wxString s1 = wxT("abcdefgABCDEFGabcABCabcABC");
wxString s2 = wxT("gAB");
CHECK( s1.find(wxT('A')) == 7u );
CHECK( s1.find(wxT('A'), 7) == 7u );
CHECK( s1.find(wxT('Z')) == wxString::npos );
CHECK( s1.find(wxT('C'), 22) == 25u );
CHECK( s1.find(wxT("gAB")) == 6u );
CHECK( s1.find(wxT("gAB"), 7) == wxString::npos );
CHECK( s1.find(wxT("gAB"), 6) == 6u );
CHECK( s1.find(wxT("gABZZZ"), 2, 3) == 6u );
CHECK( s1.find(wxT("gABZZZ"), 7, 3) == wxString::npos );
CHECK( s1.find(s2) == 6u );
CHECK( s1.find(s2, 7) == wxString::npos );
CHECK( s1.find(s2, 6) == 6u );
// 0 1 2
// 0123456 78901234567 8901234567
//wxString _s1 = wxT("abcdefg\0ABCDEFGabc\0ABCabcABC");
//wxString _s2 = wxT("g\0AB");
wxString _s1 = wxT("abcdefgABCDEFGabcABCabcABC");
wxString _s2 = wxT("gAB");
_s1.insert(7, 1, '\0');
_s1.insert(18, 1, '\0');
_s2.insert(1, 1, '\0');
CHECK( _s1.find(wxT('A')) == 8u );
CHECK( _s1.find(wxT('A'), 8) == 8u );
CHECK( _s1.find(wxT('Z')) == wxString::npos );
CHECK( _s1.find(wxT('C'), 22) == 27u );
CHECK( _s1.find(wxT("AB")) == 8u );
CHECK( _s1.find(wxT("AB"), 26) == wxString::npos );
CHECK( _s1.find(wxT("AB"), 23) == 25u );
CHECK( _s1.find(wxT("ABZZZ"), 2, 2) == 8u );
CHECK( _s1.find(wxT("ABZZZ"), 26, 2) == wxString::npos );
CHECK( _s1.find(_s2) == 6u );
CHECK( _s1.find(_s2, 7) == wxString::npos );
CHECK( _s1.find(_s2, 6) == 6u );
}
TEST_CASE("StdString::FindFirst", "[stdstring]")
{
// 0 1 2 3
// 01234567890123456789012345678901234
wxString s1 = wxT("aaaaaabcdefghlkjiaaaaaabcdbcdbcdbcd");
wxString s2 = wxT("aaaaaa");
CHECK( s1.find_first_not_of(wxT('a')) == 6u );
CHECK( s1.find_first_not_of(wxT('a'), 7) == 7u );
CHECK( s2.find_first_not_of(wxT('a')) == wxString::npos );
CHECK( s1.find_first_not_of(wxT("abde"), 4) == 7u );
CHECK( s1.find_first_not_of(wxT("abde"), 7) == 7u );
CHECK( s1.find_first_not_of(wxT("abcdefghijkl")) == wxString::npos );
CHECK( s1.find_first_not_of(wxT("abcdefghi"), 0, 4) == 9u );
CHECK( s1.find_first_of(wxT('c')) == 7u );
CHECK( s1.find_first_of(wxT('v')) == wxString::npos );
CHECK( s1.find_first_of(wxT('c'), 10) == 24u );
CHECK( s1.find_first_of(wxT("ijkl")) == 13u );
CHECK( s1.find_first_of(wxT("ddcfg"), 17) == 24u );
CHECK( s1.find_first_of(wxT("ddcfga"), 17, 5) == 24u );
}
TEST_CASE("StdString::FindLast", "[stdstring]")
{
// 0 1 2 3
// 01234567890123456789012345678901234
wxString s1 = wxT("aaaaaabcdefghlkjiaaaaaabcdbcdbcdbcd");
wxString s2 = wxT("aaaaaa");
CHECK( s2.find_last_not_of(wxT('a')) == wxString::npos );
CHECK( s1.find_last_not_of(wxT('d')) == 33u );
CHECK( s1.find_last_not_of(wxT('d'), 25) == 24u );
CHECK( s1.find_last_not_of(wxT("bcd")) == 22u );
CHECK( s1.find_last_not_of(wxT("abc"), 24) == 16u );
CHECK( s1.find_last_not_of(wxT("abcdefghijklmnopqrstuv"), 24, 3) == 16u );
CHECK( s2.find_last_of(wxT('c')) == wxString::npos );
CHECK( s1.find_last_of(wxT('a')) == 22u );
CHECK( s1.find_last_of(wxT('b'), 24) == 23u );
CHECK( s1.find_last_of(wxT("ijklm")) == 16u );
CHECK( s1.find_last_of(wxT("ijklma"), 33, 4) == 16u );
CHECK( s1.find_last_of(wxT("a"), 17) == 17u );
// 0 1 2 3
// 012345 67890123456789 01234567890123456
// wxString s1 = wxT("aaaaaa\0bcdefghlkjiaa\0aaaabcdbcdbcdbcd");
// wxString s2 = wxT("aaaaaa\0");
s1.insert(6,1,'\0');
s1.insert(20,1,'\0');
s2.insert(6,1,'\0');
CHECK( s2.find_last_not_of(wxT('a')) == 6u );
CHECK( s1.find_last_not_of(wxT('d')) == 35u );
CHECK( s1.find_last_not_of(wxT('d'), 27) == 26u );
CHECK( s1.find_last_not_of(wxT("bcd")) == 24u );
CHECK( s1.find_last_not_of(wxT("abc"), 26) == 20u );
CHECK( s1.find_last_not_of(wxT("abcdefghijklmnopqrstuv"), 26, 3) == 20u );
CHECK( s2.find_last_of(wxT('c')) == wxString::npos );
CHECK( s1.find_last_of(wxT('a')) == 24u );
CHECK( s1.find_last_of(wxT('b'), 26) == 25u );
CHECK( s1.find_last_of(wxT("ijklm")) == 17u );
CHECK( s1.find_last_of(wxT("ijklma"), 35, 4) == 17u );
CHECK( s1.find_last_of(wxT("a"), 18) == 18u );
}
TEST_CASE("StdString::StartsEndsWith", "[stdstring]")
{
const wxString s(wxT("Hello, world!"));
CHECK( s.starts_with(wxT("Hello")) == true );
CHECK( s.starts_with(wxT("Hello, ")) == true );
CHECK( s.starts_with(wxT("Hello, world!")) == true );
CHECK( s.starts_with(wxT("Hello, world!!!")) == false );
CHECK( s.starts_with(wxT("")) == true );
CHECK( s.starts_with(wxT("Goodbye")) == false );
CHECK( s.starts_with(wxT("Hi")) == false );
CHECK( s.ends_with(wxT("Hello, world!")) == true );
CHECK( s.ends_with(wxT("world!")) == true );
CHECK( s.ends_with(wxT("Hello")) == false );
CHECK( s.ends_with(wxT("!")) == true );
CHECK( s.ends_with(wxT("")) == true );
CHECK( s.ends_with(wxT("very long string")) == false );
CHECK( s.ends_with(wxT("?")) == false );
CHECK( s.ends_with(wxT("Hello, world")) == false );
CHECK( s.ends_with(wxT("Gello, world!")) == false );
}
TEST_CASE("StdString::Insert", "[stdstring]")
{
wxString s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = wxT("aaaa");
s9 = s10 = wxT("cdefg");
s1.insert(1, wxT("cc") );
s2.insert(2, wxT("cdef"), 3);
s3.insert(2, s10);
s4.insert(2, s10, 3, 7);
s5.insert(1, 2, wxT('c'));
s6.insert(s6.begin() + 3, wxT('X'));
s7.insert(s7.begin(), s9.begin(), s9.end() - 1);
s8.insert(s8.begin(), 2, wxT('c'));
CHECK( s1 == wxT("accaaa") );
CHECK( s2 == wxT("aacdeaa") );
CHECK( s3 == wxT("aacdefgaa") );
CHECK( s4 == wxT("aafgaa") );
CHECK( s5 == wxT("accaaa") );
CHECK( s6 == wxT("aaaXa") );
CHECK( s7 == wxT("cdefaaaa") );
CHECK( s8 == wxT("ccaaaa") );
s1 = s2 = s3 = wxT("aaaa");
s1.insert(0, wxT("ccc"), 2);
s2.insert(4, wxT("ccc"), 2);
CHECK( s1 == wxT("ccaaaa") );
CHECK( s2 == wxT("aaaacc") );
}
TEST_CASE("StdString::Replace", "[stdstring]")
{
wxString s1, s2, s3, s4, s5, s6, s7, s8, s9;
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = wxT("QWERTYUIOP");
s9 = wxT("werty");
s1.replace(3, 4, wxT("rtyu"));
s1.replace(8, 7, wxT("opopop"));
s2.replace(10, 12, wxT("WWWW"));
s3.replace(1, 5, s9);
s4.replace(1, 4, s9, 0, 4);
s5.replace(1, 2, s9, 1, 12);
s6.replace(0, 123, s9, 0, 123);
s7.replace(2, 7, s9);
CHECK( s1 == wxT("QWErtyuIopopop") );
CHECK( s2 == wxT("QWERTYUIOPWWWW") );
CHECK( s3 == wxT("QwertyUIOP") );
CHECK( s4 == wxT("QwertYUIOP") );
CHECK( s5 == wxT("QertyRTYUIOP") );
CHECK( s6 == s9 );
CHECK( s7 == wxT("QWwertyP") );
}
TEST_CASE("StdString::RFind", "[stdstring]")
{
// 0 1 2
// 01234567890123456789012345
wxString s1 = wxT("abcdefgABCDEFGabcABCabcABC");
wxString s2 = wxT("gAB");
wxString s3 = wxT("ab");
CHECK( s1.rfind(wxT('A')) == 23u );
CHECK( s1.rfind(wxT('A'), 7) == 7u );
CHECK( s1.rfind(wxT('Z')) == wxString::npos );
CHECK( s1.rfind(wxT('C'), 22) == 19u );
CHECK( s1.rfind(wxT("cAB")) == 22u );
CHECK( s1.rfind(wxT("cAB"), 15) == wxString::npos );
CHECK( s1.rfind(wxT("cAB"), 21) == 16u );
CHECK( s1.rfind(wxT("gABZZZ"), 7, 3) == 6u );
CHECK( s1.rfind(wxT("gABZZZ"), 5, 3) == wxString::npos );
CHECK( s1.rfind(s2) == 6u );
CHECK( s1.rfind(s2, 5) == wxString::npos );
CHECK( s1.rfind(s2, 6) == 6u );
CHECK( s1.rfind(s3, 1) == 0u );
// 0 1 2
// 01234 56789012 345678901234567
// wxString s1 = wxT("abcde\0fgABCDE\0FGabcABCabcABC");
// wxString s2 = wxT("gAB");
// wxString s3 = wxT("ab");
s1.insert(5,1,'\0');
s1.insert(13,1,'\0');
CHECK( s1.rfind(wxT('A')) == 25u );
CHECK( s1.rfind(wxT('A'), 8) == 8u );
CHECK( s1.rfind(wxT('Z')) == wxString::npos );
CHECK( s1.rfind(wxT('C'), 22) == 21u );
CHECK( s1.rfind(wxT("cAB")) == 24u );
CHECK( s1.rfind(wxT("cAB"), 15) == wxString::npos );
CHECK( s1.rfind(wxT("cAB"), 21) == 18u );
CHECK( s1.rfind(wxT("gABZZZ"), 8, 3) == 7u );
CHECK( s1.rfind(wxT("gABZZZ"), 5, 3) == wxString::npos );
}
TEST_CASE("StdString::Resize", "[stdstring]")
{
wxString s1, s2, s3, s4;
s1 = s2 = s3 = s4 = wxT("abcABCdefDEF");
s1.resize( 12 );
s2.resize( 10 );
s3.resize( 14, wxT(' ') );
s4.resize( 14, wxT('W') );
CHECK( s1 == wxT("abcABCdefDEF") );
CHECK( s2 == wxT("abcABCdefD") );
CHECK( s3 == wxT("abcABCdefDEF ") );
CHECK( s4 == wxT("abcABCdefDEFWW") );
wxString s = wxString::FromUTF8("Привет");
s.resize(3);
CHECK( s == wxString::FromUTF8("При") );
}
TEST_CASE("StdString::Riter", "[stdstring]")
{
const wxString s(wxT("fozbar"));
wxString::const_reverse_iterator ri(s.rbegin());
CHECK( wxT('r') == *ri );
CHECK( wxT('a') == *++ri );
CHECK( wxT('r') == *--ri );
ri = s.rend();
ri--;
CHECK( wxT('f') == *ri );
--ri;
CHECK( wxT('o') == *ri );
wxString::const_iterator i = ri.base();
CHECK( wxT('z') == *i );
}
TEST_CASE("StdString::Substr", "[stdstring]")
{
wxString s1 = wxT("abcdefgABCDEFG");
CHECK( s1.substr( 0, 14 ) == s1 );
CHECK( s1.substr( 1, 13 ) == wxT("bcdefgABCDEFG") );
CHECK( s1.substr( 1, 20 ) == wxT("bcdefgABCDEFG") );
CHECK( s1.substr( 14, 30 ) == wxT("") );
s1.insert(3,1,'\0');
s1.insert(8,1,'\0');
s1.insert(13,1,'\0');
wxString s2 = wxT("bcdefgABCDEFG");
s2.insert(2,1,'\0');
s2.insert(7,1,'\0');
s2.insert(12,1,'\0');
CHECK( s1.substr( 0, 17 ) == s1 );
CHECK( s1.substr( 1, 17 ) == s2 );
CHECK( s1.substr( 1, 20 ) == s2 );
CHECK( s1.substr( 17, 30 ) == wxT("") );
}
TEST_CASE("StdString::Conversion", "[stdstring]")
{
std::string strStd("std::string value");
std::wstring strStdWide(L"std::wstring value");
wxString s1(strStd);
CHECK( s1 == "std::string value" );
wxString s2(strStdWide);
CHECK( s2 == "std::wstring value" );
wxString s3;
s3 = strStd;
CHECK( s3 == "std::string value" );
s3 = strStdWide;
CHECK( s3 == "std::wstring value" );
wxString s4("hello");
#if wxUSE_STD_STRING_CONV_IN_WXSTRING && !defined(wxNO_UNSAFE_WXSTRING_CONV)
std::string s5 = s4;
#else
std::string s5 = s4.ToStdString();
#endif
CHECK( s5 == "hello" );
#if wxUSE_STD_STRING_CONV_IN_WXSTRING
std::wstring s6 = s4;
#else
std::wstring s6 = s4.ToStdWstring();
#endif
CHECK( s6 == L"hello" );
CHECK( s4.wc_string() == L"hello" );
#if wxUSE_STD_STRING_CONV_IN_WXSTRING
#if !defined(wxNO_UNSAFE_WXSTRING_CONV)
std::string s7(s4);
CHECK( s7 == "hello" );
#endif
std::wstring s8(s4);
CHECK( s8 == L"hello" );
#endif // wxUSE_STD_STRING_CONV_IN_WXSTRING
std::string s9("\xF0\x9F\x90\xB1\0\xE7\x8C\xAB", 9); /* U+1F431 U+0000 U+732B */
wxString s10 = wxString::FromUTF8(s9);
CHECK( s10.ToStdString(wxConvUTF8) == s9 );
CHECK( s10.utf8_string() == s9 );
std::string s11("xyz\0\xFF", 5); /* an invalid UTF-8 sequence */
CHECK( "" == wxString::FromUTF8(s11) );
CHECK( wxString("bye").utf8_string() == std::string("bye") );
}
TEST_CASE("StdString::Algo", "[stdstring]")
{
wxString s("AB");
std::reverse(s.begin(), s.end());
CHECK( s == "BA" );
}
#ifdef wxHAS_STD_STRING_VIEW
TEST_CASE("StdString::View", "[stdstring]")
{
std::string strStd("std::string value");
std::wstring strStdWide(L"std::wstring value");
std::string_view strStdView(strStd);
std::wstring_view strStdWideView(strStdWide);
wxString s1(strStdView);
CHECK( s1 == "std::string value" );
wxString s2(strStdWideView);
CHECK( s2 == "std::wstring value" );
wxString s3;
s3 = strStdView;
CHECK( s3 == "std::string value" );
s3 = strStdWideView;
CHECK( s3 == "std::wstring value" );
std::string strUTF("\xF0\x9F\x90\xB1\0\xE7\x8C\xAB", 9); /* U+1F431 U+0000 U+732B */
std::string_view strViewUTF(strUTF);
wxString wxstrUTF = wxString::FromUTF8(strViewUTF);
CHECK( wxstrUTF.ToStdString(wxConvUTF8) == strUTF );
CHECK( wxstrUTF.utf8_string() == strUTF );
std::string strInvalidUTF("xyz\0\xFF", 5); /* an invalid UTF-8 sequence */
std::string_view strViewInvalidUTF(strInvalidUTF);
CHECK( "" == wxString::FromUTF8(strViewInvalidUTF) );
/* Ensure we don't clobber comparisons on base types */
std::string_view view = "abc";
const char *str = "abc";
CHECK( view == str );
std::wstring_view wview = L"abc";
const wchar_t *wstr = L"abc";
CHECK( wview == wstr );
}
#endif // wxHAS_STD_STRING_VIEW

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,309 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/strings.cpp
// Purpose: wxStringTokenizer unit test
// Author: Vadim Zeitlin
// Created: 2005-12-20 (extacted from strings.cpp)
// Copyright: (c) 2004-2005 Vadim Zeitlin
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/tokenzr.h"
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class TokenizerTestCase : public CppUnit::TestCase
{
public:
TokenizerTestCase() { }
private:
CPPUNIT_TEST_SUITE( TokenizerTestCase );
CPPUNIT_TEST( GetCount );
CPPUNIT_TEST( GetPosition );
CPPUNIT_TEST( GetString );
CPPUNIT_TEST( LastDelimiter );
CPPUNIT_TEST( StrtokCompat );
CPPUNIT_TEST( CopyObj );
CPPUNIT_TEST( AssignObj );
CPPUNIT_TEST_SUITE_END();
void GetCount();
void GetPosition();
void GetString();
void LastDelimiter();
void StrtokCompat();
void CopyObj();
void AssignObj();
wxDECLARE_NO_COPY_CLASS(TokenizerTestCase);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( TokenizerTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TokenizerTestCase, "TokenizerTestCase" );
// ----------------------------------------------------------------------------
// test data
// ----------------------------------------------------------------------------
static const struct TokenizerTestData
{
// the string to tokenize
const wxChar *str;
// the delimiters to use
const wxChar *delims;
// the tokenizer mode
wxStringTokenizerMode mode;
// expected number of tokens
size_t count;
}
gs_testData[] =
{
{ wxT(""), wxT(" "), wxTOKEN_DEFAULT, 0 },
{ wxT(""), wxT(" "), wxTOKEN_RET_EMPTY, 0 },
{ wxT(""), wxT(" "), wxTOKEN_RET_EMPTY_ALL, 0 },
{ wxT(""), wxT(" "), wxTOKEN_RET_DELIMS, 0 },
{ wxT(":"), wxT(":"), wxTOKEN_RET_EMPTY, 1 },
{ wxT(":"), wxT(":"), wxTOKEN_RET_DELIMS, 1 },
{ wxT(":"), wxT(":"), wxTOKEN_RET_EMPTY_ALL, 2 },
{ wxT("::"), wxT(":"), wxTOKEN_RET_EMPTY, 1 },
{ wxT("::"), wxT(":"), wxTOKEN_RET_DELIMS, 1 },
{ wxT("::"), wxT(":"), wxTOKEN_RET_EMPTY_ALL, 3 },
{ wxT("Hello, world"), wxT(" "), wxTOKEN_DEFAULT, 2 },
{ wxT("Hello, world "), wxT(" "), wxTOKEN_DEFAULT, 2 },
{ wxT("Hello, world"), wxT(","), wxTOKEN_DEFAULT, 2 },
{ wxT("Hello, world!"), wxT(",!"), wxTOKEN_DEFAULT, 2 },
{ wxT("Hello,, world!"), wxT(",!"), wxTOKEN_DEFAULT, 3 },
{ wxT("Hello,, world!"), wxT(",!"), wxTOKEN_STRTOK, 2 },
{ wxT("Hello, world!"), wxT(",!"), wxTOKEN_RET_EMPTY_ALL, 3 },
{ wxT("username:password:uid:gid:gecos:home:shell"),
wxT(":"), wxTOKEN_DEFAULT, 7 },
{ wxT("1:2::3:"), wxT(":"), wxTOKEN_DEFAULT, 4 },
{ wxT("1:2::3:"), wxT(":"), wxTOKEN_RET_EMPTY, 4 },
{ wxT("1:2::3:"), wxT(":"), wxTOKEN_RET_EMPTY_ALL, 5 },
{ wxT("1:2::3:"), wxT(":"), wxTOKEN_RET_DELIMS, 4 },
{ wxT("1:2::3:"), wxT(":"), wxTOKEN_STRTOK, 3 },
{ wxT("1:2::3::"), wxT(":"), wxTOKEN_DEFAULT, 4 },
{ wxT("1:2::3::"), wxT(":"), wxTOKEN_RET_EMPTY, 4 },
{ wxT("1:2::3::"), wxT(":"), wxTOKEN_RET_EMPTY_ALL, 6 },
{ wxT("1:2::3::"), wxT(":"), wxTOKEN_RET_DELIMS, 4 },
{ wxT("1:2::3::"), wxT(":"), wxTOKEN_STRTOK, 3 },
{ wxT("1 \t3\t4 6 "), wxDEFAULT_DELIMITERS, wxTOKEN_DEFAULT, 4 },
{ wxT("1 \t3\t4 6 "), wxDEFAULT_DELIMITERS, wxTOKEN_STRTOK, 4 },
{ wxT("1 \t3\t4 6 "), wxDEFAULT_DELIMITERS, wxTOKEN_RET_EMPTY, 6 },
{ wxT("1 \t3\t4 6 "), wxDEFAULT_DELIMITERS, wxTOKEN_RET_EMPTY_ALL, 9 },
{ wxT("01/02/99"), wxT("/-"), wxTOKEN_DEFAULT, 3 },
{ wxT("01-02/99"), wxT("/-"), wxTOKEN_RET_DELIMS, 3 },
};
// helper function returning the string showing the index for which the test
// fails in the diagnostic message
static std::string Nth(size_t n)
{
return std::string(wxString::Format(wxT("for loop index %lu"),
(unsigned long)n).mb_str());
}
// ----------------------------------------------------------------------------
// the tests
// ----------------------------------------------------------------------------
void TokenizerTestCase::GetCount()
{
for ( size_t n = 0; n < WXSIZEOF(gs_testData); n++ )
{
const TokenizerTestData& ttd = gs_testData[n];
wxStringTokenizer tkz(ttd.str, ttd.delims, ttd.mode);
CPPUNIT_ASSERT_EQUAL_MESSAGE( Nth(n), ttd.count, tkz.CountTokens() );
size_t count = 0;
while ( tkz.HasMoreTokens() )
{
tkz.GetNextToken();
count++;
}
CPPUNIT_ASSERT_EQUAL_MESSAGE( Nth(n), ttd.count, count );
}
}
// call this with the string to tokenize, delimeters to use and the expected
// positions (i.e. results of GetPosition()) after each GetNextToken() call,
// terminate positions with 0
static void
DoTestGetPosition(const wxChar *s, const wxChar *delims, int pos, ...)
{
wxStringTokenizer tkz(s, delims);
CPPUNIT_ASSERT_EQUAL( (size_t)0, tkz.GetPosition() );
va_list ap;
va_start(ap, pos);
for ( ;; )
{
if ( !pos )
{
CPPUNIT_ASSERT( !tkz.HasMoreTokens() );
break;
}
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( (size_t)pos, tkz.GetPosition() );
pos = va_arg(ap, int);
}
va_end(ap);
}
void TokenizerTestCase::GetPosition()
{
DoTestGetPosition(wxT("foo"), wxT("_"), 3, 0);
DoTestGetPosition(wxT("foo_bar"), wxT("_"), 4, 7, 0);
DoTestGetPosition(wxT("foo_bar_"), wxT("_"), 4, 8, 0);
}
// helper for GetString(): the parameters are the same as for DoTestGetPosition
// but it checks GetString() return value instead of GetPosition()
static void
DoTestGetString(const wxChar *s, const wxChar *delims, int pos, ...)
{
wxStringTokenizer tkz(s, delims);
CPPUNIT_ASSERT_EQUAL( wxString(s), tkz.GetString() );
va_list ap;
va_start(ap, pos);
for ( ;; )
{
if ( !pos )
{
CPPUNIT_ASSERT( tkz.GetString().empty() ) ;
break;
}
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( wxString(s + pos), tkz.GetString() );
pos = va_arg(ap, int);
}
va_end(ap);
}
void TokenizerTestCase::GetString()
{
DoTestGetString(wxT("foo"), wxT("_"), 3, 0);
DoTestGetString(wxT("foo_bar"), wxT("_"), 4, 7, 0);
DoTestGetString(wxT("foo_bar_"), wxT("_"), 4, 8, 0);
}
void TokenizerTestCase::LastDelimiter()
{
wxStringTokenizer tkz(wxT("a+-b=c"), wxT("+-="));
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( wxT('+'), tkz.GetLastDelimiter() );
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( wxT('-'), tkz.GetLastDelimiter() );
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( wxT('='), tkz.GetLastDelimiter() );
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( wxT('\0'), tkz.GetLastDelimiter() );
}
void TokenizerTestCase::StrtokCompat()
{
for ( size_t n = 0; n < WXSIZEOF(gs_testData); n++ )
{
const TokenizerTestData& ttd = gs_testData[n];
if ( ttd.mode != wxTOKEN_STRTOK )
continue;
wxWCharBuffer
buf(ttd.str);
wxChar *last;
wxChar *s = wxStrtok(buf.data(), ttd.delims, &last);
wxStringTokenizer tkz(ttd.str, ttd.delims, ttd.mode);
while ( tkz.HasMoreTokens() )
{
CPPUNIT_ASSERT_EQUAL( wxString(s), tkz.GetNextToken() );
s = wxStrtok(nullptr, ttd.delims, &last);
}
}
}
void TokenizerTestCase::CopyObj()
{
// Test copy ctor
wxStringTokenizer tkzSrc(wxT("first:second:third:fourth"), wxT(":"));
while ( tkzSrc.HasMoreTokens() )
{
tkzSrc.GetNextToken();
wxStringTokenizer tkz = tkzSrc;
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetPosition(), tkz.GetPosition() );
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetString(), tkz.GetString() );
// Change the state of both objects and compare again...
tkzSrc.GetNextToken();
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetPosition(), tkz.GetPosition() );
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetString(), tkz.GetString() );
}
}
void TokenizerTestCase::AssignObj()
{
// Test assignment
wxStringTokenizer tkzSrc(wxT("first:second:third:fourth"), wxT(":"));
wxStringTokenizer tkz;
while ( tkzSrc.HasMoreTokens() )
{
tkzSrc.GetNextToken();
tkz = tkzSrc;
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetPosition(), tkz.GetPosition() );
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetString(), tkz.GetString() );
// Change the state of both objects and compare again...
tkzSrc.GetNextToken();
tkz.GetNextToken();
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetPosition(), tkz.GetPosition() );
CPPUNIT_ASSERT_EQUAL( tkzSrc.GetString(), tkz.GetString() );
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,484 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/unicode.cpp
// Purpose: Unicode unit test
// Author: Vadim Zeitlin, Wlodzimierz ABX Skiba
// Created: 2004-04-28
// Copyright: (c) 2004 Vadim Zeitlin, Wlodzimierz Skiba
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/encconv.h"
// ----------------------------------------------------------------------------
// helper class holding the matching MB and WC strings
// ----------------------------------------------------------------------------
struct StringConversionData
{
// either str or wcs (but not both) may be null, this means that the conversion
// to it should fail
StringConversionData(const char *str_, const wchar_t *wcs_, int flags_ = 0)
: str(str_), wcs(wcs_), flags(flags_)
{
}
const char * const str;
const wchar_t * const wcs;
enum
{
TEST_BOTH = 0, // test both str -> wcs and wcs -> str
ONLY_MB2WC = 1 // only test str -> wcs conversion
};
const int flags;
// test that the conversion between str and wcs (subject to flags) succeeds
//
// the first argument is the index in the test array and is used solely for
// diagnostics
void Test(size_t n, wxMBConv& conv) const
{
if ( str )
{
wxWCharBuffer wbuf = conv.cMB2WC(str);
if ( wcs )
{
CPPUNIT_ASSERT_MESSAGE
(
Message(n, "MB2WC failed"),
wbuf.data()
);
CPPUNIT_ASSERT_MESSAGE
(
Message(n, "MB2WC", wbuf, wcs),
wxStrcmp(wbuf, wcs) == 0
);
}
else // conversion is supposed to fail
{
CPPUNIT_ASSERT_MESSAGE
(
Message(n, "MB2WC succeeded"),
!wbuf.data()
);
}
}
if ( wcs && !(flags & ONLY_MB2WC) )
{
wxCharBuffer buf = conv.cWC2MB(wcs);
if ( str )
{
CPPUNIT_ASSERT_MESSAGE
(
Message(n, "WC2MB failed"),
buf.data()
);
CPPUNIT_ASSERT_MESSAGE
(
Message(n, "WC2MB", buf, str),
strcmp(buf, str) == 0
);
}
else
{
CPPUNIT_ASSERT_MESSAGE
(
Message(n, "WC2MB succeeded"),
!buf.data()
);
}
}
}
private:
static std::string
Message(size_t n, const wxString& msg)
{
return wxString::Format("#%lu: %s", (unsigned long)n, msg).ToStdString();
}
template <typename T>
static std::string
Message(size_t n,
const char *func,
const wxCharTypeBuffer<T>& actual,
const T *expected)
{
return Message(n,
wxString::Format("%s returned \"%s\", expected \"%s\"",
func, actual.data(), expected));
}
};
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class UnicodeTestCase : public CppUnit::TestCase
{
public:
UnicodeTestCase();
private:
CPPUNIT_TEST_SUITE( UnicodeTestCase );
CPPUNIT_TEST( ToFromAscii );
CPPUNIT_TEST( ConstructorsWithConversion );
CPPUNIT_TEST( ConversionFixed );
CPPUNIT_TEST( ConversionWithNULs );
CPPUNIT_TEST( ConversionUTF7 );
CPPUNIT_TEST( ConversionUTF8 );
CPPUNIT_TEST( ConversionUTF16 );
CPPUNIT_TEST( ConversionUTF32 );
CPPUNIT_TEST( IsConvOk );
CPPUNIT_TEST( Iteration );
CPPUNIT_TEST_SUITE_END();
void ToFromAscii();
void ConstructorsWithConversion();
void ConversionFixed();
void ConversionWithNULs();
void ConversionUTF7();
void ConversionUTF8();
void ConversionUTF16();
void ConversionUTF32();
void IsConvOk();
void Iteration();
wxDECLARE_NO_COPY_CLASS(UnicodeTestCase);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( UnicodeTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( UnicodeTestCase, "UnicodeTestCase" );
UnicodeTestCase::UnicodeTestCase()
{
}
void UnicodeTestCase::ToFromAscii()
{
#define TEST_TO_FROM_ASCII(txt) \
{ \
static const char *msg = txt; \
wxString s = wxString::FromAscii(msg); \
CPPUNIT_ASSERT( strcmp( s.ToAscii() , msg ) == 0 ); \
}
TEST_TO_FROM_ASCII( "Hello, world!" );
TEST_TO_FROM_ASCII( "additional \" special \t test \\ component \n :-)" );
}
void UnicodeTestCase::ConstructorsWithConversion()
{
const unsigned char utf8Buf[] = "Déjà";
const unsigned char utf8subBuf[] = "Déj";
const char* utf8 = reinterpret_cast<const char*>(utf8Buf);
const char* utf8sub = reinterpret_cast<const char*>(utf8subBuf);
wxString s1(utf8, wxConvUTF8);
const wchar_t wchar[] = {0x44,0xE9,0x6A,0xE0,0};
CPPUNIT_ASSERT_EQUAL( wchar, s1 );
wxString s2(wchar);
CPPUNIT_ASSERT_EQUAL( wchar, s2 );
CPPUNIT_ASSERT_EQUAL( wxString::FromUTF8(utf8), s2 );
wxString sub(utf8sub, wxConvUTF8); // "Dej" substring
wxString s3(utf8, wxConvUTF8, 4);
CPPUNIT_ASSERT_EQUAL( sub, s3 );
wxString s4(wchar, 3);
CPPUNIT_ASSERT_EQUAL( sub, s4 );
// conversion should stop with failure at pos 35
wxString s("\t[pl]open.format.Sformatuj dyskietk\xea=gfloppy %f", wxConvUTF8);
CPPUNIT_ASSERT( s.empty() );
// test using Unicode strings together with char* strings (this must work
// in ANSI mode as well, of course):
wxString s5("ascii");
CPPUNIT_ASSERT_EQUAL( "ascii", s5 );
s5 += " value";
CPPUNIT_ASSERT( strcmp(s5.mb_str(), "ascii value") == 0 );
CPPUNIT_ASSERT_EQUAL( "ascii value", s5 );
CPPUNIT_ASSERT( s5 != "SomethingElse" );
}
void UnicodeTestCase::ConversionFixed()
{
size_t len;
wxConvLibc.cWC2MB(L"", 0, &len);
CPPUNIT_ASSERT_EQUAL( 0, len );
// check that when we convert a fixed number of characters we obtain the
// expected return value
CPPUNIT_ASSERT_EQUAL( 0, wxConvLibc.ToWChar(nullptr, 0, "", 0) );
CPPUNIT_ASSERT_EQUAL( 1, wxConvLibc.ToWChar(nullptr, 0, "x", 1) );
CPPUNIT_ASSERT_EQUAL( 2, wxConvLibc.ToWChar(nullptr, 0, "x", 2) );
CPPUNIT_ASSERT_EQUAL( 2, wxConvLibc.ToWChar(nullptr, 0, "xy", 2) );
}
void UnicodeTestCase::ConversionWithNULs()
{
static const size_t lenNulString = 10;
wxString szTheString(L"The\0String", lenNulString);
wxCharBuffer theBuffer = szTheString.mb_str(wxConvLibc);
CPPUNIT_ASSERT( memcmp(theBuffer.data(), "The\0String",
lenNulString + 1) == 0 );
wxString szTheString2("The\0String", wxConvLocal, lenNulString);
CPPUNIT_ASSERT_EQUAL( lenNulString, szTheString2.length() );
CPPUNIT_ASSERT( wxTmemcmp(szTheString2.c_str(), L"The\0String",
lenNulString) == 0 );
const char *null4buff = "\0\0\0\0";
wxString null4str(null4buff, 4);
CPPUNIT_ASSERT_EQUAL( 4, null4str.length() );
}
void UnicodeTestCase::ConversionUTF7()
{
static const StringConversionData utf7data[] =
{
// normal fragments
StringConversionData("+AKM-", L"\xa3"),
StringConversionData("+AOk-t+AOk-", L"\xe9t\xe9"),
// this one is an alternative valid encoding of the same string
StringConversionData("+AOk-t+AOk", L"\xe9t\xe9",
StringConversionData::ONLY_MB2WC),
// some special cases
StringConversionData("+-", L"+"),
StringConversionData("+--", L"+-"),
// the following are invalid UTF-7 sequences
StringConversionData("\xa3", nullptr),
StringConversionData("+", nullptr),
StringConversionData("+~", nullptr),
StringConversionData("a+", nullptr),
};
for ( size_t n = 0; n < WXSIZEOF(utf7data); n++ )
{
const StringConversionData& d = utf7data[n];
// converting to/from UTF-7 using iconv() currently doesn't work
// because of several problems:
// - GetMBNulLen() doesn't return correct result (iconv converts L'\0'
// to an incomplete and anyhow nonsensical "+AA" string)
// - iconv refuses to convert "+-" (although it converts "+-\n" just
// fine, go figure)
//
// I have no idea how to fix this so just disable the test for now
#ifdef __WINDOWS__
wxCSConv conv("utf-7");
d.Test(n, conv);
#endif
d.Test(n, wxConvUTF7);
}
}
void UnicodeTestCase::ConversionUTF8()
{
static const StringConversionData utf8data[] =
{
#ifdef wxMUST_USE_U_ESCAPE
StringConversionData("\xc2\xa3", L"\u00a3"),
#else
StringConversionData("£", L"£"),
#endif
};
wxCSConv conv(wxT("utf-8"));
for ( size_t n = 0; n < WXSIZEOF(utf8data); n++ )
{
const StringConversionData& d = utf8data[n];
d.Test(n, conv);
d.Test(n, wxConvUTF8);
}
static const char* const u25a6 = "\xe2\x96\xa6";
wxMBConvUTF8 c(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL);
CPPUNIT_ASSERT_EQUAL( 2, c.ToWChar(nullptr, 0, u25a6, wxNO_LEN) );
CPPUNIT_ASSERT_EQUAL( 0, c.ToWChar(nullptr, 0, u25a6, 0) );
CPPUNIT_ASSERT_EQUAL( 1, c.ToWChar(nullptr, 0, u25a6, 3) );
CPPUNIT_ASSERT_EQUAL( 2, c.ToWChar(nullptr, 0, u25a6, 4) );
// Verify that converting a string with embedded NULs works.
CPPUNIT_ASSERT_EQUAL( 5, wxString::FromUTF8("abc\0\x32", 5).length() );
// Verify that converting a string containing invalid UTF-8 does not work,
// even if it happens after an embedded NUL.
CPPUNIT_ASSERT( wxString::FromUTF8("abc\xff").empty() );
CPPUNIT_ASSERT( wxString::FromUTF8("abc\0\xff", 5).empty() );
}
void UnicodeTestCase::ConversionUTF16()
{
static const StringConversionData utf16data[] =
{
#ifdef wxMUST_USE_U_ESCAPE
StringConversionData(
"\x04\x1f\x04\x40\x04\x38\x04\x32\x04\x35\x04\x42\0\0",
L"\u041f\u0440\u0438\u0432\u0435\u0442"),
#else
StringConversionData(
"\x04\x1f\x04\x40\x04\x38\x04\x32\x04\x35\x04\x42\0\0",
L"Привет"),
#endif
};
wxCSConv conv(wxFONTENCODING_UTF16BE);
for ( size_t n = 0; n < WXSIZEOF(utf16data); n++ )
{
const StringConversionData& d = utf16data[n];
d.Test(n, conv);
}
// special case: this string has consecutive NULs inside it which don't
// terminate the string, this exposed a bug in our conversion code which
// got confused in this case
size_t len;
conv.cMB2WC("\x01\0\0B\0C" /* A macron BC */, 6, &len);
CPPUNIT_ASSERT_EQUAL( 3, len );
// When using UTF-16 internally (i.e. MSW), we don't have any surrogate
// support, so the length of the string below is 2, not 1.
#if SIZEOF_WCHAR_T == 4
// Another one: verify that the length of the resulting string is computed
// correctly when there is a surrogate in the input.
wxMBConvUTF16BE().cMB2WC("\xd8\x03\xdc\x01\0" /* OLD TURKIC LETTER YENISEI A */, wxNO_LEN, &len);
CPPUNIT_ASSERT_EQUAL( 1, len );
#endif // UTF-32 internal representation
#if SIZEOF_WCHAR_T == 2
// Verify that the length of UTF-32 string is correct even when converting
// to it from a longer UTF-16 string with surrogates.
// Construct CAT FACE U+1F431 without using \U which is not supported by
// ancient compilers and without using \u with surrogates which is
// (correctly) flagged as an error by the newer ones.
wchar_t ws[2];
ws[0] = 0xd83d;
ws[1] = 0xdc31;
CPPUNIT_ASSERT_EQUAL( 4, wxMBConvUTF32BE().FromWChar(nullptr, 0, ws, 2) );
#endif // UTF-16 internal representation
}
void UnicodeTestCase::ConversionUTF32()
{
static const StringConversionData utf32data[] =
{
#ifdef wxMUST_USE_U_ESCAPE
StringConversionData(
"\0\0\x04\x1f\0\0\x04\x40\0\0\x04\x38\0\0\x04\x32\0\0\x04\x35\0\0\x04\x42\0\0\0\0",
L"\u041f\u0440\u0438\u0432\u0435\u0442"),
#else
StringConversionData(
"\0\0\x04\x1f\0\0\x04\x40\0\0\x04\x38\0\0\x04\x32\0\0\x04\x35\0\0\x04\x42\0\0\0\0",
L"Привет"),
#endif
};
wxCSConv conv(wxFONTENCODING_UTF32BE);
for ( size_t n = 0; n < WXSIZEOF(utf32data); n++ )
{
const StringConversionData& d = utf32data[n];
d.Test(n, conv);
}
size_t len;
conv.cMB2WC("\0\0\x01\0\0\0\0B\0\0\0C" /* A macron BC */, 12, &len);
CPPUNIT_ASSERT_EQUAL( 3, len );
}
void UnicodeTestCase::IsConvOk()
{
CPPUNIT_ASSERT( wxCSConv(wxFONTENCODING_SYSTEM).IsOk() );
CPPUNIT_ASSERT( wxCSConv("US-ASCII").IsOk() );
CPPUNIT_ASSERT( wxCSConv("UTF-8").IsOk() );
CPPUNIT_ASSERT( !wxCSConv("NoSuchConversion").IsOk() );
#ifdef __WINDOWS__
CPPUNIT_ASSERT( wxCSConv("WINDOWS-437").IsOk() );
#endif
}
void UnicodeTestCase::Iteration()
{
static const char *textUTF8 = "čeština";// "czech" in Czech
static const wchar_t textUTF16[] = {0x10D, 0x65, 0x161, 0x74, 0x69, 0x6E, 0x61, 0};
wxString text(wxString::FromUTF8(textUTF8));
CPPUNIT_ASSERT( wxStrcmp(text.wc_str(), textUTF16) == 0 );
// verify the string was decoded correctly:
{
size_t idx = 0;
for ( auto c : text )
{
CPPUNIT_ASSERT( c == textUTF16[idx++] );
}
}
// overwrite the string with something that is shorter in UTF-8:
{
for ( auto c : text )
c = 'x';
}
// restore the original text now:
{
wxString::iterator end1 = text.end();
wxString::const_iterator end2 = text.end();
size_t idx = 0;
for ( auto c : text )
{
c = textUTF16[idx++];
CPPUNIT_ASSERT( end1 == text.end() );
CPPUNIT_ASSERT( end2 == text.end() );
}
CPPUNIT_ASSERT( end1 == text.end() );
CPPUNIT_ASSERT( end2 == text.end() );
}
// and verify it again:
{
size_t idx = 0;
for ( auto c : text )
{
CPPUNIT_ASSERT( c == textUTF16[idx++] );
}
}
}

View File

@@ -0,0 +1,294 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/vararg.cpp
// Purpose: Test for wx vararg look-alike macros
// Author: Vaclav Slavik
// Created: 2007-02-20
// Copyright: (c) 2007 REA Elektronik GmbH
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/string.h"
// ----------------------------------------------------------------------------
// tests themselves
// ----------------------------------------------------------------------------
TEST_CASE("StringPrintf", "[wxString][Printf][vararg]")
{
wxString s, s2;
// test passing literals:
s.Printf("%s %i", "foo", 42);
CHECK( s == "foo 42" );
s.Printf("%s %s %i", wxT("bar"), "=", 11);
// test passing c_str():
CHECK( s == "bar = 11" );
s2.Printf("(%s)", s.c_str());
CHECK( s2 == "(bar = 11)" );
s2.Printf(wxT("[%s](%s)"), s.c_str(), "str");
CHECK( s2 == "[bar = 11](str)" );
s2.Printf("%s mailbox", wxString("Opening").c_str());
CHECK( s2 == "Opening mailbox" );
// test passing wxString directly:
s2.Printf(wxT("[%s](%s)"), s, "str");
CHECK( s2 == "[bar = 11](str)" );
// test passing wxCharBufferType<T>:
s = "FooBar";
s2.Printf(wxT("(%s)"), s.mb_str());
CHECK( s2 == "(FooBar)" );
s2.Printf(wxT("value=%s;"), s.wc_str());
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
// here because we want to test that this compiles, even with warnings):
wxGCC_WARNING_SUPPRESS(write-strings)
wxCLANG_WARNING_SUPPRESS(c++11-compat-deprecated-writable-strings)
bool cond = true;
s2.Printf(wxT("foo %s"), !cond ? s.c_str() : wxT("bar"));
wxGCC_WARNING_RESTORE(write-strings)
wxCLANG_WARNING_RESTORE(c++11-compat-deprecated-writable-strings)
#ifdef __cpp_lib_string_view
CHECK( wxString::Format("%s", std::string_view{"foobar", 3}) == "foo" );
CHECK( wxString::Format("%s", std::string_view{"bar"}) == "bar" );
#endif // __cpp_lib_string_view
}
TEST_CASE("CharPrintf", "[wxString][Printf][vararg]")
{
wxString foo("foo");
wxString s;
// test using wchar_t:
s.Printf("char=%c", L'c');
CHECK( s == "char=c" );
// test wxUniCharRef:
s.Printf("string[1] is %c", foo[1]);
CHECK( s == "string[1] is o" );
// test char
char c = 'z';
s.Printf("%c to %c", 'a', c);
CHECK( s == "a to z" );
// test char used as integer:
#ifdef _MSC_VER
#pragma warning(disable:4309) // truncation of constant value
#endif
wxCLANG_WARNING_SUPPRESS(constant-conversion)
c = 240;
wxCLANG_WARNING_RESTORE(constant-conversion)
#ifdef _MSC_VER
#pragma warning(default:4309)
#endif
#ifndef __CHAR_UNSIGNED__
s.Printf("value is %i (int)", c);
CHECK( s == wxString("value is -16 (int)") );
#endif
unsigned char u = 240;
s.Printf("value is %i (int)", u);
CHECK( s == "value is 240 (int)" );
}
TEST_CASE("SizetPrintf", "[wxString][Printf][vararg]")
{
size_t i = 1;
ssize_t j = -2;
CHECK( wxString::Format("size_t=%zu ssize_t=%zd", i, j)
== "size_t=1 ssize_t=-2" );
CHECK( wxString::Format("size_t=0x%zX", static_cast<size_t>(160))
== "size_t=0xA0" );
}
TEST_CASE("StdString", "[wxString][Printf][vararg]")
{
// test passing std::[w]string
wxString s;
std::string mb("multi-byte");
std::string wc("widechar");
s.Printf("string %s(%i).", mb, 1);
CHECK( s == "string multi-byte(1)." );
s.Printf("string %s(%i).", wc, 2);
CHECK( s == "string widechar(2)." );
}
TEST_CASE("LongLongPrintf", "[wxString][Printf][vararg]")
{
const char * const llfmt = "%" wxLongLongFmtSpec "d";
CHECK( wxString::Format(llfmt, wxLL(17)) == "17" );
wxLongLong ll = 1234567890;
CHECK( wxString::Format(llfmt, ll) == "1234567890" );
}
TEST_CASE("Sscanf", "[wxSscanf][vararg]")
{
int i = 0;
char str[20];
wxString input("42 test");
wxSscanf(input, "%d %s", &i, &str);
CHECK( i == 42 );
CHECK( wxString(str) == "test" );
#if !(defined(__MINGW32__) && \
defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO == 1)
// disable this test on mingw with __USE_MINGW_ANSI_STDIO=1
// to prevent a segmentation fault. See:
// https://sourceforge.net/p/mingw-w64/mailman/message/36118530/
wchar_t wstr[20];
i = 0;
wxSscanf(input, L"%d %s", &i, &wstr);
CHECK( i == 42 );
CHECK( wxString(wstr) == "test" );
#endif
}
TEST_CASE("RepeatedPrintf", "[wxString][Printf][vararg]")
{
wxCharBuffer buffer(2);
char *p = buffer.data();
*p = 'h';
p++;
*p = 'i';
wxString s;
s = wxString::Format("buffer %s, len %d", buffer, (int)wxStrlen(buffer));
CHECK( s == "buffer hi, len 2" );
s = wxString::Format("buffer %s, len %d", buffer, (int)wxStrlen(buffer));
CHECK( s == "buffer hi, len 2" );
}
TEST_CASE("ArgsValidation", "[wxString][vararg][error]")
{
int written;
void *ptr = &written;
short int swritten = 0;
wxUnusedVar(swritten); // We're not really going to use it.
// these are valid:
wxString::Format("a string(%s,%s), ptr %p, int %i",
wxString(), "foo", "char* as pointer", 1);
// Unfortunately we can't check the result as different standard libraries
// implementations format it in different ways, so just check that it
// compiles.
wxString::Format("null pointer is %p", nullptr);
// Microsoft has helpfully disabled support for "%n" in their CRT by
// default starting from VC8 and somehow even calling
// _set_printf_count_output() doesn't help here, so don't use "%n" at all
// with it.
#if defined(__VISUALC__)
#define wxNO_PRINTF_PERCENT_N
#endif // VC8+
// Similarly, many modern Linux distributions ship with g++ that uses
// -D_FORTIFY_SOURCE=2 flag by default and this option prevents "%n" from
// being used in a string outside of read-only memory, meaning that it
// can't be used in wxString to which we (may, depending on build options)
// assign it, so also disable testing of "%n" in this case lest we die with
// an abort inside vswprintf().
#if defined(_FORTIFY_SOURCE)
#if _FORTIFY_SOURCE >= 2
#define wxNO_PRINTF_PERCENT_N
#endif
#endif
#ifndef wxNO_PRINTF_PERCENT_N
wxString::Format("foo%i%n", 42, &written);
CHECK( written == 5 );
#endif
// but these are not:
WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("%d + %d = %d", 2, 2) );
WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("%i", "foo") );
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
// result in an assert in our code before the CRT functions are even called
WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("foo%i%n", &written) );
WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("foo%n", ptr) );
WX_ASSERT_FAILS_WITH_ASSERT( wxString::Format("foo%i%n", 42, &swritten) );
// %c should accept integers too
wxString::Format("%c", 80);
wxString::Format("%c", wxChar(80) + wxChar(1));
// check size_t handling
size_t len = sizeof(ptr);
#ifdef __WINDOWS__
wxString::Format("%Iu", len);
#else
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 );
}
namespace
{
// Helpers for the "PrintfError" test: we must pass by these functions
// because specifying "%c" directly inline would convert it to "%lc" and avoid
// the error.
wxString CallPrintfV(const char* format, ...)
{
va_list ap;
va_start(ap, format);
wxString s;
s.PrintfV(wxString::FromAscii(format), ap);
va_end(ap);
return s;
}
} // anonymous namespace
TEST_CASE("PrintfError", "[wxString][Format][vararg][error]")
{
// Check that using invalid argument doesn't keep doubling the buffer until
// we run out of memory and die.
const int invalidChar = 0x1780;
REQUIRE_NOTHROW( CallPrintfV("%c", invalidChar) );
}

View File

@@ -0,0 +1,540 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/strings/vsnprintf.cpp
// Purpose: wxVsnprintf unit test
// Author: Francesco Montorsi
// (part of this file was taken from CMP.c of TRIO package
// written by Bjorn Reese and Daniel Stenberg)
// Created: 2006-04-01
// Copyright: (c) 2006 Francesco Montorsi, Bjorn Reese and Daniel Stenberg
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#include "wx/crt.h"
#if wxUSE_WXVSNPRINTF
#ifndef WX_PRECOMP
#include "wx/wx.h"
#include "wx/wxchar.h"
#endif // WX_PRECOMP
#include "wx/private/localeset.h"
// NOTE: for more info about the specification of wxVsnprintf() behaviour you can
// refer to the following page of the GNU libc manual:
// http://www.gnu.org/software/libc/manual/html_node/Formatted-Output.html
// ----------------------------------------------------------------------------
// global utilities for testing
// ----------------------------------------------------------------------------
#define MAX_TEST_LEN 1024
// temporary buffers
static wxChar buf[MAX_TEST_LEN];
int r;
// Helper macro verifying both the return value of wxSnprintf() and its output.
//
// NOTE: the expected string length with this macro must not exceed MAX_TEST_LEN
#define CMP(expected, fmt, ...) \
r=wxSnprintf(buf, MAX_TEST_LEN, fmt, ##__VA_ARGS__); \
CHECK( r == (int)wxStrlen(buf) ); \
CHECK( buf == wxString(expected) )
// Another helper which takes the size explicitly instead of using MAX_TEST_LEN
//
// NOTE: this macro is used also with too-small buffers (see Miscellaneous())
// test function, thus the return value can be either -1 or > size and we
// cannot check if r == (int)wxStrlen(buf)
#define CMPTOSIZE(buffer, size, failuremsg, expected, fmt, ...) \
r=wxSnprintf(buffer, size, fmt, ##__VA_ARGS__); \
INFO(failuremsg); \
CHECK( buffer == wxString(expected).Left(size - 1) )
// this is the same as wxSnprintf() but it passes the format string to
// wxVsnprintf() without using WX_ATTRIBUTE_PRINTF and thus suppresses the gcc
// checks (and resulting warnings) for the format string
//
// use with extreme care and only when you're really sure the warnings must be
// suppressed!
template<typename T>
static int
wxUnsafeSnprintf(T *buf, size_t len, const wxChar *fmt, ...)
{
va_list args;
va_start(args, fmt);
int rc = wxVsnprintf(buf, len, fmt, args);
va_end(args);
return rc;
}
// ----------------------------------------------------------------------------
// test fixture
// ----------------------------------------------------------------------------
// Explicitly set C locale to avoid check failures when running on machines
// with a locale where the decimal point is not '.'
class VsnprintfTestCase : wxCLocaleSetter
{
public:
VsnprintfTestCase() : wxCLocaleSetter() { }
protected:
template<typename T>
void DoBigToSmallBuffer(T *buffer, int size);
// compares the expectedString and the result of wxVsnprintf() char by char
// for all its length (not only for first expectedLen chars) and also
// checks the return value
void DoMisc(int expectedLen, const wxString& expectedString,
size_t max, const wxChar *format, ...);
wxDECLARE_NO_COPY_CLASS(VsnprintfTestCase);
};
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::C", "[vsnprintf]")
{
CMP("hi!", "%c%c%c", wxT('h'), wxT('i'), wxT('!'));
// NOTE:
// the NUL characters _can_ be passed to %c to e.g. create strings
// with embedded NULs (because strings are not always supposed to be
// NUL-terminated).
DoMisc(14, wxT("Hello \0 World!"), 16, wxT("Hello %c World!"), wxT('\0'));
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::D", "[vsnprintf]")
{
CMP("+123456", "%+d", 123456);
CMP("-123456", "%d", -123456);
CMP(" 123456", "% d", 123456);
CMP(" 123456", "%10d", 123456);
CMP("0000123456", "%010d", 123456);
CMP("-123456 ", "%-10d", -123456);
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::X", "[vsnprintf]")
{
CMP("ABCD", "%X", 0xABCD);
CMP("0XABCD", "%#X", 0xABCD);
CMP("0xabcd", "%#x", 0xABCD);
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::O", "[vsnprintf]")
{
CMP("1234567", "%o", 01234567);
CMP("01234567", "%#o", 01234567);
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::P", "[vsnprintf]")
{
// The exact format used for "%p" is not specified by the standard and so
// varies among different platforms, so we need to expect different results
// here (remember that while we test our own wxPrintf() code here, it uses
// the system sprintf() for actual formatting so the results are still
// different under different systems).
#if defined(__VISUALC__) || (defined(__MINGW32__) && \
(!defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO))
#if SIZEOF_VOID_P == 4
CMP("00ABCDEF", "%p", (void*)0xABCDEF);
CMP("00000000", "%p", (void*)nullptr);
#elif SIZEOF_VOID_P == 8
CMP("0000ABCDEFABCDEF", "%p", (void*)0xABCDEFABCDEF);
CMP("0000000000000000", "%p", (void*)nullptr);
#endif
#elif defined(__MINGW32__)
#if SIZEOF_VOID_P == 4
CMP("00abcdef", "%p", (void*)0xABCDEF);
CMP("00000000", "%p", (void*)nullptr);
#elif SIZEOF_VOID_P == 8
CMP("0000abcdefabcdef", "%p", (void*)0xABCDEFABCDEF);
CMP("0000000000000000", "%p", (void*)nullptr);
#endif
#elif defined(__GNUG__)
// glibc prints pointers as %#x except for null pointers which are printed
// as '(nil)'.
CMP("0xabcdef", "%p", (void*)0xABCDEF);
CMP("(nil)", "%p", (void*)nullptr);
#endif
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::N", "[vsnprintf]")
{
int nchar;
wxSnprintf(buf, MAX_TEST_LEN, wxT("%d %s%n\n"), 3, wxT("bears"), &nchar);
CHECK( nchar == 7 );
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::E", "[vsnprintf]")
{
// NB: Use at least three digits for the exponent to workaround
// differences between MSVC, MinGW and GNU libc.
// See wxUSING_MANTISSA_SIZE_3 in testprec.h as well.
//
// Some examples:
// printf("%e",2.342E+02);
// -> under MSVC7.1 prints: 2.342000e+002
// -> under GNU libc 2.4 prints: 2.342000e+02
CMP("2.342000e+112", "%e",2.342E+112);
CMP("-2.3420e-112", "%10.4e",-2.342E-112);
CMP("-2.3420e-112", "%11.4e",-2.342E-112);
CMP(" -2.3420e-112", "%15.4e",-2.342E-112);
CMP("-0.02342", "%G",-2.342E-02);
CMP("3.1415E-116", "%G",3.1415e-116);
CMP("0003.141500e+103", "%016e", 3141.5e100);
CMP(" 3.141500e+103", "%16e", 3141.5e100);
CMP("3.141500e+103 ", "%-16e", 3141.5e100);
CMP("3.142e+103", "%010.3e", 3141.5e100);
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::F", "[vsnprintf]")
{
CMP("3.300000", "%5f", 3.3);
CMP("3.000000", "%5f", 3.0);
CMP("0.000100", "%5f", .999999E-4);
CMP("0.000990", "%5f", .99E-3);
CMP("3333.000000", "%5f", 3333.0);
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::G", "[vsnprintf]")
{
// NOTE: the same about E() testcase applies here...
CMP(" 3.3", "%5g", 3.3);
CMP(" 3", "%5g", 3.0);
CMP("9.99999e-115", "%5g", .999999E-114);
CMP("0.00099", "%5g", .99E-3);
CMP(" 3333", "%5g", 3333.0);
CMP(" 0.01", "%5g", 0.01);
CMP(" 3", "%5.g", 3.3);
CMP(" 3", "%5.g", 3.0);
CMP("1e-114", "%5.g", .999999E-114);
CMP("0.0001", "%5.g", 1.0E-4);
CMP("0.001", "%5.g", .99E-3);
CMP("3e+103", "%5.g", 3333.0E100);
CMP(" 0.01", "%5.g", 0.01);
CMP(" 3.3", "%5.2g", 3.3);
CMP(" 3", "%5.2g", 3.0);
CMP("1e-114", "%5.2g", .999999E-114);
CMP("0.00099", "%5.2g", .99E-3);
CMP("3.3e+103", "%5.2g", 3333.0E100);
CMP(" 0.01", "%5.2g", 0.01);
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::S", "[vsnprintf]")
{
CMP(" abc", "%5s", wxT("abc"));
CMP(" a", "%5s", wxT("a"));
CMP("abcdefghi", "%5s", wxT("abcdefghi"));
CMP("abc ", "%-5s", wxT("abc"));
CMP("abcdefghi", "%-5s", wxT("abcdefghi"));
CMP("abcde", "%.5s", wxT("abcdefghi"));
// do the same tests but with Unicode characters:
// Unicode code points from U+03B1 to U+03B9 are the greek letters alpha-iota;
// UTF8 encoding of such code points is 0xCEB1 to 0xCEB9
#define ALPHA "α"
// alpha
#define ABC "αβγ"
// alpha+beta+gamma
#define ABCDE "αβγδε"
// alpha+beta+gamma+delta+epsilon
#define ABCDEFGHI "αβγδεζηθι"
// alpha+beta+gamma+delta+epsilon+zeta+eta+theta+iota
// the 'expected' and 'arg' parameters of this macro are supposed to be
// UTF-8 strings
#define CMP_UTF8(expected, fmt, arg) \
CHECK \
( \
(int)wxString::FromUTF8(expected).length() == \
wxSnprintf(buf, MAX_TEST_LEN, fmt, wxString::FromUTF8(arg)) \
); \
CHECK( wxString::FromUTF8(expected) == buf )
CMP_UTF8(" " ABC, "%5s", ABC);
CMP_UTF8(" " ALPHA, "%5s", ALPHA);
CMP_UTF8(ABCDEFGHI, "%5s", ABCDEFGHI);
CMP_UTF8(ABC " ", "%-5s", ABC);
CMP_UTF8(ABCDEFGHI, "%-5s", ABCDEFGHI);
CMP_UTF8(ABCDE, "%.5s", ABCDEFGHI);
// test a string which has a NUL character after "ab";
// obviously it should be handled exactly like just as "ab"
CMP(" ab", "%5s", wxT("ab\0cdefghi"));
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::Asterisk", "[vsnprintf]")
{
CMP(" 0.1", "%*.*f", 10, 1, 0.123);
CMP(" 0.1230", "%*.*f", 10, 4, 0.123);
CMP("0.1", "%*.*f", 3, 1, 0.123);
CMP("%0.002", "%%%.*f", 3, 0.0023456789);
CMP(" a", "%*c", 8, 'a');
CMP(" four", "%*s", 8, "four");
CMP(" four four", "%*s %*s", 8, "four", 6, "four");
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::Percent", "[vsnprintf]")
{
// some tests without any argument passed through ...
CMP("%", "%%");
CMP("%%%", "%%%%%%");
CMP("% abc", "%%%5s", wxT("abc"));
CMP("% abc%", "%%%5s%%", wxT("abc"));
// do not test odd number of '%' symbols as different implementations
// of snprintf() give different outputs as this situation is not considered
// by any standard (in fact, GCC will also warn you about a spurious % if
// you write %%% as argument of some *printf function !)
// Compare(wxT("%"), wxT("%%%"));
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::LongLong", "[vsnprintf]")
{
CMP("123456789", "%lld", (wxLongLong_t)123456789);
CMP("-123456789", "%lld", (wxLongLong_t)-123456789);
CMP("123456789", "%llu", (wxULongLong_t)123456789);
#ifdef __WINDOWS__
CMP("123456789", "%I64d", (wxLongLong_t)123456789);
CMP("123456789abcdef", "%I64x", wxLL(0x123456789abcdef));
#endif
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::WrongFormatStrings", "[vsnprintf]")
{
// test how wxVsnprintf() behaves with wrong format string:
// a missing positional arg should result in an assert
WX_ASSERT_FAILS_WITH_ASSERT(
wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$d %3$d"), 1, 2, 3) );
// positional and non-positionals in the same format string:
errno = 0;
r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$d %d %3$d"), 1, 2, 3);
CHECK( r == -1 );
CHECK( errno == EINVAL );
}
// BigToSmallBuffer() test case helper:
template<typename T>
void VsnprintfTestCase::DoBigToSmallBuffer(T *buffer, int size)
{
// Remember that wx*printf could be mapped either to system
// implementation or to wx implementation.
// In the first case, when the output buffer is too small, the returned
// value can be the number of characters required for the output buffer
// (conforming to ISO C99; implemented in e.g. GNU libc >= 2.1), or
// just a negative number, usually -1; (this is how e.g. MSVC's
// *printf() behaves). Luckily, in all implementations, when the
// output buffer is too small, it's nonetheless filled up to its max size.
//
// Note that in the second case (i.e. when we're using our own implementation),
// wxVsnprintf() will return the number of characters written in the standard
// output or
// -1 if there was an error in the format string
// maxSize+1 if the output buffer is too small
wxString errStr;
errStr << "The size of the buffer was " << size;
std::string errMsg(errStr.mb_str());
// test without positionals
CMPTOSIZE(buffer, size, errMsg,
"123456789012 - test - 123 -4.567",
"%i%li - test - %d %.3f",
123, (long int)456789012, 123, -4.567);
#if wxUSE_PRINTF_POS_PARAMS
// test with positional
CMPTOSIZE(buffer, size, errMsg,
"-4.567 123 - test - 456789012 123",
"%4$.3f %1$i - test - %2$li %3$d",
123, (long int)456789012, 123, -4.567);
#endif
// test unicode/ansi conversion specifiers
//
// NB: we use wxUnsafeSnprintf() as %hs and %hc are invalid in printf
// format and gcc would warn about this otherwise
r = wxUnsafeSnprintf(buffer, size,
wxT("unicode string/char: %ls/%lc -- ansi string/char: %hs/%hc"),
L"unicode", L'U', "ansi", 'A');
wxString expected =
wxString(wxT("unicode string/char: unicode/U -- ansi string/char: ansi/A")).Left(size - 1);
CHECK( expected == buffer );
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::BigToSmallBuffer", "[vsnprintf]")
{
wchar_t bufw[1024], bufw2[16], bufw3[4], bufw4;
DoBigToSmallBuffer(bufw, 1024);
DoBigToSmallBuffer(bufw2, 16);
DoBigToSmallBuffer(bufw3, 4);
DoBigToSmallBuffer(&bufw4, 1);
char bufa[1024], bufa2[16], bufa3[4], bufa4;
DoBigToSmallBuffer(bufa, 1024);
DoBigToSmallBuffer(bufa2, 16);
DoBigToSmallBuffer(bufa3, 4);
DoBigToSmallBuffer(&bufa4, 1);
}
// Miscellaneous() test case helper:
void VsnprintfTestCase::DoMisc(
int expectedLen,
const wxString& expectedString,
size_t max,
const wxChar *format, ...)
{
const size_t BUFSIZE = MAX_TEST_LEN - 1;
size_t i;
static int count = 0;
wxASSERT(max <= BUFSIZE);
for (i = 0; i < BUFSIZE; i++)
buf[i] = '*';
buf[BUFSIZE] = 0;
va_list ap;
va_start(ap, format);
int n = wxVsnprintf(buf, max, format, ap);
va_end(ap);
// Prepare messages so that it is possible to see from the error which
// test was running.
wxString errStr, overflowStr;
errStr << wxT("No.: ") << ++count << wxT(", expected: ") << expectedLen
<< wxT(" '") << expectedString << wxT("', result: ");
overflowStr << errStr << wxT("buffer overflow");
errStr << n << wxT(" '") << buf << wxT("'");
// turn them into std::strings
std::string errMsg(errStr.mb_str());
std::string overflowMsg(overflowStr.mb_str());
INFO(errMsg);
if ( size_t(n) < max )
CHECK(expectedLen == n);
else
CHECK(expectedLen == -1);
CHECK(expectedString == buf);
for (i = max; i < BUFSIZE; i++)
{
INFO(overflowMsg);
CHECK(buf[i] == '*');
}
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::Miscellaneous", "[vsnprintf]")
{
// expectedLen, expectedString, max, format, ...
DoMisc(5, wxT("-1234"), 8, wxT("%d"), -1234);
DoMisc(7, wxT("1234567"), 8, wxT("%d"), 1234567);
DoMisc(-1, wxT("1234567"), 8, wxT("%d"), 12345678);
DoMisc(-1, wxT("-123456"), 8, wxT("%d"), -1234567890);
DoMisc(6, wxT("123456"), 8, wxT("123456"));
DoMisc(7, wxT("1234567"), 8, wxT("1234567"));
DoMisc(-1, wxT("1234567"), 8, wxT("12345678"));
DoMisc(6, wxT("123450"), 8, wxT("12345%d"), 0);
DoMisc(7, wxT("1234560"), 8, wxT("123456%d"), 0);
DoMisc(-1, wxT("1234567"), 8, wxT("1234567%d"), 0);
DoMisc(-1, wxT("1234567"), 8, wxT("12345678%d"), 0);
DoMisc(6, wxT("12%45%"), 8, wxT("12%%45%%"));
DoMisc(7, wxT("12%45%7"), 8, wxT("12%%45%%7"));
DoMisc(-1, wxT("12%45%7"), 8, wxT("12%%45%%78"));
DoMisc(5, wxT("%%%%%"), 6, wxT("%%%%%%%%%%"));
DoMisc(6, wxT("%%%%12"), 7, wxT("%%%%%%%%%d"), 12);
}
/* (C) Copyright C E Chew
*
* Feel free to copy, use and distribute this software provided:
*
* 1. you do not pretend that you wrote it
* 2. you leave this copyright notice intact.
*/
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::GlibcMisc1", "[vsnprintf]")
{
CMP(" ", "%5.s", "xyz");
CMP(" 33", "%5.f", 33.3);
#if defined(wxDEFAULT_MANTISSA_SIZE_3)
CMP(" 3e+008", "%8.e", 33.3e7);
CMP(" 3E+008", "%8.E", 33.3e7);
CMP("3e+001", "%.g", 33.3);
CMP("3E+001", "%.G", 33.3);
#else
CMP(" 3e+08", "%8.e", 33.3e7);
CMP(" 3E+08", "%8.E", 33.3e7);
CMP("3e+01", "%.g", 33.3);
CMP("3E+01", "%.G", 33.3);
#endif
}
TEST_CASE_METHOD(VsnprintfTestCase, "Vsnprintf::GlibcMisc2", "[vsnprintf]")
{
int prec;
prec = 0;
CMP("3", "%.*g", prec, 3.3);
prec = 0;
CMP("3", "%.*G", prec, 3.3);
prec = 0;
CMP(" 3", "%7.*G", prec, 3.33);
prec = 3;
CMP(" 041", "%04.*o", prec, 33);
prec = 7;
CMP(" 0000033", "%09.*u", prec, 33);
prec = 3;
CMP(" 021", "%04.*x", prec, 33);
prec = 3;
CMP(" 021", "%04.*X", prec, 33);
}
#endif // wxUSE_WXVSNPRINTF