1 //
2 // StringTest.cpp
3 //
4 // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
5 // and Contributors.
6 //
7 // SPDX-License-Identifier:	BSL-1.0
8 //
9 
10 
11 #include "StringTest.h"
12 #include "CppUnit/TestCaller.h"
13 #include "CppUnit/TestSuite.h"
14 #include "Poco/String.h"
15 #include "Poco/JSONString.h"
16 #include "Poco/Format.h"
17 #include "Poco/MemoryStream.h"
18 #include "Poco/Stopwatch.h"
19 #include "Poco/FPEnvironment.h"
20 #include "Poco/Exception.h"
21 #include <iostream>
22 #include <sstream>
23 #include <iomanip>
24 #include <cstdio>
25 #include <climits>
26 #include <map>
27 #include <set>
28 
29 
30 using Poco::trimLeft;
31 using Poco::trimLeftInPlace;
32 using Poco::trimRight;
33 using Poco::trimRightInPlace;
34 using Poco::trim;
35 using Poco::trimInPlace;
36 using Poco::toUpper;
37 using Poco::toUpperInPlace;
38 using Poco::toLower;
39 using Poco::toLowerInPlace;
40 using Poco::icompare;
41 using Poco::istring;
42 using Poco::isubstr;
43 using Poco::translate;
44 using Poco::translateInPlace;
45 using Poco::replace;
46 using Poco::replaceInPlace;
47 using Poco::remove;
48 using Poco::removeInPlace;
49 using Poco::cat;
50 using Poco::startsWith;
51 using Poco::endsWith;
52 using Poco::strToInt;
53 using Poco::strToFloat;
54 using Poco::strToDouble;
55 using Poco::intToStr;
56 using Poco::uIntToStr;
57 using Poco::floatToStr;
58 using Poco::doubleToStr;
59 using Poco::thousandSeparator;
60 using Poco::decimalSeparator;
61 using Poco::format;
62 using Poco::toJSON;
63 using Poco::CILess;
64 using Poco::MemoryInputStream;
65 using Poco::Stopwatch;
66 using Poco::RangeException;
67 using Poco::isIntOverflow;
68 using Poco::isSafeIntCast;
69 using Poco::safeIntCast;
70 using Poco::FPEnvironment;
71 
72 
StringTest(const std::string & rName)73 StringTest::StringTest(const std::string& rName): CppUnit::TestCase(rName)
74 {
75 }
76 
77 
~StringTest()78 StringTest::~StringTest()
79 {
80 }
81 
82 
testTrimLeft()83 void StringTest::testTrimLeft()
84 {
85 	{
86 		std::string s = "abc";
87 		assertTrue (trimLeft(s) == "abc");
88 	}
89 		std::string s = " abc ";
90 		assertTrue (trimLeft(s) == "abc ");
91 	{
92 	std::string s = "  ab c ";
93 	assertTrue (trimLeft(s) == "ab c ");
94 	}
95 }
96 
97 
testTrimLeftInPlace()98 void StringTest::testTrimLeftInPlace()
99 {
100 	{
101 		std::string s = "abc";
102 		assertTrue (trimLeftInPlace(s) == "abc");
103 	}
104 	{
105 		std::string s = " abc ";
106 		assertTrue (trimLeftInPlace(s) == "abc ");
107 	}
108 	{
109 		std::string s = "  ab c ";
110 		assertTrue (trimLeftInPlace(s) == "ab c ");
111 	}
112 }
113 
114 
testTrimRight()115 void StringTest::testTrimRight()
116 {
117 	{
118 		std::string s = "abc";
119 		assertTrue (trimRight(s) == "abc");
120 	}
121 	{
122 		std::string s = " abc ";
123 		assertTrue (trimRight(s) == " abc");
124 	}
125 	{
126 		std::string s = "  ab c  ";
127 		assertTrue (trimRight(s) == "  ab c");
128 	}
129 }
130 
131 
testTrimRightInPlace()132 void StringTest::testTrimRightInPlace()
133 {
134 	{
135 		std::string s = "abc";
136 		assertTrue (trimRightInPlace(s) == "abc");
137 	}
138 	{
139 		std::string s = " abc ";
140 		assertTrue (trimRightInPlace(s) == " abc");
141 	}
142 	{
143 		std::string s = "  ab c  ";
144 		assertTrue (trimRightInPlace(s) == "  ab c");
145 	}
146 }
147 
148 
testTrim()149 void StringTest::testTrim()
150 {
151 	{
152 		std::string s = "abc";
153 		assertTrue (trim(s) == "abc");
154 	}
155 	{
156 		std::string s = "abc ";
157 		assertTrue (trim(s) == "abc");
158 	}
159 	{
160 		std::string s = "  ab c  ";
161 		assertTrue (trim(s) == "ab c");
162 	}
163 }
164 
165 
testTrimInPlace()166 void StringTest::testTrimInPlace()
167 {
168 	{
169 		std::string s = "abc";
170 		assertTrue (trimInPlace(s) == "abc");
171 	}
172 	{
173 		std::string s = " abc ";
174 		assertTrue (trimInPlace(s) == "abc");
175 	}
176 	{
177 		std::string s = "  ab c  ";
178 		assertTrue (trimInPlace(s) == "ab c");
179 	}
180 }
181 
182 
testToUpper()183 void StringTest::testToUpper()
184 {
185 	{
186 		std::string s = "abc";
187 		assertTrue (toUpper(s) == "ABC");
188 	}
189 	{
190 		std::string s = "Abc";
191 		assertTrue (toUpper(s) == "ABC");
192 	}
193 	{
194 		std::string s = "abc";
195 		assertTrue (toUpperInPlace(s) == "ABC");
196 	}
197 	{
198 		std::string s = "Abc";
199 		assertTrue (toUpperInPlace(s) == "ABC");
200 	}
201 }
202 
203 
testToLower()204 void StringTest::testToLower()
205 {
206 	{
207 		std::string s = "ABC";
208 		assertTrue (toLower(s) == "abc");
209 	}
210 	{
211 		std::string s = "aBC";
212 		assertTrue (toLower(s) == "abc");
213 	}
214 	{
215 		std::string s = "ABC";
216 		assertTrue (toLowerInPlace(s) == "abc");
217 	}
218 	{
219 		std::string s = "aBC";
220 		assertTrue (toLowerInPlace(s) == "abc");
221 	}
222 }
223 
224 
testIstring()225 void StringTest::testIstring()
226 {
227 	istring is1 = "AbC";
228 	istring is2 = "aBc";
229 	assertTrue (is1 == is2);
230 
231 	const char c1[] = { 'G', 0, (char) 0xFC, 'n', 't', 'e', 'r', '\0' };
232 	const char c2[] = { 'g', 0, (char) 0xDC, 'N', 'T', 'E', 'R', '\0' };
233 	is1 = c1;
234 	is2 = c2;
235 	assertTrue (is1 == is2);
236 	is1[0] = 'f';
237 	assertTrue (is1 < is2);
238 	is1[0] = 'F';
239 	assertTrue (is1 < is2);
240 	is1[0] = 'H';
241 	assertTrue (is1 > is2);
242 	is1[0] = 'h';
243 	assertTrue (is1 > is2);
244 
245 	is1 = "aAaBbBcCc";
246 	is2 = "bbb";
247 	assertTrue (isubstr(is1, is2) == 3);
248 	is2 = "bC";
249 	assertTrue (isubstr(is1, is2) == 5);
250 	is2 = "xxx";
251 	assertTrue (isubstr(is1, is2) == istring::npos);
252 }
253 
254 
testIcompare()255 void StringTest::testIcompare()
256 {
257 	std::string s1 = "AAA";
258 	std::string s2 = "aaa";
259 	std::string s3 = "bbb";
260 	std::string s4 = "cCcCc";
261 	std::string s5;
262 	assertTrue (icompare(s1, s2) == 0);
263 	assertTrue (icompare(s1, s3) < 0);
264 	assertTrue (icompare(s1, s4) < 0);
265 	assertTrue (icompare(s3, s1) > 0);
266 	assertTrue (icompare(s4, s2) > 0);
267 	assertTrue (icompare(s2, s4) < 0);
268 	assertTrue (icompare(s1, s5) > 0);
269 	assertTrue (icompare(s5, s4) < 0);
270 
271 	std::string ss1 = "xxAAAzz";
272 	std::string ss2 = "YaaaX";
273 	std::string ss3 = "YbbbX";
274 	assertTrue (icompare(ss1, 2, 3, ss2, 1, 3) == 0);
275 	assertTrue (icompare(ss1, 2, 3, ss3, 1, 3) < 0);
276 	assertTrue (icompare(ss1, 2, 3, ss2, 1) == 0);
277 	assertTrue (icompare(ss1, 2, 3, ss3, 1) < 0);
278 	assertTrue (icompare(ss1, 2, 2, ss2, 1, 3) < 0);
279 	assertTrue (icompare(ss1, 2, 2, ss2, 1, 2) == 0);
280 	assertTrue (icompare(ss3, 1, 3, ss1, 2, 3) > 0);
281 
282 	assertTrue (icompare(s1, s2.c_str()) == 0);
283 	assertTrue (icompare(s1, s3.c_str()) < 0);
284 	assertTrue (icompare(s1, s4.c_str()) < 0);
285 	assertTrue (icompare(s3, s1.c_str()) > 0);
286 	assertTrue (icompare(s4, s2.c_str()) > 0);
287 	assertTrue (icompare(s2, s4.c_str()) < 0);
288 	assertTrue (icompare(s1, s5.c_str()) > 0);
289 	assertTrue (icompare(s5, s4.c_str()) < 0);
290 
291 	assertTrue (icompare(ss1, 2, 3, "aaa") == 0);
292 	assertTrue (icompare(ss1, 2, 2, "aaa") < 0);
293 	assertTrue (icompare(ss1, 2, 3, "AAA") == 0);
294 	assertTrue (icompare(ss1, 2, 2, "bb") < 0);
295 
296 	assertTrue (icompare(ss1, 2, "aaa") > 0);
297 }
298 
299 
testCILessThan()300 void StringTest::testCILessThan()
301 {
302 	typedef std::map<std::string, int, CILess> CIMapType;
303 	CIMapType ciMap;
304 
305 	ciMap["z"] = 1;
306 	ciMap["b"] = 2;
307 	ciMap["A"] = 3;
308 	ciMap["Z"] = 4;
309 
310 	assertTrue (ciMap.size() == 3);
311 	CIMapType::iterator it = ciMap.begin();
312 	assertTrue (it->first == "A"); ++it;
313 	assertTrue (it->first == "b"); ++it;
314 	assertTrue (it->first == "z");
315 	assertTrue (it->second == 4);
316 
317 	typedef std::set<std::string, CILess> CISetType;
318 
319 	CISetType ciSet;
320 	ciSet.insert("z");
321 	ciSet.insert("b");
322 	ciSet.insert("A");
323 	ciSet.insert("Z");
324 
325 	assertTrue (ciSet.size() == 3);
326 	CISetType::iterator sIt = ciSet.begin();
327 	assertTrue (*sIt == "A"); ++sIt;
328 	assertTrue (*sIt == "b"); ++sIt;
329 	assertTrue (*sIt == "z");
330 }
331 
332 
testTranslate()333 void StringTest::testTranslate()
334 {
335 	std::string s = "aabbccdd";
336 	assertTrue (translate(s, "abc", "ABC") == "AABBCCdd");
337 	assertTrue (translate(s, "abc", "AB") == "AABBdd");
338 	assertTrue (translate(s, "abc", "") == "dd");
339 	assertTrue (translate(s, "cba", "CB") == "BBCCdd");
340 	assertTrue (translate(s, "", "CB") == "aabbccdd");
341 }
342 
343 
testTranslateInPlace()344 void StringTest::testTranslateInPlace()
345 {
346 	std::string s = "aabbccdd";
347 	translateInPlace(s, "abc", "ABC");
348 	assertTrue (s == "AABBCCdd");
349 }
350 
351 
testReplace()352 void StringTest::testReplace()
353 {
354 	std::string s("aabbccdd");
355 
356 	assertTrue (replace(s, std::string("aa"), std::string("xx")) == "xxbbccdd");
357 	assertTrue (replace(s, std::string("bb"), std::string("xx")) == "aaxxccdd");
358 	assertTrue (replace(s, std::string("dd"), std::string("xx")) == "aabbccxx");
359 	assertTrue (replace(s, std::string("bbcc"), std::string("xx")) == "aaxxdd");
360 	assertTrue (replace(s, std::string("b"), std::string("xx")) == "aaxxxxccdd");
361 	assertTrue (replace(s, std::string("bb"), std::string("")) == "aaccdd");
362 	assertTrue (replace(s, std::string("b"), std::string("")) == "aaccdd");
363 	assertTrue (replace(s, std::string("ee"), std::string("xx")) == "aabbccdd");
364 	assertTrue (replace(s, std::string("dd"), std::string("")) == "aabbcc");
365 
366 	assertTrue (replace(s, "aa", "xx") == "xxbbccdd");
367 	assertTrue (replace(s, "bb", "xx") == "aaxxccdd");
368 	assertTrue (replace(s, "dd", "xx") == "aabbccxx");
369 	assertTrue (replace(s, "bbcc", "xx") == "aaxxdd");
370 	assertTrue (replace(s, "bb", "") == "aaccdd");
371 	assertTrue (replace(s, "b", "") == "aaccdd");
372 	assertTrue (replace(s, "ee", "xx") == "aabbccdd");
373 	assertTrue (replace(s, "dd", "") == "aabbcc");
374 
375 	s = "aabbaabb";
376 	assertTrue (replace(s, std::string("aa"), std::string("")) == "bbbb");
377 	assertTrue (replace(s, std::string("a"), std::string("")) == "bbbb");
378 	assertTrue (replace(s, std::string("a"), std::string("x")) == "xxbbxxbb");
379 	assertTrue (replace(s, std::string("a"), std::string("xx")) == "xxxxbbxxxxbb");
380 	assertTrue (replace(s, std::string("aa"), std::string("xxx")) == "xxxbbxxxbb");
381 
382 	assertTrue (replace(s, std::string("aa"), std::string("xx"), 2) == "aabbxxbb");
383 
384 	assertTrue (replace(s, "aa", "") == "bbbb");
385 	assertTrue (replace(s, "a", "") == "bbbb");
386 	assertTrue (replace(s, "a", "x") == "xxbbxxbb");
387 	assertTrue (replace(s, "a", "xx") == "xxxxbbxxxxbb");
388 	assertTrue (replace(s, "aa", "xxx") == "xxxbbxxxbb");
389 
390 	assertTrue (replace(s, "aa", "xx", 2) == "aabbxxbb");
391 	assertTrue (replace(s, 'a', 'x', 2) == "aabbxxbb");
392 	assertTrue (remove(s, 'a', 2) == "aabbbb");
393 	assertTrue (remove(s, 'a') == "bbbb");
394 	assertTrue (remove(s, 'b', 2) == "aaaa");
395 }
396 
397 
testReplaceInPlace()398 void StringTest::testReplaceInPlace()
399 {
400 	std::string s("aabbccdd");
401 
402 	replaceInPlace(s, std::string("aa"), std::string("xx"));
403 	assertTrue (s == "xxbbccdd");
404 
405 	s = "aabbccdd";
406 	replaceInPlace(s, 'a', 'x');
407 	assertTrue (s == "xxbbccdd");
408 	replaceInPlace(s, 'x');
409 	assertTrue (s == "bbccdd");
410 	removeInPlace(s, 'b', 1);
411 	assertTrue (s == "bccdd");
412 	removeInPlace(s, 'd');
413 	assertTrue (s == "bcc");
414 }
415 
416 
testCat()417 void StringTest::testCat()
418 {
419 	std::string s1("one");
420 	std::string s2("two");
421 	std::string s3("three");
422 	std::string s4("four");
423 	std::string s5("five");
424 	std::string s6("six");
425 
426 	assertTrue (cat(s1, s2) == "onetwo");
427 	assertTrue (cat(s1, s2, s3) == "onetwothree");
428 	assertTrue (cat(s1, s2, s3, s4) == "onetwothreefour");
429 	assertTrue (cat(s1, s2, s3, s4, s5) == "onetwothreefourfive");
430 	assertTrue (cat(s1, s2, s3, s4, s5, s6) == "onetwothreefourfivesix");
431 
432 	std::vector<std::string> vec;
433 	assertTrue (cat(std::string(), vec.begin(), vec.end()) == "");
434 	assertTrue (cat(std::string(","), vec.begin(), vec.end()) == "");
435 	vec.push_back(s1);
436 	assertTrue (cat(std::string(","), vec.begin(), vec.end()) == "one");
437 	vec.push_back(s2);
438 	assertTrue (cat(std::string(","), vec.begin(), vec.end()) == "one,two");
439 	vec.push_back(s3);
440 	assertTrue (cat(std::string(","), vec.begin(), vec.end()) == "one,two,three");
441 }
442 
443 
testStartsWith()444 void StringTest::testStartsWith()
445 {
446 	std::string s1("o");
447 
448 	assertTrue (startsWith(s1, std::string("o")));
449 	assertTrue (startsWith(s1, std::string("")));
450 
451 	assertTrue (!startsWith(s1, std::string("O")));
452 	assertTrue (!startsWith(s1, std::string("1")));
453 
454 	std::string s2("");
455 
456 	assertTrue (startsWith(s2, std::string("")));
457 
458 	assertTrue (!startsWith(s2, std::string("o")));
459 
460 	std::string s3("oO");
461 
462 	assertTrue (startsWith(s3, std::string("o")));
463 
464 	assertTrue (!startsWith(s3, std::string(" o")));
465 }
466 
467 
testEndsWith()468 void StringTest::testEndsWith()
469 {
470 	std::string s1("o");
471 
472 	assertTrue (endsWith(s1, std::string("o")));
473 	assertTrue (endsWith(s1, std::string("")));
474 
475 	assertTrue (!endsWith(s1, std::string("O")));
476 	assertTrue (!endsWith(s1, std::string("1")));
477 
478 
479 	std::string s2("");
480 
481 	assertTrue (endsWith(s2, std::string("")));
482 
483 	assertTrue (!endsWith(s2, std::string("o")));
484 
485 	std::string s3("Oo");
486 
487 	assertTrue (endsWith(s3, std::string("o")));
488 
489 	assertTrue (!endsWith(s3, std::string("o ")));
490 }
491 
492 
testStringToInt()493 void StringTest::testStringToInt()
494 {
495 //gcc on Mac emits warnings that cannot be suppressed
496 #ifndef POCO_OS_FAMILY_BSD
497 	stringToInt<Poco::Int8>();
498 	stringToInt<Poco::UInt8>();
499 	stringToInt<Poco::Int16>();
500 	stringToInt<Poco::UInt16>();
501 #endif
502 	stringToInt<Poco::Int32>();
503 	stringToInt<Poco::UInt32>();
504 #if defined(POCO_HAVE_INT64)
505 	stringToInt<Poco::Int64>();
506 	stringToInt<Poco::UInt64>();
507 #endif
508 }
509 
510 
testStringToFloat()511 void StringTest::testStringToFloat()
512 {
513 	float result;
514 	std::string sep(".,");
515 
516 	for (int i = 0; i < 2; ++i)
517 	{
518 		char ds = sep[i];
519 		for (int j = 0; j < 2; ++j)
520 		{
521 			char ts = sep[j];
522 			if (ts == ds) continue;
523 
524 			assertTrue (strToFloat("1", result, ds, ts));
525 			assertEqualDelta(1.0, result, 0.01);
526 			assertTrue (strToFloat(format("%c1", ds), result, ds, ts));
527 			assertEqualDelta(.1, result, 0.01);
528 			assertTrue (strToFloat(format("1%c", ds), result, ds, ts));
529 			assertEqualDelta(1., result, 0.01);
530 			assertTrue (strToFloat("0", result, ds, ts));
531 			assertEqualDelta(0.0, result, 0.01);
532 			assertTrue (strToFloat(format("0%c", ds), result, ds, ts));
533 			assertEqualDelta(0.0, result, 0.01);
534 			assertTrue (strToFloat(format("%c0", ds), result, ds, ts));
535 			assertEqualDelta(0.0, result, 0.01);
536 			assertTrue (strToFloat(format("0%c0", ds), result, ds, ts));
537 			assertEqualDelta(0.0, result, 0.01);
538 			assertTrue (strToFloat(format("0%c0", ds), result, ds, ts));
539 			assertEqualDelta(0., result, 0.01);
540 			assertTrue (strToFloat(format("0%c0", ds), result, ds, ts));
541 			assertEqualDelta(.0, result, 0.01);
542 			assertTrue (strToFloat(format("12%c34", ds), result, ds, ts));
543 			assertEqualDelta(12.34, result, 0.01);
544 			assertTrue (strToFloat(format("12%c34", ds), result, ds, ts));
545 			assertEqualDelta(12.34, result, 0.01);
546 			assertTrue (strToFloat(format("-12%c34", ds), result, ds, ts));
547 			assertEqualDelta(-12.34, result, 0.01);
548 			assertTrue (strToFloat(format("%c34", ds), result, ds, ts));
549 			assertEqualDelta(.34, result, 0.01);
550 			assertTrue (strToFloat(format("-%c34", ds), result, ds, ts));
551 			assertEqualDelta(-.34, result, 0.01);
552 			assertTrue (strToFloat(format("12%c", ds), result, ds, ts));
553 			assertEqualDelta(12., result, 0.01);
554 			assertTrue (strToFloat(format("-12%c", ds), result, ds, ts));
555 			assertEqualDelta(-12., result, 0.01);
556 			assertTrue (strToFloat("12", result, ds, ts));
557 			assertEqualDelta(12, result, 0.01);
558 			assertTrue (strToFloat("-12", result, ds, ts));
559 			assertEqualDelta(-12, result, 0.01);
560 			assertTrue (strToFloat(format("12%c34", ds), result, ds, ts));
561 			assertEqualDelta(12.34, result, 0.01);
562 
563 			assertTrue (strToFloat(format("1%c234%c34", ts, ds), result, ds, ts));
564 			assertEqualDelta(1234.34, result, 0.01);
565 			assertTrue (strToFloat(format("12%c345%c34", ts, ds), result, ds, ts));
566 			assertEqualDelta(12345.34, result, 0.01);
567 			assertTrue (strToFloat(format("123%c456%c34", ts, ds), result, ds, ts));
568 			assertEqualDelta(123456.34, result, 0.01);
569 			assertTrue (strToFloat(format("1%c234%c567%c34", ts, ts, ds), result, ds, ts));
570 
571 			if ((std::numeric_limits<double>::max() / 10) < 1.23456e10)
572 				fail ("test value larger than max value for this platform");
573 			else
574 			{
575 				float d = 12e34f;
576 				assertTrue (strToFloat(format("12e34", ds), result, ds, ts));
577 				assertEqualDelta(d, result, 0.01e34);
578 
579 				d = 1.234e30f;
580 				assertTrue (strToFloat(format("1%c234e30", ds), result, ds, ts));
581 				assertEqualDelta(d, result, 0.01);
582 				assertTrue (strToFloat(format("1%c234E+30", ds), result, ds, ts));
583 				assertEqualDelta(d, result, 0.01);
584 			}
585 
586 			float d = 12.34e-10f;
587 			assertTrue (strToFloat(format("12%c34e-10", ds), result, ds, ts));
588 			assertEqualDelta(d, result, 0.01);
589 			assertTrue (strToFloat(format("-12%c34", ds), result, ds, ts));
590 			assertEqualDelta(-12.34, result, 0.01);
591 
592 			assertTrue (strToFloat(format("   12%c34", ds), result, ds, ts));
593 			assertEqualDelta(12.34, result, 0.01);
594 			assertTrue (strToFloat(format("12%c34   ", ds), result, ds, ts));
595 			assertEqualDelta(12.34, result, 0.01);
596 			assertTrue (strToFloat(format(" 12%c34  ", ds), result, ds, ts));
597 			assertEqualDelta(12.34, result, 0.01);
598 		}
599 	}
600 
601 	assertTrue (FPEnvironment::isNaN(strToFloat("nan")));
602 	assertTrue (FPEnvironment::isNaN(strToFloat("xNaNy")));
603 	assertTrue (!FPEnvironment::isNaN(strToFloat("inf")));
604 	assertTrue (!FPEnvironment::isNaN(strToFloat("-inf")));
605 	assertTrue (FPEnvironment::isNaN(strToFloat("infinity")));
606 	assertTrue (!FPEnvironment::isNaN(strToFloat("infinity", "infinity")));
607 	assertTrue (!FPEnvironment::isNaN(strToFloat("-infinity", "infinity")));
608 	assertTrue (!FPEnvironment::isNaN(strToFloat("1.23")));
609 	assertTrue (FPEnvironment::isNaN(strToFloat("Inf")));
610 	assertTrue (!FPEnvironment::isNaN(strToFloat("Inf", "Inf")));
611 
612 	assertTrue (FPEnvironment::isInfinite(strToFloat("inf")));
613 	assertTrue (FPEnvironment::isInfinite(strToFloat("-inf")));
614 	assertTrue (FPEnvironment::isInfinite(strToFloat("infinity", "infinity")));
615 	assertTrue (FPEnvironment::isInfinite(strToFloat("-infinity", "infinity")));
616 	assertTrue (!FPEnvironment::isInfinite(strToFloat("1.23")));
617 	assertTrue (!FPEnvironment::isInfinite(strToFloat("abc")));
618 	assertTrue (FPEnvironment::isInfinite(strToFloat("Inf", "Inf")));
619 }
620 
621 
testStringToDouble()622 void StringTest::testStringToDouble()
623 {
624 	double result;
625 	std::string sep(".,");
626 
627 	for (int i = 0; i < 2; ++i)
628 	{
629 		char ds = sep[i];
630 		for (int j = 0; j < 2; ++j)
631 		{
632 			char ts = sep[j];
633 			if (ts == ds) continue;
634 
635 			assertTrue (strToDouble("1", result, ds, ts));
636 			assertEqualDelta(1.0, result, 0.01);
637 			assertTrue (strToDouble(format("%c1", ds), result, ds, ts));
638 			assertEqualDelta(.1, result, 0.01);
639 			assertTrue (strToDouble(format("1%c", ds), result, ds, ts));
640 			assertEqualDelta(1., result, 0.01);
641 			assertTrue (strToDouble("0", result, ds, ts));
642 			assertEqualDelta(0.0, result, 0.01);
643 			assertTrue (strToDouble(format("0%c", ds), result, ds, ts));
644 			assertEqualDelta(0.0, result, 0.01);
645 			assertTrue (strToDouble(format("%c0", ds), result, ds, ts));
646 			assertEqualDelta(0.0, result, 0.01);
647 			assertTrue (strToDouble(format("0%c0", ds), result, ds, ts));
648 			assertEqualDelta(0.0, result, 0.01);
649 			assertTrue (strToDouble(format("0%c0", ds), result, ds, ts));
650 			assertEqualDelta(0., result, 0.01);
651 			assertTrue (strToDouble(format("0%c0", ds), result, ds, ts));
652 			assertEqualDelta(.0, result, 0.01);
653 			assertTrue (strToDouble(format("12%c34", ds), result, ds, ts));
654 			assertEqualDelta(12.34, result, 0.01);
655 			assertTrue (strToDouble(format("12%c34", ds), result, ds, ts));
656 			assertEqualDelta(12.34, result, 0.01);
657 			assertTrue (strToDouble(format("-12%c34", ds), result, ds, ts));
658 			assertEqualDelta(-12.34, result, 0.01);
659 			assertTrue (strToDouble(format("%c34", ds), result, ds, ts));
660 			assertEqualDelta(.34, result, 0.01);
661 			assertTrue (strToDouble(format("-%c34", ds), result, ds, ts));
662 			assertEqualDelta(-.34, result, 0.01);
663 			assertTrue (strToDouble(format("12%c", ds), result, ds, ts));
664 			assertEqualDelta(12., result, 0.01);
665 			assertTrue (strToDouble(format("-12%c", ds), result, ds, ts));
666 			assertEqualDelta(-12., result, 0.01);
667 			assertTrue (strToDouble("12", result, ds, ts));
668 			assertEqualDelta(12, result, 0.01);
669 			assertTrue (strToDouble("-12", result, ds, ts));
670 			assertEqualDelta(-12, result, 0.01);
671 			assertTrue (strToDouble(format("12%c3456789012345678901234567890", ds), result, ds, ts));
672 			assertEqualDelta(12.34, result, 0.01);
673 
674 			assertTrue (strToDouble("1234345", result, ds, ts));
675 			assertEqualDelta(1234345, result, 0.00000001);
676 			assertTrue (strToDouble(format("1%c234%c345", ts, ts), result, ds, ts));
677 			assertEqualDelta(1234345, result, 0.00000001);
678 			assertTrue (strToDouble(format("1%c234%c3456789012345678901234567890", ts, ds), result, ds, ts));
679 			assertEqualDelta(1234.3456789, result, 0.00000001);
680 			assertTrue (strToDouble(format("12%c345%c3456789012345678901234567890", ts, ds), result, ds, ts));
681 			assertEqualDelta(12345.3456789, result, 0.00000001);
682 			assertTrue (strToDouble(format("123%c456%c3456789012345678901234567890", ts, ds), result, ds, ts));
683 			assertEqualDelta(123456.3456789, result, 0.00000001);
684 			assertTrue (strToDouble(format("1%c234%c567%c3456789012345678901234567890", ts, ts, ds), result, ds, ts));
685 			assertEqualDelta(1234567.3456789, result, 0.00000001);
686 			assertTrue (strToDouble(format("12%c345%c678%c3456789012345678901234567890", ts, ts, ds), result, ds, ts));
687 			assertEqualDelta(12345678.3456789, result, 0.00000001);
688 			assertTrue (strToDouble(format("123%c456%c789%c3456789012345678901234567890", ts, ts, ds), result, ds, ts));
689 			assertEqualDelta(123456789.3456789, result, 0.00000001);
690 
691 			if ((std::numeric_limits<double>::max() / 10) < 1.23456e10)
692 				fail ("test value larger than max value for this platform");
693 			else
694 			{
695 				double d = 12e34;
696 				assertTrue (strToDouble(format("12e34", ds), result, ds, ts));
697 				assertEqualDelta(d, result, 0.01e34);
698 
699 				d = 1.234e100;
700 				assertTrue (strToDouble(format("1%c234e100", ds), result, ds, ts));
701 				assertEqualDelta(d, result, 0.01);
702 				assertTrue (strToDouble(format("1%c234E+100", ds), result, ds, ts));
703 				assertEqualDelta(d, result, 0.01);
704 
705 				d = 1.234e-100;
706 				assertTrue (strToDouble(format("1%c234E-100", ds), result, ds, ts));
707 				assertEqualDelta(d, result, 0.01);
708 
709 				d = -1.234e100;
710 				assertTrue (strToDouble(format("-1%c234e+100", ds), result, ds, ts));
711 				assertEqualDelta(d, result, 0.01);
712 				assertTrue (strToDouble(format("-1%c234E100", ds), result, ds, ts));
713 				assertEqualDelta(d, result, 0.01);
714 
715 				d = 1.234e-100;
716 				assertTrue (strToDouble(format(" 1%c234e-100 ", ds), result, ds, ts));
717 				assertEqualDelta(d, result, 0.01);
718 				assertTrue (strToDouble(format(" 1%c234e-100 ", ds), result, ds, ts));
719 				assertEqualDelta(d, result, 0.01);
720 				assertTrue (strToDouble(format("  1%c234e-100 ", ds), result, ds, ts));
721 				assertEqualDelta(d, result, 0.01);
722 
723 				d = 1234.234e-100;
724 				assertTrue (strToDouble(format(" 1%c234%c234e-100 ", ts, ds), result, ds, ts));
725 				assertEqualDelta(d, result, 0.01);
726 				d = 12345.234e-100;
727 				assertTrue (strToDouble(format(" 12%c345%c234e-100 ", ts, ds), result, ds, ts));
728 				assertEqualDelta(d, result, 0.01);
729 				d = 123456.234e-100;
730 				assertTrue (strToDouble(format("  123%c456%c234e-100 ", ts, ds), result, ds, ts));
731 				assertEqualDelta(d, result, 0.01);
732 
733 				d = -1234.234e-100;
734 				assertTrue (strToDouble(format(" -1%c234%c234e-100 ", ts, ds), result, ds, ts));
735 				assertEqualDelta(d, result, 0.01);
736 				d = -12345.234e-100;
737 				assertTrue (strToDouble(format(" -12%c345%c234e-100 ", ts, ds), result, ds, ts));
738 				assertEqualDelta(d, result, 0.01);
739 				d = -123456.234e-100;
740 				char ou = 0;
741 				assertTrue (strToDouble(format("  -123%c456%c234e-100 ", ts, ds), result, ds, ts));
742 				assertEqualDelta(d, result, 0.01);
743 				assertTrue (ou == 0);
744 			}
745 
746 			double d = 12.34e-10;
747 			assertTrue (strToDouble(format("12%c34e-10", ds), result, ds, ts));
748 			assertEqualDelta(d, result, 0.01);
749 			assertTrue (strToDouble(format("-12%c34", ds), result, ds, ts));
750 			assertEqualDelta(-12.34, result, 0.01);
751 
752 			assertTrue (strToDouble(format("   12%c34", ds), result, ds, ts));
753 			assertEqualDelta(12.34, result, 0.01);
754 			assertTrue (strToDouble(format("12%c34   ", ds), result, ds, ts));
755 			assertEqualDelta(12.34, result, 0.01);
756 			assertTrue (strToDouble(format(" 12%c34  ", ds), result, ds, ts));
757 			assertEqualDelta(12.34, result, 0.01);
758 		}
759 	}
760 
761 	assertTrue (FPEnvironment::isNaN(strToDouble("nan")));
762 	assertTrue (FPEnvironment::isNaN(strToDouble("xNaNy")));
763 	assertTrue (!FPEnvironment::isNaN(strToDouble("inf")));
764 	assertTrue (!FPEnvironment::isNaN(strToDouble("-inf")));
765 	assertTrue (FPEnvironment::isNaN(strToDouble("infinity")));
766 	assertTrue (!FPEnvironment::isNaN(strToDouble("infinity", "infinity")));
767 	assertTrue (!FPEnvironment::isNaN(strToDouble("-infinity", "infinity")));
768 	assertTrue (!FPEnvironment::isNaN(strToDouble("1.23")));
769 	assertTrue (FPEnvironment::isNaN(strToDouble("Inf")));
770 	assertTrue (!FPEnvironment::isNaN(strToDouble("Inf", "Inf")));
771 
772 	assertTrue (FPEnvironment::isInfinite(strToDouble("inf")));
773 	assertTrue (FPEnvironment::isInfinite(strToDouble("-inf")));
774 	assertTrue (FPEnvironment::isInfinite(strToDouble("infinity", "infinity")));
775 	assertTrue (FPEnvironment::isInfinite(strToDouble("-infinity", "infinity")));
776 	assertTrue (!FPEnvironment::isInfinite(strToDouble("1.23")));
777 	assertTrue (!FPEnvironment::isInfinite(strToDouble("abc")));
778 	assertTrue (FPEnvironment::isInfinite(strToDouble("Inf", "Inf")));
779 }
780 
781 
testNumericStringPadding()782 void StringTest::testNumericStringPadding()
783 {
784 	std::string str;
785 	assertTrue (floatToStr(str, 0.999f, 2, 4) == "1.00");
786 	assertTrue (floatToStr(str, 0.945f, 2, 4) == "0.95");
787 	assertTrue (floatToStr(str, 0.944f, 2, 4) == "0.94");
788 	assertTrue (floatToStr(str, 12.45f, 2, 5) == "12.45");
789 	assertTrue (floatToStr(str, 12.45f, 1, 4) == "12.5");
790 	assertTrue (floatToStr(str, 12.45f, 2, 6) == " 12.45");
791 	assertTrue (floatToStr(str, 12.455f, 3, 7) == " 12.455");
792 	assertTrue (floatToStr(str, 12.455f, 2, 6) == " 12.46");
793 	assertTrue (floatToStr(str, 1.23556E-16f, 2, 6) == "1.24e-16");
794 
795 	assertTrue (doubleToStr(str, 0.999, 2, 4) == "1.00");
796 	assertTrue (doubleToStr(str, 0.945, 2, 4) == "0.95");
797 	assertTrue (doubleToStr(str, 0.944, 2, 4) == "0.94");
798 	assertTrue (doubleToStr(str, 12.45, 2, 5) == "12.45");
799 	assertTrue (doubleToStr(str, 12.45, 1, 4) == "12.5");
800 	assertTrue (doubleToStr(str, 12.45, 2, 6) == " 12.45");
801 	assertTrue (doubleToStr(str, 12.455, 3, 7) == " 12.455");
802 	assertTrue (doubleToStr(str, 12.455, 2, 6) == " 12.46");
803 	assertTrue (doubleToStr(str, 1.23556E-16, 2, 6) == "1.24e-16");
804 }
805 
testStringToFloatError()806 void StringTest::testStringToFloatError()
807 {
808 	char ds = decimalSeparator();
809 	if (ds == 0) ds = '.';
810 	char ts = thousandSeparator();
811 	if (ts == 0) ts = ',';
812 	assertTrue (ds != ts);
813 
814 	double result = 0.0;
815 	assertTrue (!strToDouble(format("a12%c3", ds), result));
816 	assertTrue (!strToDouble(format("1b2%c3", ds), result));
817 	assertTrue (!strToDouble(format("12c%c3", ds), result));
818 	assertTrue (!strToDouble(format("12%cx3", ds), result));
819 
820 	assertTrue (!strToDouble(format("123%c456%c234e1000000", ts, ds), result));
821 	assertTrue (!strToDouble(format("123%c456%c234e+1000000", ts, ds), result));
822 	//assertTrue (!strToDouble(0, result, ou)); // strToDouble is resilient to null pointers
823 	assertTrue (!strToDouble("", result));
824 }
825 
826 
testNumericLocale()827 void StringTest::testNumericLocale()
828 {
829 #if !defined(POCO_NO_LOCALE) && POCO_OS == POCO_OS_WINDOWS_NT
830 	try
831 	{
832 		char buffer[POCO_MAX_FLT_STRING_LEN];
833 
834 		char dp = decimalSeparator();
835 		char ts = thousandSeparator();
836 		std::locale loc;
837 		std::cout << "Original locale: '" << loc.name() << '\'' << std::endl;
838 		std::cout << "Decimal point: '" << decimalSeparator() << '\'' << std::endl;
839 		std::cout << "Thousand separator: '" << ts << '\'' << std::endl;
840 		doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, 1.23);
841 		assertTrue (std::strncmp(buffer, "1.23", 4) == 0);
842 		std::cout << "1.23 == '" << buffer << '\'' << std::endl;
843 
844 		std::locale::global(std::locale("German"));
845 		std::locale locGerman;
846 		assertTrue (',' == decimalSeparator());
847 		assertTrue ('.' == thousandSeparator());
848 		std::cout << "New locale: '" << locGerman.name() << '\'' << std::endl;
849 		std::cout << "Decimal point: '" << decimalSeparator() << '\'' << std::endl;
850 		std::cout << "Thousand separator: '" << thousandSeparator() << '\'' << std::endl;
851 		doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, 1.23);
852 		assertTrue (std::strncmp(buffer, "1.23", 4) == 0);
853 		std::cout << "1.23 == '" << buffer << '\'' << std::endl;
854 
855 		std::locale::global(std::locale("US"));
856 		std::locale locUS;
857 		assertTrue ('.' == decimalSeparator());
858 		assertTrue (',' == thousandSeparator());
859 		std::cout << "New locale: '" << locUS.name() << '\'' << std::endl;
860 		std::cout << "Decimal point: '" << decimalSeparator() << '\'' << std::endl;
861 		std::cout << "Thousand separator: '" << thousandSeparator() << '\'' << std::endl;
862 		doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, 1.23);
863 		assertTrue (std::strncmp(buffer, "1.23", 4) == 0);
864 		std::cout << "1.23 == '" << buffer << '\'' << std::endl;
865 
866 		std::locale::global(loc);
867 		dp = decimalSeparator();
868 		ts = thousandSeparator();
869 		std::cout << "Final locale: '" << loc.name() << '\'' << std::endl;
870 		std::cout << "Decimal point: '" << decimalSeparator() << '\'' << std::endl;
871 		std::cout << "Thousand separator: '" << thousandSeparator() << '\'' << std::endl;
872 		doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, 1.23);
873 		assertTrue (std::strncmp(buffer, "1.23", 4) == 0);
874 		std::cout << "1.23 == '" << buffer << '\'' << std::endl;
875 
876 		assertTrue (dp == decimalSeparator());
877 		assertTrue (ts == thousandSeparator());
878 	} catch (std::runtime_error& ex)
879 	{
880 		std::cout << ex.what() << std::endl;
881 		warnmsg ("Locale not found, skipping test");
882 	}
883 #endif
884 }
885 
886 
benchmarkStrToInt()887 void StringTest::benchmarkStrToInt()
888 {
889 	Poco::Stopwatch sw;
890 	std::string num = "123456789";
891 	int res;
892 	sw.start();
893 	for (int i = 0; i < 1000000; ++i) parseStream(num, res);
894 	sw.stop();
895 	std::cout << "parseStream Number: " << res << std::endl;
896 	double timeStream = sw.elapsed() / 1000.0;
897 
898 	char* pC = 0;
899 	sw.restart();
900 	for (int i = 0; i < 1000000; ++i) res = std::strtol(num.c_str(), &pC, 10);
901 	sw.stop();
902 	std::cout << "std::strtol Number: " << res << std::endl;
903 	double timeStrtol = sw.elapsed() / 1000.0;
904 
905 	sw.restart();
906 	for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res, 10);
907 	sw.stop();
908 	std::cout << "strToInt Number: " << res << std::endl;
909 	double timeStrToInt = sw.elapsed() / 1000.0;
910 
911 	sw.restart();
912 	for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d", &res);
913 	sw.stop();
914 	std::cout << "sscanf Number: " << res << std::endl;
915 	double timeScanf = sw.elapsed() / 1000.0;
916 
917 	int graph;
918 	std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
919 	std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << timeStream << "[ms]" << std::endl;
920 
921 	std::cout << std::setw(14) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
922 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
923 	graph = (int) (timeStream / timeStrtol); for (int i = 0; i < graph; ++i) std::cout << '|';
924 
925 	std::cout << std::endl << std::setw(14) << "strToInt:\t" << std::setw(10) << std::setfill(' ') << timeStrToInt << "[ms]" <<
926 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
927 	graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
928 
929 	std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ')  << timeScanf << "[ms]" <<
930 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeScanf) << '\t' ;
931 	graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '|';
932 	std::cout << std::endl;
933 }
934 
935 
benchmarkStrToFloat()936 void StringTest::benchmarkStrToFloat()
937 {
938 	Poco::Stopwatch sw;
939 	std::string num = "1.0372157551632929e-112";
940 	std::cout << "The Number: " << num << std::endl;
941 	double res;
942 	sw.start();
943 	for (int i = 0; i < 1000000; ++i) parseStream(num, res);
944 	sw.stop();
945 	std::cout << "parseStream Number: " << std::setprecision(std::numeric_limits<double>::digits10) << res << std::endl;
946 	double timeStream = sw.elapsed() / 1000.0;
947 
948 	// standard strtod
949 	char* pC = 0;
950 	sw.restart();
951 	for (int i = 0; i < 1000000; ++i) res = std::strtod(num.c_str(), &pC);
952 	sw.stop();
953 	std::cout << "std::strtod Number: " << res << std::endl;
954 	double timeStdStrtod = sw.elapsed() / 1000.0;
955 
956 	// POCO Way
957 	sw.restart();
958 	char ou = 0;
959 	for (int i = 0; i < 1000000; ++i) strToDouble(num, res, ou);
960 	sw.stop();
961 	std::cout << "strToDouble Number: " << res << std::endl;
962 	double timeStrToDouble = sw.elapsed() / 1000.0;
963 
964 	// standard sscanf
965 	sw.restart();
966 	for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%lf", &res);
967 	sw.stop();
968 	std::cout << "sscanf Number: " << res << std::endl;
969 	double timeScanf = sw.elapsed() / 1000.0;
970 
971 	// double-conversion Strtod
972 	sw.restart();
973 	for (int i = 0; i < 1000000; ++i) strToDouble(num.c_str());
974 	sw.stop();
975 	std::cout << "Strtod Number: " << res << std::endl;
976 	double timeStrtod = sw.elapsed() / 1000.0;
977 
978 	int graph;
979 	std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
980 	std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
981 
982 	std::cout << std::setw(14) << "std::strtod:\t" << std::setw(10) << std::setfill(' ') << timeStdStrtod << "[ms]" <<
983 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeStdStrtod) << '\t' ;
984 	graph = (int) (timeStream / timeStdStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
985 
986 	std::cout << std::endl << std::setw(14) << "strToDouble:\t" << std::setw(10) << std::setfill(' ') << timeStrToDouble << "[ms]" <<
987 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeStrToDouble) << '\t' ;
988 	graph = (int) (timeStream / timeStrToDouble); for (int i = 0; i < graph; ++i) std::cout << '#';
989 
990 	std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ')  << timeScanf << "[ms]" <<
991 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeScanf) << '\t' ;
992 	graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '#';
993 
994 	std::cout << std::endl << std::setw(14) << "StrtoD:\t" << std::setw(10) << std::setfill(' ')  << timeScanf << "[ms]" <<
995 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeStrtod) << '\t' ;
996 	graph = (int) (timeStream / timeStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
997 
998 	std::cout << std::endl;
999 }
1000 
1001 
testIntToString()1002 void StringTest::testIntToString()
1003 {
1004 	//intToStr(T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0)
1005 
1006 	// decimal
1007 	std::string result;
1008 	assertTrue (intToStr(0, 10, result));
1009 	assertTrue (result == "0");
1010 	assertTrue (intToStr(0, 10, result, false, 10, '0'));
1011 	assertTrue (result == "0000000000");
1012 	assertTrue (intToStr(1234567890, 10, result));
1013 	assertTrue (result == "1234567890");
1014 	assertTrue (intToStr(-1234567890, 10, result));
1015 	assertTrue (result == "-1234567890");
1016 	assertTrue (intToStr(-1234567890, 10, result, false, 15, '0'));
1017 	assertTrue (result == "-00001234567890");
1018 	assertTrue (intToStr(-1234567890, 10, result, false, 15));
1019 	assertTrue (result == "    -1234567890");
1020 	assertTrue (intToStr(-1234567890, 10, result, false, 0, 0, ','));
1021 	assertTrue (result == "-1,234,567,890");
1022 
1023 	// binary
1024 	assertTrue (intToStr(1234567890, 2, result));
1025 	assertTrue (result == "1001001100101100000001011010010");
1026 	assertTrue (intToStr(1234567890, 2, result, true));
1027 	assertTrue (result == "1001001100101100000001011010010");
1028 	assertTrue (intToStr(1234567890, 2, result, true, 35, '0'));
1029 	assertTrue (result == "00001001001100101100000001011010010");
1030 	assertTrue (uIntToStr(0xFF, 2, result));
1031 	assertTrue (result == "11111111");
1032 	assertTrue (uIntToStr(0x0F, 2, result, false, 8, '0'));
1033 	assertTrue (result == "00001111");
1034 	assertTrue (uIntToStr(0x0F, 2, result));
1035 	assertTrue (result == "1111");
1036 	assertTrue (uIntToStr(0xF0, 2, result));
1037 	assertTrue (result == "11110000");
1038 	assertTrue (uIntToStr(0xFFFF, 2, result));
1039 	assertTrue (result == "1111111111111111");
1040 	assertTrue (uIntToStr(0xFF00, 2, result));
1041 	assertTrue (result == "1111111100000000");
1042 	assertTrue (uIntToStr(0xFFFFFFFF, 2, result));
1043 	assertTrue (result == "11111111111111111111111111111111");
1044 	assertTrue (uIntToStr(0xFF00FF00, 2, result));
1045 	assertTrue (result == "11111111000000001111111100000000");
1046 	assertTrue (uIntToStr(0xF0F0F0F0, 2, result));
1047 	assertTrue (result == "11110000111100001111000011110000");
1048 #if defined(POCO_HAVE_INT64)
1049 	assertTrue (uIntToStr(0xFFFFFFFFFFFFFFFF, 2, result));
1050 	assertTrue (result == "1111111111111111111111111111111111111111111111111111111111111111");
1051 	assertTrue (uIntToStr(0xFF00000FF00000FF, 2, result));
1052 	assertTrue (result == "1111111100000000000000000000111111110000000000000000000011111111");
1053 #endif
1054 
1055 	// octal
1056 	assertTrue (uIntToStr(1234567890, 010, result));
1057 	assertTrue (result == "11145401322");
1058 	assertTrue (uIntToStr(1234567890, 010, result, true));
1059 	assertTrue (result == "011145401322");
1060 	assertTrue (uIntToStr(1234567890, 010, result, true, 15, '0'));
1061 	assertTrue (result == "000011145401322");
1062 	assertTrue (uIntToStr(012345670, 010, result, true));
1063 	assertTrue (result == "012345670");
1064 	assertTrue (uIntToStr(012345670, 010, result));
1065 	assertTrue (result == "12345670");
1066 
1067 	// hexadecimal
1068 	assertTrue (uIntToStr(0, 0x10, result, true));
1069 	assertTrue (result == "0x0");
1070 	assertTrue (uIntToStr(0, 0x10, result, true, 4, '0'));
1071 	assertTrue (result == "0x00");
1072 	assertTrue (uIntToStr(0, 0x10, result, false, 4, '0'));
1073 	assertTrue (result == "0000");
1074 	assertTrue (uIntToStr(1234567890, 0x10, result));
1075 	assertTrue (result == "499602D2");
1076 	assertTrue (uIntToStr(1234567890, 0x10, result, true));
1077 	assertTrue (result == "0x499602D2");
1078 	assertTrue (uIntToStr(1234567890, 0x10, result, true, 15, '0'));
1079 	assertTrue (result == "0x00000499602D2");
1080 	assertTrue (uIntToStr(0x1234567890ABCDEF, 0x10, result, true));
1081 	assertTrue (result == "0x1234567890ABCDEF");
1082 	assertTrue (uIntToStr(0xDEADBEEF, 0x10, result));
1083 	assertTrue (result == "DEADBEEF");
1084 #if defined(POCO_HAVE_INT64)
1085 	assertTrue (uIntToStr(0xFFFFFFFFFFFFFFFF, 0x10, result));
1086 	assertTrue (result == "FFFFFFFFFFFFFFFF");
1087 	assertTrue (uIntToStr(0xFFFFFFFFFFFFFFFF, 0x10, result, true));
1088 	assertTrue (result == "0xFFFFFFFFFFFFFFFF");
1089 #endif
1090 
1091 	try
1092 	{
1093 		char pResult[POCO_MAX_INT_STRING_LEN];
1094 		std::size_t sz = POCO_MAX_INT_STRING_LEN;
1095 		intToStr(0, 10, pResult, sz, false, (int) sz + 1, ' ');
1096 		fail ("must throw RangeException");
1097 	} catch (RangeException&) { }
1098 }
1099 
1100 
testFloatToString()1101 void StringTest::testFloatToString()
1102 {
1103 	double val = 1.03721575516329e-112;
1104 	std::string str;
1105 
1106 	assertTrue (doubleToStr(str, val, 14, 21) == "1.03721575516329e-112");
1107 	assertTrue (doubleToStr(str, val, 14, 22) == " 1.03721575516329e-112");
1108 	val = -val;
1109 	assertTrue (doubleToStr(str, val, 14, 22) == "-1.03721575516329e-112");
1110 	assertTrue (doubleToStr(str, val, 14, 23) == " -1.03721575516329e-112");
1111 
1112 	val = -10372157551632.9;
1113 	assertTrue (doubleToStr(str, val, 1, 21, ',') == "-10,372,157,551,632.9");
1114 	assertTrue (doubleToStr(str, val, 1, 22, ',') == " -10,372,157,551,632.9");
1115 	assertTrue (doubleToStr(str, val, 2, 22, ',') == "-10,372,157,551,632.90");
1116 	assertTrue (doubleToStr(str, val, 2, 22, '.', ',') == "-10.372.157.551.632,90");
1117 	assertTrue (doubleToStr(str, val, 2, 22, ' ', ',') == "-10 372 157 551 632,90");
1118 
1119 	int ival = 1234567890;
1120 	assertTrue (doubleToStr(str, ival, 1, 15, ',') == "1,234,567,890.0");
1121 	ival = -123456789;
1122 	assertTrue (doubleToStr(str, ival, 1, 14, ',') == "-123,456,789.0");
1123 }
1124 
1125 
testNumericStringLimit()1126 void StringTest::testNumericStringLimit()
1127 {
1128 	char c = 0, t = -1;
1129 	assertTrue(!isIntOverflow<char>(c));
1130 	assertTrue(safeIntCast<char>(c, t) == c);
1131 	assertTrue(t == c);
1132 
1133 	short s = SHRT_MAX;
1134 	assertTrue(isIntOverflow<char>(s));
1135 	try
1136 	{
1137 		safeIntCast(s, t);
1138 		fail("cast must fail");
1139 	}
1140 	catch(Poco::BadCastException&){}
1141 
1142 	s = SHRT_MIN;
1143 	assertTrue(isIntOverflow<char>(s));
1144 	try
1145 	{
1146 		safeIntCast(s, t);
1147 		fail("short => char cast must fail");
1148 	}
1149 	catch(Poco::BadCastException&){}
1150 
1151 	signed char sc = 0, st = -1;
1152 	assertTrue(!isIntOverflow<signed char>(sc));
1153 	assertTrue(safeIntCast<char>(sc, st) == sc);
1154 	assertTrue(st == sc);
1155 
1156 	short ss = SHRT_MAX;
1157 	assertTrue(isIntOverflow<signed char>(ss));
1158 	assertTrue(isIntOverflow<char>(ss));
1159 	try
1160 	{
1161 		safeIntCast(ss, st);
1162 		fail("short => signed char  cast must fail");
1163 	}
1164 	catch(Poco::BadCastException&){}
1165 
1166 	ss = SHRT_MIN;
1167 	assertTrue(isIntOverflow<signed char>(ss));
1168 	assertTrue(isIntOverflow<char>(ss));
1169 	try
1170 	{
1171 		safeIntCast(ss, st);
1172 		fail("short => signed char cast must fail");
1173 	}
1174 	catch(Poco::BadCastException&){}
1175 
1176 	assertTrue(safeIntCast<signed char>(sc, st) == c);
1177 	assertTrue(st == sc);
1178 
1179 	unsigned char uc = 0, ut = -1;
1180 	assertTrue(!isIntOverflow<unsigned char>(uc));
1181 	assertTrue(safeIntCast<char>(uc, ut) == uc);
1182 	assertTrue(ut == uc);
1183 
1184 	ss = SHRT_MAX;
1185 	assertTrue(isIntOverflow<unsigned char>(ss));
1186 	try
1187 	{
1188 		safeIntCast(ss, st);
1189 		fail("cast must fail");
1190 	}
1191 	catch(Poco::BadCastException&){}
1192 
1193 	ss = -1;
1194 	assertTrue(isIntOverflow<unsigned char>(ss));
1195 	try
1196 	{
1197 		safeIntCast(ss, uc);
1198 		fail("unsigned short => unsigned char cast must fail");
1199 	}
1200 	catch(Poco::BadCastException&){}
1201 
1202 	int i = 0;
1203 	assertTrue(!isIntOverflow<int>(i));
1204 	assertTrue(!isIntOverflow<unsigned>(i));
1205 	i = -1;
1206 	unsigned int ti = -1;
1207 	assertTrue(isIntOverflow<unsigned>(i));
1208 	try
1209 	{
1210 		safeIntCast(i, ti);
1211 		fail("unsigned int => int cast must fail");
1212 	}
1213 	catch(Poco::BadCastException&){}
1214 
1215 	if (sizeof(long) > sizeof(int))
1216 	{
1217 		long l = LONG_MAX;
1218 		assertTrue(isIntOverflow<int>(l));
1219 		l = -1L;
1220 		assertTrue(isIntOverflow<unsigned>(l));
1221 		i = -1;
1222 		assertTrue(!isIntOverflow<long>(i));
1223 		long tl = 0;
1224 		assertTrue(safeIntCast(i, tl) == i);
1225 		unsigned long ul = ULONG_MAX, tul = 0;
1226 		assertTrue(isIntOverflow<long>(ul));
1227 		try
1228 		{
1229 			safeIntCast(ul, tl);
1230 			fail("unsigned long => long cast must fail");
1231 		}
1232 		catch(Poco::BadCastException&){}
1233 		assertTrue(!isIntOverflow<unsigned long>(ul));
1234 		tl = 0;
1235 		assertTrue(safeIntCast(ul, tul) == ul);
1236 		l = LONG_MIN;
1237 		assertTrue(isIntOverflow<unsigned long>(l));
1238 		try
1239 		{
1240 			safeIntCast(l, ul);
1241 			fail("unsigned long => long cast must fail");
1242 		}
1243 		catch(Poco::BadCastException&){}
1244 		ul = LONG_MAX;
1245 		assertTrue(!isIntOverflow<long>(ul));
1246 		assertTrue(safeIntCast(ul, l) == ul);
1247 	}
1248 
1249 	numericStringLimitSameSign<unsigned short, unsigned char>();
1250 	numericStringLimitSameSign<short, char>();
1251 	numericStringLimitSameSign<unsigned int, unsigned short>();
1252 	numericStringLimitSameSign<int, short>();
1253 
1254 	if (sizeof(long) > sizeof(int))
1255 	{
1256 		numericStringLimitSameSign<unsigned long, unsigned int>();
1257 		numericStringLimitSameSign<long, int>();
1258 	}
1259 
1260 	numericStringLowerLimit<short, char>();
1261 	numericStringLowerLimit<int, short>();
1262 
1263 	if (sizeof(long) > sizeof(int))
1264 	{
1265 		numericStringLowerLimit<Poco::Int64, Poco::Int32>();
1266 	}
1267 
1268 	assertTrue(!isIntOverflow<int8_t>(0));
1269 	assertTrue(isIntOverflow<int8_t>(std::numeric_limits<int16_t>::max()));
1270 	assertTrue(isIntOverflow<int8_t>(std::numeric_limits<int16_t>::min()));
1271 	assertTrue(!isIntOverflow<uint8_t>(0));
1272 	assertTrue(isIntOverflow<uint8_t>(std::numeric_limits<int16_t>::max()));
1273 	assertTrue(isIntOverflow<uint8_t>(-1));
1274 	assertTrue(!isIntOverflow<int32_t>(0));
1275 	assertTrue(isIntOverflow<int32_t>(std::numeric_limits<int64_t>::max()));
1276 	assertTrue(!isIntOverflow<uint32_t>(0));
1277 	assertTrue(isIntOverflow<uint32_t>(-1));
1278 	assertTrue(isIntOverflow<uint32_t>(-1L));
1279 	assertTrue(isIntOverflow<uint32_t>(-1LL));
1280 	assertTrue(!isIntOverflow<int64_t>(-1));
1281 	assertTrue(isIntOverflow<int64_t>(std::numeric_limits<uint64_t>::max()));
1282 	assertTrue(!isIntOverflow<uint64_t>(std::numeric_limits<uint64_t>::max()));
1283 	assertTrue(isIntOverflow<uint64_t>(std::numeric_limits<int64_t>::min()));
1284 	assertTrue(!isIntOverflow<uint64_t>(std::numeric_limits<uint64_t>::min()));
1285 	assertTrue(!isIntOverflow<int64_t>(std::numeric_limits<int64_t>::max()));
1286 
1287 	numericStringLimitSameSign<uint16_t, uint8_t>();
1288 	numericStringLimitSameSign<int16_t, int8_t>();
1289 	numericStringLimitSameSign<uint32_t, uint16_t>();
1290 	numericStringLimitSameSign<int32_t, int16_t>();
1291 	numericStringLimitSameSign<uint64_t, uint32_t>();
1292 	numericStringLimitSameSign<int64_t, int32_t>();
1293 
1294 	numericStringLowerLimit<int16_t, int8_t>();
1295 	numericStringLowerLimit<int32_t, int16_t>();
1296 	numericStringLowerLimit<int64_t, int32_t>();
1297 }
1298 
1299 
formatStream(double value,std::string & str)1300 void formatStream(double value, std::string& str)
1301 {
1302 	char buffer[128];
1303 	Poco::MemoryOutputStream ostr(buffer, sizeof(buffer));
1304 #if !defined(POCO_NO_LOCALE)
1305 	ostr.imbue(std::locale::classic());
1306 #endif
1307 	ostr << std::setprecision(16) << value;
1308 	str.assign(buffer, static_cast<std::string::size_type>(ostr.charsWritten()));
1309 }
1310 
1311 
formatSprintf(double value,std::string & str)1312 void formatSprintf(double value, std::string& str)
1313 {
1314 	char buffer[128];
1315 	std::sprintf(buffer, "%.*g", 16, value);
1316 	str = buffer;
1317 }
1318 
1319 
benchmarkFloatToStr()1320 void StringTest::benchmarkFloatToStr()
1321 {
1322 	Poco::Stopwatch sw;
1323 	double val = 1.0372157551632929e-112;
1324 	std::cout << "The Number: " << std::setprecision(std::numeric_limits<double>::digits10) << val << std::endl;
1325 	std::string str;
1326 	sw.start();
1327 	for (int i = 0; i < 1000000; ++i) formatStream(val, str);
1328 	sw.stop();
1329 	std::cout << "formatStream Number: " << str << std::endl;
1330 	double timeStream = sw.elapsed() / 1000.0;
1331 
1332 	// standard sprintf
1333 	str = "";
1334 	sw.restart();
1335 	for (int i = 0; i < 1000000; ++i) formatSprintf(val, str);
1336 	sw.stop();
1337 	std::cout << "std::sprintf Number: " << str << std::endl;
1338 	double timeSprintf = sw.elapsed() / 1000.0;
1339 
1340 	// POCO Way (via double-conversion)
1341 	// no padding
1342 	sw.restart();
1343 	char buffer[POCO_MAX_FLT_STRING_LEN];
1344 	for (int i = 0; i < 1000000; ++i) doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, val);
1345 	sw.stop();
1346 	std::cout << "doubleToStr(char) Number: " << buffer << std::endl;
1347 	double timeDoubleToStrChar = sw.elapsed() / 1000.0;
1348 
1349 	// with padding
1350 	str = "";
1351 	sw.restart();
1352 	for (int i = 0; i < 1000000; ++i) doubleToStr(str, val);
1353 	sw.stop();
1354 	std::cout << "doubleToStr(std::string) Number: " << str << std::endl;
1355 	double timeDoubleToStrString = sw.elapsed() / 1000.0;
1356 
1357 	int graph;
1358 	std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
1359 	std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
1360 
1361 	std::cout << std::setw(14) << "sprintf:\t" << std::setw(10) << std::setfill(' ') << timeSprintf << "[ms]" <<
1362 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeSprintf) << '\t' ;
1363 	graph = (int) (timeStream / timeSprintf); for (int i = 0; i < graph; ++i) std::cout << '#';
1364 
1365 	std::cout << std::endl << std::setw(14) << "doubleToChar:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrChar << "[ms]" <<
1366 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeDoubleToStrChar) << '\t' ;
1367 	graph = (int) (timeStream / timeDoubleToStrChar); for (int i = 0; i < graph; ++i) std::cout << '#';
1368 
1369 	std::cout << std::endl << std::setw(14) << "doubleToString:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrString << "[ms]" <<
1370 	std::setw(10) << std::setfill(' ')  << "Speedup: " << (timeStream / timeDoubleToStrString) << '\t' ;
1371 	graph = (int) (timeStream / timeDoubleToStrString); for (int i = 0; i < graph; ++i) std::cout << '#';
1372 
1373 	std::cout << std::endl;
1374 }
1375 
1376 
testJSONString()1377 void StringTest::testJSONString()
1378 {
1379 	assertTrue (toJSON("\\", false) == "\\\\");
1380 	assertTrue (toJSON("\"", false) == "\\\"");
1381 	assertTrue (toJSON("/", false) == "\\/");
1382 	assertTrue (toJSON("\a", false) == "\\u0007");
1383 	assertTrue (toJSON("\b", false) == "\\b");
1384 	assertTrue (toJSON("\f", false) == "\\f");
1385 	assertTrue (toJSON("\n", false) == "\\n");
1386 	assertTrue (toJSON("\r", false) == "\\r");
1387 	assertTrue (toJSON("\t", false) == "\\t");
1388 	assertTrue (toJSON("\v", false) == "\\u000B");
1389 	assertTrue (toJSON("a", false) == "a");
1390 	assertTrue (toJSON("\xD0\x82", 0) == "\xD0\x82");
1391 	assertTrue (toJSON("\xD0\x82", Poco::JSON_ESCAPE_UNICODE) == "\\u0402");
1392 
1393 	// ??? on MSVC, the assert macro expansion
1394 	// fails to compile when this string is inline ???
1395 	std::string str = "\"foo\\\\\"";
1396 	assertTrue (toJSON("foo\\") == str);
1397 
1398 	assertTrue (toJSON("bar/") == "\"bar\\/\"");
1399 	assertTrue (toJSON("baz") == "\"baz\"");
1400 	assertTrue (toJSON("q\"uote\"d") == "\"q\\\"uote\\\"d\"");
1401 	assertTrue (toJSON("bs\b") == "\"bs\\b\"");
1402 	assertTrue (toJSON("nl\n") == "\"nl\\n\"");
1403 	assertTrue (toJSON("tb\t") == "\"tb\\t\"");
1404 	assertTrue (toJSON("\xD0\x82") == "\"\xD0\x82\"");
1405 	assertTrue (toJSON("\xD0\x82", Poco::JSON_WRAP_STRINGS) == "\"\xD0\x82\"");
1406 	assertTrue (toJSON("\xD0\x82",
1407 			Poco::JSON_WRAP_STRINGS | Poco::JSON_ESCAPE_UNICODE) == "\"\\u0402\"");
1408 
1409 	std::ostringstream ostr;
1410 	toJSON("foo\\", ostr);
1411 	assertTrue (ostr.str() == str);
1412 	ostr.str("");
1413 
1414 	toJSON("foo\\", ostr);
1415 	assertTrue (toJSON("bar/") == "\"bar\\/\"");
1416 	ostr.str("");
1417 	toJSON("baz", ostr);
1418 	assertTrue (ostr.str() == "\"baz\"");
1419 	ostr.str("");
1420 	toJSON("q\"uote\"d", ostr);
1421 	assertTrue (ostr.str() == "\"q\\\"uote\\\"d\"");
1422 	ostr.str("");
1423 	toJSON("bs\b", ostr);
1424 	assertTrue (ostr.str() == "\"bs\\b\"");
1425 	ostr.str("");
1426 	toJSON("nl\n", ostr);
1427 	assertTrue (ostr.str() == "\"nl\\n\"");
1428 	ostr.str("");
1429 	toJSON("tb\t", ostr);
1430 	assertTrue (ostr.str() == "\"tb\\t\"");
1431 	ostr.str("");
1432 	toJSON("\xD0\x82", ostr);
1433 	assertTrue (ostr.str() == "\"\xD0\x82\"");
1434 	ostr.str("");
1435 	toJSON("\xD0\x82", ostr, Poco::JSON_WRAP_STRINGS);
1436 	assertTrue (ostr.str() == "\"\xD0\x82\"");
1437 	ostr.str("");
1438 	toJSON("\xD0\x82", ostr, Poco::JSON_WRAP_STRINGS | Poco::JSON_ESCAPE_UNICODE);
1439 	assertTrue (ostr.str() == "\"\\u0402\"");
1440 	ostr.str("");
1441 }
1442 
1443 
setUp()1444 void StringTest::setUp()
1445 {
1446 }
1447 
1448 
tearDown()1449 void StringTest::tearDown()
1450 {
1451 }
1452 
1453 
suite()1454 CppUnit::Test* StringTest::suite()
1455 {
1456 	CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("StringTest");
1457 
1458 	CppUnit_addTest(pSuite, StringTest, testTrimLeft);
1459 	CppUnit_addTest(pSuite, StringTest, testTrimLeftInPlace);
1460 	CppUnit_addTest(pSuite, StringTest, testTrimRight);
1461 	CppUnit_addTest(pSuite, StringTest, testTrimInPlace);
1462 	CppUnit_addTest(pSuite, StringTest, testTrim);
1463 	CppUnit_addTest(pSuite, StringTest, testTrimRightInPlace);
1464 	CppUnit_addTest(pSuite, StringTest, testToUpper);
1465 	CppUnit_addTest(pSuite, StringTest, testToLower);
1466 	CppUnit_addTest(pSuite, StringTest, testIstring);
1467 	CppUnit_addTest(pSuite, StringTest, testIcompare);
1468 	CppUnit_addTest(pSuite, StringTest, testCILessThan);
1469 	CppUnit_addTest(pSuite, StringTest, testTranslate);
1470 	CppUnit_addTest(pSuite, StringTest, testTranslateInPlace);
1471 	CppUnit_addTest(pSuite, StringTest, testReplace);
1472 	CppUnit_addTest(pSuite, StringTest, testReplaceInPlace);
1473 	CppUnit_addTest(pSuite, StringTest, testCat);
1474 	CppUnit_addTest(pSuite, StringTest, testStartsWith);
1475 	CppUnit_addTest(pSuite, StringTest, testEndsWith);
1476 	CppUnit_addTest(pSuite, StringTest, testStringToInt);
1477 	CppUnit_addTest(pSuite, StringTest, testStringToFloat);
1478 	CppUnit_addTest(pSuite, StringTest, testStringToDouble);
1479 	CppUnit_addTest(pSuite, StringTest, testNumericStringPadding);
1480 	CppUnit_addTest(pSuite, StringTest, testNumericStringLimit);
1481 	CppUnit_addTest(pSuite, StringTest, testStringToFloatError);
1482 	CppUnit_addTest(pSuite, StringTest, testNumericLocale);
1483 	//CppUnit_addTest(pSuite, StringTest, benchmarkStrToFloat);
1484 	//CppUnit_addTest(pSuite, StringTest, benchmarkStrToInt);
1485 	CppUnit_addTest(pSuite, StringTest, testIntToString);
1486 	CppUnit_addTest(pSuite, StringTest, testFloatToString);
1487 	//CppUnit_addTest(pSuite, StringTest, benchmarkFloatToStr);
1488 	CppUnit_addTest(pSuite, StringTest, testJSONString);
1489 
1490 	return pSuite;
1491 }
1492