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>
38 using namespace folly;
40 static const int seed = folly::randomNumberSeed();
41 typedef boost::mt19937 RandomT;
42 static RandomT rng(seed);
43 static const size_t maxString = 100;
44 static const bool avoidAliasing = true;
46 template <class Integral1, class Integral2>
47 Integral2 random(Integral1 low, Integral2 up) {
48 boost::uniform_int<> range(low, up);
52 template <class String>
53 void randomString(String* toFill, unsigned int maxSize = 1000) {
55 toFill->resize(random(0, maxSize));
56 FOR_EACH (i, *toFill) {
57 *i = random('a', 'z');
61 template <class String, class Integral>
62 void Num2String(String& str, Integral n) {
64 std::string tmp = folly::to<std::string>(n);
65 str = String(tmp.begin(), tmp.end());
68 std::list<char> RandomList(unsigned int maxSize) {
69 std::list<char> lst(random(0u, maxSize));
70 std::list<char>::iterator i = lst.begin();
71 for (; i != lst.end(); ++i) {
72 *i = random('a', 'z');
77 ////////////////////////////////////////////////////////////////////////////////
79 ////////////////////////////////////////////////////////////////////////////////
81 template <class String> void clause11_21_4_2_a(String & test) {
82 test.String::~String();
85 template <class String> void clause11_21_4_2_b(String & test) {
87 assert(test2 == test);
89 template <class String> void clause11_21_4_2_c(String & test) {
90 // Test move constructor. There is a more specialized test, see
91 // TEST(FBString, testMoveCtor)
93 String test2(std::move(donor));
94 EXPECT_EQ(test2, test);
95 // Technically not required, but all implementations that actually
96 // support move will move large strings. Make a guess for 128 as the
97 // maximum small string optimization that's reasonable.
98 EXPECT_LE(donor.size(), 128);
100 template <class String> void clause11_21_4_2_d(String & test) {
101 // Copy constructor with position and length
102 const size_t pos = random(0, test.size());
103 String s(test, pos, random(0, 9)
104 ? random(0, (size_t)(test.size() - pos))
105 : String::npos); // test for npos, too, in 10% of the cases
108 template <class String> void clause11_21_4_2_e(String & test) {
109 // Constructor from char*, size_t
111 pos = random(0, test.size()),
112 n = random(0, test.size() - pos);
113 String before(test.data(), test.size());
114 String s(test.c_str() + pos, n);
115 String after(test.data(), test.size());
116 EXPECT_EQ(before, after);
119 template <class String> void clause11_21_4_2_f(String & test) {
120 // Constructor from char*
121 const size_t pos = random(0, test.size());
122 String before(test.data(), test.size());
123 String s(test.c_str() + pos);
124 String after(test.data(), test.size());
125 EXPECT_EQ(before, after);
128 template <class String> void clause11_21_4_2_g(String & test) {
129 // Constructor from size_t, char
130 const size_t n = random(0, test.size());
131 const auto c = test.front();
134 template <class String> void clause11_21_4_2_h(String & test) {
135 // Constructors from various iterator pairs
136 // Constructor from char*, char*
137 String s1(test.begin(), test.end());
139 String s2(test.data(), test.data() + test.size());
141 // Constructor from other iterators
143 for (auto c : test) lst.push_back(c);
144 String s3(lst.begin(), lst.end());
146 // Constructor from wchar_t iterators
147 std::list<wchar_t> lst1;
148 for (auto c : test) lst1.push_back(c);
149 String s4(lst1.begin(), lst1.end());
151 // Constructor from wchar_t pointers
155 fbstring s5(t, t + 2);;
158 template <class String> void clause11_21_4_2_i(String & test) {
159 // From initializer_list<char>
160 std::initializer_list<typename String::value_type>
161 il = { 'h', 'e', 'l', 'l', 'o' };
165 template <class String> void clause11_21_4_2_j(String & test) {
166 // Assignment from const String&
167 auto size = random(0, 2000);
168 String s(size, '\0');
169 EXPECT_EQ(s.size(), size);
170 FOR_EACH_RANGE (i, 0, s.size()) {
171 s[i] = random('a', 'z');
175 template <class String> void clause11_21_4_2_k(String & test) {
176 // Assignment from String&&
177 auto size = random(0, 2000);
178 String s(size, '\0');
179 EXPECT_EQ(s.size(), size);
180 FOR_EACH_RANGE (i, 0, s.size()) {
181 s[i] = random('a', 'z');
184 if (typeid(String) == typeid(fbstring)) {
185 EXPECT_LE(s.size(), 128);
188 template <class String> void clause11_21_4_2_l(String & test) {
189 // Assignment from char*
190 String s(random(0, 1000), '\0');
192 for (; i != s.size(); ++i) {
193 s[i] = random('a', 'z');
197 template <class String> void clause11_21_4_2_lprime(String & test) {
199 const size_t pos = random(0, test.size());
201 test = String(test.c_str() + pos);
203 test = test.c_str() + pos;
206 template <class String> void clause11_21_4_2_m(String & test) {
207 // Assignment from char
208 test = random('a', 'z');
210 template <class String> void clause11_21_4_2_n(String & test) {
211 // Assignment from initializer_list<char>
212 initializer_list<typename String::value_type>
213 il = { 'h', 'e', 'l', 'l', 'o' };
217 template <class String> void clause11_21_4_3(String & test) {
218 // Iterators. The code below should leave test unchanged
219 EXPECT_EQ(test.size(), test.end() - test.begin());
220 EXPECT_EQ(test.size(), test.rend() - test.rbegin());
221 EXPECT_EQ(test.size(), test.cend() - test.cbegin());
222 EXPECT_EQ(test.size(), test.crend() - test.crbegin());
224 auto s = test.size();
225 test.resize(test.end() - test.begin());
226 EXPECT_EQ(s, test.size());
227 test.resize(test.rend() - test.rbegin());
228 EXPECT_EQ(s, test.size());
231 template <class String> void clause11_21_4_4(String & test) {
232 // exercise capacity, size, max_size
233 EXPECT_EQ(test.size(), test.length());
234 EXPECT_LE(test.size(), test.max_size());
235 EXPECT_LE(test.capacity(), test.max_size());
236 EXPECT_LE(test.size(), test.capacity());
238 // exercise shrink_to_fit. Nonbinding request so we can't really do
239 // much beyond calling it.
241 copy.reserve(copy.capacity() * 3);
242 copy.shrink_to_fit();
243 EXPECT_EQ(copy, test);
246 string empty("empty");
247 string notempty("not empty");
248 if (test.empty()) test = String(empty.begin(), empty.end());
249 else test = String(notempty.begin(), notempty.end());
252 template <class String> void clause11_21_4_5(String & test) {
253 // exercise element access
255 EXPECT_EQ(test[0], test.front());
256 EXPECT_EQ(test[test.size() - 1], test.back());
257 auto const i = random(0, test.size() - 1);
258 EXPECT_EQ(test[i], test.at(i));
263 template <class String> void clause11_21_4_6_1(String & test) {
264 // 21.3.5 modifiers (+=)
266 randomString(&test1);
267 assert(test1.size() == char_traits
268 <typename String::value_type>::length(test1.c_str()));
269 auto len = test.size();
271 EXPECT_EQ(test.size(), test1.size() + len);
272 FOR_EACH_RANGE (i, 0, test1.size()) {
273 EXPECT_EQ(test[len + i], test1[i]);
275 // aliasing modifiers
277 auto dt = test2.data();
278 auto sz = test.c_str();
280 EXPECT_EQ(memcmp(sz, dt, len), 0);
281 String copy(test.data(), test.size());
282 EXPECT_EQ(char_traits
283 <typename String::value_type>::length(test.c_str()), len);
286 EXPECT_EQ(test.size(), 2 * len);
287 EXPECT_EQ(char_traits
288 <typename String::value_type>::length(test.c_str()), 2 * len);
289 FOR_EACH_RANGE (i, 0, len) {
290 EXPECT_EQ(test[i], copy[i]);
291 EXPECT_EQ(test[i], test[len + i]);
294 EXPECT_EQ(char_traits
295 <typename String::value_type>::length(test.c_str()), len);
297 auto const pos = random(0, test.size());
298 EXPECT_EQ(char_traits
299 <typename String::value_type>::length(test.c_str() + pos), len - pos);
301 String addMe(test.c_str() + pos);
302 EXPECT_EQ(addMe.size(), len - pos);
305 test += test.c_str() + pos;
307 EXPECT_EQ(test.size(), 2 * len - pos);
310 test += random('a', 'z');
311 EXPECT_EQ(test.size(), len + 1);
313 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
317 template <class String> void clause11_21_4_6_2(String & test) {
318 // 21.3.5 modifiers (append, push_back)
321 // Test with a small string first
322 char c = random('a', 'z');
324 EXPECT_EQ(s[s.size() - 1], c);
325 EXPECT_EQ(s.size(), 1);
326 s.resize(s.size() - 1);
328 randomString(&s, maxString);
330 randomString(&s, maxString);
331 test.append(s, random(0, s.size()), random(0, maxString));
332 randomString(&s, maxString);
333 test.append(s.c_str(), random(0, s.size()));
334 randomString(&s, maxString);
335 test.append(s.c_str());
336 test.append(random(0, maxString), random('a', 'z'));
337 std::list<char> lst(RandomList(maxString));
338 test.append(lst.begin(), lst.end());
339 c = random('a', 'z');
341 EXPECT_EQ(test[test.size() - 1], c);
343 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
347 template <class String> void clause11_21_4_6_3_a(String & test) {
354 test.assign(std::move(s));
355 if (typeid(String) == typeid(fbstring)) {
356 EXPECT_LE(s.size(), 128);
360 template <class String> void clause11_21_4_6_3_b(String & test) {
363 randomString(&s, maxString);
364 test.assign(s, random(0, s.size()), random(0, maxString));
367 template <class String> void clause11_21_4_6_3_c(String & test) {
370 randomString(&s, maxString);
371 test.assign(s.c_str(), random(0, s.size()));
374 template <class String> void clause11_21_4_6_3_d(String & test) {
377 randomString(&s, maxString);
378 test.assign(s.c_str());
381 template <class String> void clause11_21_4_6_3_e(String & test) {
384 randomString(&s, maxString);
385 test.assign(random(0, maxString), random('a', 'z'));
388 template <class String> void clause11_21_4_6_3_f(String & test) {
389 // assign from bidirectional iterator
390 std::list<char> lst(RandomList(maxString));
391 test.assign(lst.begin(), lst.end());
394 template <class String> void clause11_21_4_6_3_g(String & test) {
395 // assign from aliased source
399 template <class String> void clause11_21_4_6_3_h(String & test) {
400 // assign from aliased source
401 test.assign(test, random(0, test.size()), random(0, maxString));
404 template <class String> void clause11_21_4_6_3_i(String & test) {
405 // assign from aliased source
406 test.assign(test.c_str(), random(0, test.size()));
409 template <class String> void clause11_21_4_6_3_j(String & test) {
410 // assign from aliased source
411 test.assign(test.c_str());
414 template <class String> void clause11_21_4_6_3_k(String & test) {
415 // assign from initializer_list
416 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
420 template <class String> void clause11_21_4_6_4(String & test) {
423 randomString(&s, maxString);
424 test.insert(random(0, test.size()), s);
425 randomString(&s, maxString);
426 test.insert(random(0, test.size()),
427 s, random(0, s.size()),
428 random(0, maxString));
429 randomString(&s, maxString);
430 test.insert(random(0, test.size()),
431 s.c_str(), random(0, s.size()));
432 randomString(&s, maxString);
433 test.insert(random(0, test.size()), s.c_str());
434 test.insert(random(0, test.size()),
435 random(0, maxString), random('a', 'z'));
436 typename String::size_type pos = random(0, test.size());
437 typename String::iterator res =
438 test.insert(test.begin() + pos, random('a', 'z'));
439 EXPECT_EQ(res - test.begin(), pos);
440 std::list<char> lst(RandomList(maxString));
441 pos = random(0, test.size());
442 // Uncomment below to see a bug in gcc
443 /*res = */test.insert(test.begin() + pos, lst.begin(), lst.end());
444 // insert from initializer_list
445 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
446 pos = random(0, test.size());
447 // Uncomment below to see a bug in gcc
448 /*res = */test.insert(test.begin() + pos, il);
450 // Test with actual input iterators
452 ss << "hello cruel world";
453 auto i = istream_iterator<char>(ss);
454 test.insert(test.begin(), i, istream_iterator<char>());
457 template <class String> void clause11_21_4_6_5(String & test) {
458 // erase and pop_back
460 test.erase(random(0, test.size()), random(0, maxString));
463 // TODO: is erase(end()) allowed?
464 test.erase(test.begin() + random(0, test.size() - 1));
467 auto const i = test.begin() + random(0, test.size());
468 if (i != test.end()) {
469 test.erase(i, i + random(0, size_t(test.end() - i)));
473 // Can't test pop_back with std::string, doesn't support it yet.
478 template <class String> void clause11_21_4_6_6(String & test) {
479 auto pos = random(0, test.size());
481 test.replace(pos, random(0, test.size() - pos),
484 test.replace(pos, random(0, test.size() - pos), test);
486 pos = random(0, test.size());
488 randomString(&s, maxString);
489 test.replace(pos, pos + random(0, test.size() - pos), s);
490 auto pos1 = random(0, test.size());
491 auto pos2 = random(0, test.size());
493 test.replace(pos1, pos1 + random(0, test.size() - pos1),
495 pos2, pos2 + random(0, test.size() - pos2));
497 test.replace(pos1, pos1 + random(0, test.size() - pos1),
498 test, pos2, pos2 + random(0, test.size() - pos2));
500 pos1 = random(0, test.size());
502 randomString(&str, maxString);
503 pos2 = random(0, str.size());
504 test.replace(pos1, pos1 + random(0, test.size() - pos1),
505 str, pos2, pos2 + random(0, str.size() - pos2));
506 pos = random(0, test.size());
508 test.replace(pos, random(0, test.size() - pos),
509 String(test).c_str(), test.size());
511 test.replace(pos, random(0, test.size() - pos),
512 test.c_str(), test.size());
514 pos = random(0, test.size());
515 randomString(&str, maxString);
516 test.replace(pos, pos + random(0, test.size() - pos),
517 str.c_str(), str.size());
518 pos = random(0, test.size());
519 randomString(&str, maxString);
520 test.replace(pos, pos + random(0, test.size() - pos),
522 pos = random(0, test.size());
523 test.replace(pos, random(0, test.size() - pos),
524 random(0, maxString), random('a', 'z'));
525 pos = random(0, test.size());
527 auto newString = String(test);
530 test.begin() + pos + random(0, test.size() - pos),
535 test.begin() + pos + random(0, test.size() - pos),
538 pos = random(0, test.size());
540 auto newString = String(test);
543 test.begin() + pos + random(0, test.size() - pos),
545 test.size() - random(0, test.size()));
549 test.begin() + pos + random(0, test.size() - pos),
551 test.size() - random(0, test.size()));
553 pos = random(0, test.size());
554 auto const n = random(0, test.size() - pos);
555 typename String::iterator b = test.begin();
557 randomString(&str1, maxString);
558 const String & str3 = str1;
559 const typename String::value_type* ss = str3.c_str();
564 pos = random(0, test.size());
567 test.begin() + pos + random(0, test.size() - pos),
568 random(0, maxString), random('a', 'z'));
571 template <class String> void clause11_21_4_6_7(String & test) {
572 std::vector<typename String::value_type>
573 vec(random(0, maxString));
577 random(0, test.size()));
580 template <class String> void clause11_21_4_6_8(String & test) {
582 randomString(&s, maxString);
586 template <class String> void clause11_21_4_7_1(String & test) {
587 // 21.3.6 string operations
588 // exercise c_str() and data()
589 assert(test.c_str() == test.data());
590 // exercise get_allocator()
592 randomString(&s, maxString);
593 assert(test.get_allocator() == s.get_allocator());
596 template <class String> void clause11_21_4_7_2_a(String & test) {
597 String str = test.substr(
598 random(0, test.size()),
599 random(0, test.size()));
600 Num2String(test, test.find(str, random(0, test.size())));
603 template <class String> void clause11_21_4_7_2_a1(String & test) {
604 String str = String(test).substr(
605 random(0, test.size()),
606 random(0, test.size()));
607 Num2String(test, test.find(str, random(0, test.size())));
610 template <class String> void clause11_21_4_7_2_a2(String & test) {
611 auto const& cTest = test;
612 String str = cTest.substr(
613 random(0, test.size()),
614 random(0, test.size()));
615 Num2String(test, test.find(str, random(0, test.size())));
618 template <class String> void clause11_21_4_7_2_b(String & test) {
619 auto from = random(0, test.size());
620 auto length = random(0, test.size() - from);
621 String str = test.substr(from, length);
622 Num2String(test, test.find(str.c_str(),
623 random(0, test.size()),
624 random(0, str.size())));
627 template <class String> void clause11_21_4_7_2_b1(String & test) {
628 auto from = random(0, test.size());
629 auto length = random(0, test.size() - from);
630 String str = String(test).substr(from, length);
631 Num2String(test, test.find(str.c_str(),
632 random(0, test.size()),
633 random(0, str.size())));
636 template <class String> void clause11_21_4_7_2_b2(String & test) {
637 auto from = random(0, test.size());
638 auto length = random(0, test.size() - from);
639 const auto& cTest = test;
640 String str = cTest.substr(from, length);
641 Num2String(test, test.find(str.c_str(),
642 random(0, test.size()),
643 random(0, str.size())));
646 template <class String> void clause11_21_4_7_2_c(String & test) {
647 String str = test.substr(
648 random(0, test.size()),
649 random(0, test.size()));
650 Num2String(test, test.find(str.c_str(),
651 random(0, test.size())));
654 template <class String> void clause11_21_4_7_2_c1(String & test) {
655 String str = String(test).substr(
656 random(0, test.size()),
657 random(0, test.size()));
658 Num2String(test, test.find(str.c_str(),
659 random(0, test.size())));
662 template <class String> void clause11_21_4_7_2_c2(String & test) {
663 const auto& cTest = test;
664 String str = cTest.substr(
665 random(0, test.size()),
666 random(0, test.size()));
667 Num2String(test, test.find(str.c_str(),
668 random(0, test.size())));
671 template <class String> void clause11_21_4_7_2_d(String & test) {
672 Num2String(test, test.find(
674 random(0, test.size())));
677 template <class String> void clause11_21_4_7_3_a(String & test) {
678 String str = test.substr(
679 random(0, test.size()),
680 random(0, test.size()));
681 Num2String(test, test.rfind(str, random(0, test.size())));
684 template <class String> void clause11_21_4_7_3_b(String & test) {
685 String str = test.substr(
686 random(0, test.size()),
687 random(0, test.size()));
688 Num2String(test, test.rfind(str.c_str(),
689 random(0, test.size()),
690 random(0, str.size())));
693 template <class String> void clause11_21_4_7_3_c(String & test) {
694 String str = test.substr(
695 random(0, test.size()),
696 random(0, test.size()));
697 Num2String(test, test.rfind(str.c_str(),
698 random(0, test.size())));
701 template <class String> void clause11_21_4_7_3_d(String & test) {
702 Num2String(test, test.rfind(
704 random(0, test.size())));
707 template <class String> void clause11_21_4_7_4_a(String & test) {
709 randomString(&str, maxString);
710 Num2String(test, test.find_first_of(str,
711 random(0, test.size())));
714 template <class String> void clause11_21_4_7_4_b(String & test) {
716 randomString(&str, maxString);
717 Num2String(test, test.find_first_of(str.c_str(),
718 random(0, test.size()),
719 random(0, str.size())));
722 template <class String> void clause11_21_4_7_4_c(String & test) {
724 randomString(&str, maxString);
725 Num2String(test, test.find_first_of(str.c_str(),
726 random(0, test.size())));
729 template <class String> void clause11_21_4_7_4_d(String & test) {
730 Num2String(test, test.find_first_of(
732 random(0, test.size())));
735 template <class String> void clause11_21_4_7_5_a(String & test) {
737 randomString(&str, maxString);
738 Num2String(test, test.find_last_of(str,
739 random(0, test.size())));
742 template <class String> void clause11_21_4_7_5_b(String & test) {
744 randomString(&str, maxString);
745 Num2String(test, test.find_last_of(str.c_str(),
746 random(0, test.size()),
747 random(0, str.size())));
750 template <class String> void clause11_21_4_7_5_c(String & test) {
752 randomString(&str, maxString);
753 Num2String(test, test.find_last_of(str.c_str(),
754 random(0, test.size())));
757 template <class String> void clause11_21_4_7_5_d(String & test) {
758 Num2String(test, test.find_last_of(
760 random(0, test.size())));
763 template <class String> void clause11_21_4_7_6_a(String & test) {
765 randomString(&str, maxString);
766 Num2String(test, test.find_first_not_of(str,
767 random(0, test.size())));
770 template <class String> void clause11_21_4_7_6_b(String & test) {
772 randomString(&str, maxString);
773 Num2String(test, test.find_first_not_of(str.c_str(),
774 random(0, test.size()),
775 random(0, str.size())));
778 template <class String> void clause11_21_4_7_6_c(String & test) {
780 randomString(&str, maxString);
781 Num2String(test, test.find_first_not_of(str.c_str(),
782 random(0, test.size())));
785 template <class String> void clause11_21_4_7_6_d(String & test) {
786 Num2String(test, test.find_first_not_of(
788 random(0, test.size())));
791 template <class String> void clause11_21_4_7_7_a(String & test) {
793 randomString(&str, maxString);
794 Num2String(test, test.find_last_not_of(str,
795 random(0, test.size())));
798 template <class String> void clause11_21_4_7_7_b(String & test) {
800 randomString(&str, maxString);
801 Num2String(test, test.find_last_not_of(str.c_str(),
802 random(0, test.size()),
803 random(0, str.size())));
806 template <class String> void clause11_21_4_7_7_c(String & test) {
808 randomString(&str, maxString);
809 Num2String(test, test.find_last_not_of(str.c_str(),
810 random(0, test.size())));
813 template <class String> void clause11_21_4_7_7_d(String & test) {
814 Num2String(test, test.find_last_not_of(
816 random(0, test.size())));
819 template <class String> void clause11_21_4_7_8(String & test) {
820 test = test.substr(random(0, test.size()), random(0, test.size()));
823 template <class String> void clause11_21_4_7_9_a(String & test) {
825 randomString(&s, maxString);
826 int tristate = test.compare(s);
827 if (tristate > 0) tristate = 1;
828 else if (tristate < 0) tristate = 2;
829 Num2String(test, tristate);
832 template <class String> void clause11_21_4_7_9_b(String & test) {
834 randomString(&s, maxString);
835 int tristate = test.compare(
836 random(0, test.size()),
837 random(0, test.size()),
839 if (tristate > 0) tristate = 1;
840 else if (tristate < 0) tristate = 2;
841 Num2String(test, tristate);
844 template <class String> void clause11_21_4_7_9_c(String & test) {
846 randomString(&str, maxString);
847 int tristate = test.compare(
848 random(0, test.size()),
849 random(0, test.size()),
851 random(0, str.size()),
852 random(0, str.size()));
853 if (tristate > 0) tristate = 1;
854 else if (tristate < 0) tristate = 2;
855 Num2String(test, tristate);
858 template <class String> void clause11_21_4_7_9_d(String & test) {
860 randomString(&s, maxString);
861 int tristate = test.compare(s.c_str());
862 if (tristate > 0) tristate = 1;
863 else if (tristate < 0) tristate = 2;
864 Num2String(test, tristate);
867 template <class String> void clause11_21_4_7_9_e(String & test) {
869 randomString(&str, maxString);
870 int tristate = test.compare(
871 random(0, test.size()),
872 random(0, test.size()),
874 random(0, str.size()));
875 if (tristate > 0) tristate = 1;
876 else if (tristate < 0) tristate = 2;
877 Num2String(test, tristate);
880 template <class String> void clause11_21_4_8_1_a(String & test) {
882 randomString(&s1, maxString);
884 randomString(&s2, maxString);
888 template <class String> void clause11_21_4_8_1_b(String & test) {
890 randomString(&s1, maxString);
892 randomString(&s2, maxString);
893 test = move(s1) + s2;
896 template <class String> void clause11_21_4_8_1_c(String & test) {
898 randomString(&s1, maxString);
900 randomString(&s2, maxString);
901 test = s1 + move(s2);
904 template <class String> void clause11_21_4_8_1_d(String & test) {
906 randomString(&s1, maxString);
908 randomString(&s2, maxString);
909 test = move(s1) + move(s2);
912 template <class String> void clause11_21_4_8_1_e(String & test) {
914 randomString(&s, maxString);
916 randomString(&s1, maxString);
917 test = s.c_str() + s1;
920 template <class String> void clause11_21_4_8_1_f(String & test) {
922 randomString(&s, maxString);
924 randomString(&s1, maxString);
925 test = s.c_str() + move(s1);
928 template <class String> void clause11_21_4_8_1_g(String & test) {
930 randomString(&s, maxString);
931 test = typename String::value_type(random('a', 'z')) + s;
934 template <class String> void clause11_21_4_8_1_h(String & test) {
936 randomString(&s, maxString);
937 test = typename String::value_type(random('a', 'z')) + move(s);
940 template <class String> void clause11_21_4_8_1_i(String & test) {
942 randomString(&s, maxString);
944 randomString(&s1, maxString);
945 test = s + s1.c_str();
948 template <class String> void clause11_21_4_8_1_j(String & test) {
950 randomString(&s, maxString);
952 randomString(&s1, maxString);
953 test = move(s) + s1.c_str();
956 template <class String> void clause11_21_4_8_1_k(String & test) {
958 randomString(&s, maxString);
959 test = s + typename String::value_type(random('a', 'z'));
962 template <class String> void clause11_21_4_8_1_l(String & test) {
964 randomString(&s, maxString);
966 randomString(&s1, maxString);
967 test = move(s) + s1.c_str();
970 // Numbering here is from C++11
971 template <class String> void clause11_21_4_8_9_a(String & test) {
972 basic_stringstream<typename String::value_type> stst(test.c_str());
980 TEST(FBString, testAllClauses) {
981 EXPECT_TRUE(1) << "Starting with seed: " << seed;
985 folly::basic_fbstring<wchar_t> wc;
988 auto l = [&](const char * const clause,
989 void(*f_string)(std::string&),
990 void(*f_fbstring)(folly::fbstring&),
991 void(*f_wfbstring)(folly::basic_fbstring<wchar_t>&)) {
993 if (1) {} else EXPECT_TRUE(1) << "Testing clause " << clause;
997 wr = std::wstring(r.begin(), r.end());
998 wc = folly::basic_fbstring<wchar_t>(wr.c_str());
999 auto localSeed = seed + count;
1000 rng = RandomT(localSeed);
1002 rng = RandomT(localSeed);
1005 << "Lengths: " << r.size() << " vs. " << c.size()
1006 << "\nReference: '" << r << "'"
1007 << "\nActual: '" << c.data()[0] << "'";
1008 rng = RandomT(localSeed);
1010 int wret = wcslen(wc.c_str());
1012 int ret = wcstombs(mb, wc.c_str(), sizeof(mb));
1013 if (ret == wret) mb[wret] = '\0';
1014 const char *mc = c.c_str();
1015 std::string one(mb);
1016 std::string two(mc);
1017 EXPECT_EQ(one, two);
1018 } while (++count % 100 != 0);
1021 #define TEST_CLAUSE(x) \
1023 clause11_##x<std::string>, \
1024 clause11_##x<folly::fbstring>, \
1025 clause11_##x<folly::basic_fbstring<wchar_t>>);
1027 TEST_CLAUSE(21_4_2_a);
1028 TEST_CLAUSE(21_4_2_b);
1029 TEST_CLAUSE(21_4_2_c);
1030 TEST_CLAUSE(21_4_2_d);
1031 TEST_CLAUSE(21_4_2_e);
1032 TEST_CLAUSE(21_4_2_f);
1033 TEST_CLAUSE(21_4_2_g);
1034 TEST_CLAUSE(21_4_2_h);
1035 TEST_CLAUSE(21_4_2_i);
1036 TEST_CLAUSE(21_4_2_j);
1037 TEST_CLAUSE(21_4_2_k);
1038 TEST_CLAUSE(21_4_2_l);
1039 TEST_CLAUSE(21_4_2_lprime);
1040 TEST_CLAUSE(21_4_2_m);
1041 TEST_CLAUSE(21_4_2_n);
1042 TEST_CLAUSE(21_4_3);
1043 TEST_CLAUSE(21_4_4);
1044 TEST_CLAUSE(21_4_5);
1045 TEST_CLAUSE(21_4_6_1);
1046 TEST_CLAUSE(21_4_6_2);
1047 TEST_CLAUSE(21_4_6_3_a);
1048 TEST_CLAUSE(21_4_6_3_b);
1049 TEST_CLAUSE(21_4_6_3_c);
1050 TEST_CLAUSE(21_4_6_3_d);
1051 TEST_CLAUSE(21_4_6_3_e);
1052 TEST_CLAUSE(21_4_6_3_f);
1053 TEST_CLAUSE(21_4_6_3_g);
1054 TEST_CLAUSE(21_4_6_3_h);
1055 TEST_CLAUSE(21_4_6_3_i);
1056 TEST_CLAUSE(21_4_6_3_j);
1057 TEST_CLAUSE(21_4_6_3_k);
1058 TEST_CLAUSE(21_4_6_4);
1059 TEST_CLAUSE(21_4_6_5);
1060 TEST_CLAUSE(21_4_6_6);
1061 TEST_CLAUSE(21_4_6_7);
1062 TEST_CLAUSE(21_4_6_8);
1063 TEST_CLAUSE(21_4_7_1);
1065 TEST_CLAUSE(21_4_7_2_a);
1066 TEST_CLAUSE(21_4_7_2_a1);
1067 TEST_CLAUSE(21_4_7_2_a2);
1068 TEST_CLAUSE(21_4_7_2_b);
1069 TEST_CLAUSE(21_4_7_2_b1);
1070 TEST_CLAUSE(21_4_7_2_b2);
1071 TEST_CLAUSE(21_4_7_2_c);
1072 TEST_CLAUSE(21_4_7_2_c1);
1073 TEST_CLAUSE(21_4_7_2_c2);
1074 TEST_CLAUSE(21_4_7_2_d);
1075 TEST_CLAUSE(21_4_7_3_a);
1076 TEST_CLAUSE(21_4_7_3_b);
1077 TEST_CLAUSE(21_4_7_3_c);
1078 TEST_CLAUSE(21_4_7_3_d);
1079 TEST_CLAUSE(21_4_7_4_a);
1080 TEST_CLAUSE(21_4_7_4_b);
1081 TEST_CLAUSE(21_4_7_4_c);
1082 TEST_CLAUSE(21_4_7_4_d);
1083 TEST_CLAUSE(21_4_7_5_a);
1084 TEST_CLAUSE(21_4_7_5_b);
1085 TEST_CLAUSE(21_4_7_5_c);
1086 TEST_CLAUSE(21_4_7_5_d);
1087 TEST_CLAUSE(21_4_7_6_a);
1088 TEST_CLAUSE(21_4_7_6_b);
1089 TEST_CLAUSE(21_4_7_6_c);
1090 TEST_CLAUSE(21_4_7_6_d);
1091 TEST_CLAUSE(21_4_7_7_a);
1092 TEST_CLAUSE(21_4_7_7_b);
1093 TEST_CLAUSE(21_4_7_7_c);
1094 TEST_CLAUSE(21_4_7_7_d);
1095 TEST_CLAUSE(21_4_7_8);
1096 TEST_CLAUSE(21_4_7_9_a);
1097 TEST_CLAUSE(21_4_7_9_b);
1098 TEST_CLAUSE(21_4_7_9_c);
1099 TEST_CLAUSE(21_4_7_9_d);
1100 TEST_CLAUSE(21_4_7_9_e);
1101 TEST_CLAUSE(21_4_8_1_a);
1102 TEST_CLAUSE(21_4_8_1_b);
1103 TEST_CLAUSE(21_4_8_1_c);
1104 TEST_CLAUSE(21_4_8_1_d);
1105 TEST_CLAUSE(21_4_8_1_e);
1106 TEST_CLAUSE(21_4_8_1_f);
1107 TEST_CLAUSE(21_4_8_1_g);
1108 TEST_CLAUSE(21_4_8_1_h);
1109 TEST_CLAUSE(21_4_8_1_i);
1110 TEST_CLAUSE(21_4_8_1_j);
1111 TEST_CLAUSE(21_4_8_1_k);
1112 TEST_CLAUSE(21_4_8_1_l);
1113 TEST_CLAUSE(21_4_8_9_a);
1116 TEST(FBString, testGetline) {
1118 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan \n\
1119 elit ut urna consectetur in sagittis mi auctor. Nulla facilisi. In nec \n\
1120 dolor leo, vitae imperdiet neque. Donec ut erat mauris, a faucibus \n\
1121 elit. Integer consectetur gravida augue, sit amet mattis mauris auctor \n\
1122 sed. Morbi congue libero eu nunc sodales adipiscing. In lectus nunc, \n\
1123 vulputate a fringilla at, venenatis quis justo. Proin eu velit \n\
1124 nibh. Maecenas vitae tellus eros. Pellentesque habitant morbi \n\
1125 tristique senectus et netus et malesuada fames ac turpis \n\
1126 egestas. Vivamus faucibus feugiat consequat. Donec fermentum neque sit \n\
1127 amet ligula suscipit porta. Phasellus facilisis felis in purus luctus \n\
1128 quis posuere leo tempor. Nam nunc purus, luctus a pharetra ut, \n\
1129 placerat at dui. Donec imperdiet, diam quis convallis pulvinar, dui \n\
1130 est commodo lorem, ut tincidunt diam nibh et nibh. Maecenas nec velit \n\
1131 massa, ut accumsan magna. Donec imperdiet tempor nisi et \n\
1132 laoreet. Phasellus lectus quam, ultricies ut tincidunt in, dignissim \n\
1133 id eros. Mauris vulputate tortor nec neque pellentesque sagittis quis \n\
1134 sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam.";
1137 boost::split(v, s1, boost::is_any_of("\n"));
1139 istringstream input(s1);
1142 EXPECT_TRUE(!getline(input, line).fail());
1143 EXPECT_EQ(line, *i);
1148 TEST(FBString, testMoveCtor) {
1149 // Move constructor. Make sure we allocate a large string, so the
1150 // small string optimization doesn't kick in.
1151 auto size = random(100, 2000);
1152 fbstring s(size, 'a');
1153 fbstring test = std::move(s);
1154 EXPECT_TRUE(s.empty());
1155 EXPECT_EQ(size, test.size());
1158 TEST(FBString, testMoveAssign) {
1159 // Move constructor. Make sure we allocate a large string, so the
1160 // small string optimization doesn't kick in.
1161 auto size = random(100, 2000);
1162 fbstring s(size, 'a');
1164 test = std::move(s);
1165 EXPECT_TRUE(s.empty());
1166 EXPECT_EQ(size, test.size());
1169 TEST(FBString, testMoveOperatorPlusLhs) {
1170 // Make sure we allocate a large string, so the
1171 // small string optimization doesn't kick in.
1172 auto size1 = random(100, 2000);
1173 auto size2 = random(100, 2000);
1174 fbstring s1(size1, 'a');
1175 fbstring s2(size2, 'b');
1177 test = std::move(s1) + s2;
1178 EXPECT_TRUE(s1.empty());
1179 EXPECT_EQ(size1 + size2, test.size());
1182 TEST(FBString, testMoveOperatorPlusRhs) {
1183 // Make sure we allocate a large string, so the
1184 // small string optimization doesn't kick in.
1185 auto size1 = random(100, 2000);
1186 auto size2 = random(100, 2000);
1187 fbstring s1(size1, 'a');
1188 fbstring s2(size2, 'b');
1190 test = s1 + std::move(s2);
1191 EXPECT_EQ(size1 + size2, test.size());
1194 // The GNU C++ standard library throws an std::logic_error when an std::string
1195 // is constructed with a null pointer. Verify that we mirror this behavior.
1197 // N.B. We behave this way even if the C++ library being used is something
1198 // other than libstdc++. Someday if we deem it important to present
1199 // identical undefined behavior for other platforms, we can re-visit this.
1200 TEST(FBString, testConstructionFromLiteralZero) {
1201 EXPECT_THROW(fbstring s(0), std::logic_error);
1204 TEST(FBString, testFixedBugs) {
1206 fbstring str(1337, 'f');
1210 EXPECT_EQ(str.front(), 'f');
1213 fbstring str(1337, 'f');
1214 for (int i = 0; i < 2; ++i) {
1217 EXPECT_EQ(cp.c_str()[cp.size()], '\0');
1223 fbstring str(1337, 'f');
1228 fbstring str(1337, 'f');
1234 folly::basic_fbstring<wchar_t> s;
1235 EXPECT_EQ(0, s.size());
1238 fbstring str(1337, 'f');
1239 std::swap(str, str);
1240 EXPECT_EQ(1337, str.size());
1242 { // D1012196, --allocator=malloc
1243 fbstring str(128, 'f');
1244 str.clear(); // Empty medium string.
1245 fbstring copy(str); // Medium string of 0 capacity.
1246 copy.push_back('b');
1247 EXPECT_GE(copy.capacity(), 1);
1251 s1.reserve(8); // Trigger the optimized code path.
1252 auto test1 = '\0' + std::move(s1);
1253 EXPECT_EQ(2, test1.size());
1255 fbstring s2(1, '\0');
1257 auto test2 = "a" + std::move(s2);
1258 EXPECT_EQ(2, test2.size());
1262 TEST(FBString, findWithNpos) {
1263 fbstring fbstr("localhost:80");
1264 EXPECT_EQ(fbstring::npos, fbstr.find(":", fbstring::npos));
1267 TEST(FBString, testHash) {
1274 std::hash<fbstring> hashfunc;
1275 EXPECT_NE(hashfunc(a), hashfunc(b));
1278 TEST(FBString, testFrontBack) {
1279 fbstring str("hello");
1280 EXPECT_EQ(str.front(), 'h');
1281 EXPECT_EQ(str.back(), 'o');
1283 EXPECT_EQ(str.front(), 'H');
1285 EXPECT_EQ(str.back(), 'O');
1286 EXPECT_EQ(str, "HellO");
1289 TEST(FBString, noexcept) {
1290 EXPECT_TRUE(noexcept(fbstring()));
1292 EXPECT_FALSE(noexcept(fbstring(x)));
1293 EXPECT_TRUE(noexcept(fbstring(std::move(x))));
1295 EXPECT_FALSE(noexcept(y = x));
1296 EXPECT_TRUE(noexcept(y = std::move(x)));
1299 TEST(FBString, iomanip) {
1301 fbstring fbstr("Hello");
1303 ss << setw(6) << fbstr;
1304 EXPECT_EQ(ss.str(), " Hello");
1307 ss << left << setw(6) << fbstr;
1308 EXPECT_EQ(ss.str(), "Hello ");
1311 ss << right << setw(6) << fbstr;
1312 EXPECT_EQ(ss.str(), " Hello");
1315 ss << setw(4) << fbstr;
1316 EXPECT_EQ(ss.str(), "Hello");
1319 ss << setfill('^') << setw(6) << fbstr;
1320 EXPECT_EQ(ss.str(), "^Hello");
1324 TEST(FBString, rvalueIterators) {
1325 // you cannot take &* of a move-iterator, so use that for testing
1326 fbstring s = "base";
1327 fbstring r = "hello";
1328 r.replace(r.begin(), r.end(),
1329 make_move_iterator(s.begin()), make_move_iterator(s.end()));
1330 EXPECT_EQ("base", r);
1332 // The following test is probably not required by the standard.
1333 // i.e. this could be in the realm of undefined behavior.
1334 fbstring b = "123abcXYZ";
1335 auto ait = b.begin() + 3;
1336 auto Xit = b.begin() + 6;
1337 b.replace(ait, b.end(), b.begin(), Xit);
1338 EXPECT_EQ("123123abc", b); // if things go wrong, you'd get "123123123"
1341 TEST(FBString, moveTerminator) {
1342 // The source of a move must remain in a valid state
1343 fbstring s(100, 'x'); // too big to be in-situ
1347 EXPECT_EQ(0, s.size());
1348 EXPECT_EQ('\0', *s.c_str());
1353 * t8968589: Clang 3.7 refused to compile w/ certain constructors (specifically
1354 * those that were "explicit" and had a defaulted parameter, if they were used
1355 * in structs which were default-initialized). Exercise these just to ensure
1358 * In diff D2632953 the old constructor:
1359 * explicit basic_fbstring(const A& a = A()) noexcept;
1361 * was split into these two, as a workaround:
1362 * basic_fbstring() noexcept;
1363 * explicit basic_fbstring(const A& a) noexcept;
1366 struct TestStructDefaultAllocator {
1367 folly::basic_fbstring<char> stringMember;
1371 struct TestStructWithAllocator {
1372 folly::basic_fbstring<char, std::char_traits<char>, A> stringMember;
1375 std::atomic<size_t> allocatorConstructedCount(0);
1376 struct TestStructStringAllocator : std::allocator<char> {
1377 TestStructStringAllocator() {
1378 ++ allocatorConstructedCount;
1384 TEST(FBStringCtorTest, DefaultInitStructDefaultAlloc) {
1385 TestStructDefaultAllocator t1 { };
1386 EXPECT_TRUE(t1.stringMember.empty());
1389 TEST(FBStringCtorTest, DefaultInitStructAlloc) {
1390 EXPECT_EQ(allocatorConstructedCount.load(), 0);
1391 TestStructWithAllocator<TestStructStringAllocator> t2;
1392 EXPECT_TRUE(t2.stringMember.empty());
1393 EXPECT_EQ(allocatorConstructedCount.load(), 1);