1/////////////////////////////////////////////////////////////////////////////// 2// Name: tests/strings/vsnprintf.cpp 3// Purpose: wxVsnprintf unit test 4// Author: Francesco Montorsi 5// (part of this file was taken from CMP.c of TRIO package 6// written by Bjorn Reese and Daniel Stenberg) 7// Created: 2006-04-01 8// RCS-ID: $Id: vsnprintf.cpp 58994 2009-02-18 15:49:09Z FM $ 9// Copyright: (c) 2006 Francesco Montorsi, Bjorn Reese and Daniel Stenberg 10/////////////////////////////////////////////////////////////////////////////// 11 12// ---------------------------------------------------------------------------- 13// headers 14// ---------------------------------------------------------------------------- 15 16#include "testprec.h" 17 18#ifdef __BORLANDC__ 19 #pragma hdrstop 20#endif 21 22#if wxUSE_WXVSNPRINTF 23 24#ifndef WX_PRECOMP 25 #include "wx/wx.h" 26 #include "wx/wxchar.h" 27#endif // WX_PRECOMP 28 29 30 31#define MAX_TEST_LEN 1024 32 33 34// temporary buffers 35static wxChar buf[MAX_TEST_LEN]; 36int r; 37 38// these macros makes it possible to write all tests without repeating a lot of times wxT() macro 39 40#define ASSERT_STR_EQUAL( a, b ) \ 41 CPPUNIT_ASSERT_EQUAL( wxString(a), wxString(b) ); 42 43#define CMP6(expected, x, y, z, w, t) \ 44 r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y, z, w, t); \ 45 CPPUNIT_ASSERT( r > 0 ); \ 46 ASSERT_STR_EQUAL( wxT(expected), buf ); 47 48#define CMP5(expected, x, y, z, w) \ 49 r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y, z, w); \ 50 CPPUNIT_ASSERT( r > 0 ); \ 51 ASSERT_STR_EQUAL( wxT(expected), buf ); 52 53#define CMP4(expected, x, y, z) \ 54 r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y, z); \ 55 CPPUNIT_ASSERT( r > 0 ); \ 56 ASSERT_STR_EQUAL( wxT(expected), buf ); 57 58#define CMP3(expected, x, y) \ 59 r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x), y); \ 60 CPPUNIT_ASSERT( r > 0 ); \ 61 ASSERT_STR_EQUAL( wxT(expected), buf ); 62 63#define CMP2(expected, x) \ 64 r=wxSnprintf(buf, MAX_TEST_LEN, wxT(x)); \ 65 CPPUNIT_ASSERT( r > 0 ); \ 66 ASSERT_STR_EQUAL( wxT(expected), buf ); 67 68#define CMPTOSIZE(buffer, size, expected, fmt, x, y, z, w) \ 69 r=wxSnprintf(buffer, size, wxT(fmt), x, y, z, w); \ 70 CPPUNIT_ASSERT( r > 0 ); \ 71 CPPUNIT_ASSERT_EQUAL( wxString(wxT(expected)).Left(size - 1), \ 72 wxString(buffer) ) 73 74 75 76// ---------------------------------------------------------------------------- 77// test class 78// ---------------------------------------------------------------------------- 79 80class VsnprintfTestCase : public CppUnit::TestCase 81{ 82public: 83 VsnprintfTestCase(); 84 85private: 86 CPPUNIT_TEST_SUITE( VsnprintfTestCase ); 87 CPPUNIT_TEST( D ); 88 CPPUNIT_TEST( X ); 89 CPPUNIT_TEST( O ); 90 CPPUNIT_TEST( P ); 91 CPPUNIT_TEST( N ); 92 CPPUNIT_TEST( E ); 93 CPPUNIT_TEST( F ); 94 CPPUNIT_TEST( G ); 95 CPPUNIT_TEST( S ); 96 CPPUNIT_TEST( Asterisk ); 97 CPPUNIT_TEST( Percent ); 98#ifdef wxLongLong_t 99 CPPUNIT_TEST( LongLong ); 100#endif 101 102 CPPUNIT_TEST( BigToSmallBuffer ); 103 CPPUNIT_TEST( WrongFormatStrings ); 104 CPPUNIT_TEST( Miscellaneous ); 105 CPPUNIT_TEST_SUITE_END(); 106 107 void D(); 108 void X(); 109 void O(); 110 void P(); 111 void N(); 112 void E(); 113 void F(); 114 void G(); 115 void S(); 116 void Asterisk(); 117 void Percent(); 118#ifdef wxLongLong_t 119 void LongLong(); 120#endif 121 void Unicode(); 122 123 void BigToSmallBuffer(); 124 void WrongFormatStrings(); 125 void Miscellaneous(); 126 void Misc(wxChar *buffer, int size); 127 128 DECLARE_NO_COPY_CLASS(VsnprintfTestCase) 129}; 130 131// register in the unnamed registry so that these tests are run by default 132CPPUNIT_TEST_SUITE_REGISTRATION( VsnprintfTestCase ); 133 134// also include in it's own registry so that these tests can be run alone 135CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( VsnprintfTestCase, "VsnprintfTestCase" ); 136 137VsnprintfTestCase::VsnprintfTestCase() 138{ 139} 140 141void VsnprintfTestCase::D() 142{ 143 CMP3("+123456", "%+d", 123456); 144 CMP3("-123456", "%d", -123456); 145 CMP3(" 123456", "% d", 123456); 146 CMP3(" 123456", "%10d", 123456); 147 CMP3("0000123456", "%010d", 123456); 148 CMP3("-123456 ", "%-10d", -123456); 149} 150 151void VsnprintfTestCase::X() 152{ 153 CMP3("ABCD", "%X", 0xABCD); 154 CMP3("0XABCD", "%#X", 0xABCD); 155 CMP3("0xabcd", "%#x", 0xABCD); 156} 157 158void VsnprintfTestCase::O() 159{ 160 CMP3("1234567", "%o", 01234567); 161 CMP3("01234567", "%#o", 01234567); 162} 163 164void VsnprintfTestCase::P() 165{ 166 // WARNING: printing of pointers is not fully standard. 167 // GNU prints them as %#x except for NULL pointers which are 168 // printed as '(nil)'. 169 // MSVC always print them as %8X on 32 bit systems and as %16X 170 // on 64 bit systems 171#ifdef __VISUALC__ 172 #if SIZEOF_VOID_P == 4 173 CMP3("00ABCDEF", "%p", (void*)0xABCDEF); 174 CMP3("00000000", "%p", (void*)NULL); 175 #elif SIZEOF_VOID_P == 8 176 CMP3("0000ABCDEFABCDEF", "%p", (void*)0xABCDEFABCDEF); 177 CMP3("0000000000000000", "%p", (void*)NULL); 178 #endif 179#elif defined(__GNUG__) 180 CMP3("0xabcdef", "%p", (void*)0xABCDEF); 181 CMP3("(nil)", "%p", (void*)NULL); 182#endif 183} 184 185void VsnprintfTestCase::N() 186{ 187 int nchar; 188 189 wxSnprintf(buf, MAX_TEST_LEN, _T("%d %s%n\n"), 3, _T("bears"), &nchar); 190 CPPUNIT_ASSERT_EQUAL( 7, nchar ); 191} 192 193void VsnprintfTestCase::E() 194{ 195 // NB: there are no standards about the minimum exponent width 196 // (and the width of the %e conversion specifier refers to the 197 // mantissa, not to the exponent). 198 // Since newer MSVC versions use 3 digits as minimum exponent 199 // width while GNU libc uses 2 digits as minimum width, here we 200 // workaround this problem using for the exponent values with at 201 // least three digits. 202 // Some examples: 203 // printf("%e",2.342E+02); 204 // -> under MSVC7.1 prints: 2.342000e+002 205 // -> under GNU libc 2.4 prints: 2.342000e+02 206 CMP3("2.342000e+112", "%e",2.342E+112); 207 CMP3("-2.3420e-112", "%10.4e",-2.342E-112); 208 CMP3("-2.3420e-112", "%11.4e",-2.342E-112); 209 CMP3(" -2.3420e-112", "%15.4e",-2.342E-112); 210 211 CMP3("-0.02342", "%G",-2.342E-02); 212 CMP3("3.1415E-116", "%G",3.1415e-116); 213 CMP3("0003.141500e+103", "%016e", 3141.5e100); 214 CMP3(" 3.141500e+103", "%16e", 3141.5e100); 215 CMP3("3.141500e+103 ", "%-16e", 3141.5e100); 216 CMP3("3.142e+103", "%010.3e", 3141.5e100); 217} 218 219void VsnprintfTestCase::F() 220{ 221 CMP3("3.300000", "%5f", 3.3); 222 CMP3("3.000000", "%5f", 3.0); 223 CMP3("0.000100", "%5f", .999999E-4); 224 CMP3("0.000990", "%5f", .99E-3); 225 CMP3("3333.000000", "%5f", 3333.0); 226} 227 228void VsnprintfTestCase::G() 229{ 230 // NOTE: the same about E() testcase applies here... 231 232 CMP3(" 3.3", "%5g", 3.3); 233 CMP3(" 3", "%5g", 3.0); 234 CMP3("9.99999e-115", "%5g", .999999E-114); 235 CMP3("0.00099", "%5g", .99E-3); 236 CMP3(" 3333", "%5g", 3333.0); 237 CMP3(" 0.01", "%5g", 0.01); 238 239 CMP3(" 3", "%5.g", 3.3); 240 CMP3(" 3", "%5.g", 3.0); 241 CMP3("1e-114", "%5.g", .999999E-114); 242 CMP3("0.0001", "%5.g", 1.0E-4); 243 CMP3("0.001", "%5.g", .99E-3); 244 CMP3("3e+103", "%5.g", 3333.0E100); 245 CMP3(" 0.01", "%5.g", 0.01); 246 247 CMP3(" 3.3", "%5.2g", 3.3); 248 CMP3(" 3", "%5.2g", 3.0); 249 CMP3("1e-114", "%5.2g", .999999E-114); 250 CMP3("0.00099", "%5.2g", .99E-3); 251 CMP3("3.3e+103", "%5.2g", 3333.0E100); 252 CMP3(" 0.01", "%5.2g", 0.01); 253} 254 255void VsnprintfTestCase::S() 256{ 257 CMP3(" abc", "%5s", wxT("abc")); 258 CMP3(" a", "%5s", wxT("a")); 259 CMP3("abcdefghi", "%5s", wxT("abcdefghi")); 260 CMP3("abc ", "%-5s", wxT("abc")); 261 CMP3("abcdefghi", "%-5s", wxT("abcdefghi")); 262 263 CMP3("abcde", "%.5s", wxT("abcdefghi")); 264 265 // do the same tests but with Unicode characters: 266#if wxUSE_UNICODE && !defined(__VISUALC__) // FIXME: this doesn't compile with VC7 267 #define ALPHA "\x3B1" 268 #define BETA "\x3B2" 269 #define GAMMA "\x3B3" 270 #define DELTA "\x3B4" 271 #define EPSILON "\x3B5" 272 #define ZETA "\x3B6" 273 #define ETA "\x3B7" 274 #define THETA "\x3B8" 275 #define IOTA "\x3B9" 276 277 #define ABC ALPHA BETA GAMMA 278 #define ABCDE ALPHA BETA GAMMA DELTA EPSILON 279 #define ABCDEFGHI ALPHA BETA GAMMA DELTA EPSILON ZETA ETA THETA IOTA 280 281 CMP3(" " ABC, "%5s", wxT(ABC)); 282 CMP3(" " ALPHA, "%5s", wxT(ALPHA)); 283 CMP3(ABCDEFGHI, "%5s", wxT(ABCDEFGHI)); 284 CMP3(ABC " ", "%-5s", wxT(ABC)); 285 CMP3(ABCDEFGHI, "%-5s", wxT(ABCDEFGHI)); 286 287 CMP3(ABCDE, "%.5s", wxT(ABCDEFGHI)); 288#endif 289} 290 291void VsnprintfTestCase::Asterisk() 292{ 293 CMP5(" 0.1", "%*.*f", 10, 1, 0.123); 294 CMP5(" 0.1230", "%*.*f", 10, 4, 0.123); 295 CMP5("0.1", "%*.*f", 3, 1, 0.123); 296 297 CMP4("%0.002", "%%%.*f", 3, 0.0023456789); 298 299 CMP4(" a", "%*c", 8, 'a'); 300 CMP4(" four", "%*s", 8, "four"); 301 CMP6(" four four", "%*s %*s", 8, "four", 6, "four"); 302} 303 304void VsnprintfTestCase::Percent() 305{ 306 // some tests without any argument passed through ... 307 CMP2("%", "%%"); 308 CMP2("%%%", "%%%%%%"); 309 310 CMP3("% abc", "%%%5s", wxT("abc")); 311 CMP3("% abc%", "%%%5s%%", wxT("abc")); 312 313 // do not test odd number of '%' symbols as different implementations 314 // of snprintf() give different outputs as this situation is not considered 315 // by any standard (in fact, GCC will also warn you about a spurious % if 316 // you write %%% as argument of some *printf function !) 317 // Compare(wxT("%"), wxT("%%%")); 318} 319 320#ifdef wxLongLong_t 321void VsnprintfTestCase::LongLong() 322{ 323 CMP3("123456789", "%lld", (wxLongLong_t)123456789); 324 CMP3("-123456789", "%lld", (wxLongLong_t)-123456789); 325 326 CMP3("123456789", "%llu", (wxULongLong_t)123456789); 327 328#ifdef __WXMSW__ 329 CMP3("123456789", "%I64d", (wxLongLong_t)123456789); 330 CMP3("123456789abcdef", "%I64x", wxLL(0x123456789abcdef)); 331#endif 332} 333#endif 334 335void VsnprintfTestCase::Misc(wxChar *buffer, int size) 336{ 337 // NB: remember that wx*printf could be mapped either to system 338 // implementation or to wx implementation. 339 // In the first case, when the output buffer is too small, the returned 340 // value can be the number of characters required for the output buffer 341 // (conforming to ISO C99; implemented in e.g. GNU libc >= 2.1), or 342 // just a negative number, usually -1; (this is how e.g. MSVC's 343 // *printf() behaves). Luckily, in all implementations, when the 344 // output buffer is too small, it's nonetheless filled up to its max 345 // size. 346 // 347 // Note that in the second case (i.e. when we're using our own implementation), 348 // wxVsnprintf() will always return the number of characters which 349 350 // test without positionals 351 CMPTOSIZE(buffer, size, "123 444444444 - test - 555 -0.666", 352 "%i %li - test - %d %.3f", 353 123, (long int)444444444, 555, -0.666); 354 355#if wxUSE_PRINTF_POS_PARAMS 356 // test with positional 357 CMPTOSIZE(buffer, size, "-0.666 123 - test - 444444444 555", 358 "%4$.3f %1$i - test - %2$li %3$d", 359 123, (long int)444444444, 555, -0.666); 360#endif 361 362 // test unicode/ansi conversion specifiers 363 // NB: this line will output two warnings like these, on GCC: 364 // warning: use of 'h' length modifier with 's' type character (i.e. 365 // GCC warns you that 'h' is not legal on 's' conv spec) but they must 366 // be ignored as here we explicitely want to test the wxSnprintf() 367 // behaviour in such case 368 369 CMPTOSIZE(buffer, size, 370 "unicode string: unicode!! W - ansi string: ansi!! w\n\n", 371 "unicode string: %ls %lc - ansi string: %hs %hc\n\n", 372 L"unicode!!", L'W', "ansi!!", 'w'); 373} 374 375void VsnprintfTestCase::WrongFormatStrings() 376{ 377 // test how wxVsnprintf() behaves with wrong format string: 378 379#if wxUSE_PRINTF_POS_PARAMS 380 381 // two positionals with the same index: 382 r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$s %1$s"), "hello"); 383 CPPUNIT_ASSERT(r == -1); 384 385 // three positionals with the same index mixed with other pos args: 386 r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%4$d %2$f %1$s %2$s %3$d"), "hello", "world", 3, 4); 387 CPPUNIT_ASSERT(r == -1); 388 389 // a missing positional arg: 390 r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$d %3$d"), 1, 2, 3); 391 CPPUNIT_ASSERT(r == -1); 392 393 // positional and non-positionals in the same format string: 394 r = wxSnprintf(buf, MAX_TEST_LEN, wxT("%1$d %d %3$d"), 1, 2, 3); 395 CPPUNIT_ASSERT(r == -1); 396 397#endif // wxUSE_PRINTF_POS_PARAMS 398} 399 400void VsnprintfTestCase::BigToSmallBuffer() 401{ 402 wxChar buf[1024], buf2[16], buf3[4], buf4; 403 404 Misc(buf, 1024); 405 Misc(buf2, 16); 406 Misc(buf3, 4); 407 Misc(&buf4, 1); 408} 409 410static void DoMisc( 411 int expectedLen, 412 const wxString& expectedString, 413 size_t max, 414 const wxChar *format, ...) 415{ 416 const size_t BUFSIZE = 16; 417 wxChar buf[BUFSIZE + 1]; 418 size_t i; 419 static int count = 0; 420 421 wxASSERT(max <= BUFSIZE); 422 423 for (i = 0; i < BUFSIZE; i++) 424 buf[i] = '*'; 425 buf[BUFSIZE] = 0; 426 427 va_list ap; 428 va_start(ap, format); 429 430 int n = wxVsnprintf(buf, max, format, ap); 431 432 va_end(ap); 433 434 // Prepare messages so that it is possible to see from the error which 435 // test was running. 436 wxString errStr, overflowStr; 437 errStr << _T("No.: ") << ++count << _T(", expected: ") << expectedLen 438 << _T(" '") << expectedString << _T("', result: "); 439 overflowStr << errStr << _T("buffer overflow"); 440 errStr << n << _T(" '") << buf << _T("'"); 441 442 // turn them into std::strings 443 std::string errMsg(errStr.mb_str()); 444 std::string overflowMsg(overflowStr.mb_str()); 445 446 CPPUNIT_ASSERT_MESSAGE(errMsg, 447 (expectedLen == -1 && size_t(n) >= max) || expectedLen == n); 448 449 CPPUNIT_ASSERT_MESSAGE(errMsg, expectedString == buf); 450 451 for (i = max; i < BUFSIZE; i++) 452 CPPUNIT_ASSERT_MESSAGE(overflowMsg, buf[i] == '*'); 453} 454 455void VsnprintfTestCase::Miscellaneous() 456{ 457 // expectedLen, expectedString, max, format, ... 458 DoMisc(5, wxT("-1234"), 8, wxT("%d"), -1234); 459 DoMisc(7, wxT("1234567"), 8, wxT("%d"), 1234567); 460 DoMisc(-1, wxT("1234567"), 8, wxT("%d"), 12345678); 461 DoMisc(-1, wxT("-123456"), 8, wxT("%d"), -1234567890); 462 463 DoMisc(6, wxT("123456"), 8, wxT("123456")); 464 DoMisc(7, wxT("1234567"), 8, wxT("1234567")); 465 DoMisc(-1, wxT("1234567"), 8, wxT("12345678")); 466 467 DoMisc(6, wxT("123450"), 8, wxT("12345%d"), 0); 468 DoMisc(7, wxT("1234560"), 8, wxT("123456%d"), 0); 469 DoMisc(-1, wxT("1234567"), 8, wxT("1234567%d"), 0); 470 DoMisc(-1, wxT("1234567"), 8, wxT("12345678%d"), 0); 471 472 DoMisc(6, wxT("12%45%"), 8, wxT("12%%45%%")); 473 DoMisc(7, wxT("12%45%7"), 8, wxT("12%%45%%7")); 474 DoMisc(-1, wxT("12%45%7"), 8, wxT("12%%45%%78")); 475 476 DoMisc(5, wxT("%%%%%"), 6, wxT("%%%%%%%%%%")); 477 DoMisc(6, wxT("%%%%12"), 7, wxT("%%%%%%%%%d"), 12); 478} 479 480#endif // wxUSE_WXVSNPRINTF 481