2 * Copyright 2016 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;
42 static const int seed = folly::randomNumberSeed();
43 typedef boost::mt19937 RandomT;
44 static RandomT rng(seed);
45 static const size_t maxString = 100;
46 static const bool avoidAliasing = true;
48 template <class Integral1, class Integral2>
49 Integral2 random(Integral1 low, Integral2 up) {
50 boost::uniform_int<> range(low, up);
54 template <class String>
55 void randomString(String* toFill, unsigned int maxSize = 1000) {
57 toFill->resize(random(0, maxSize));
58 FOR_EACH (i, *toFill) {
59 *i = random('a', 'z');
63 template <class String, class Integral>
64 void Num2String(String& str, Integral n) {
66 std::string tmp = folly::to<std::string>(n);
67 str = String(tmp.begin(), tmp.end());
70 std::list<char> RandomList(unsigned int maxSize) {
71 std::list<char> lst(random(0u, maxSize));
72 std::list<char>::iterator i = lst.begin();
73 for (; i != lst.end(); ++i) {
74 *i = random('a', 'z');
80 ////////////////////////////////////////////////////////////////////////////////
82 ////////////////////////////////////////////////////////////////////////////////
84 template <class String> void clause11_21_4_2_a(String & test) {
85 test.String::~String();
88 template <class String> void clause11_21_4_2_b(String & test) {
90 assert(test2 == test);
92 template <class String> void clause11_21_4_2_c(String & test) {
93 // Test move constructor. There is a more specialized test, see
94 // TEST(FBString, testMoveCtor)
96 String test2(std::move(donor));
97 EXPECT_EQ(test2, test);
98 // Technically not required, but all implementations that actually
99 // support move will move large strings. Make a guess for 128 as the
100 // maximum small string optimization that's reasonable.
101 EXPECT_LE(donor.size(), 128);
103 template <class String> void clause11_21_4_2_d(String & test) {
104 // Copy constructor with position and length
105 const size_t pos = random(0, test.size());
106 String s(test, pos, random(0, 9)
107 ? random(0, (size_t)(test.size() - pos))
108 : String::npos); // test for npos, too, in 10% of the cases
111 template <class String> void clause11_21_4_2_e(String & test) {
112 // Constructor from char*, size_t
114 pos = random(0, test.size()),
115 n = random(0, test.size() - pos);
116 String before(test.data(), test.size());
117 String s(test.c_str() + pos, n);
118 String after(test.data(), test.size());
119 EXPECT_EQ(before, after);
122 template <class String> void clause11_21_4_2_f(String & test) {
123 // Constructor from char*
124 const size_t pos = random(0, test.size());
125 String before(test.data(), test.size());
126 String s(test.c_str() + pos);
127 String after(test.data(), test.size());
128 EXPECT_EQ(before, after);
131 template <class String> void clause11_21_4_2_g(String & test) {
132 // Constructor from size_t, char
133 const size_t n = random(0, test.size());
134 const auto c = test.front();
137 template <class String> void clause11_21_4_2_h(String & test) {
138 // Constructors from various iterator pairs
139 // Constructor from char*, char*
140 String s1(test.begin(), test.end());
142 String s2(test.data(), test.data() + test.size());
144 // Constructor from other iterators
146 for (auto c : test) lst.push_back(c);
147 String s3(lst.begin(), lst.end());
149 // Constructor from wchar_t iterators
150 std::list<wchar_t> lst1;
151 for (auto c : test) lst1.push_back(c);
152 String s4(lst1.begin(), lst1.end());
154 // Constructor from wchar_t pointers
158 fbstring s5(t, t + 2);;
161 template <class String> void clause11_21_4_2_i(String & test) {
162 // From initializer_list<char>
163 std::initializer_list<typename String::value_type>
164 il = { 'h', 'e', 'l', 'l', 'o' };
168 template <class String> void clause11_21_4_2_j(String & test) {
169 // Assignment from const String&
170 auto size = random(0, 2000);
171 String s(size, '\0');
172 EXPECT_EQ(s.size(), size);
173 FOR_EACH_RANGE (i, 0, s.size()) {
174 s[i] = random('a', 'z');
178 template <class String> void clause11_21_4_2_k(String & test) {
179 // Assignment from String&&
180 auto size = random(0, 2000);
181 String s(size, '\0');
182 EXPECT_EQ(s.size(), size);
183 FOR_EACH_RANGE (i, 0, s.size()) {
184 s[i] = random('a', 'z');
187 if (typeid(String) == typeid(fbstring)) {
188 EXPECT_LE(s.size(), 128);
191 template <class String> void clause11_21_4_2_l(String & test) {
192 // Assignment from char*
193 String s(random(0, 1000), '\0');
195 for (; i != s.size(); ++i) {
196 s[i] = random('a', 'z');
200 template <class String> void clause11_21_4_2_lprime(String & test) {
202 const size_t pos = random(0, test.size());
204 test = String(test.c_str() + pos);
206 test = test.c_str() + pos;
209 template <class String> void clause11_21_4_2_m(String & test) {
210 // Assignment from char
211 test = random('a', 'z');
213 template <class String> void clause11_21_4_2_n(String & test) {
214 // Assignment from initializer_list<char>
215 initializer_list<typename String::value_type>
216 il = { 'h', 'e', 'l', 'l', 'o' };
220 template <class String> void clause11_21_4_3(String & test) {
221 // Iterators. The code below should leave test unchanged
222 EXPECT_EQ(test.size(), test.end() - test.begin());
223 EXPECT_EQ(test.size(), test.rend() - test.rbegin());
224 EXPECT_EQ(test.size(), test.cend() - test.cbegin());
225 EXPECT_EQ(test.size(), test.crend() - test.crbegin());
227 auto s = test.size();
228 test.resize(test.end() - test.begin());
229 EXPECT_EQ(s, test.size());
230 test.resize(test.rend() - test.rbegin());
231 EXPECT_EQ(s, test.size());
234 template <class String> void clause11_21_4_4(String & test) {
235 // exercise capacity, size, max_size
236 EXPECT_EQ(test.size(), test.length());
237 EXPECT_LE(test.size(), test.max_size());
238 EXPECT_LE(test.capacity(), test.max_size());
239 EXPECT_LE(test.size(), test.capacity());
241 // exercise shrink_to_fit. Nonbinding request so we can't really do
242 // much beyond calling it.
244 copy.reserve(copy.capacity() * 3);
245 copy.shrink_to_fit();
246 EXPECT_EQ(copy, test);
249 string empty("empty");
250 string notempty("not empty");
251 if (test.empty()) test = String(empty.begin(), empty.end());
252 else test = String(notempty.begin(), notempty.end());
255 template <class String> void clause11_21_4_5(String & test) {
256 // exercise element access
258 EXPECT_EQ(test[0], test.front());
259 EXPECT_EQ(test[test.size() - 1], test.back());
260 auto const i = random(0, test.size() - 1);
261 EXPECT_EQ(test[i], test.at(i));
266 template <class String> void clause11_21_4_6_1(String & test) {
267 // 21.3.5 modifiers (+=)
269 randomString(&test1);
270 assert(test1.size() == char_traits
271 <typename String::value_type>::length(test1.c_str()));
272 auto len = test.size();
274 EXPECT_EQ(test.size(), test1.size() + len);
275 FOR_EACH_RANGE (i, 0, test1.size()) {
276 EXPECT_EQ(test[len + i], test1[i]);
278 // aliasing modifiers
280 auto dt = test2.data();
281 auto sz = test.c_str();
283 EXPECT_EQ(memcmp(sz, dt, len), 0);
284 String copy(test.data(), test.size());
285 EXPECT_EQ(char_traits
286 <typename String::value_type>::length(test.c_str()), len);
289 EXPECT_EQ(test.size(), 2 * len);
290 EXPECT_EQ(char_traits
291 <typename String::value_type>::length(test.c_str()), 2 * len);
292 FOR_EACH_RANGE (i, 0, len) {
293 EXPECT_EQ(test[i], copy[i]);
294 EXPECT_EQ(test[i], test[len + i]);
297 EXPECT_EQ(char_traits
298 <typename String::value_type>::length(test.c_str()), len);
300 auto const pos = random(0, test.size());
301 EXPECT_EQ(char_traits
302 <typename String::value_type>::length(test.c_str() + pos), len - pos);
304 String addMe(test.c_str() + pos);
305 EXPECT_EQ(addMe.size(), len - pos);
308 test += test.c_str() + pos;
310 EXPECT_EQ(test.size(), 2 * len - pos);
313 test += random('a', 'z');
314 EXPECT_EQ(test.size(), len + 1);
316 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
320 template <class String> void clause11_21_4_6_2(String & test) {
321 // 21.3.5 modifiers (append, push_back)
324 // Test with a small string first
325 char c = random('a', 'z');
327 EXPECT_EQ(s[s.size() - 1], c);
328 EXPECT_EQ(s.size(), 1);
329 s.resize(s.size() - 1);
331 randomString(&s, maxString);
333 randomString(&s, maxString);
334 test.append(s, random(0, s.size()), random(0, maxString));
335 randomString(&s, maxString);
336 test.append(s.c_str(), random(0, s.size()));
337 randomString(&s, maxString);
338 test.append(s.c_str());
339 test.append(random(0, maxString), random('a', 'z'));
340 std::list<char> lst(RandomList(maxString));
341 test.append(lst.begin(), lst.end());
342 c = random('a', 'z');
344 EXPECT_EQ(test[test.size() - 1], c);
346 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
350 template <class String> void clause11_21_4_6_3_a(String & test) {
357 test.assign(std::move(s));
358 if (typeid(String) == typeid(fbstring)) {
359 EXPECT_LE(s.size(), 128);
363 template <class String> void clause11_21_4_6_3_b(String & test) {
366 randomString(&s, maxString);
367 test.assign(s, random(0, s.size()), random(0, maxString));
370 template <class String> void clause11_21_4_6_3_c(String & test) {
373 randomString(&s, maxString);
374 test.assign(s.c_str(), random(0, s.size()));
377 template <class String> void clause11_21_4_6_3_d(String & test) {
380 randomString(&s, maxString);
381 test.assign(s.c_str());
384 template <class String> void clause11_21_4_6_3_e(String & test) {
387 randomString(&s, maxString);
388 test.assign(random(0, maxString), random('a', 'z'));
391 template <class String> void clause11_21_4_6_3_f(String & test) {
392 // assign from bidirectional iterator
393 std::list<char> lst(RandomList(maxString));
394 test.assign(lst.begin(), lst.end());
397 template <class String> void clause11_21_4_6_3_g(String & test) {
398 // assign from aliased source
402 template <class String> void clause11_21_4_6_3_h(String & test) {
403 // assign from aliased source
404 test.assign(test, random(0, test.size()), random(0, maxString));
407 template <class String> void clause11_21_4_6_3_i(String & test) {
408 // assign from aliased source
409 test.assign(test.c_str(), random(0, test.size()));
412 template <class String> void clause11_21_4_6_3_j(String & test) {
413 // assign from aliased source
414 test.assign(test.c_str());
417 template <class String> void clause11_21_4_6_3_k(String & test) {
418 // assign from initializer_list
419 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
423 template <class String> void clause11_21_4_6_4(String & test) {
426 randomString(&s, maxString);
427 test.insert(random(0, test.size()), s);
428 randomString(&s, maxString);
429 test.insert(random(0, test.size()),
430 s, random(0, s.size()),
431 random(0, maxString));
432 randomString(&s, maxString);
433 test.insert(random(0, test.size()),
434 s.c_str(), random(0, s.size()));
435 randomString(&s, maxString);
436 test.insert(random(0, test.size()), s.c_str());
437 test.insert(random(0, test.size()),
438 random(0, maxString), random('a', 'z'));
439 typename String::size_type pos = random(0, test.size());
440 typename String::iterator res =
441 test.insert(test.begin() + pos, random('a', 'z'));
442 EXPECT_EQ(res - test.begin(), pos);
443 std::list<char> lst(RandomList(maxString));
444 pos = random(0, test.size());
445 // Uncomment below to see a bug in gcc
446 /*res = */test.insert(test.begin() + pos, lst.begin(), lst.end());
447 // insert from initializer_list
448 initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
449 pos = random(0, test.size());
450 // Uncomment below to see a bug in gcc
451 /*res = */test.insert(test.begin() + pos, il);
453 // Test with actual input iterators
455 ss << "hello cruel world";
456 auto i = istream_iterator<char>(ss);
457 test.insert(test.begin(), i, istream_iterator<char>());
460 template <class String> void clause11_21_4_6_5(String & test) {
461 // erase and pop_back
463 test.erase(random(0, test.size()), random(0, maxString));
466 // TODO: is erase(end()) allowed?
467 test.erase(test.begin() + random(0, test.size() - 1));
470 auto const i = test.begin() + random(0, test.size());
471 if (i != test.end()) {
472 test.erase(i, i + random(0, size_t(test.end() - i)));
476 // Can't test pop_back with std::string, doesn't support it yet.
481 template <class String> void clause11_21_4_6_6(String & test) {
482 auto pos = random(0, test.size());
484 test.replace(pos, random(0, test.size() - pos),
487 test.replace(pos, random(0, test.size() - pos), test);
489 pos = random(0, test.size());
491 randomString(&s, maxString);
492 test.replace(pos, pos + random(0, test.size() - pos), s);
493 auto pos1 = random(0, test.size());
494 auto pos2 = random(0, test.size());
496 test.replace(pos1, pos1 + random(0, test.size() - pos1),
498 pos2, pos2 + random(0, test.size() - pos2));
500 test.replace(pos1, pos1 + random(0, test.size() - pos1),
501 test, pos2, pos2 + random(0, test.size() - pos2));
503 pos1 = random(0, test.size());
505 randomString(&str, maxString);
506 pos2 = random(0, str.size());
507 test.replace(pos1, pos1 + random(0, test.size() - pos1),
508 str, pos2, pos2 + random(0, str.size() - pos2));
509 pos = random(0, test.size());
511 test.replace(pos, random(0, test.size() - pos),
512 String(test).c_str(), test.size());
514 test.replace(pos, random(0, test.size() - pos),
515 test.c_str(), test.size());
517 pos = random(0, test.size());
518 randomString(&str, maxString);
519 test.replace(pos, pos + random(0, test.size() - pos),
520 str.c_str(), str.size());
521 pos = random(0, test.size());
522 randomString(&str, maxString);
523 test.replace(pos, pos + random(0, test.size() - pos),
525 pos = random(0, test.size());
526 test.replace(pos, random(0, test.size() - pos),
527 random(0, maxString), random('a', 'z'));
528 pos = random(0, test.size());
530 auto newString = String(test);
533 test.begin() + pos + random(0, test.size() - pos),
538 test.begin() + pos + random(0, test.size() - pos),
541 pos = random(0, test.size());
543 auto newString = String(test);
546 test.begin() + pos + random(0, test.size() - pos),
548 test.size() - random(0, test.size()));
552 test.begin() + pos + random(0, test.size() - pos),
554 test.size() - random(0, test.size()));
556 pos = random(0, test.size());
557 auto const n = random(0, test.size() - pos);
558 typename String::iterator b = test.begin();
560 randomString(&str1, maxString);
561 const String & str3 = str1;
562 const typename String::value_type* ss = str3.c_str();
567 pos = random(0, test.size());
570 test.begin() + pos + random(0, test.size() - pos),
571 random(0, maxString), random('a', 'z'));
574 template <class String> void clause11_21_4_6_7(String & test) {
575 std::vector<typename String::value_type>
576 vec(random(0, maxString));
580 test.copy(vec.data(), vec.size(), random(0, test.size()));
583 template <class String> void clause11_21_4_6_8(String & test) {
585 randomString(&s, maxString);
589 template <class String> void clause11_21_4_7_1(String & test) {
590 // 21.3.6 string operations
591 // exercise c_str() and data()
592 assert(test.c_str() == test.data());
593 // exercise get_allocator()
595 randomString(&s, maxString);
596 DCHECK(test.get_allocator() == s.get_allocator());
599 template <class String> void clause11_21_4_7_2_a(String & test) {
600 String str = test.substr(
601 random(0, test.size()),
602 random(0, test.size()));
603 Num2String(test, test.find(str, random(0, test.size())));
606 template <class String> void clause11_21_4_7_2_a1(String & test) {
607 String str = String(test).substr(
608 random(0, test.size()),
609 random(0, test.size()));
610 Num2String(test, test.find(str, random(0, test.size())));
613 template <class String> void clause11_21_4_7_2_a2(String & test) {
614 auto const& cTest = test;
615 String str = cTest.substr(
616 random(0, test.size()),
617 random(0, test.size()));
618 Num2String(test, test.find(str, random(0, test.size())));
621 template <class String> void clause11_21_4_7_2_b(String & test) {
622 auto from = random(0, test.size());
623 auto length = random(0, test.size() - from);
624 String str = test.substr(from, length);
625 Num2String(test, test.find(str.c_str(),
626 random(0, test.size()),
627 random(0, str.size())));
630 template <class String> void clause11_21_4_7_2_b1(String & test) {
631 auto from = random(0, test.size());
632 auto length = random(0, test.size() - from);
633 String str = String(test).substr(from, length);
634 Num2String(test, test.find(str.c_str(),
635 random(0, test.size()),
636 random(0, str.size())));
639 template <class String> void clause11_21_4_7_2_b2(String & test) {
640 auto from = random(0, test.size());
641 auto length = random(0, test.size() - from);
642 const auto& cTest = test;
643 String str = cTest.substr(from, length);
644 Num2String(test, test.find(str.c_str(),
645 random(0, test.size()),
646 random(0, str.size())));
649 template <class String> void clause11_21_4_7_2_c(String & test) {
650 String str = test.substr(
651 random(0, test.size()),
652 random(0, test.size()));
653 Num2String(test, test.find(str.c_str(),
654 random(0, test.size())));
657 template <class String> void clause11_21_4_7_2_c1(String & test) {
658 String str = String(test).substr(
659 random(0, test.size()),
660 random(0, test.size()));
661 Num2String(test, test.find(str.c_str(),
662 random(0, test.size())));
665 template <class String> void clause11_21_4_7_2_c2(String & test) {
666 const auto& cTest = test;
667 String str = cTest.substr(
668 random(0, test.size()),
669 random(0, test.size()));
670 Num2String(test, test.find(str.c_str(),
671 random(0, test.size())));
674 template <class String> void clause11_21_4_7_2_d(String & test) {
675 Num2String(test, test.find(
677 random(0, test.size())));
680 template <class String> void clause11_21_4_7_3_a(String & test) {
681 String str = test.substr(
682 random(0, test.size()),
683 random(0, test.size()));
684 Num2String(test, test.rfind(str, random(0, test.size())));
687 template <class String> void clause11_21_4_7_3_b(String & test) {
688 String str = test.substr(
689 random(0, test.size()),
690 random(0, test.size()));
691 Num2String(test, test.rfind(str.c_str(),
692 random(0, test.size()),
693 random(0, str.size())));
696 template <class String> void clause11_21_4_7_3_c(String & test) {
697 String str = test.substr(
698 random(0, test.size()),
699 random(0, test.size()));
700 Num2String(test, test.rfind(str.c_str(),
701 random(0, test.size())));
704 template <class String> void clause11_21_4_7_3_d(String & test) {
705 Num2String(test, test.rfind(
707 random(0, test.size())));
710 template <class String> void clause11_21_4_7_4_a(String & test) {
712 randomString(&str, maxString);
713 Num2String(test, test.find_first_of(str,
714 random(0, test.size())));
717 template <class String> void clause11_21_4_7_4_b(String & test) {
719 randomString(&str, maxString);
720 Num2String(test, test.find_first_of(str.c_str(),
721 random(0, test.size()),
722 random(0, str.size())));
725 template <class String> void clause11_21_4_7_4_c(String & test) {
727 randomString(&str, maxString);
728 Num2String(test, test.find_first_of(str.c_str(),
729 random(0, test.size())));
732 template <class String> void clause11_21_4_7_4_d(String & test) {
733 Num2String(test, test.find_first_of(
735 random(0, test.size())));
738 template <class String> void clause11_21_4_7_5_a(String & test) {
740 randomString(&str, maxString);
741 Num2String(test, test.find_last_of(str,
742 random(0, test.size())));
745 template <class String> void clause11_21_4_7_5_b(String & test) {
747 randomString(&str, maxString);
748 Num2String(test, test.find_last_of(str.c_str(),
749 random(0, test.size()),
750 random(0, str.size())));
753 template <class String> void clause11_21_4_7_5_c(String & test) {
755 randomString(&str, maxString);
756 Num2String(test, test.find_last_of(str.c_str(),
757 random(0, test.size())));
760 template <class String> void clause11_21_4_7_5_d(String & test) {
761 Num2String(test, test.find_last_of(
763 random(0, test.size())));
766 template <class String> void clause11_21_4_7_6_a(String & test) {
768 randomString(&str, maxString);
769 Num2String(test, test.find_first_not_of(str,
770 random(0, test.size())));
773 template <class String> void clause11_21_4_7_6_b(String & test) {
775 randomString(&str, maxString);
776 Num2String(test, test.find_first_not_of(str.c_str(),
777 random(0, test.size()),
778 random(0, str.size())));
781 template <class String> void clause11_21_4_7_6_c(String & test) {
783 randomString(&str, maxString);
784 Num2String(test, test.find_first_not_of(str.c_str(),
785 random(0, test.size())));
788 template <class String> void clause11_21_4_7_6_d(String & test) {
789 Num2String(test, test.find_first_not_of(
791 random(0, test.size())));
794 template <class String> void clause11_21_4_7_7_a(String & test) {
796 randomString(&str, maxString);
797 Num2String(test, test.find_last_not_of(str,
798 random(0, test.size())));
801 template <class String> void clause11_21_4_7_7_b(String & test) {
803 randomString(&str, maxString);
804 Num2String(test, test.find_last_not_of(str.c_str(),
805 random(0, test.size()),
806 random(0, str.size())));
809 template <class String> void clause11_21_4_7_7_c(String & test) {
811 randomString(&str, maxString);
812 Num2String(test, test.find_last_not_of(str.c_str(),
813 random(0, test.size())));
816 template <class String> void clause11_21_4_7_7_d(String & test) {
817 Num2String(test, test.find_last_not_of(
819 random(0, test.size())));
822 template <class String> void clause11_21_4_7_8(String & test) {
823 test = test.substr(random(0, test.size()), random(0, test.size()));
826 template <class String> void clause11_21_4_7_9_a(String & test) {
828 randomString(&s, maxString);
829 int tristate = test.compare(s);
830 if (tristate > 0) tristate = 1;
831 else if (tristate < 0) tristate = 2;
832 Num2String(test, tristate);
835 template <class String> void clause11_21_4_7_9_b(String & test) {
837 randomString(&s, maxString);
838 int tristate = test.compare(
839 random(0, test.size()),
840 random(0, test.size()),
842 if (tristate > 0) tristate = 1;
843 else if (tristate < 0) tristate = 2;
844 Num2String(test, tristate);
847 template <class String> void clause11_21_4_7_9_c(String & test) {
849 randomString(&str, maxString);
850 int tristate = test.compare(
851 random(0, test.size()),
852 random(0, test.size()),
854 random(0, str.size()),
855 random(0, str.size()));
856 if (tristate > 0) tristate = 1;
857 else if (tristate < 0) tristate = 2;
858 Num2String(test, tristate);
861 template <class String> void clause11_21_4_7_9_d(String & test) {
863 randomString(&s, maxString);
864 int tristate = test.compare(s.c_str());
865 if (tristate > 0) tristate = 1;
866 else if (tristate < 0) tristate = 2;
867 Num2String(test, tristate);
870 template <class String> void clause11_21_4_7_9_e(String & test) {
872 randomString(&str, maxString);
873 int tristate = test.compare(
874 random(0, test.size()),
875 random(0, test.size()),
877 random(0, str.size()));
878 if (tristate > 0) tristate = 1;
879 else if (tristate < 0) tristate = 2;
880 Num2String(test, tristate);
883 template <class String> void clause11_21_4_8_1_a(String & test) {
885 randomString(&s1, maxString);
887 randomString(&s2, maxString);
891 template <class String> void clause11_21_4_8_1_b(String & test) {
893 randomString(&s1, maxString);
895 randomString(&s2, maxString);
896 test = move(s1) + s2;
899 template <class String> void clause11_21_4_8_1_c(String & test) {
901 randomString(&s1, maxString);
903 randomString(&s2, maxString);
904 test = s1 + move(s2);
907 template <class String> void clause11_21_4_8_1_d(String & test) {
909 randomString(&s1, maxString);
911 randomString(&s2, maxString);
912 test = move(s1) + move(s2);
915 template <class String> void clause11_21_4_8_1_e(String & test) {
917 randomString(&s, maxString);
919 randomString(&s1, maxString);
920 test = s.c_str() + s1;
923 template <class String> void clause11_21_4_8_1_f(String & test) {
925 randomString(&s, maxString);
927 randomString(&s1, maxString);
928 test = s.c_str() + move(s1);
931 template <class String> void clause11_21_4_8_1_g(String & test) {
933 randomString(&s, maxString);
934 test = typename String::value_type(random('a', 'z')) + s;
937 template <class String> void clause11_21_4_8_1_h(String & test) {
939 randomString(&s, maxString);
940 test = typename String::value_type(random('a', 'z')) + move(s);
943 template <class String> void clause11_21_4_8_1_i(String & test) {
945 randomString(&s, maxString);
947 randomString(&s1, maxString);
948 test = s + s1.c_str();
951 template <class String> void clause11_21_4_8_1_j(String & test) {
953 randomString(&s, maxString);
955 randomString(&s1, maxString);
956 test = move(s) + s1.c_str();
959 template <class String> void clause11_21_4_8_1_k(String & test) {
961 randomString(&s, maxString);
962 test = s + typename String::value_type(random('a', 'z'));
965 template <class String> void clause11_21_4_8_1_l(String & test) {
967 randomString(&s, maxString);
969 randomString(&s1, maxString);
970 test = move(s) + s1.c_str();
973 // Numbering here is from C++11
974 template <class String> void clause11_21_4_8_9_a(String & test) {
975 basic_stringstream<typename String::value_type> stst(test.c_str());
983 TEST(FBString, testAllClauses) {
984 EXPECT_TRUE(1) << "Starting with seed: " << seed;
987 #if FOLLY_HAVE_WCHAR_SUPPORT
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;
1002 #if FOLLY_HAVE_WCHAR_SUPPORT
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] << "'";
1015 #if FOLLY_HAVE_WCHAR_SUPPORT
1016 rng = RandomT(localSeed);
1018 int wret = wcslen(wc.c_str());
1019 auto mbv = std::vector<char>(wret + 1);
1020 auto mb = mbv.data();
1021 int ret = wcstombs(mb, wc.c_str(), wret + 1);
1022 if (ret == wret) mb[wret] = '\0';
1023 const char *mc = c.c_str();
1024 std::string one(mb);
1025 std::string two(mc);
1026 EXPECT_EQ(one, two);
1028 } while (++count % 100 != 0);
1031 #define TEST_CLAUSE(x) \
1033 clause11_##x<std::string>, \
1034 clause11_##x<folly::fbstring>, \
1035 clause11_##x<folly::basic_fbstring<wchar_t>>);
1037 TEST_CLAUSE(21_4_2_a);
1038 TEST_CLAUSE(21_4_2_b);
1039 TEST_CLAUSE(21_4_2_c);
1040 TEST_CLAUSE(21_4_2_d);
1041 TEST_CLAUSE(21_4_2_e);
1042 TEST_CLAUSE(21_4_2_f);
1043 TEST_CLAUSE(21_4_2_g);
1044 TEST_CLAUSE(21_4_2_h);
1045 TEST_CLAUSE(21_4_2_i);
1046 TEST_CLAUSE(21_4_2_j);
1047 TEST_CLAUSE(21_4_2_k);
1048 TEST_CLAUSE(21_4_2_l);
1049 TEST_CLAUSE(21_4_2_lprime);
1050 TEST_CLAUSE(21_4_2_m);
1051 TEST_CLAUSE(21_4_2_n);
1052 TEST_CLAUSE(21_4_3);
1053 TEST_CLAUSE(21_4_4);
1054 TEST_CLAUSE(21_4_5);
1055 TEST_CLAUSE(21_4_6_1);
1056 TEST_CLAUSE(21_4_6_2);
1057 TEST_CLAUSE(21_4_6_3_a);
1058 TEST_CLAUSE(21_4_6_3_b);
1059 TEST_CLAUSE(21_4_6_3_c);
1060 TEST_CLAUSE(21_4_6_3_d);
1061 TEST_CLAUSE(21_4_6_3_e);
1062 TEST_CLAUSE(21_4_6_3_f);
1063 TEST_CLAUSE(21_4_6_3_g);
1064 TEST_CLAUSE(21_4_6_3_h);
1065 TEST_CLAUSE(21_4_6_3_i);
1066 TEST_CLAUSE(21_4_6_3_j);
1067 TEST_CLAUSE(21_4_6_3_k);
1068 TEST_CLAUSE(21_4_6_4);
1069 TEST_CLAUSE(21_4_6_5);
1070 TEST_CLAUSE(21_4_6_6);
1071 TEST_CLAUSE(21_4_6_7);
1072 TEST_CLAUSE(21_4_6_8);
1073 TEST_CLAUSE(21_4_7_1);
1075 TEST_CLAUSE(21_4_7_2_a);
1076 TEST_CLAUSE(21_4_7_2_a1);
1077 TEST_CLAUSE(21_4_7_2_a2);
1078 TEST_CLAUSE(21_4_7_2_b);
1079 TEST_CLAUSE(21_4_7_2_b1);
1080 TEST_CLAUSE(21_4_7_2_b2);
1081 TEST_CLAUSE(21_4_7_2_c);
1082 TEST_CLAUSE(21_4_7_2_c1);
1083 TEST_CLAUSE(21_4_7_2_c2);
1084 TEST_CLAUSE(21_4_7_2_d);
1085 TEST_CLAUSE(21_4_7_3_a);
1086 TEST_CLAUSE(21_4_7_3_b);
1087 TEST_CLAUSE(21_4_7_3_c);
1088 TEST_CLAUSE(21_4_7_3_d);
1089 TEST_CLAUSE(21_4_7_4_a);
1090 TEST_CLAUSE(21_4_7_4_b);
1091 TEST_CLAUSE(21_4_7_4_c);
1092 TEST_CLAUSE(21_4_7_4_d);
1093 TEST_CLAUSE(21_4_7_5_a);
1094 TEST_CLAUSE(21_4_7_5_b);
1095 TEST_CLAUSE(21_4_7_5_c);
1096 TEST_CLAUSE(21_4_7_5_d);
1097 TEST_CLAUSE(21_4_7_6_a);
1098 TEST_CLAUSE(21_4_7_6_b);
1099 TEST_CLAUSE(21_4_7_6_c);
1100 TEST_CLAUSE(21_4_7_6_d);
1101 TEST_CLAUSE(21_4_7_7_a);
1102 TEST_CLAUSE(21_4_7_7_b);
1103 TEST_CLAUSE(21_4_7_7_c);
1104 TEST_CLAUSE(21_4_7_7_d);
1105 TEST_CLAUSE(21_4_7_8);
1106 TEST_CLAUSE(21_4_7_9_a);
1107 TEST_CLAUSE(21_4_7_9_b);
1108 TEST_CLAUSE(21_4_7_9_c);
1109 TEST_CLAUSE(21_4_7_9_d);
1110 TEST_CLAUSE(21_4_7_9_e);
1111 TEST_CLAUSE(21_4_8_1_a);
1112 TEST_CLAUSE(21_4_8_1_b);
1113 TEST_CLAUSE(21_4_8_1_c);
1114 TEST_CLAUSE(21_4_8_1_d);
1115 TEST_CLAUSE(21_4_8_1_e);
1116 TEST_CLAUSE(21_4_8_1_f);
1117 TEST_CLAUSE(21_4_8_1_g);
1118 TEST_CLAUSE(21_4_8_1_h);
1119 TEST_CLAUSE(21_4_8_1_i);
1120 TEST_CLAUSE(21_4_8_1_j);
1121 TEST_CLAUSE(21_4_8_1_k);
1122 TEST_CLAUSE(21_4_8_1_l);
1123 TEST_CLAUSE(21_4_8_9_a);
1126 TEST(FBString, testGetline) {
1128 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan \n\
1129 elit ut urna consectetur in sagittis mi auctor. Nulla facilisi. In nec \n\
1130 dolor leo, vitae imperdiet neque. Donec ut erat mauris, a faucibus \n\
1131 elit. Integer consectetur gravida augue, sit amet mattis mauris auctor \n\
1132 sed. Morbi congue libero eu nunc sodales adipiscing. In lectus nunc, \n\
1133 vulputate a fringilla at, venenatis quis justo. Proin eu velit \n\
1134 nibh. Maecenas vitae tellus eros. Pellentesque habitant morbi \n\
1135 tristique senectus et netus et malesuada fames ac turpis \n\
1136 egestas. Vivamus faucibus feugiat consequat. Donec fermentum neque sit \n\
1137 amet ligula suscipit porta. Phasellus facilisis felis in purus luctus \n\
1138 quis posuere leo tempor. Nam nunc purus, luctus a pharetra ut, \n\
1139 placerat at dui. Donec imperdiet, diam quis convallis pulvinar, dui \n\
1140 est commodo lorem, ut tincidunt diam nibh et nibh. Maecenas nec velit \n\
1141 massa, ut accumsan magna. Donec imperdiet tempor nisi et \n\
1142 laoreet. Phasellus lectus quam, ultricies ut tincidunt in, dignissim \n\
1143 id eros. Mauris vulputate tortor nec neque pellentesque sagittis quis \n\
1144 sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam.";
1147 boost::split(v, s1, boost::is_any_of("\n"));
1149 istringstream input(s1);
1152 EXPECT_TRUE(!getline(input, line).fail());
1153 EXPECT_EQ(line, *i);
1158 TEST(FBString, testMoveCtor) {
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');
1163 fbstring test = std::move(s);
1164 EXPECT_TRUE(s.empty());
1165 EXPECT_EQ(size, test.size());
1168 TEST(FBString, testMoveAssign) {
1169 // Move constructor. Make sure we allocate a large string, so the
1170 // small string optimization doesn't kick in.
1171 auto size = random(100, 2000);
1172 fbstring s(size, 'a');
1174 test = std::move(s);
1175 EXPECT_TRUE(s.empty());
1176 EXPECT_EQ(size, test.size());
1179 TEST(FBString, testMoveOperatorPlusLhs) {
1180 // Make sure we allocate a large string, so the
1181 // small string optimization doesn't kick in.
1182 auto size1 = random(100, 2000);
1183 auto size2 = random(100, 2000);
1184 fbstring s1(size1, 'a');
1185 fbstring s2(size2, 'b');
1187 test = std::move(s1) + s2;
1188 EXPECT_TRUE(s1.empty());
1189 EXPECT_EQ(size1 + size2, test.size());
1192 TEST(FBString, testMoveOperatorPlusRhs) {
1193 // Make sure we allocate a large string, so the
1194 // small string optimization doesn't kick in.
1195 auto size1 = random(100, 2000);
1196 auto size2 = random(100, 2000);
1197 fbstring s1(size1, 'a');
1198 fbstring s2(size2, 'b');
1200 test = s1 + std::move(s2);
1201 EXPECT_EQ(size1 + size2, test.size());
1204 // The GNU C++ standard library throws an std::logic_error when an std::string
1205 // is constructed with a null pointer. Verify that we mirror this behavior.
1207 // N.B. We behave this way even if the C++ library being used is something
1208 // other than libstdc++. Someday if we deem it important to present
1209 // identical undefined behavior for other platforms, we can re-visit this.
1210 TEST(FBString, testConstructionFromLiteralZero) {
1211 EXPECT_THROW(fbstring s(0), std::logic_error);
1214 TEST(FBString, testFixedBugs) {
1216 fbstring str(1337, 'f');
1220 EXPECT_EQ(str.front(), 'f');
1223 fbstring str(1337, 'f');
1224 for (int i = 0; i < 2; ++i) {
1227 EXPECT_EQ(cp.c_str()[cp.size()], '\0');
1233 fbstring str(1337, 'f');
1238 fbstring str(1337, 'f');
1244 folly::basic_fbstring<wchar_t> s;
1245 EXPECT_EQ(0, s.size());
1248 fbstring str(1337, 'f');
1249 std::swap(str, str);
1250 EXPECT_EQ(1337, str.size());
1252 { // D1012196, --allocator=malloc
1253 fbstring str(128, 'f');
1254 str.clear(); // Empty medium string.
1255 fbstring copy(str); // Medium string of 0 capacity.
1256 copy.push_back('b');
1257 EXPECT_GE(copy.capacity(), 1);
1261 s1.reserve(8); // Trigger the optimized code path.
1262 auto test1 = '\0' + std::move(s1);
1263 EXPECT_EQ(2, test1.size());
1265 fbstring s2(1, '\0');
1267 auto test2 = "a" + std::move(s2);
1268 EXPECT_EQ(2, test2.size());
1271 EXPECT_EQ(fbstring().find(fbstring(), 4), fbstring::npos);
1275 TEST(FBString, findWithNpos) {
1276 fbstring fbstr("localhost:80");
1277 EXPECT_EQ(fbstring::npos, fbstr.find(":", fbstring::npos));
1280 TEST(FBString, testHash) {
1287 std::hash<fbstring> hashfunc;
1288 EXPECT_NE(hashfunc(a), hashfunc(b));
1291 #if FOLLY_HAVE_WCHAR_SUPPORT
1292 TEST(FBString, testHashChar16) {
1293 using u16fbstring = folly::basic_fbstring<char16_t>;
1300 std::hash<u16fbstring> hashfunc;
1301 EXPECT_NE(hashfunc(a), hashfunc(b));
1305 TEST(FBString, testFrontBack) {
1306 fbstring str("hello");
1307 EXPECT_EQ(str.front(), 'h');
1308 EXPECT_EQ(str.back(), 'o');
1310 EXPECT_EQ(str.front(), 'H');
1312 EXPECT_EQ(str.back(), 'O');
1313 EXPECT_EQ(str, "HellO");
1316 TEST(FBString, noexcept) {
1317 EXPECT_TRUE(noexcept(fbstring()));
1319 EXPECT_FALSE(noexcept(fbstring(x)));
1320 EXPECT_TRUE(noexcept(fbstring(std::move(x))));
1322 EXPECT_FALSE(noexcept(y = x));
1323 EXPECT_TRUE(noexcept(y = std::move(x)));
1326 TEST(FBString, iomanip) {
1328 fbstring fbstr("Hello");
1330 ss << setw(6) << fbstr;
1331 EXPECT_EQ(ss.str(), " Hello");
1334 ss << left << setw(6) << fbstr;
1335 EXPECT_EQ(ss.str(), "Hello ");
1338 ss << right << setw(6) << fbstr;
1339 EXPECT_EQ(ss.str(), " Hello");
1342 ss << setw(4) << fbstr;
1343 EXPECT_EQ(ss.str(), "Hello");
1346 ss << setfill('^') << setw(6) << fbstr;
1347 EXPECT_EQ(ss.str(), "^Hello");
1351 TEST(FBString, rvalueIterators) {
1352 // you cannot take &* of a move-iterator, so use that for testing
1353 fbstring s = "base";
1354 fbstring r = "hello";
1355 r.replace(r.begin(), r.end(),
1356 make_move_iterator(s.begin()), make_move_iterator(s.end()));
1357 EXPECT_EQ("base", r);
1359 // The following test is probably not required by the standard.
1360 // i.e. this could be in the realm of undefined behavior.
1361 fbstring b = "123abcXYZ";
1362 auto ait = b.begin() + 3;
1363 auto Xit = b.begin() + 6;
1364 b.replace(ait, b.end(), b.begin(), Xit);
1365 EXPECT_EQ("123123abc", b); // if things go wrong, you'd get "123123123"
1368 TEST(FBString, moveTerminator) {
1369 // The source of a move must remain in a valid state
1370 fbstring s(100, 'x'); // too big to be in-situ
1374 EXPECT_EQ(0, s.size());
1375 EXPECT_EQ('\0', *s.c_str());
1380 * t8968589: Clang 3.7 refused to compile w/ certain constructors (specifically
1381 * those that were "explicit" and had a defaulted parameter, if they were used
1382 * in structs which were default-initialized). Exercise these just to ensure
1385 * In diff D2632953 the old constructor:
1386 * explicit basic_fbstring(const A& a = A()) noexcept;
1388 * was split into these two, as a workaround:
1389 * basic_fbstring() noexcept;
1390 * explicit basic_fbstring(const A& a) noexcept;
1393 struct TestStructDefaultAllocator {
1394 folly::basic_fbstring<char> stringMember;
1398 struct TestStructWithAllocator {
1399 folly::basic_fbstring<char, std::char_traits<char>, A> stringMember;
1402 std::atomic<size_t> allocatorConstructedCount(0);
1403 struct TestStructStringAllocator : std::allocator<char> {
1404 TestStructStringAllocator() {
1405 ++ allocatorConstructedCount;
1411 TEST(FBStringCtorTest, DefaultInitStructDefaultAlloc) {
1412 TestStructDefaultAllocator t1 { };
1413 EXPECT_TRUE(t1.stringMember.empty());
1416 TEST(FBStringCtorTest, DefaultInitStructAlloc) {
1417 EXPECT_EQ(allocatorConstructedCount.load(), 0);
1418 TestStructWithAllocator<TestStructStringAllocator> t2;
1419 EXPECT_TRUE(t2.stringMember.empty());
1420 EXPECT_EQ(allocatorConstructedCount.load(), 1);