2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 // Author: andrei.alexandrescu@fb.com
20 #include <folly/FBString.h>
28 #include <boost/algorithm/string.hpp>
29 #include <boost/random.hpp>
30 #include <gtest/gtest.h>
32 #include <folly/Foreach.h>
33 #include <folly/Portability.h>
34 #include <folly/Random.h>
35 #include <folly/Conv.h>
36 #include <folly/experimental/TestUtil.h>
39 using namespace folly;
41 static const int seed = folly::randomNumberSeed();
42 typedef boost::mt19937 RandomT;
43 static RandomT rng(seed);
44 static const size_t maxString = 100;
45 static const bool avoidAliasing = true;
47 template <class Integral1, class Integral2>
48 Integral2 random(Integral1 low, Integral2 up) {
49 boost::uniform_int<> range(low, up);
53 template <class String>
54 void randomString(String* toFill, unsigned int maxSize = 1000) {
56 toFill->resize(random(0, maxSize));
57 FOR_EACH (i, *toFill) {
58 *i = random('a', 'z');
62 template <class String, class Integral>
63 void Num2String(String& str, Integral n) {
65 std::string tmp = folly::to<std::string>(n);
66 str = String(tmp.begin(), tmp.end());
69 std::list<char> RandomList(unsigned int maxSize) {
70 std::list<char> lst(random(0u, maxSize));
71 std::list<char>::iterator i = lst.begin();
72 for (; i != lst.end(); ++i) {
73 *i = random('a', 'z');
78 ////////////////////////////////////////////////////////////////////////////////
80 ////////////////////////////////////////////////////////////////////////////////
82 template <class String> void clause11_21_4_2_a(String & test) {
83 test.String::~String();
86 template <class String> void clause11_21_4_2_b(String & test) {
88 assert(test2 == test);
90 template <class String> void clause11_21_4_2_c(String & test) {
91 // Test move constructor. There is a more specialized test, see
92 // TEST(FBString, testMoveCtor)
94 String test2(std::move(donor));
95 EXPECT_EQ(test2, test);
96 // Technically not required, but all implementations that actually
97 // support move will move large strings. Make a guess for 128 as the
98 // maximum small string optimization that's reasonable.
99 EXPECT_LE(donor.size(), 128);
101 template <class String> void clause11_21_4_2_d(String & test) {
102 // Copy constructor with position and length
103 const size_t pos = random(0, test.size());
104 String s(test, pos, random(0, 9)
105 ? random(0, (size_t)(test.size() - pos))
106 : String::npos); // test for npos, too, in 10% of the cases
109 template <class String> void clause11_21_4_2_e(String & test) {
110 // Constructor from char*, size_t
112 pos = random(0, test.size()),
113 n = random(0, test.size() - pos);
114 String before(test.data(), test.size());
115 String s(test.c_str() + pos, n);
116 String after(test.data(), test.size());
117 EXPECT_EQ(before, after);
120 template <class String> void clause11_21_4_2_f(String & test) {
121 // Constructor from char*
122 const size_t pos = random(0, test.size());
123 String before(test.data(), test.size());
124 String s(test.c_str() + pos);
125 String after(test.data(), test.size());
126 EXPECT_EQ(before, after);
129 template <class String> void clause11_21_4_2_g(String & test) {
130 // Constructor from size_t, char
131 const size_t n = random(0, test.size());
132 const auto c = test.front();
135 template <class String> void clause11_21_4_2_h(String & test) {
136 // Constructors from various iterator pairs
137 // Constructor from char*, char*
138 String s1(test.begin(), test.end());
140 String s2(test.data(), test.data() + test.size());
142 // Constructor from other iterators
144 for (auto c : test) lst.push_back(c);
145 String s3(lst.begin(), lst.end());
147 // Constructor from wchar_t iterators
148 std::list<wchar_t> lst1;
149 for (auto c : test) lst1.push_back(c);
150 String s4(lst1.begin(), lst1.end());
152 // Constructor from wchar_t pointers
156 fbstring s5(t, t + 2);;
159 template <class String> void clause11_21_4_2_i(String & test) {
160 // From initializer_list<char>
161 std::initializer_list<typename String::value_type>
162 il = { 'h', 'e', 'l', 'l', 'o' };
166 template <class String> void clause11_21_4_2_j(String & test) {
167 // Assignment from const String&
168 auto size = random(0, 2000);
169 String s(size, '\0');
170 EXPECT_EQ(s.size(), size);
171 FOR_EACH_RANGE (i, 0, s.size()) {
172 s[i] = random('a', 'z');
176 template <class String> void clause11_21_4_2_k(String & test) {
177 // Assignment from String&&
178 auto size = random(0, 2000);
179 String s(size, '\0');
180 EXPECT_EQ(s.size(), size);
181 FOR_EACH_RANGE (i, 0, s.size()) {
182 s[i] = random('a', 'z');
185 if (typeid(String) == typeid(fbstring)) {
186 EXPECT_LE(s.size(), 128);
189 template <class String> void clause11_21_4_2_l(String & test) {
190 // Assignment from char*
191 String s(random(0, 1000), '\0');
193 for (; i != s.size(); ++i) {
194 s[i] = random('a', 'z');
198 template <class String> void clause11_21_4_2_lprime(String & test) {
200 const size_t pos = random(0, test.size());
202 test = String(test.c_str() + pos);
204 test = test.c_str() + pos;
207 template <class String> void clause11_21_4_2_m(String & test) {
208 // Assignment from char
209 test = random('a', 'z');
211 template <class String> void clause11_21_4_2_n(String & test) {
212 // Assignment from initializer_list<char>
213 initializer_list<typename String::value_type>
214 il = { 'h', 'e', 'l', 'l', 'o' };
218 template <class String> void clause11_21_4_3(String & test) {
219 // Iterators. The code below should leave test unchanged
220 EXPECT_EQ(test.size(), test.end() - test.begin());
221 EXPECT_EQ(test.size(), test.rend() - test.rbegin());
222 EXPECT_EQ(test.size(), test.cend() - test.cbegin());
223 EXPECT_EQ(test.size(), test.crend() - test.crbegin());
225 auto s = test.size();
226 test.resize(test.end() - test.begin());
227 EXPECT_EQ(s, test.size());
228 test.resize(test.rend() - test.rbegin());
229 EXPECT_EQ(s, test.size());
232 template <class String> void clause11_21_4_4(String & test) {
233 // exercise capacity, size, max_size
234 EXPECT_EQ(test.size(), test.length());
235 EXPECT_LE(test.size(), test.max_size());
236 EXPECT_LE(test.capacity(), test.max_size());
237 EXPECT_LE(test.size(), test.capacity());
239 // exercise shrink_to_fit. Nonbinding request so we can't really do
240 // much beyond calling it.
242 copy.reserve(copy.capacity() * 3);
243 copy.shrink_to_fit();
244 EXPECT_EQ(copy, test);
247 string empty("empty");
248 string notempty("not empty");
249 if (test.empty()) test = String(empty.begin(), empty.end());
250 else test = String(notempty.begin(), notempty.end());
253 template <class String> void clause11_21_4_5(String & test) {
254 // exercise element access
256 EXPECT_EQ(test[0], test.front());
257 EXPECT_EQ(test[test.size() - 1], test.back());
258 auto const i = random(0, test.size() - 1);
259 EXPECT_EQ(test[i], test.at(i));
264 template <class String> void clause11_21_4_6_1(String & test) {
265 // 21.3.5 modifiers (+=)
267 randomString(&test1);
268 assert(test1.size() == char_traits
269 <typename String::value_type>::length(test1.c_str()));
270 auto len = test.size();
272 EXPECT_EQ(test.size(), test1.size() + len);
273 FOR_EACH_RANGE (i, 0, test1.size()) {
274 EXPECT_EQ(test[len + i], test1[i]);
276 // aliasing modifiers
278 auto dt = test2.data();
279 auto sz = test.c_str();
281 EXPECT_EQ(memcmp(sz, dt, len), 0);
282 String copy(test.data(), test.size());
283 EXPECT_EQ(char_traits
284 <typename String::value_type>::length(test.c_str()), len);
287 EXPECT_EQ(test.size(), 2 * len);
288 EXPECT_EQ(char_traits
289 <typename String::value_type>::length(test.c_str()), 2 * len);
290 FOR_EACH_RANGE (i, 0, len) {
291 EXPECT_EQ(test[i], copy[i]);
292 EXPECT_EQ(test[i], test[len + i]);
295 EXPECT_EQ(char_traits
296 <typename String::value_type>::length(test.c_str()), len);
298 auto const pos = random(0, test.size());
299 EXPECT_EQ(char_traits
300 <typename String::value_type>::length(test.c_str() + pos), len - pos);
302 String addMe(test.c_str() + pos);
303 EXPECT_EQ(addMe.size(), len - pos);
306 test += test.c_str() + pos;
308 EXPECT_EQ(test.size(), 2 * len - pos);
311 test += random('a', 'z');
312 EXPECT_EQ(test.size(), len + 1);
314 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
318 template <class String> void clause11_21_4_6_2(String & test) {
319 // 21.3.5 modifiers (append, push_back)
322 // Test with a small string first
323 char c = random('a', 'z');
325 EXPECT_EQ(s[s.size() - 1], c);
326 EXPECT_EQ(s.size(), 1);
327 s.resize(s.size() - 1);
329 randomString(&s, maxString);
331 randomString(&s, maxString);
332 test.append(s, random(0, s.size()), random(0, maxString));
333 randomString(&s, maxString);
334 test.append(s.c_str(), random(0, s.size()));
335 randomString(&s, maxString);
336 test.append(s.c_str());
337 test.append(random(0, maxString), random('a', 'z'));
338 std::list<char> lst(RandomList(maxString));
339 test.append(lst.begin(), lst.end());
340 c = random('a', 'z');
342 EXPECT_EQ(test[test.size() - 1], c);
344 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
348 template <class String> void clause11_21_4_6_3_a(String & test) {
355 test.assign(std::move(s));
356 if (typeid(String) == typeid(fbstring)) {
357 EXPECT_LE(s.size(), 128);
361 template <class String> void clause11_21_4_6_3_b(String & test) {
364 randomString(&s, maxString);
365 test.assign(s, random(0, s.size()), random(0, maxString));
368 template <class String> void clause11_21_4_6_3_c(String & test) {
371 randomString(&s, maxString);
372 test.assign(s.c_str(), random(0, s.size()));
375 template <class String> void clause11_21_4_6_3_d(String & test) {
378 randomString(&s, maxString);
379 test.assign(s.c_str());
382 template <class String> void clause11_21_4_6_3_e(String & test) {
385 randomString(&s, maxString);
386 test.assign(random(0, maxString), random('a', 'z'));
389 template <class String> void clause11_21_4_6_3_f(String & test) {
390 // assign from bidirectional iterator
391 std::list<char> lst(RandomList(maxString));
392 test.assign(lst.begin(), lst.end());
395 template <class String> void clause11_21_4_6_3_g(String & test) {
396 // assign from aliased source
400 template <class String> void clause11_21_4_6_3_h(String & test) {
401 // assign from aliased source
402 test.assign(test, random(0, test.size()), random(0, maxString));
405 template <class String> void clause11_21_4_6_3_i(String & test) {
406 // assign from aliased source
407 test.assign(test.c_str(), random(0, test.size()));
410 template <class String> void clause11_21_4_6_3_j(String & test) {
411 // assign from aliased source
412 test.assign(test.c_str());
415 template <class String> void clause11_21_4_6_3_k(String & test) {
416 // assign from initializer_list
417 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
421 template <class String> void clause11_21_4_6_4(String & test) {
424 randomString(&s, maxString);
425 test.insert(random(0, test.size()), s);
426 randomString(&s, maxString);
427 test.insert(random(0, test.size()),
428 s, random(0, s.size()),
429 random(0, maxString));
430 randomString(&s, maxString);
431 test.insert(random(0, test.size()),
432 s.c_str(), random(0, s.size()));
433 randomString(&s, maxString);
434 test.insert(random(0, test.size()), s.c_str());
435 test.insert(random(0, test.size()),
436 random(0, maxString), random('a', 'z'));
437 typename String::size_type pos = random(0, test.size());
438 typename String::iterator res =
439 test.insert(test.begin() + pos, random('a', 'z'));
440 EXPECT_EQ(res - test.begin(), pos);
441 std::list<char> lst(RandomList(maxString));
442 pos = random(0, test.size());
443 // Uncomment below to see a bug in gcc
444 /*res = */test.insert(test.begin() + pos, lst.begin(), lst.end());
445 // insert from initializer_list
446 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
447 pos = random(0, test.size());
448 // Uncomment below to see a bug in gcc
449 /*res = */test.insert(test.begin() + pos, il);
451 // Test with actual input iterators
453 ss << "hello cruel world";
454 auto i = istream_iterator<char>(ss);
455 test.insert(test.begin(), i, istream_iterator<char>());
458 template <class String> void clause11_21_4_6_5(String & test) {
459 // erase and pop_back
461 test.erase(random(0, test.size()), random(0, maxString));
464 // TODO: is erase(end()) allowed?
465 test.erase(test.begin() + random(0, test.size() - 1));
468 auto const i = test.begin() + random(0, test.size());
469 if (i != test.end()) {
470 test.erase(i, i + random(0, size_t(test.end() - i)));
474 // Can't test pop_back with std::string, doesn't support it yet.
479 template <class String> void clause11_21_4_6_6(String & test) {
480 auto pos = random(0, test.size());
482 test.replace(pos, random(0, test.size() - pos),
485 test.replace(pos, random(0, test.size() - pos), test);
487 pos = random(0, test.size());
489 randomString(&s, maxString);
490 test.replace(pos, pos + random(0, test.size() - pos), s);
491 auto pos1 = random(0, test.size());
492 auto pos2 = random(0, test.size());
494 test.replace(pos1, pos1 + random(0, test.size() - pos1),
496 pos2, pos2 + random(0, test.size() - pos2));
498 test.replace(pos1, pos1 + random(0, test.size() - pos1),
499 test, pos2, pos2 + random(0, test.size() - pos2));
501 pos1 = random(0, test.size());
503 randomString(&str, maxString);
504 pos2 = random(0, str.size());
505 test.replace(pos1, pos1 + random(0, test.size() - pos1),
506 str, pos2, pos2 + random(0, str.size() - pos2));
507 pos = random(0, test.size());
509 test.replace(pos, random(0, test.size() - pos),
510 String(test).c_str(), test.size());
512 test.replace(pos, random(0, test.size() - pos),
513 test.c_str(), test.size());
515 pos = random(0, test.size());
516 randomString(&str, maxString);
517 test.replace(pos, pos + random(0, test.size() - pos),
518 str.c_str(), str.size());
519 pos = random(0, test.size());
520 randomString(&str, maxString);
521 test.replace(pos, pos + random(0, test.size() - pos),
523 pos = random(0, test.size());
524 test.replace(pos, random(0, test.size() - pos),
525 random(0, maxString), random('a', 'z'));
526 pos = random(0, test.size());
528 auto newString = String(test);
531 test.begin() + pos + random(0, test.size() - pos),
536 test.begin() + pos + random(0, test.size() - pos),
539 pos = random(0, test.size());
541 auto newString = String(test);
544 test.begin() + pos + random(0, test.size() - pos),
546 test.size() - random(0, test.size()));
550 test.begin() + pos + random(0, test.size() - pos),
552 test.size() - random(0, test.size()));
554 pos = random(0, test.size());
555 auto const n = random(0, test.size() - pos);
556 typename String::iterator b = test.begin();
558 randomString(&str1, maxString);
559 const String & str3 = str1;
560 const typename String::value_type* ss = str3.c_str();
565 pos = random(0, test.size());
568 test.begin() + pos + random(0, test.size() - pos),
569 random(0, maxString), random('a', 'z'));
572 template <class String> void clause11_21_4_6_7(String & test) {
573 std::vector<typename String::value_type>
574 vec(random(0, maxString));
578 random(0, test.size()));
581 template <class String> void clause11_21_4_6_8(String & test) {
583 randomString(&s, maxString);
587 template <class String> void clause11_21_4_7_1(String & test) {
588 // 21.3.6 string operations
589 // exercise c_str() and data()
590 assert(test.c_str() == test.data());
591 // exercise get_allocator()
593 randomString(&s, maxString);
594 DCHECK(test.get_allocator() == s.get_allocator());
597 template <class String> void clause11_21_4_7_2_a(String & test) {
598 String str = test.substr(
599 random(0, test.size()),
600 random(0, test.size()));
601 Num2String(test, test.find(str, random(0, test.size())));
604 template <class String> void clause11_21_4_7_2_a1(String & test) {
605 String str = String(test).substr(
606 random(0, test.size()),
607 random(0, test.size()));
608 Num2String(test, test.find(str, random(0, test.size())));
611 template <class String> void clause11_21_4_7_2_a2(String & test) {
612 auto const& cTest = test;
613 String str = cTest.substr(
614 random(0, test.size()),
615 random(0, test.size()));
616 Num2String(test, test.find(str, random(0, test.size())));
619 template <class String> void clause11_21_4_7_2_b(String & test) {
620 auto from = random(0, test.size());
621 auto length = random(0, test.size() - from);
622 String str = test.substr(from, length);
623 Num2String(test, test.find(str.c_str(),
624 random(0, test.size()),
625 random(0, str.size())));
628 template <class String> void clause11_21_4_7_2_b1(String & test) {
629 auto from = random(0, test.size());
630 auto length = random(0, test.size() - from);
631 String str = String(test).substr(from, length);
632 Num2String(test, test.find(str.c_str(),
633 random(0, test.size()),
634 random(0, str.size())));
637 template <class String> void clause11_21_4_7_2_b2(String & test) {
638 auto from = random(0, test.size());
639 auto length = random(0, test.size() - from);
640 const auto& cTest = test;
641 String str = cTest.substr(from, length);
642 Num2String(test, test.find(str.c_str(),
643 random(0, test.size()),
644 random(0, str.size())));
647 template <class String> void clause11_21_4_7_2_c(String & test) {
648 String str = test.substr(
649 random(0, test.size()),
650 random(0, test.size()));
651 Num2String(test, test.find(str.c_str(),
652 random(0, test.size())));
655 template <class String> void clause11_21_4_7_2_c1(String & test) {
656 String str = String(test).substr(
657 random(0, test.size()),
658 random(0, test.size()));
659 Num2String(test, test.find(str.c_str(),
660 random(0, test.size())));
663 template <class String> void clause11_21_4_7_2_c2(String & test) {
664 const auto& cTest = test;
665 String str = cTest.substr(
666 random(0, test.size()),
667 random(0, test.size()));
668 Num2String(test, test.find(str.c_str(),
669 random(0, test.size())));
672 template <class String> void clause11_21_4_7_2_d(String & test) {
673 Num2String(test, test.find(
675 random(0, test.size())));
678 template <class String> void clause11_21_4_7_3_a(String & test) {
679 String str = test.substr(
680 random(0, test.size()),
681 random(0, test.size()));
682 Num2String(test, test.rfind(str, random(0, test.size())));
685 template <class String> void clause11_21_4_7_3_b(String & test) {
686 String str = test.substr(
687 random(0, test.size()),
688 random(0, test.size()));
689 Num2String(test, test.rfind(str.c_str(),
690 random(0, test.size()),
691 random(0, str.size())));
694 template <class String> void clause11_21_4_7_3_c(String & test) {
695 String str = test.substr(
696 random(0, test.size()),
697 random(0, test.size()));
698 Num2String(test, test.rfind(str.c_str(),
699 random(0, test.size())));
702 template <class String> void clause11_21_4_7_3_d(String & test) {
703 Num2String(test, test.rfind(
705 random(0, test.size())));
708 template <class String> void clause11_21_4_7_4_a(String & test) {
710 randomString(&str, maxString);
711 Num2String(test, test.find_first_of(str,
712 random(0, test.size())));
715 template <class String> void clause11_21_4_7_4_b(String & test) {
717 randomString(&str, maxString);
718 Num2String(test, test.find_first_of(str.c_str(),
719 random(0, test.size()),
720 random(0, str.size())));
723 template <class String> void clause11_21_4_7_4_c(String & test) {
725 randomString(&str, maxString);
726 Num2String(test, test.find_first_of(str.c_str(),
727 random(0, test.size())));
730 template <class String> void clause11_21_4_7_4_d(String & test) {
731 Num2String(test, test.find_first_of(
733 random(0, test.size())));
736 template <class String> void clause11_21_4_7_5_a(String & test) {
738 randomString(&str, maxString);
739 Num2String(test, test.find_last_of(str,
740 random(0, test.size())));
743 template <class String> void clause11_21_4_7_5_b(String & test) {
745 randomString(&str, maxString);
746 Num2String(test, test.find_last_of(str.c_str(),
747 random(0, test.size()),
748 random(0, str.size())));
751 template <class String> void clause11_21_4_7_5_c(String & test) {
753 randomString(&str, maxString);
754 Num2String(test, test.find_last_of(str.c_str(),
755 random(0, test.size())));
758 template <class String> void clause11_21_4_7_5_d(String & test) {
759 Num2String(test, test.find_last_of(
761 random(0, test.size())));
764 template <class String> void clause11_21_4_7_6_a(String & test) {
766 randomString(&str, maxString);
767 Num2String(test, test.find_first_not_of(str,
768 random(0, test.size())));
771 template <class String> void clause11_21_4_7_6_b(String & test) {
773 randomString(&str, maxString);
774 Num2String(test, test.find_first_not_of(str.c_str(),
775 random(0, test.size()),
776 random(0, str.size())));
779 template <class String> void clause11_21_4_7_6_c(String & test) {
781 randomString(&str, maxString);
782 Num2String(test, test.find_first_not_of(str.c_str(),
783 random(0, test.size())));
786 template <class String> void clause11_21_4_7_6_d(String & test) {
787 Num2String(test, test.find_first_not_of(
789 random(0, test.size())));
792 template <class String> void clause11_21_4_7_7_a(String & test) {
794 randomString(&str, maxString);
795 Num2String(test, test.find_last_not_of(str,
796 random(0, test.size())));
799 template <class String> void clause11_21_4_7_7_b(String & test) {
801 randomString(&str, maxString);
802 Num2String(test, test.find_last_not_of(str.c_str(),
803 random(0, test.size()),
804 random(0, str.size())));
807 template <class String> void clause11_21_4_7_7_c(String & test) {
809 randomString(&str, maxString);
810 Num2String(test, test.find_last_not_of(str.c_str(),
811 random(0, test.size())));
814 template <class String> void clause11_21_4_7_7_d(String & test) {
815 Num2String(test, test.find_last_not_of(
817 random(0, test.size())));
820 template <class String> void clause11_21_4_7_8(String & test) {
821 test = test.substr(random(0, test.size()), random(0, test.size()));
824 template <class String> void clause11_21_4_7_9_a(String & test) {
826 randomString(&s, maxString);
827 int tristate = test.compare(s);
828 if (tristate > 0) tristate = 1;
829 else if (tristate < 0) tristate = 2;
830 Num2String(test, tristate);
833 template <class String> void clause11_21_4_7_9_b(String & test) {
835 randomString(&s, maxString);
836 int tristate = test.compare(
837 random(0, test.size()),
838 random(0, test.size()),
840 if (tristate > 0) tristate = 1;
841 else if (tristate < 0) tristate = 2;
842 Num2String(test, tristate);
845 template <class String> void clause11_21_4_7_9_c(String & test) {
847 randomString(&str, maxString);
848 int tristate = test.compare(
849 random(0, test.size()),
850 random(0, test.size()),
852 random(0, str.size()),
853 random(0, str.size()));
854 if (tristate > 0) tristate = 1;
855 else if (tristate < 0) tristate = 2;
856 Num2String(test, tristate);
859 template <class String> void clause11_21_4_7_9_d(String & test) {
861 randomString(&s, maxString);
862 int tristate = test.compare(s.c_str());
863 if (tristate > 0) tristate = 1;
864 else if (tristate < 0) tristate = 2;
865 Num2String(test, tristate);
868 template <class String> void clause11_21_4_7_9_e(String & test) {
870 randomString(&str, maxString);
871 int tristate = test.compare(
872 random(0, test.size()),
873 random(0, test.size()),
875 random(0, str.size()));
876 if (tristate > 0) tristate = 1;
877 else if (tristate < 0) tristate = 2;
878 Num2String(test, tristate);
881 template <class String> void clause11_21_4_8_1_a(String & test) {
883 randomString(&s1, maxString);
885 randomString(&s2, maxString);
889 template <class String> void clause11_21_4_8_1_b(String & test) {
891 randomString(&s1, maxString);
893 randomString(&s2, maxString);
894 test = move(s1) + s2;
897 template <class String> void clause11_21_4_8_1_c(String & test) {
899 randomString(&s1, maxString);
901 randomString(&s2, maxString);
902 test = s1 + move(s2);
905 template <class String> void clause11_21_4_8_1_d(String & test) {
907 randomString(&s1, maxString);
909 randomString(&s2, maxString);
910 test = move(s1) + move(s2);
913 template <class String> void clause11_21_4_8_1_e(String & test) {
915 randomString(&s, maxString);
917 randomString(&s1, maxString);
918 test = s.c_str() + s1;
921 template <class String> void clause11_21_4_8_1_f(String & test) {
923 randomString(&s, maxString);
925 randomString(&s1, maxString);
926 test = s.c_str() + move(s1);
929 template <class String> void clause11_21_4_8_1_g(String & test) {
931 randomString(&s, maxString);
932 test = typename String::value_type(random('a', 'z')) + s;
935 template <class String> void clause11_21_4_8_1_h(String & test) {
937 randomString(&s, maxString);
938 test = typename String::value_type(random('a', 'z')) + move(s);
941 template <class String> void clause11_21_4_8_1_i(String & test) {
943 randomString(&s, maxString);
945 randomString(&s1, maxString);
946 test = s + s1.c_str();
949 template <class String> void clause11_21_4_8_1_j(String & test) {
951 randomString(&s, maxString);
953 randomString(&s1, maxString);
954 test = move(s) + s1.c_str();
957 template <class String> void clause11_21_4_8_1_k(String & test) {
959 randomString(&s, maxString);
960 test = s + typename String::value_type(random('a', 'z'));
963 template <class String> void clause11_21_4_8_1_l(String & test) {
965 randomString(&s, maxString);
967 randomString(&s1, maxString);
968 test = move(s) + s1.c_str();
971 // Numbering here is from C++11
972 template <class String> void clause11_21_4_8_9_a(String & test) {
973 basic_stringstream<typename String::value_type> stst(test.c_str());
981 TEST(FBString, testAllClauses) {
982 EXPECT_TRUE(1) << "Starting with seed: " << seed;
986 // Disabled on Android: wchar support is not recommended and does not
987 // always behave as expected
989 folly::basic_fbstring<wchar_t> wc;
993 auto l = [&](const char * const clause,
994 void(*f_string)(std::string&),
995 void(*f_fbstring)(folly::fbstring&),
996 void(*f_wfbstring)(folly::basic_fbstring<wchar_t>&)) {
998 if (1) {} else EXPECT_TRUE(1) << "Testing clause " << clause;
1003 wr = std::wstring(r.begin(), r.end());
1004 wc = folly::basic_fbstring<wchar_t>(wr.c_str());
1006 auto localSeed = seed + count;
1007 rng = RandomT(localSeed);
1009 rng = RandomT(localSeed);
1012 << "Lengths: " << r.size() << " vs. " << c.size()
1013 << "\nReference: '" << r << "'"
1014 << "\nActual: '" << c.data()[0] << "'";
1016 rng = RandomT(localSeed);
1018 int wret = wcslen(wc.c_str());
1020 int ret = wcstombs(mb, wc.c_str(), sizeof(mb));
1021 if (ret == wret) mb[wret] = '\0';
1022 const char *mc = c.c_str();
1023 std::string one(mb);
1024 std::string two(mc);
1025 EXPECT_EQ(one, two);
1027 } while (++count % 100 != 0);
1030 #define TEST_CLAUSE(x) \
1032 clause11_##x<std::string>, \
1033 clause11_##x<folly::fbstring>, \
1034 clause11_##x<folly::basic_fbstring<wchar_t>>);
1036 TEST_CLAUSE(21_4_2_a);
1037 TEST_CLAUSE(21_4_2_b);
1038 TEST_CLAUSE(21_4_2_c);
1039 TEST_CLAUSE(21_4_2_d);
1040 TEST_CLAUSE(21_4_2_e);
1041 TEST_CLAUSE(21_4_2_f);
1042 TEST_CLAUSE(21_4_2_g);
1043 TEST_CLAUSE(21_4_2_h);
1044 TEST_CLAUSE(21_4_2_i);
1045 TEST_CLAUSE(21_4_2_j);
1046 TEST_CLAUSE(21_4_2_k);
1047 TEST_CLAUSE(21_4_2_l);
1048 TEST_CLAUSE(21_4_2_lprime);
1049 TEST_CLAUSE(21_4_2_m);
1050 TEST_CLAUSE(21_4_2_n);
1051 TEST_CLAUSE(21_4_3);
1052 TEST_CLAUSE(21_4_4);
1053 TEST_CLAUSE(21_4_5);
1054 TEST_CLAUSE(21_4_6_1);
1055 TEST_CLAUSE(21_4_6_2);
1056 TEST_CLAUSE(21_4_6_3_a);
1057 TEST_CLAUSE(21_4_6_3_b);
1058 TEST_CLAUSE(21_4_6_3_c);
1059 TEST_CLAUSE(21_4_6_3_d);
1060 TEST_CLAUSE(21_4_6_3_e);
1061 TEST_CLAUSE(21_4_6_3_f);
1062 TEST_CLAUSE(21_4_6_3_g);
1063 TEST_CLAUSE(21_4_6_3_h);
1064 TEST_CLAUSE(21_4_6_3_i);
1065 TEST_CLAUSE(21_4_6_3_j);
1066 TEST_CLAUSE(21_4_6_3_k);
1067 TEST_CLAUSE(21_4_6_4);
1068 TEST_CLAUSE(21_4_6_5);
1069 TEST_CLAUSE(21_4_6_6);
1070 TEST_CLAUSE(21_4_6_7);
1071 TEST_CLAUSE(21_4_6_8);
1072 TEST_CLAUSE(21_4_7_1);
1074 TEST_CLAUSE(21_4_7_2_a);
1075 TEST_CLAUSE(21_4_7_2_a1);
1076 TEST_CLAUSE(21_4_7_2_a2);
1077 TEST_CLAUSE(21_4_7_2_b);
1078 TEST_CLAUSE(21_4_7_2_b1);
1079 TEST_CLAUSE(21_4_7_2_b2);
1080 TEST_CLAUSE(21_4_7_2_c);
1081 TEST_CLAUSE(21_4_7_2_c1);
1082 TEST_CLAUSE(21_4_7_2_c2);
1083 TEST_CLAUSE(21_4_7_2_d);
1084 TEST_CLAUSE(21_4_7_3_a);
1085 TEST_CLAUSE(21_4_7_3_b);
1086 TEST_CLAUSE(21_4_7_3_c);
1087 TEST_CLAUSE(21_4_7_3_d);
1088 TEST_CLAUSE(21_4_7_4_a);
1089 TEST_CLAUSE(21_4_7_4_b);
1090 TEST_CLAUSE(21_4_7_4_c);
1091 TEST_CLAUSE(21_4_7_4_d);
1092 TEST_CLAUSE(21_4_7_5_a);
1093 TEST_CLAUSE(21_4_7_5_b);
1094 TEST_CLAUSE(21_4_7_5_c);
1095 TEST_CLAUSE(21_4_7_5_d);
1096 TEST_CLAUSE(21_4_7_6_a);
1097 TEST_CLAUSE(21_4_7_6_b);
1098 TEST_CLAUSE(21_4_7_6_c);
1099 TEST_CLAUSE(21_4_7_6_d);
1100 TEST_CLAUSE(21_4_7_7_a);
1101 TEST_CLAUSE(21_4_7_7_b);
1102 TEST_CLAUSE(21_4_7_7_c);
1103 TEST_CLAUSE(21_4_7_7_d);
1104 TEST_CLAUSE(21_4_7_8);
1105 TEST_CLAUSE(21_4_7_9_a);
1106 TEST_CLAUSE(21_4_7_9_b);
1107 TEST_CLAUSE(21_4_7_9_c);
1108 TEST_CLAUSE(21_4_7_9_d);
1109 TEST_CLAUSE(21_4_7_9_e);
1110 TEST_CLAUSE(21_4_8_1_a);
1111 TEST_CLAUSE(21_4_8_1_b);
1112 TEST_CLAUSE(21_4_8_1_c);
1113 TEST_CLAUSE(21_4_8_1_d);
1114 TEST_CLAUSE(21_4_8_1_e);
1115 TEST_CLAUSE(21_4_8_1_f);
1116 TEST_CLAUSE(21_4_8_1_g);
1117 TEST_CLAUSE(21_4_8_1_h);
1118 TEST_CLAUSE(21_4_8_1_i);
1119 TEST_CLAUSE(21_4_8_1_j);
1120 TEST_CLAUSE(21_4_8_1_k);
1121 TEST_CLAUSE(21_4_8_1_l);
1122 TEST_CLAUSE(21_4_8_9_a);
1125 TEST(FBString, testGetline) {
1127 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan \n\
1128 elit ut urna consectetur in sagittis mi auctor. Nulla facilisi. In nec \n\
1129 dolor leo, vitae imperdiet neque. Donec ut erat mauris, a faucibus \n\
1130 elit. Integer consectetur gravida augue, sit amet mattis mauris auctor \n\
1131 sed. Morbi congue libero eu nunc sodales adipiscing. In lectus nunc, \n\
1132 vulputate a fringilla at, venenatis quis justo. Proin eu velit \n\
1133 nibh. Maecenas vitae tellus eros. Pellentesque habitant morbi \n\
1134 tristique senectus et netus et malesuada fames ac turpis \n\
1135 egestas. Vivamus faucibus feugiat consequat. Donec fermentum neque sit \n\
1136 amet ligula suscipit porta. Phasellus facilisis felis in purus luctus \n\
1137 quis posuere leo tempor. Nam nunc purus, luctus a pharetra ut, \n\
1138 placerat at dui. Donec imperdiet, diam quis convallis pulvinar, dui \n\
1139 est commodo lorem, ut tincidunt diam nibh et nibh. Maecenas nec velit \n\
1140 massa, ut accumsan magna. Donec imperdiet tempor nisi et \n\
1141 laoreet. Phasellus lectus quam, ultricies ut tincidunt in, dignissim \n\
1142 id eros. Mauris vulputate tortor nec neque pellentesque sagittis quis \n\
1143 sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam.";
1146 boost::split(v, s1, boost::is_any_of("\n"));
1148 istringstream input(s1);
1151 EXPECT_TRUE(!getline(input, line).fail());
1152 EXPECT_EQ(line, *i);
1157 TEST(FBString, testMoveCtor) {
1158 // Move constructor. Make sure we allocate a large string, so the
1159 // small string optimization doesn't kick in.
1160 auto size = random(100, 2000);
1161 fbstring s(size, 'a');
1162 fbstring test = std::move(s);
1163 EXPECT_TRUE(s.empty());
1164 EXPECT_EQ(size, test.size());
1167 TEST(FBString, testMoveAssign) {
1168 // Move constructor. Make sure we allocate a large string, so the
1169 // small string optimization doesn't kick in.
1170 auto size = random(100, 2000);
1171 fbstring s(size, 'a');
1173 test = std::move(s);
1174 EXPECT_TRUE(s.empty());
1175 EXPECT_EQ(size, test.size());
1178 TEST(FBString, testMoveOperatorPlusLhs) {
1179 // Make sure we allocate a large string, so the
1180 // small string optimization doesn't kick in.
1181 auto size1 = random(100, 2000);
1182 auto size2 = random(100, 2000);
1183 fbstring s1(size1, 'a');
1184 fbstring s2(size2, 'b');
1186 test = std::move(s1) + s2;
1187 EXPECT_TRUE(s1.empty());
1188 EXPECT_EQ(size1 + size2, test.size());
1191 TEST(FBString, testMoveOperatorPlusRhs) {
1192 // Make sure we allocate a large string, so the
1193 // small string optimization doesn't kick in.
1194 auto size1 = random(100, 2000);
1195 auto size2 = random(100, 2000);
1196 fbstring s1(size1, 'a');
1197 fbstring s2(size2, 'b');
1199 test = s1 + std::move(s2);
1200 EXPECT_EQ(size1 + size2, test.size());
1203 // The GNU C++ standard library throws an std::logic_error when an std::string
1204 // is constructed with a null pointer. Verify that we mirror this behavior.
1206 // N.B. We behave this way even if the C++ library being used is something
1207 // other than libstdc++. Someday if we deem it important to present
1208 // identical undefined behavior for other platforms, we can re-visit this.
1209 TEST(FBString, testConstructionFromLiteralZero) {
1210 EXPECT_THROW(fbstring s(0), std::logic_error);
1213 TEST(FBString, testFixedBugs) {
1215 fbstring str(1337, 'f');
1219 EXPECT_EQ(str.front(), 'f');
1222 fbstring str(1337, 'f');
1223 for (int i = 0; i < 2; ++i) {
1226 EXPECT_EQ(cp.c_str()[cp.size()], '\0');
1232 fbstring str(1337, 'f');
1237 fbstring str(1337, 'f');
1243 folly::basic_fbstring<wchar_t> s;
1244 EXPECT_EQ(0, s.size());
1247 fbstring str(1337, 'f');
1248 std::swap(str, str);
1249 EXPECT_EQ(1337, str.size());
1251 { // D1012196, --allocator=malloc
1252 fbstring str(128, 'f');
1253 str.clear(); // Empty medium string.
1254 fbstring copy(str); // Medium string of 0 capacity.
1255 copy.push_back('b');
1256 EXPECT_GE(copy.capacity(), 1);
1260 s1.reserve(8); // Trigger the optimized code path.
1261 auto test1 = '\0' + std::move(s1);
1262 EXPECT_EQ(2, test1.size());
1264 fbstring s2(1, '\0');
1266 auto test2 = "a" + std::move(s2);
1267 EXPECT_EQ(2, test2.size());
1271 TEST(FBString, findWithNpos) {
1272 fbstring fbstr("localhost:80");
1273 EXPECT_EQ(fbstring::npos, fbstr.find(":", fbstring::npos));
1276 TEST(FBString, testHash) {
1283 std::hash<fbstring> hashfunc;
1284 EXPECT_NE(hashfunc(a), hashfunc(b));
1287 TEST(FBString, testFrontBack) {
1288 fbstring str("hello");
1289 EXPECT_EQ(str.front(), 'h');
1290 EXPECT_EQ(str.back(), 'o');
1292 EXPECT_EQ(str.front(), 'H');
1294 EXPECT_EQ(str.back(), 'O');
1295 EXPECT_EQ(str, "HellO");
1298 TEST(FBString, noexcept) {
1299 EXPECT_TRUE(noexcept(fbstring()));
1301 EXPECT_FALSE(noexcept(fbstring(x)));
1302 EXPECT_TRUE(noexcept(fbstring(std::move(x))));
1304 EXPECT_FALSE(noexcept(y = x));
1305 EXPECT_TRUE(noexcept(y = std::move(x)));
1308 TEST(FBString, iomanip) {
1310 fbstring fbstr("Hello");
1312 ss << setw(6) << fbstr;
1313 EXPECT_EQ(ss.str(), " Hello");
1316 ss << left << setw(6) << fbstr;
1317 EXPECT_EQ(ss.str(), "Hello ");
1320 ss << right << setw(6) << fbstr;
1321 EXPECT_EQ(ss.str(), " Hello");
1324 ss << setw(4) << fbstr;
1325 EXPECT_EQ(ss.str(), "Hello");
1328 ss << setfill('^') << setw(6) << fbstr;
1329 EXPECT_EQ(ss.str(), "^Hello");
1333 TEST(FBString, rvalueIterators) {
1334 // you cannot take &* of a move-iterator, so use that for testing
1335 fbstring s = "base";
1336 fbstring r = "hello";
1337 r.replace(r.begin(), r.end(),
1338 make_move_iterator(s.begin()), make_move_iterator(s.end()));
1339 EXPECT_EQ("base", r);
1341 // The following test is probably not required by the standard.
1342 // i.e. this could be in the realm of undefined behavior.
1343 fbstring b = "123abcXYZ";
1344 auto ait = b.begin() + 3;
1345 auto Xit = b.begin() + 6;
1346 b.replace(ait, b.end(), b.begin(), Xit);
1347 EXPECT_EQ("123123abc", b); // if things go wrong, you'd get "123123123"
1350 TEST(FBString, moveTerminator) {
1351 // The source of a move must remain in a valid state
1352 fbstring s(100, 'x'); // too big to be in-situ
1356 EXPECT_EQ(0, s.size());
1357 EXPECT_EQ('\0', *s.c_str());
1362 * t8968589: Clang 3.7 refused to compile w/ certain constructors (specifically
1363 * those that were "explicit" and had a defaulted parameter, if they were used
1364 * in structs which were default-initialized). Exercise these just to ensure
1367 * In diff D2632953 the old constructor:
1368 * explicit basic_fbstring(const A& a = A()) noexcept;
1370 * was split into these two, as a workaround:
1371 * basic_fbstring() noexcept;
1372 * explicit basic_fbstring(const A& a) noexcept;
1375 struct TestStructDefaultAllocator {
1376 folly::basic_fbstring<char> stringMember;
1380 struct TestStructWithAllocator {
1381 folly::basic_fbstring<char, std::char_traits<char>, A> stringMember;
1384 std::atomic<size_t> allocatorConstructedCount(0);
1385 struct TestStructStringAllocator : std::allocator<char> {
1386 TestStructStringAllocator() {
1387 ++ allocatorConstructedCount;
1393 TEST(FBStringCtorTest, DefaultInitStructDefaultAlloc) {
1394 TestStructDefaultAllocator t1 { };
1395 EXPECT_TRUE(t1.stringMember.empty());
1398 TEST(FBStringCtorTest, DefaultInitStructAlloc) {
1399 EXPECT_EQ(allocatorConstructedCount.load(), 0);
1400 TestStructWithAllocator<TestStructStringAllocator> t2;
1401 EXPECT_TRUE(t2.stringMember.empty());
1402 EXPECT_EQ(allocatorConstructedCount.load(), 1);