1 /*******************************************************************************
2 * tests/string_test.cpp
3 *
4 * Part of tlx - http://panthema.net/tlx
5 *
6 * Copyright (C) 2007-2017 Timo Bingmann <tb@panthema.net>
7 *
8 * All rights reserved. Published under the Boost Software License, Version 1.0
9 ******************************************************************************/
10
11 #include <random>
12 #include <stdexcept>
13
14 #include <tlx/die.hpp>
15 #include <tlx/port/setenv.hpp>
16 #include <tlx/string.hpp>
17 #include <tlx/string/appendline.hpp>
18 #include <tlx/string/ssprintf_generic.hpp>
19
20 //! Returns an initialized unsigned char[] array inside an std::string
21 #define ARRAY_AS_STRING(array) \
22 std::string(reinterpret_cast<const char*>(array), sizeof(array))
23
24 /*!
25 * Generate a random binary string of given length. Any byte from 0-256 is
26 * equally probable. Uses the pseudo-random number generator from stdlib; take
27 * care to seed it using srand() before calling this function.
28 *
29 * \param size length of result
30 * \return random binary string of given length
31 */
32 static inline
random_binary(std::string::size_type size)33 std::string random_binary(std::string::size_type size) {
34 static std::random_device random_device;
35 std::minstd_rand prng(random_device());
36
37 std::string out;
38 out.resize(size);
39
40 for (size_t i = 0; i < size; ++i)
41 out[i] = static_cast<unsigned char>(prng() % 256);
42
43 return out;
44 }
45
test_appendline()46 static void test_appendline() {
47 std::string input =
48 "abc\n" "def\n" "ghi\n" "jk";
49
50 std::stringstream ss1(input);
51 std::string line;
52
53 die_unless(tlx::appendline(ss1, line));
54 die_unequal(line, "abc");
55 die_unless(tlx::appendline(ss1, line));
56 die_unequal(line, "abcdef");
57 die_unless(tlx::appendline(ss1, line));
58 die_unequal(line, "abcdefghi");
59 die_unless(tlx::appendline(ss1, line));
60 die_unequal(line, "abcdefghijk");
61 die_if(tlx::appendline(ss1, line));
62
63 // add one last newline
64 input += "\n";
65 std::stringstream ss2(input);
66
67 line.clear();
68 die_unless(tlx::appendline(ss2, line));
69 die_unequal(line, "abc");
70 die_unless(tlx::appendline(ss2, line));
71 die_unequal(line, "abcdef");
72 die_unless(tlx::appendline(ss2, line));
73 die_unequal(line, "abcdefghi");
74 die_unless(tlx::appendline(ss2, line));
75 die_unequal(line, "abcdefghijk");
76 die_if(tlx::appendline(ss2, line));
77 }
78
test_base64()79 static void test_base64() {
80 // take some static hex data and dump it using base64 encoding, then decode
81 // it again.
82 const unsigned char rand1data[42] = {
83 0x16, 0x35, 0xCA, 0x03, 0x90, 0x6B, 0x47, 0x11,
84 0x85, 0x02, 0xE7, 0x40, 0x9E, 0x3A, 0xCE, 0x43,
85 0x0C, 0x57, 0x3E, 0x35, 0xE7, 0xA6, 0xB2, 0x37,
86 0xEC, 0x6D, 0xF6, 0x68, 0xF6, 0x0E, 0x74, 0x0C,
87 0x44, 0x3F, 0x0F, 0xD4, 0xAA, 0x56, 0xE5, 0x2F,
88 0x58, 0xCC
89 };
90
91 std::string rand1 = ARRAY_AS_STRING(rand1data);
92
93 std::string rand1base64 = tlx::base64_encode(rand1);
94
95 die_unequal(rand1base64,
96 "FjXKA5BrRxGFAudAnjrOQwxXPjXnprI37G32aPYOdAxEPw/UqlblL1jM");
97
98 die_unequal(tlx::base64_decode(rand1base64), rand1);
99
100 // check line-splitting
101 std::string rand1base64lines = tlx::base64_encode(rand1, 16);
102
103 die_unequal(rand1base64lines,
104 "FjXKA5BrRxGFAudA\n" "njrOQwxXPjXnprI3\n"
105 "7G32aPYOdAxEPw/U\n" "qlblL1jM");
106
107 // take three random binary data string with different sizes and run
108 // the base64 encoding->decoding->checking drill.
109
110 std::string rand12 = random_binary(12);
111 die_unequal(tlx::base64_decode(tlx::base64_encode(rand12)), rand12);
112
113 std::string rand13 = random_binary(13);
114 die_unequal(tlx::base64_decode(tlx::base64_encode(rand13)), rand13);
115
116 std::string rand14 = random_binary(14);
117 die_unequal(tlx::base64_decode(tlx::base64_encode(rand14)), rand14);
118
119 // run a larger set of random tests
120 for (unsigned int ti = 0; ti < 1000; ++ti)
121 {
122 unsigned int randlen = ti; // rand() % 1000;
123 std::string randstr = random_binary(randlen);
124
125 die_unequal(
126 tlx::base64_decode(tlx::base64_encode(randstr)), randstr);
127 }
128
129 die_unless_throws(
130 tlx::base64_decode("FjXKA5!!RxGFAudA"), std::runtime_error);
131 }
132
test_bitdump()133 static void test_bitdump() {
134 die_unequal(tlx::bitdump_le8("0123"),
135 "00110000 00110001 00110010 00110011");
136 die_unequal(tlx::bitdump_be8("0123"),
137 "00001100 10001100 01001100 11001100");
138
139 die_unequal(tlx::bitdump_le8_type(uint16_t(0x1234)),
140 "00110100 00010010");
141 die_unequal(tlx::bitdump_be8_type(uint16_t(0x1234)),
142 "00101100 01001000");
143 }
144
test_compare_icase()145 static void test_compare_icase() {
146 die_unless(std::string("ABC") != std::string("abc"));
147
148 die_unless(tlx::equal_icase("ABC", "abc"));
149 die_unless(!tlx::equal_icase("ABC", "abd"));
150 die_unless(!tlx::equal_icase("ABC", "abcedf"));
151
152 die_unless(std::string("ABC") < std::string("abc"));
153 die_unless(!tlx::less_icase("ABC", "abc"));
154 die_unless(tlx::less_icase("abc", "abcdef"));
155 die_unless(!tlx::less_icase("abcdef", "abcd"));
156
157 die_unless(tlx::compare_icase("ABC", "abc") == 0);
158 die_unless(tlx::compare_icase("ABC", "abd") < 0);
159 die_unless(tlx::compare_icase("ABC", "abb") > 0);
160 }
161
test_contains_word()162 static void test_contains_word() {
163 std::string data = "test admin write readall read do";
164
165 die_unless(tlx::contains_word(data, "test"));
166 die_unless(!tlx::contains_word(data, "testit"));
167
168 die_unless(tlx::contains_word(data, "read"));
169 die_unless(tlx::contains_word(data, "readall"));
170
171 die_unless(tlx::contains_word(data, std::string("read")));
172 die_unless(tlx::contains_word(data, std::string("readall")));
173
174 die_unless(!tlx::contains_word(data, "doit"));
175 }
176
test_erase_all()177 static void test_erase_all() {
178
179 die_unequal(
180 tlx::erase_all(" abcdef ghi jk "), "abcdefghijk");
181
182 die_unequal(
183 tlx::erase_all("abcdef ghi jk"), "abcdefghijk");
184
185 die_unequal(
186 tlx::erase_all(" abcdef ghi jk ", " bg"), "acdefhijk");
187
188 die_unequal(
189 tlx::erase_all("abcdef ghi jk", " bg"), "acdefhijk");
190
191 std::string s1 = " abcdef ghi jk ";
192 die_unequal(tlx::erase_all(&s1), "abcdefghijk");
193
194 std::string s2 = "abcdef ghi jk";
195 die_unequal(tlx::erase_all(&s2), "abcdefghijk");
196
197 std::string s3 = " abcdef ghi jk ";
198 die_unequal(tlx::erase_all(&s3, " bg"), "acdefhijk");
199
200 std::string s4 = "abcdef ghi jk";
201 die_unequal(tlx::erase_all(&s4, " bg"), "acdefhijk");
202 }
203
test_escape_html()204 static void test_escape_html() {
205
206 die_unequal(
207 tlx::escape_html("hello <tag> \"abc\" & \"def\""),
208 "hello <tag> "abc" & "def"");
209 }
210
test_escape_uri()211 static void test_escape_uri() {
212
213 die_unequal(
214 tlx::escape_uri("hello <tag>\""), "hello%20%3Ctag%3E%22");
215 }
216
test_expand_environment_variables()217 static void test_expand_environment_variables() {
218
219 tlx::setenv("TEST_1", "def", /* overwrite */ true);
220 tlx::setenv("VAR_2", "uvw", /* overwrite */ true);
221
222 die_unequal(
223 tlx::expand_environment_variables("abc$TEST_1 ---${VAR_2}xyz"),
224 "abcdef ---uvwxyz");
225
226 die_unequal(
227 tlx::expand_environment_variables("abc$4TEST_1 -$$--${VAR_2}xyz"),
228 "abc$4TEST_1 -$$--uvwxyz");
229
230 die_unequal(
231 tlx::expand_environment_variables("abc${NON_EXISTING_VARIABLE}xyz"),
232 "abcxyz");
233 }
234
test_extract_between()235 static void test_extract_between() {
236 std::string data =
237 "Content-Disposition: form-data; name='testfile'; filename='test.html'";
238
239 die_unequal(tlx::extract_between(data, "name='", "'"), "testfile");
240 die_unequal(tlx::extract_between(data, "filename='", "'"), "test.html");
241 die_unequal(tlx::extract_between(data, "other='", "'"), "");
242
243 die_unequal(tlx::extract_between(data, "Name='", "'"), "");
244 }
245
test_format_si_iec_units()246 static void test_format_si_iec_units() {
247
248 die_unequal(tlx::format_si_units(33 * 1024 * 1024 * 1024LLU), "35.433 G");
249 die_unequal(tlx::format_iec_units(33 * 1024 * 1024 * 1024LLU), "33.000 Gi");
250 }
251
test_hash_djb2()252 static void test_hash_djb2() {
253 die_unequal(
254 tlx::hash_djb2("hello hash me"), 0x2DA4090Fu);
255 die_unequal(
256 tlx::hash_djb2(std::string("hello hash me")), 0x2DA4090Fu);
257 }
258
test_hash_sdbm()259 static void test_hash_sdbm() {
260 die_unequal(
261 tlx::hash_sdbm("hello hash me"), 0x290130BCu);
262 die_unequal(
263 tlx::hash_sdbm(std::string("hello hash me")), 0x290130BCu);
264 }
265
test_hexdump()266 static void test_hexdump() {
267
268 // take hex data and dump it into a string, then parse back into array
269 const unsigned char hexdump[8] = {
270 0x8D, 0xE2, 0x85, 0xD4, 0xBF, 0x98, 0xE6, 0x03
271 };
272
273 std::string hexdata = ARRAY_AS_STRING(hexdump);
274 std::string hexstring = tlx::hexdump(hexdata);
275
276 die_unequal(hexstring, "8DE285D4BF98E603");
277 die_unequal(tlx::hexdump(hexdump, sizeof(hexdump)), "8DE285D4BF98E603");
278
279 std::string hexparsed = tlx::parse_hexdump(hexstring);
280 die_unequal(hexparsed, hexdata);
281
282 // dump random binary string into hex and parse it back
283 std::string rand1 = random_binary(42);
284 die_unequal(tlx::parse_hexdump(tlx::hexdump(rand1)), rand1);
285
286 // take the first hex list and dump it into source code format, then
287 // compare it with correct data (which was also dumped with
288 // hexdump_sourcecode())
289 std::string hexsource = tlx::hexdump_sourcecode(hexdata, "abc");
290
291 const unsigned char hexsourcecmp[68] = {
292 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x75, 0x69,
293 0x6E, 0x74, 0x38, 0x5F, 0x74, 0x20, 0x61, 0x62,
294 0x63, 0x5B, 0x38, 0x5D, 0x20, 0x3D, 0x20, 0x7B,
295 0x0A, 0x30, 0x78, 0x38, 0x44, 0x2C, 0x30, 0x78,
296 0x45, 0x32, 0x2C, 0x30, 0x78, 0x38, 0x35, 0x2C,
297 0x30, 0x78, 0x44, 0x34, 0x2C, 0x30, 0x78, 0x42,
298 0x46, 0x2C, 0x30, 0x78, 0x39, 0x38, 0x2C, 0x30,
299 0x78, 0x45, 0x36, 0x2C, 0x30, 0x78, 0x30, 0x33,
300 0x0A, 0x7D, 0x3B, 0x0A
301 };
302
303 die_unequal(hexsource, ARRAY_AS_STRING(hexsourcecmp));
304
305 // test parse_hexdump with illegal strings
306 die_unless_throws(tlx::parse_hexdump("illegal"), std::runtime_error);
307 die_unless_throws(tlx::parse_hexdump("8DE285D4BF98E60"), std::runtime_error);
308 }
309
test_join()310 static void test_join() {
311 // simple string split and join
312 std::vector<std::string> sv = tlx::split('/', "/usr/bin/test");
313 die_unequal(sv.size(), 4u);
314
315 die_unequal(tlx::join("--", sv), "--usr--bin--test");
316 die_unequal(tlx::join(";", sv), ";usr;bin;test");
317
318 std::vector<std::string> sv2;
319 for (unsigned int i = 0; i < 6; ++i)
320 sv2.emplace_back("abc");
321
322 die_unequal(tlx::join(".", sv2), "abc.abc.abc.abc.abc.abc");
323 }
324
test_levenshtein()325 static void test_levenshtein() {
326 die_unequal(tlx::levenshtein("Demonstration", "Comparison"), 9u);
327 die_unequal(tlx::levenshtein("Levenshtein", "Distance"), 10u);
328 die_unequal(tlx::levenshtein("Distance", "Distance"), 0u);
329 die_unequal(tlx::levenshtein("Distance", "LVDistance"), 2u);
330
331 die_unequal(tlx::levenshtein_icase("distance", "DISTANCE"), 0u);
332 die_unequal(tlx::levenshtein_icase("Levenshtein", "Distance"), 10u);
333
334 die_unequal(tlx::levenshtein_icase("Test this distance", "to this one"), 9u);
335 }
336
test_parse_si_iec_units()337 static void test_parse_si_iec_units() {
338
339 uint64_t size;
340 die_unless(tlx::parse_si_iec_units(" 33 GiB ", &size));
341 die_unequal(33 * 1024 * 1024 * 1024LLU, size);
342
343 die_if(tlx::parse_si_iec_units(" 33 GiBX ", &size));
344 }
345
test_split()346 static void test_split() {
347 // simple char split
348 std::vector<std::string> sv = tlx::split('/', "/usr/bin/test/");
349
350 die_unequal(sv.size(), 5u);
351 die_unequal(sv[0], "");
352 die_unequal(sv[1], "usr");
353 die_unequal(sv[2], "bin");
354 die_unequal(sv[3], "test");
355 die_unequal(sv[4], "");
356
357 sv = tlx::split('/', "/usr/bin/test", 3);
358
359 die_unequal(sv.size(), 3u);
360 die_unequal(sv[0], "");
361 die_unequal(sv[1], "usr");
362 die_unequal(sv[2], "bin/test");
363
364 // char split with some strange limits
365 sv = tlx::split('/', "/usr//bin/test", 0);
366 die_unequal(sv.size(), 0u);
367
368 sv = tlx::split('/', "/usr//bin/test", 1);
369 die_unequal(sv.size(), 1u);
370 die_unequal(sv[0], "/usr//bin/test");
371
372 // simple str split
373 sv = tlx::split("/", "/usr/bin/test");
374
375 die_unequal(sv.size(), 4u);
376 die_unequal(sv[0], "");
377 die_unequal(sv[1], "usr");
378 die_unequal(sv[2], "bin");
379 die_unequal(sv[3], "test");
380
381 sv = tlx::split("/", "/usr/bin/test", 3);
382
383 die_unequal(sv.size(), 3u);
384 die_unequal(sv[0], "");
385 die_unequal(sv[1], "usr");
386 die_unequal(sv[2], "bin/test");
387
388 // str split with some strange limits
389 sv = tlx::split("/", "/usr//bin/test", 0);
390 die_unequal(sv.size(), 0u);
391
392 sv = tlx::split("/", "/usr//bin/test", 1);
393 die_unequal(sv.size(), 1u);
394 die_unequal(sv[0], "/usr//bin/test");
395
396 // str split with parital needle at end
397 sv = tlx::split("abc", "testabcblahabcabcab");
398 die_unequal(sv.size(), 4u);
399 die_unequal(sv[0], "test");
400 die_unequal(sv[1], "blah");
401 die_unequal(sv[2], "");
402 die_unequal(sv[3], "ab");
403
404 // str split with "" separator
405 sv = tlx::split("", "abcdef");
406 die_unequal(sv.size(), 6u);
407 die_unequal(sv[0], "a");
408 die_unequal(sv[1], "b");
409 die_unequal(sv[2], "c");
410 die_unequal(sv[3], "d");
411 die_unequal(sv[4], "e");
412 die_unequal(sv[5], "f");
413
414 /**************************************************************************/
415
416 // str split with min-limit
417 sv = tlx::split('/', "/usr/bin/test", 2, 2);
418 die_unequal(sv.size(), 2u);
419 die_unequal(sv[0], "");
420 die_unequal(sv[1], "usr/bin/test");
421
422 // str split with min-limit
423 sv = tlx::split('/', "/usr/bin/test", 5, 5);
424 die_unequal(sv.size(), 5u);
425 die_unequal(sv[0], "");
426 die_unequal(sv[1], "usr");
427 die_unequal(sv[2], "bin");
428 die_unequal(sv[3], "test");
429 die_unequal(sv[4], "");
430
431 // str split with min-limit
432 sv = tlx::split("/", "/usr/bin/test", 5, 5);
433 die_unequal(sv.size(), 5u);
434 die_unequal(sv[0], "");
435 die_unequal(sv[1], "usr");
436 die_unequal(sv[2], "bin");
437 die_unequal(sv[3], "test");
438 die_unequal(sv[4], "");
439 }
440
test_split_join_quoted()441 static void test_split_join_quoted() {
442 // simple whitespace split
443 std::vector<std::string> sv = tlx::split_quoted(" ab c df fdlk f ");
444
445 die_unequal(sv.size(), 5u);
446 die_unequal(sv[0], "ab");
447 die_unequal(sv[1], "c");
448 die_unequal(sv[2], "df");
449 die_unequal(sv[3], "fdlk");
450 die_unequal(sv[4], "f");
451
452 die_unequal(tlx::join_quoted(sv), "ab c df fdlk f");
453
454 // simple whitespace split
455
456 sv = tlx::split_quoted("ab c df fdlk f ");
457
458 die_unequal(sv.size(), 5u);
459 die_unequal(sv[0], "ab");
460 die_unequal(sv[1], "c");
461 die_unequal(sv[2], "df");
462 die_unequal(sv[3], "fdlk");
463 die_unequal(sv[4], "f");
464
465 die_unequal(tlx::join_quoted(sv), "ab c df fdlk f");
466
467 // simple whitespace split
468
469 sv = tlx::split_quoted("ab c df fdlk f");
470
471 die_unequal(sv.size(), 5u);
472 die_unequal(sv[0], "ab");
473 die_unequal(sv[1], "c");
474 die_unequal(sv[2], "df");
475 die_unequal(sv[3], "fdlk");
476 die_unequal(sv[4], "f");
477
478 die_unequal(tlx::join_quoted(sv), "ab c df fdlk f");
479
480 // with quoted entry
481 sv = tlx::split_quoted("ab c \"df fdlk \" f ");
482
483 die_unequal(sv.size(), 4u);
484 die_unequal(sv[0], "ab");
485 die_unequal(sv[1], "c");
486 die_unequal(sv[2], "df fdlk ");
487 die_unequal(sv[3], "f");
488
489 die_unequal(tlx::join_quoted(sv), "ab c \"df fdlk \" f");
490
491 // with quoted entry containing quote
492 sv = tlx::split_quoted("ab c \"d\\\\f\\n \\\"fdlk \" f ");
493
494 die_unequal(sv.size(), 4u);
495 die_unequal(sv[0], "ab");
496 die_unequal(sv[1], "c");
497 die_unequal(sv[2], "d\\f\n \"fdlk ");
498 die_unequal(sv[3], "f");
499
500 die_unequal(tlx::join_quoted(sv), "ab c \"d\\\\f\\n \\\"fdlk \" f");
501 }
502
test_split_words()503 static void test_split_words() {
504 // simple whitespace split
505 std::vector<std::string> sv = tlx::split_words(" ab c df fdlk f ");
506
507 die_unequal(sv.size(), 5u);
508 die_unequal(sv[0], "ab");
509 die_unequal(sv[1], "c");
510 die_unequal(sv[2], "df");
511 die_unequal(sv[3], "fdlk");
512 die_unequal(sv[4], "f");
513
514 sv = tlx::split_words("ab c df fdlk f ");
515
516 die_unequal(sv.size(), 5u);
517 die_unequal(sv[0], "ab");
518 die_unequal(sv[1], "c");
519 die_unequal(sv[2], "df");
520 die_unequal(sv[3], "fdlk");
521 die_unequal(sv[4], "f");
522
523 sv = tlx::split_words("ab c df fdlk f");
524
525 die_unequal(sv.size(), 5u);
526 die_unequal(sv[0], "ab");
527 die_unequal(sv[1], "c");
528 die_unequal(sv[2], "df");
529 die_unequal(sv[3], "fdlk");
530 die_unequal(sv[4], "f");
531
532 sv = tlx::split_words("");
533 die_unequal(sv.size(), 0u);
534
535 sv = tlx::split_words(" ");
536 die_unequal(sv.size(), 0u);
537
538 // whitespace split with limit
539 sv = tlx::split_words(" ab c df fdlk f ", 3);
540
541 die_unequal(sv.size(), 3u);
542 die_unequal(sv[0], "ab");
543 die_unequal(sv[1], "c");
544 die_unequal(sv[2], "df fdlk f ");
545
546 // whitespace split with some strange limits
547 sv = tlx::split_words(" ab c df fdlk f ", 0);
548 die_unequal(sv.size(), 0u);
549
550 sv = tlx::split_words(" ab c df fdlk f ", 1);
551
552 die_unequal(sv.size(), 1u);
553 die_unequal(sv[0], "ab c df fdlk f ");
554
555 // whitespace split with large limit
556 sv = tlx::split_words(" ab c df fdlk f ", 10);
557
558 die_unequal(sv.size(), 5u);
559 die_unequal(sv[0], "ab");
560 die_unequal(sv[1], "c");
561 die_unequal(sv[2], "df");
562 die_unequal(sv[3], "fdlk");
563 die_unequal(sv[4], "f");
564
565 // whitespace split with limit at exactly the end
566 sv = tlx::split_words(" ab c df fdlk f ", 5);
567
568 die_unequal(sv.size(), 5u);
569 die_unequal(sv[0], "ab");
570 die_unequal(sv[1], "c");
571 die_unequal(sv[2], "df");
572 die_unequal(sv[3], "fdlk");
573 die_unequal(sv[4], "f ");
574 }
575
test_ssprintf()576 static void test_ssprintf() {
577 die_unequal(
578 tlx::ssprintf("abc %d %s test", 42, "hello"),
579 "abc 42 hello test");
580 die_unequal(
581 tlx::ssnprintf(5, "abc %d %s test", 42, "hello"),
582 "abc 4");
583 die_unequal(
584 tlx::ssnprintf(5, "%d", 42), "42");
585
586 // "generic" version
587 die_unequal(
588 tlx::ssprintf_generic<std::string>("abc %d %s test", 42, "hello"),
589 "abc 42 hello test");
590 die_unequal(
591 tlx::ssnprintf_generic<std::string>(5, "abc %d %s test", 42, "hello"),
592 "abc 4");
593 die_unequal(
594 tlx::ssnprintf_generic<std::string>(5, "%d", 42), "42");
595 }
596
test_replace()597 static void test_replace() {
598 // copy variants
599 die_unequal(
600 tlx::replace_first("abcdef abcdef", "abc", "a"), "adef abcdef");
601 die_unequal(
602 tlx::replace_first("abcdef abcdef", "cba", "a"), "abcdef abcdef");
603 die_unequal(
604 tlx::replace_all("abcdef abcdef", "abc", "a"), "adef adef");
605 die_unequal(
606 tlx::replace_all("abcdef abcdef", "cba", "a"), "abcdef abcdef");
607
608 die_unequal(
609 tlx::replace_first("abcdef abcdef", "a", "aaa"),
610 "aaabcdef abcdef");
611 die_unequal(
612 tlx::replace_all("abcdef abcdef", "a", "aaa"),
613 "aaabcdef aaabcdef");
614
615 // in-place variants
616 std::string str1 = "abcdef abcdef";
617 std::string str2 = "abcdef abcdef";
618 die_unequal(
619 tlx::replace_first(&str1, "abc", "a"), "adef abcdef");
620 die_unequal(
621 tlx::replace_first(&str2, "cba", "a"), "abcdef abcdef");
622
623 str1 = "abcdef abcdef";
624 str2 = "abcdef abcdef";
625 die_unequal(
626 tlx::replace_all(&str1, "abc", "a"), "adef adef");
627 die_unequal(
628 tlx::replace_all(&str2, "cba", "a"), "abcdef abcdef");
629
630 str1 = "abcdef abcdef";
631 str2 = "abcdef abcdef";
632 die_unequal(
633 tlx::replace_first(&str1, "a", "aaa"), "aaabcdef abcdef");
634 die_unequal(
635 tlx::replace_all(&str2, "a", "aaa"), "aaabcdef aaabcdef");
636 }
637
638 template <typename TypeA, typename TypeB>
test_starts_with_ends_with_template()639 void test_starts_with_ends_with_template() {
640
641 die_unless(tlx::starts_with(TypeA("abcdef"), TypeB("abc")));
642 die_unless(!tlx::starts_with(TypeA("abcdef"), TypeB("def")));
643 die_unless(tlx::ends_with(TypeA("abcdef"), TypeB("def")));
644 die_unless(!tlx::ends_with(TypeA("abcdef"), TypeB("abc")));
645
646 die_unless(!tlx::starts_with(TypeA("abcdef"), TypeB("ABC")));
647
648 die_unless(tlx::starts_with_icase(TypeA("abcdef"), TypeB("ABC")));
649 die_unless(!tlx::starts_with_icase(TypeA("abcdef"), TypeB("DEF")));
650 die_unless(tlx::ends_with_icase(TypeA("abcdef"), TypeB("DEF")));
651 die_unless(!tlx::ends_with_icase(TypeA("abcdef"), TypeB("ABC")));
652
653 die_unless(tlx::starts_with(TypeA("abcdef"), TypeB("")));
654 die_unless(tlx::ends_with(TypeA("abcdef"), TypeB("")));
655
656 die_unless(!tlx::starts_with(TypeA(""), TypeB("abc")));
657 die_unless(!tlx::ends_with(TypeA(""), TypeB("abc")));
658
659 die_unless(tlx::starts_with(TypeA(""), TypeB("")));
660 die_unless(tlx::ends_with(TypeA(""), TypeB("")));
661 }
662
test_starts_with_ends_with()663 static void test_starts_with_ends_with() {
664 test_starts_with_ends_with_template<const char*, const char*>();
665 test_starts_with_ends_with_template<const char*, std::string>();
666 test_starts_with_ends_with_template<std::string, const char*>();
667 test_starts_with_ends_with_template<std::string, std::string>();
668 }
669
test_toupper_tolower()670 static void test_toupper_tolower() {
671 // string-copy functions
672 die_unequal(tlx::to_upper(" aBc "), " ABC ");
673 die_unequal(tlx::to_lower(" AbCdEfG "), " abcdefg ");
674
675 // in-place functions
676 std::string str1 = " aBc ";
677 std::string str2 = "AbCdEfGh ";
678
679 die_unequal(tlx::to_upper(&str1), " ABC ");
680 die_unequal(tlx::to_lower(&str2), "abcdefgh ");
681 }
682
test_trim()683 static void test_trim() {
684 // string-copy functions
685 die_unequal(tlx::trim(" abc "), "abc");
686 die_unequal(tlx::trim("abc "), "abc");
687 die_unequal(tlx::trim(" abc"), "abc");
688 die_unequal(tlx::trim(" "), "");
689
690 die_unequal(tlx::trim_left(" abc "), "abc ");
691 die_unequal(tlx::trim_left("abc "), "abc ");
692 die_unequal(tlx::trim_left(" "), "");
693
694 die_unequal(tlx::trim_right(" abc "), " abc");
695 die_unequal(tlx::trim_right(" abc"), " abc");
696 die_unequal(tlx::trim_right(" "), "");
697
698 // in-place functions
699 std::string str1 = " abc ";
700 std::string str2 = "abc ";
701 std::string str3 = " ";
702
703 die_unequal(tlx::trim_left(&str1), "abc ");
704 die_unequal(tlx::trim_left(&str2), "abc ");
705 die_unequal(tlx::trim_left(&str3), "");
706
707 str1 = " abc ";
708 str2 = " abc";
709 str3 = " ";
710
711 die_unequal(tlx::trim_right(&str1), " abc");
712 die_unequal(tlx::trim_right(&str2), " abc");
713 die_unequal(tlx::trim_right(&str3), "");
714
715 str1 = " abc ";
716 str2 = " abc";
717 str3 = "abc ";
718 std::string str4 = " ";
719
720 die_unequal(tlx::trim(&str1), "abc");
721 die_unequal(tlx::trim(&str2), "abc");
722 die_unequal(tlx::trim(&str3), "abc");
723 die_unequal(tlx::trim(&str4), "");
724 }
725
test_word_wrap()726 static void test_word_wrap() {
727
728 const char* text =
729 "Alice was beginning to get very tired of sitting by her sister on the "
730 "bank, and of having nothing to do: once or twice she had peeped into "
731 "the book her sister was reading, but it had no pictures or "
732 "conversations in it, 'and what is the use of a book,' thought Alice "
733 "'without pictures or conversations?'\n\nSo she was considering in "
734 "her own mind (as well as she could, for the hot day made her feel "
735 "very sleepy and stupid), whether the pleasure of making a daisy-chain "
736 "would be worth the trouble of getting up and picking the daisies, "
737 "when suddenly a White Rabbit with pink eyes ran close by "
738 "her.\n\nThere was nothing so VERY remarkable in that; nor did Alice "
739 "think it so VERY much out of the way to hear the Rabbit say to "
740 "itself, 'Oh dear! Oh dear! I shall be late!' (when she thought it "
741 "over afterwards, it occurred to her that she ought to have wondered "
742 "at this, but at the time it all seemed quite natural); but when the "
743 "Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT-POCKET, and looked "
744 "at it, and then hurried on, Alice started to her feet, for it flashed "
745 "across her mind that she had never before seen a rabbit with either a "
746 "waistcoat-pocket, or a watch to take out of it, and burning with "
747 "curiosity, she ran across the field after it, and fortunately was "
748 "just in time to see it pop down a large rabbit-hole under the "
749 "hedge.\nIn another moment down went Alice after it, never once "
750 "considering how in the world she was to get out again.\n\nThe "
751 "rabbit-hole went straight on like a tunnel for some way, and then "
752 "dipped suddenly down, so suddenly that Alice had not a moment to "
753 "think about stopping herself before she found herself falling down a "
754 "very deep well.\n\nEither the well was very deep, or she fell very "
755 "slowly, for she had plenty of time as she went down to look about her "
756 "and to wonder what was going to happen next. First, she tried to look "
757 "down and make out what she was coming to, but it was too dark to see "
758 "anything; then she looked at the sides of the well, and noticed that "
759 "they were filled with cupboards and book-shelves; here and there she "
760 "saw maps and pictures hung upon pegs. She took down a jar from one of "
761 "the shelves as she passed; it was labelled 'ORANGE MARMALADE', but to "
762 "her great disappointment it was empty: she did not like to drop the "
763 "jar for fear of killing somebody, so managed to put it into one of "
764 "the cupboards as she fell past it.\n\n'Well!' thought Alice to "
765 "herself, 'after such a fall as this, I shall think nothing of "
766 "tumbling down stairs! How brave they'll all think me at home! Why, I "
767 "wouldn't say anything about it, even if I fell off the top of the "
768 "house!' (Which was very likely true.)";
769
770 const char* text_correct =
771 "Alice was beginning to get very tired of sitting by her\n"
772 "sister on the bank, and of having nothing to do: once or\n"
773 "twice she had peeped into the book her sister was reading,\n"
774 "but it had no pictures or conversations in it, 'and what is\n"
775 "the use of a book,' thought Alice 'without pictures or \n"
776 "conversations?'\n"
777 "\n"
778 "So she was considering in her own mind (as well as she\n"
779 "could, for the hot day made her feel very sleepy and\n"
780 "stupid), whether the pleasure of making a daisy-chain would\n"
781 "be worth the trouble of getting up and picking the daisies,\n"
782 "when suddenly a White Rabbit with pink eyes ran close by\n"
783 "her.\n"
784 "\n"
785 "There was nothing so VERY remarkable in that; nor did\n"
786 "Alice think it so VERY much out of the way to hear the\n"
787 "Rabbit say to itself, 'Oh dear! Oh dear! I shall be late!'\n"
788 "(when she thought it over afterwards, it occurred to her\n"
789 "that she ought to have wondered at this, but at the time it\n"
790 "all seemed quite natural); but when the Rabbit actually\n"
791 "TOOK A WATCH OUT OF ITS WAISTCOAT-POCKET, and looked at it,\n"
792 "and then hurried on, Alice started to her feet, for it\n"
793 "flashed across her mind that she had never before seen a\n"
794 "rabbit with either a waistcoat-pocket, or a watch to take\n"
795 "out of it, and burning with curiosity, she ran across the\n"
796 "field after it, and fortunately was just in time to see it\n"
797 "pop down a large rabbit-hole under the hedge.\n"
798 "In another moment down went Alice after it, never once\n"
799 "considering how in the world she was to get out again.\n"
800 "\n"
801 "The rabbit-hole went straight on like a tunnel for some\n"
802 "way, and then dipped suddenly down, so suddenly that Alice\n"
803 "had not a moment to think about stopping herself before she\n"
804 "found herself falling down a very deep well.\n"
805 "\n"
806 "Either the well was very deep, or she fell very slowly,\n"
807 "for she had plenty of time as she went down to look about\n"
808 "her and to wonder what was going to happen next. First, she\n"
809 "tried to look down and make out what she was coming to, but\n"
810 "it was too dark to see anything; then she looked at the\n"
811 "sides of the well, and noticed that they were filled with\n"
812 "cupboards and book-shelves; here and there she saw maps and\n"
813 "pictures hung upon pegs. She took down a jar from one of\n"
814 "the shelves as she passed; it was labelled 'ORANGE\n"
815 "MARMALADE', but to her great disappointment it was empty:\n"
816 "she did not like to drop the jar for fear of killing\n"
817 "somebody, so managed to put it into one of the cupboards as\n"
818 "she fell past it.\n"
819 "\n"
820 "'Well!' thought Alice to herself, 'after such a fall as\n"
821 "this, I shall think nothing of tumbling down stairs! How\n"
822 "brave they'll all think me at home! Why, I wouldn't say\n"
823 "anything about it, even if I fell off the top of the\n"
824 "house!' (Which was very likely true.)";
825
826 die_unequal(tlx::word_wrap(text, 60), text_correct);
827
828 const char* long_line =
829 "abc abc abc abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
830 "abcdefghijklmnopqrstuvwxyz xyz xyz abcdefghijklmnopqrstuvwxyz"
831 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz def def def";
832
833 const char* long_line_correct =
834 "abc abc abc\n"
835 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
836 "abcdefghijklmnopqrstuvwxyz\n"
837 "xyz xyz\n"
838 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
839 "abcdefghijklmnopqrstuvwxyz\n"
840 "def def def";
841
842 die_unequal(tlx::word_wrap(long_line, 60), long_line_correct);
843 }
844
main()845 int main() {
846
847 test_appendline();
848 test_base64();
849 test_bitdump();
850 test_compare_icase();
851 test_contains_word();
852 test_erase_all();
853 test_escape_html();
854 test_escape_uri();
855 test_expand_environment_variables();
856 test_extract_between();
857 test_format_si_iec_units();
858 test_hash_djb2();
859 test_hash_sdbm();
860 test_hexdump();
861 test_join();
862 test_levenshtein();
863 test_parse_si_iec_units();
864 test_replace();
865 test_split();
866 test_split_join_quoted();
867 test_split_words();
868 test_ssprintf();
869 test_starts_with_ends_with();
870 test_toupper_tolower();
871 test_trim();
872 test_word_wrap();
873
874 return 0;
875 }
876
877 /******************************************************************************/
878