Consistency in namespace-closing comments
[folly.git] / folly / test / FBStringTest.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 //
18 // Author: andrei.alexandrescu@fb.com
19
20 #include <folly/FBString.h>
21
22 #include <atomic>
23 #include <cstdlib>
24 #include <iomanip>
25 #include <list>
26 #include <sstream>
27
28 #include <boost/algorithm/string.hpp>
29 #include <boost/random.hpp>
30
31 #include <folly/Conv.h>
32 #include <folly/Foreach.h>
33 #include <folly/Portability.h>
34 #include <folly/Random.h>
35 #include <folly/portability/GTest.h>
36
37 using namespace std;
38 using namespace folly;
39
40 namespace {
41
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;
47
48 template <class Integral1, class Integral2>
49 Integral2 random(Integral1 low, Integral2 up) {
50   boost::uniform_int<> range(low, up);
51   return range(rng);
52 }
53
54 template <class String>
55 void randomString(String* toFill, unsigned int maxSize = 1000) {
56   assert(toFill);
57   toFill->resize(random(0, maxSize));
58   FOR_EACH (i, *toFill) {
59     *i = random('a', 'z');
60   }
61 }
62
63 template <class String, class Integral>
64 void Num2String(String& str, Integral n) {
65
66   std::string tmp = folly::to<std::string>(n);
67   str = String(tmp.begin(), tmp.end());
68 }
69
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');
75  }
76   return lst;
77 }
78 }
79
80 ////////////////////////////////////////////////////////////////////////////////
81 // Tests begin here
82 ////////////////////////////////////////////////////////////////////////////////
83
84 template <class String> void clause11_21_4_2_a(String & test) {
85   test.String::~String();
86   new(&test) String();
87 }
88 template <class String> void clause11_21_4_2_b(String & test) {
89   String test2(test);
90   assert(test2 == test);
91 }
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)
95   String donor(test);
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);
102 }
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
109   test = s;
110 }
111 template <class String> void clause11_21_4_2_e(String & test) {
112   // Constructor from char*, size_t
113   const 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);
120   test.swap(s);
121 }
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);
129   test.swap(s);
130 }
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();
135   test = String(n, c);
136 }
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());
141   EXPECT_EQ(test, s1);
142   String s2(test.data(), test.data() + test.size());
143   EXPECT_EQ(test, s2);
144   // Constructor from other iterators
145   std::list<char> lst;
146   for (auto c : test) lst.push_back(c);
147   String s3(lst.begin(), lst.end());
148   EXPECT_EQ(test, s3);
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());
153   EXPECT_EQ(test, s4);
154   // Constructor from wchar_t pointers
155   wchar_t t[20];
156   t[0] = 'a';
157   t[1] = 'b';
158   fbstring s5(t, t + 2);;
159   EXPECT_EQ("ab", s5);
160 }
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' };
165   String s(il);
166   test.swap(s);
167 }
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');
175   }
176   test = s;
177 }
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');
185   }
186   test = std::move(s);
187   if (typeid(String) == typeid(fbstring)) {
188     EXPECT_LE(s.size(), 128);
189   }
190 }
191 template <class String> void clause11_21_4_2_l(String & test) {
192   // Assignment from char*
193   String s(random(0, 1000), '\0');
194   size_t i = 0;
195   for (; i != s.size(); ++i) {
196     s[i] = random('a', 'z');
197   }
198   test = s.c_str();
199 }
200 template <class String> void clause11_21_4_2_lprime(String & test) {
201   // Aliased assign
202   const size_t pos = random(0, test.size());
203   if (avoidAliasing) {
204     test = String(test.c_str() + pos);
205   } else {
206     test = test.c_str() + pos;
207   }
208 }
209 template <class String> void clause11_21_4_2_m(String & test) {
210   // Assignment from char
211   using value_type = typename String::value_type;
212   test = random(static_cast<value_type>('a'), static_cast<value_type>('z'));
213 }
214 template <class String> void clause11_21_4_2_n(String & test) {
215   // Assignment from initializer_list<char>
216   initializer_list<typename String::value_type>
217     il = { 'h', 'e', 'l', 'l', 'o' };
218   test = il;
219 }
220
221 template <class String> void clause11_21_4_3(String & test) {
222   // Iterators. The code below should leave test unchanged
223   EXPECT_EQ(test.size(), test.end() - test.begin());
224   EXPECT_EQ(test.size(), test.rend() - test.rbegin());
225   EXPECT_EQ(test.size(), test.cend() - test.cbegin());
226   EXPECT_EQ(test.size(), test.crend() - test.crbegin());
227
228   auto s = test.size();
229   test.resize(test.end() - test.begin());
230   EXPECT_EQ(s, test.size());
231   test.resize(test.rend() - test.rbegin());
232   EXPECT_EQ(s, test.size());
233 }
234
235 template <class String> void clause11_21_4_4(String & test) {
236   // exercise capacity, size, max_size
237   EXPECT_EQ(test.size(), test.length());
238   EXPECT_LE(test.size(), test.max_size());
239   EXPECT_LE(test.capacity(), test.max_size());
240   EXPECT_LE(test.size(), test.capacity());
241
242   // exercise shrink_to_fit. Nonbinding request so we can't really do
243   // much beyond calling it.
244   auto copy = test;
245   copy.reserve(copy.capacity() * 3);
246   copy.shrink_to_fit();
247   EXPECT_EQ(copy, test);
248
249   // exercise empty
250   string empty("empty");
251   string notempty("not empty");
252   if (test.empty()) test = String(empty.begin(), empty.end());
253   else test = String(notempty.begin(), notempty.end());
254 }
255
256 template <class String> void clause11_21_4_5(String & test) {
257   // exercise element access
258   if (!test.empty()) {
259     EXPECT_EQ(test[0], test.front());
260     EXPECT_EQ(test[test.size() - 1], test.back());
261     auto const i = random(0, test.size() - 1);
262     EXPECT_EQ(test[i], test.at(i));
263     test = test[i];
264   }
265 }
266
267 template <class String> void clause11_21_4_6_1(String & test) {
268   // 21.3.5 modifiers (+=)
269   String test1;
270   randomString(&test1);
271   assert(test1.size() == char_traits
272       <typename String::value_type>::length(test1.c_str()));
273   auto len = test.size();
274   test += test1;
275   EXPECT_EQ(test.size(), test1.size() + len);
276   FOR_EACH_RANGE (i, 0, test1.size()) {
277     EXPECT_EQ(test[len + i], test1[i]);
278   }
279   // aliasing modifiers
280   String test2 = test;
281   auto dt = test2.data();
282   auto sz = test.c_str();
283   len = test.size();
284   EXPECT_EQ(memcmp(sz, dt, len), 0);
285   String copy(test.data(), test.size());
286   EXPECT_EQ(char_traits
287       <typename String::value_type>::length(test.c_str()), len);
288   test += test;
289   //test.append(test);
290   EXPECT_EQ(test.size(), 2 * len);
291   EXPECT_EQ(char_traits
292       <typename String::value_type>::length(test.c_str()), 2 * len);
293   FOR_EACH_RANGE (i, 0, len) {
294     EXPECT_EQ(test[i], copy[i]);
295     EXPECT_EQ(test[i], test[len + i]);
296   }
297   len = test.size();
298   EXPECT_EQ(char_traits
299       <typename String::value_type>::length(test.c_str()), len);
300   // more aliasing
301   auto const pos = random(0, test.size());
302   EXPECT_EQ(char_traits
303       <typename String::value_type>::length(test.c_str() + pos), len - pos);
304   if (avoidAliasing) {
305     String addMe(test.c_str() + pos);
306     EXPECT_EQ(addMe.size(), len - pos);
307     test += addMe;
308   } else {
309     test += test.c_str() + pos;
310   }
311   EXPECT_EQ(test.size(), 2 * len - pos);
312   // single char
313   len = test.size();
314   test += random('a', 'z');
315   EXPECT_EQ(test.size(), len + 1);
316   // initializer_list
317   initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
318   test += il;
319 }
320
321 template <class String> void clause11_21_4_6_2(String & test) {
322   // 21.3.5 modifiers (append, push_back)
323   String s;
324
325   // Test with a small string first
326   char c = random('a', 'z');
327   s.push_back(c);
328   EXPECT_EQ(s[s.size() - 1], c);
329   EXPECT_EQ(s.size(), 1);
330   s.resize(s.size() - 1);
331
332   randomString(&s, maxString);
333   test.append(s);
334   randomString(&s, maxString);
335   test.append(s, random(0, s.size()), random(0, maxString));
336   randomString(&s, maxString);
337   test.append(s.c_str(), random(0, s.size()));
338   randomString(&s, maxString);
339   test.append(s.c_str());
340   test.append(random(0, maxString), random('a', 'z'));
341   std::list<char> lst(RandomList(maxString));
342   test.append(lst.begin(), lst.end());
343   c = random('a', 'z');
344   test.push_back(c);
345   EXPECT_EQ(test[test.size() - 1], c);
346   // initializer_list
347   initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
348   test.append(il);
349 }
350
351 template <class String> void clause11_21_4_6_3_a(String & test) {
352   // assign
353   String s;
354   randomString(&s);
355   test.assign(s);
356   EXPECT_EQ(test, s);
357   // move assign
358   test.assign(std::move(s));
359   if (typeid(String) == typeid(fbstring)) {
360     EXPECT_LE(s.size(), 128);
361   }
362 }
363
364 template <class String> void clause11_21_4_6_3_b(String & test) {
365   // assign
366   String s;
367   randomString(&s, maxString);
368   test.assign(s, random(0, s.size()), random(0, maxString));
369 }
370
371 template <class String> void clause11_21_4_6_3_c(String & test) {
372   // assign
373   String s;
374   randomString(&s, maxString);
375   test.assign(s.c_str(), random(0, s.size()));
376 }
377
378 template <class String> void clause11_21_4_6_3_d(String & test) {
379   // assign
380   String s;
381   randomString(&s, maxString);
382   test.assign(s.c_str());
383 }
384
385 template <class String> void clause11_21_4_6_3_e(String & test) {
386   // assign
387   String s;
388   randomString(&s, maxString);
389   test.assign(random(0, maxString), random('a', 'z'));
390 }
391
392 template <class String> void clause11_21_4_6_3_f(String & test) {
393   // assign from bidirectional iterator
394   std::list<char> lst(RandomList(maxString));
395   test.assign(lst.begin(), lst.end());
396 }
397
398 template <class String> void clause11_21_4_6_3_g(String & test) {
399   // assign from aliased source
400   test.assign(test);
401 }
402
403 template <class String> void clause11_21_4_6_3_h(String & test) {
404   // assign from aliased source
405   test.assign(test, random(0, test.size()), random(0, maxString));
406 }
407
408 template <class String> void clause11_21_4_6_3_i(String & test) {
409   // assign from aliased source
410   test.assign(test.c_str(), random(0, test.size()));
411 }
412
413 template <class String> void clause11_21_4_6_3_j(String & test) {
414   // assign from aliased source
415   test.assign(test.c_str());
416 }
417
418 template <class String> void clause11_21_4_6_3_k(String & test) {
419   // assign from initializer_list
420   initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
421   test.assign(il);
422 }
423
424 template <class String> void clause11_21_4_6_4(String & test) {
425   // insert
426   String s;
427   randomString(&s, maxString);
428   test.insert(random(0, test.size()), s);
429   randomString(&s, maxString);
430   test.insert(random(0, test.size()),
431               s, random(0, s.size()),
432               random(0, maxString));
433   randomString(&s, maxString);
434   test.insert(random(0, test.size()),
435               s.c_str(), random(0, s.size()));
436   randomString(&s, maxString);
437   test.insert(random(0, test.size()), s.c_str());
438   test.insert(random(0, test.size()),
439               random(0, maxString), random('a', 'z'));
440   typename String::size_type pos = random(0, test.size());
441   typename String::iterator res =
442     test.insert(test.begin() + pos, random('a', 'z'));
443   EXPECT_EQ(res - test.begin(), pos);
444   std::list<char> lst(RandomList(maxString));
445   pos = random(0, test.size());
446   // Uncomment below to see a bug in gcc
447   /*res = */test.insert(test.begin() + pos, lst.begin(), lst.end());
448   // insert from initializer_list
449   initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
450   pos = random(0, test.size());
451   // Uncomment below to see a bug in gcc
452   /*res = */test.insert(test.begin() + pos, il);
453
454   // Test with actual input iterators
455   stringstream ss;
456   ss << "hello cruel world";
457   auto i = istream_iterator<char>(ss);
458   test.insert(test.begin(), i, istream_iterator<char>());
459 }
460
461 template <class String> void clause11_21_4_6_5(String & test) {
462   // erase and pop_back
463   if (!test.empty()) {
464     test.erase(random(0, test.size()), random(0, maxString));
465   }
466   if (!test.empty()) {
467     // TODO: is erase(end()) allowed?
468     test.erase(test.begin() + random(0, test.size() - 1));
469   }
470   if (!test.empty()) {
471     auto const i = test.begin() + random(0, test.size());
472     if (i != test.end()) {
473       test.erase(i, i + random(0, size_t(test.end() - i)));
474     }
475   }
476   if (!test.empty()) {
477     // Can't test pop_back with std::string, doesn't support it yet.
478     //test.pop_back();
479   }
480 }
481
482 template <class String> void clause11_21_4_6_6(String & test) {
483   auto pos = random(0, test.size());
484   if (avoidAliasing) {
485     test.replace(pos, random(0, test.size() - pos),
486                  String(test));
487   } else {
488     test.replace(pos, random(0, test.size() - pos), test);
489   }
490   pos = random(0, test.size());
491   String s;
492   randomString(&s, maxString);
493   test.replace(pos, pos + random(0, test.size() - pos), s);
494   auto pos1 = random(0, test.size());
495   auto pos2 = random(0, test.size());
496   if (avoidAliasing) {
497     test.replace(pos1, pos1 + random(0, test.size() - pos1),
498                  String(test),
499                  pos2, pos2 + random(0, test.size() - pos2));
500   } else {
501     test.replace(pos1, pos1 + random(0, test.size() - pos1),
502                  test, pos2, pos2 + random(0, test.size() - pos2));
503   }
504   pos1 = random(0, test.size());
505   String str;
506   randomString(&str, maxString);
507   pos2 = random(0, str.size());
508   test.replace(pos1, pos1 + random(0, test.size() - pos1),
509                str, pos2, pos2 + random(0, str.size() - pos2));
510   pos = random(0, test.size());
511   if (avoidAliasing) {
512     test.replace(pos, random(0, test.size() - pos),
513                  String(test).c_str(), test.size());
514   } else {
515     test.replace(pos, random(0, test.size() - pos),
516                  test.c_str(), test.size());
517   }
518   pos = random(0, test.size());
519   randomString(&str, maxString);
520   test.replace(pos, pos + random(0, test.size() - pos),
521                str.c_str(), str.size());
522   pos = random(0, test.size());
523   randomString(&str, maxString);
524   test.replace(pos, pos + random(0, test.size() - pos),
525                str.c_str());
526   pos = random(0, test.size());
527   test.replace(pos, random(0, test.size() - pos),
528                random(0, maxString), random('a', 'z'));
529   pos = random(0, test.size());
530   if (avoidAliasing) {
531     auto newString = String(test);
532     test.replace(
533       test.begin() + pos,
534       test.begin() + pos + random(0, test.size() - pos),
535       newString);
536   } else {
537     test.replace(
538       test.begin() + pos,
539       test.begin() + pos + random(0, test.size() - pos),
540       test);
541   }
542   pos = random(0, test.size());
543   if (avoidAliasing) {
544     auto newString = String(test);
545     test.replace(
546       test.begin() + pos,
547       test.begin() + pos + random(0, test.size() - pos),
548       newString.c_str(),
549       test.size() - random(0, test.size()));
550   } else {
551     test.replace(
552       test.begin() + pos,
553       test.begin() + pos + random(0, test.size() - pos),
554       test.c_str(),
555       test.size() - random(0, test.size()));
556   }
557   pos = random(0, test.size());
558   auto const n = random(0, test.size() - pos);
559   typename String::iterator b = test.begin();
560   String str1;
561   randomString(&str1, maxString);
562   const String & str3 = str1;
563   const typename String::value_type* ss = str3.c_str();
564   test.replace(
565     b + pos,
566     b + pos + n,
567     ss);
568   pos = random(0, test.size());
569   test.replace(
570     test.begin() + pos,
571     test.begin() + pos + random(0, test.size() - pos),
572     random(0, maxString), random('a', 'z'));
573 }
574
575 template <class String> void clause11_21_4_6_7(String & test) {
576   std::vector<typename String::value_type>
577     vec(random(0, maxString));
578   if (vec.empty()) {
579     return;
580   }
581   test.copy(vec.data(), vec.size(), random(0, test.size()));
582 }
583
584 template <class String> void clause11_21_4_6_8(String & test) {
585   String s;
586   randomString(&s, maxString);
587   s.swap(test);
588 }
589
590 template <class String> void clause11_21_4_7_1(String & test) {
591   // 21.3.6 string operations
592   // exercise c_str() and data()
593   assert(test.c_str() == test.data());
594   // exercise get_allocator()
595   String s;
596   randomString(&s, maxString);
597   DCHECK(test.get_allocator() == s.get_allocator());
598 }
599
600 template <class String> void clause11_21_4_7_2_a(String & test) {
601   String str = test.substr(
602     random(0, test.size()),
603     random(0, test.size()));
604   Num2String(test, test.find(str, random(0, test.size())));
605 }
606
607 template <class String> void clause11_21_4_7_2_a1(String & test) {
608   String str = String(test).substr(
609     random(0, test.size()),
610     random(0, test.size()));
611   Num2String(test, test.find(str, random(0, test.size())));
612 }
613
614 template <class String> void clause11_21_4_7_2_a2(String & test) {
615   auto const& cTest = test;
616   String str = cTest.substr(
617     random(0, test.size()),
618     random(0, test.size()));
619   Num2String(test, test.find(str, random(0, test.size())));
620 }
621
622 template <class String> void clause11_21_4_7_2_b(String & test) {
623   auto from = random(0, test.size());
624   auto length = random(0, test.size() - from);
625   String str = test.substr(from, length);
626   Num2String(test, test.find(str.c_str(),
627                              random(0, test.size()),
628                              random(0, str.size())));
629 }
630
631 template <class String> void clause11_21_4_7_2_b1(String & test) {
632   auto from = random(0, test.size());
633   auto length = random(0, test.size() - from);
634   String str = String(test).substr(from, length);
635   Num2String(test, test.find(str.c_str(),
636                              random(0, test.size()),
637                              random(0, str.size())));
638 }
639
640 template <class String> void clause11_21_4_7_2_b2(String & test) {
641   auto from = random(0, test.size());
642   auto length = random(0, test.size() - from);
643   const auto& cTest = test;
644   String str = cTest.substr(from, length);
645   Num2String(test, test.find(str.c_str(),
646                              random(0, test.size()),
647                              random(0, str.size())));
648 }
649
650 template <class String> void clause11_21_4_7_2_c(String & test) {
651   String str = test.substr(
652     random(0, test.size()),
653     random(0, test.size()));
654   Num2String(test, test.find(str.c_str(),
655                              random(0, test.size())));
656 }
657
658 template <class String> void clause11_21_4_7_2_c1(String & test) {
659   String str = String(test).substr(
660     random(0, test.size()),
661     random(0, test.size()));
662   Num2String(test, test.find(str.c_str(),
663                              random(0, test.size())));
664 }
665
666 template <class String> void clause11_21_4_7_2_c2(String & test) {
667   const auto& cTest = test;
668   String str = cTest.substr(
669     random(0, test.size()),
670     random(0, test.size()));
671   Num2String(test, test.find(str.c_str(),
672                              random(0, test.size())));
673 }
674
675 template <class String> void clause11_21_4_7_2_d(String & test) {
676   Num2String(test, test.find(
677                random('a', 'z'),
678                random(0, test.size())));
679 }
680
681 template <class String> void clause11_21_4_7_3_a(String & test) {
682   String str = test.substr(
683     random(0, test.size()),
684     random(0, test.size()));
685   Num2String(test, test.rfind(str, random(0, test.size())));
686 }
687
688 template <class String> void clause11_21_4_7_3_b(String & test) {
689   String str = test.substr(
690     random(0, test.size()),
691     random(0, test.size()));
692   Num2String(test, test.rfind(str.c_str(),
693                               random(0, test.size()),
694                               random(0, str.size())));
695 }
696
697 template <class String> void clause11_21_4_7_3_c(String & test) {
698   String str = test.substr(
699     random(0, test.size()),
700     random(0, test.size()));
701   Num2String(test, test.rfind(str.c_str(),
702                               random(0, test.size())));
703 }
704
705 template <class String> void clause11_21_4_7_3_d(String & test) {
706   Num2String(test, test.rfind(
707                random('a', 'z'),
708                random(0, test.size())));
709 }
710
711 template <class String> void clause11_21_4_7_4_a(String & test) {
712   String str;
713   randomString(&str, maxString);
714   Num2String(test, test.find_first_of(str,
715                                       random(0, test.size())));
716 }
717
718 template <class String> void clause11_21_4_7_4_b(String & test) {
719   String str;
720   randomString(&str, maxString);
721   Num2String(test, test.find_first_of(str.c_str(),
722                                       random(0, test.size()),
723                                       random(0, str.size())));
724 }
725
726 template <class String> void clause11_21_4_7_4_c(String & test) {
727   String str;
728   randomString(&str, maxString);
729   Num2String(test, test.find_first_of(str.c_str(),
730                                       random(0, test.size())));
731 }
732
733 template <class String> void clause11_21_4_7_4_d(String & test) {
734   Num2String(test, test.find_first_of(
735                random('a', 'z'),
736                random(0, test.size())));
737 }
738
739 template <class String> void clause11_21_4_7_5_a(String & test) {
740   String str;
741   randomString(&str, maxString);
742   Num2String(test, test.find_last_of(str,
743                                      random(0, test.size())));
744 }
745
746 template <class String> void clause11_21_4_7_5_b(String & test) {
747   String str;
748   randomString(&str, maxString);
749   Num2String(test, test.find_last_of(str.c_str(),
750                                      random(0, test.size()),
751                                      random(0, str.size())));
752 }
753
754 template <class String> void clause11_21_4_7_5_c(String & test) {
755   String str;
756   randomString(&str, maxString);
757   Num2String(test, test.find_last_of(str.c_str(),
758                                      random(0, test.size())));
759 }
760
761 template <class String> void clause11_21_4_7_5_d(String & test) {
762   Num2String(test, test.find_last_of(
763                random('a', 'z'),
764                random(0, test.size())));
765 }
766
767 template <class String> void clause11_21_4_7_6_a(String & test) {
768   String str;
769   randomString(&str, maxString);
770   Num2String(test, test.find_first_not_of(str,
771                                           random(0, test.size())));
772 }
773
774 template <class String> void clause11_21_4_7_6_b(String & test) {
775   String str;
776   randomString(&str, maxString);
777   Num2String(test, test.find_first_not_of(str.c_str(),
778                                           random(0, test.size()),
779                                           random(0, str.size())));
780 }
781
782 template <class String> void clause11_21_4_7_6_c(String & test) {
783   String str;
784   randomString(&str, maxString);
785   Num2String(test, test.find_first_not_of(str.c_str(),
786                                           random(0, test.size())));
787 }
788
789 template <class String> void clause11_21_4_7_6_d(String & test) {
790   Num2String(test, test.find_first_not_of(
791                random('a', 'z'),
792                random(0, test.size())));
793 }
794
795 template <class String> void clause11_21_4_7_7_a(String & test) {
796   String str;
797   randomString(&str, maxString);
798   Num2String(test, test.find_last_not_of(str,
799                                          random(0, test.size())));
800 }
801
802 template <class String> void clause11_21_4_7_7_b(String & test) {
803   String str;
804   randomString(&str, maxString);
805   Num2String(test, test.find_last_not_of(str.c_str(),
806                                          random(0, test.size()),
807                                          random(0, str.size())));
808 }
809
810 template <class String> void clause11_21_4_7_7_c(String & test) {
811   String str;
812   randomString(&str, maxString);
813   Num2String(test, test.find_last_not_of(str.c_str(),
814                                          random(0, test.size())));
815 }
816
817 template <class String> void clause11_21_4_7_7_d(String & test) {
818   Num2String(test, test.find_last_not_of(
819                random('a', 'z'),
820                random(0, test.size())));
821 }
822
823 template <class String> void clause11_21_4_7_8(String & test) {
824   test = test.substr(random(0, test.size()), random(0, test.size()));
825 }
826
827 template <class String> void clause11_21_4_7_9_a(String & test) {
828   String s;
829   randomString(&s, maxString);
830   int tristate = test.compare(s);
831   if (tristate > 0) tristate = 1;
832   else if (tristate < 0) tristate = 2;
833   Num2String(test, tristate);
834 }
835
836 template <class String> void clause11_21_4_7_9_b(String & test) {
837   String s;
838   randomString(&s, maxString);
839   int tristate = test.compare(
840     random(0, test.size()),
841     random(0, test.size()),
842     s);
843   if (tristate > 0) tristate = 1;
844   else if (tristate < 0) tristate = 2;
845   Num2String(test, tristate);
846 }
847
848 template <class String> void clause11_21_4_7_9_c(String & test) {
849   String str;
850   randomString(&str, maxString);
851   int tristate = test.compare(
852     random(0, test.size()),
853     random(0, test.size()),
854     str,
855     random(0, str.size()),
856     random(0, str.size()));
857   if (tristate > 0) tristate = 1;
858   else if (tristate < 0) tristate = 2;
859   Num2String(test, tristate);
860 }
861
862 template <class String> void clause11_21_4_7_9_d(String & test) {
863   String s;
864   randomString(&s, maxString);
865   int tristate = test.compare(s.c_str());
866   if (tristate > 0) tristate = 1;
867   else if (tristate < 0) tristate = 2;
868                 Num2String(test, tristate);
869 }
870
871 template <class String> void clause11_21_4_7_9_e(String & test) {
872   String str;
873   randomString(&str, maxString);
874   int tristate = test.compare(
875     random(0, test.size()),
876     random(0, test.size()),
877     str.c_str(),
878     random(0, str.size()));
879   if (tristate > 0) tristate = 1;
880   else if (tristate < 0) tristate = 2;
881   Num2String(test, tristate);
882 }
883
884 template <class String> void clause11_21_4_8_1_a(String & test) {
885   String s1;
886   randomString(&s1, maxString);
887   String s2;
888   randomString(&s2, maxString);
889   test = s1 + s2;
890 }
891
892 template <class String> void clause11_21_4_8_1_b(String & test) {
893   String s1;
894   randomString(&s1, maxString);
895   String s2;
896   randomString(&s2, maxString);
897   test = move(s1) + s2;
898 }
899
900 template <class String> void clause11_21_4_8_1_c(String & test) {
901   String s1;
902   randomString(&s1, maxString);
903   String s2;
904   randomString(&s2, maxString);
905   test = s1 + move(s2);
906 }
907
908 template <class String> void clause11_21_4_8_1_d(String & test) {
909   String s1;
910   randomString(&s1, maxString);
911   String s2;
912   randomString(&s2, maxString);
913   test = move(s1) + move(s2);
914 }
915
916 template <class String> void clause11_21_4_8_1_e(String & test) {
917   String s;
918   randomString(&s, maxString);
919   String s1;
920   randomString(&s1, maxString);
921   test = s.c_str() + s1;
922 }
923
924 template <class String> void clause11_21_4_8_1_f(String & test) {
925   String s;
926   randomString(&s, maxString);
927   String s1;
928   randomString(&s1, maxString);
929   test = s.c_str() + move(s1);
930 }
931
932 template <class String> void clause11_21_4_8_1_g(String & test) {
933   String s;
934   randomString(&s, maxString);
935   test = typename String::value_type(random('a', 'z')) + s;
936 }
937
938 template <class String> void clause11_21_4_8_1_h(String & test) {
939   String s;
940   randomString(&s, maxString);
941   test = typename String::value_type(random('a', 'z')) + move(s);
942 }
943
944 template <class String> void clause11_21_4_8_1_i(String & test) {
945   String s;
946   randomString(&s, maxString);
947   String s1;
948   randomString(&s1, maxString);
949   test = s + s1.c_str();
950 }
951
952 template <class String> void clause11_21_4_8_1_j(String & test) {
953   String s;
954   randomString(&s, maxString);
955   String s1;
956   randomString(&s1, maxString);
957   test = move(s) + s1.c_str();
958 }
959
960 template <class String> void clause11_21_4_8_1_k(String & test) {
961   String s;
962   randomString(&s, maxString);
963   test = s + typename String::value_type(random('a', 'z'));
964 }
965
966 template <class String> void clause11_21_4_8_1_l(String & test) {
967   String s;
968   randomString(&s, maxString);
969   String s1;
970   randomString(&s1, maxString);
971   test = move(s) + s1.c_str();
972 }
973
974 // Numbering here is from C++11
975 template <class String> void clause11_21_4_8_9_a(String & test) {
976   basic_stringstream<typename String::value_type> stst(test.c_str());
977   String str;
978   while (stst) {
979     stst >> str;
980     test += str + test;
981   }
982 }
983
984 TEST(FBString, testAllClauses) {
985   EXPECT_TRUE(1) << "Starting with seed: " << seed;
986   std::string r;
987   folly::fbstring c;
988 #if FOLLY_HAVE_WCHAR_SUPPORT
989   std::wstring wr;
990   folly::basic_fbstring<wchar_t> wc;
991 #endif
992   int count = 0;
993
994   auto l = [&](const char * const clause,
995                void(*f_string)(std::string&),
996                void(*f_fbstring)(folly::fbstring&),
997                void(*f_wfbstring)(folly::basic_fbstring<wchar_t>&)) {
998     do {
999       if (1) {} else EXPECT_TRUE(1) << "Testing clause " << clause;
1000       randomString(&r);
1001       c = r;
1002       EXPECT_EQ(c, r);
1003 #if FOLLY_HAVE_WCHAR_SUPPORT
1004       wr = std::wstring(r.begin(), r.end());
1005       wc = folly::basic_fbstring<wchar_t>(wr.c_str());
1006 #endif
1007       auto localSeed = seed + count;
1008       rng = RandomT(localSeed);
1009       f_string(r);
1010       rng = RandomT(localSeed);
1011       f_fbstring(c);
1012       EXPECT_EQ(r, c)
1013         << "Lengths: " << r.size() << " vs. " << c.size()
1014         << "\nReference: '" << r << "'"
1015         << "\nActual:    '" << c.data()[0] << "'";
1016 #if FOLLY_HAVE_WCHAR_SUPPORT
1017       rng = RandomT(localSeed);
1018       f_wfbstring(wc);
1019       int wret = wcslen(wc.c_str());
1020       auto mbv = std::vector<char>(wret + 1);
1021       auto mb = mbv.data();
1022       int ret = wcstombs(mb, wc.c_str(), wret + 1);
1023       if (ret == wret) mb[wret] = '\0';
1024       const char *mc = c.c_str();
1025       std::string one(mb);
1026       std::string two(mc);
1027       EXPECT_EQ(one, two);
1028 #endif
1029     } while (++count % 100 != 0);
1030   };
1031
1032 #define TEST_CLAUSE(x) \
1033   l(#x, \
1034     clause11_##x<std::string>, \
1035     clause11_##x<folly::fbstring>, \
1036     clause11_##x<folly::basic_fbstring<wchar_t>>);
1037
1038   TEST_CLAUSE(21_4_2_a);
1039   TEST_CLAUSE(21_4_2_b);
1040   TEST_CLAUSE(21_4_2_c);
1041   TEST_CLAUSE(21_4_2_d);
1042   TEST_CLAUSE(21_4_2_e);
1043   TEST_CLAUSE(21_4_2_f);
1044   TEST_CLAUSE(21_4_2_g);
1045   TEST_CLAUSE(21_4_2_h);
1046   TEST_CLAUSE(21_4_2_i);
1047   TEST_CLAUSE(21_4_2_j);
1048   TEST_CLAUSE(21_4_2_k);
1049   TEST_CLAUSE(21_4_2_l);
1050   TEST_CLAUSE(21_4_2_lprime);
1051   TEST_CLAUSE(21_4_2_m);
1052   TEST_CLAUSE(21_4_2_n);
1053   TEST_CLAUSE(21_4_3);
1054   TEST_CLAUSE(21_4_4);
1055   TEST_CLAUSE(21_4_5);
1056   TEST_CLAUSE(21_4_6_1);
1057   TEST_CLAUSE(21_4_6_2);
1058   TEST_CLAUSE(21_4_6_3_a);
1059   TEST_CLAUSE(21_4_6_3_b);
1060   TEST_CLAUSE(21_4_6_3_c);
1061   TEST_CLAUSE(21_4_6_3_d);
1062   TEST_CLAUSE(21_4_6_3_e);
1063   TEST_CLAUSE(21_4_6_3_f);
1064   TEST_CLAUSE(21_4_6_3_g);
1065   TEST_CLAUSE(21_4_6_3_h);
1066   TEST_CLAUSE(21_4_6_3_i);
1067   TEST_CLAUSE(21_4_6_3_j);
1068   TEST_CLAUSE(21_4_6_3_k);
1069   TEST_CLAUSE(21_4_6_4);
1070   TEST_CLAUSE(21_4_6_5);
1071   TEST_CLAUSE(21_4_6_6);
1072   TEST_CLAUSE(21_4_6_7);
1073   TEST_CLAUSE(21_4_6_8);
1074   TEST_CLAUSE(21_4_7_1);
1075
1076   TEST_CLAUSE(21_4_7_2_a);
1077   TEST_CLAUSE(21_4_7_2_a1);
1078   TEST_CLAUSE(21_4_7_2_a2);
1079   TEST_CLAUSE(21_4_7_2_b);
1080   TEST_CLAUSE(21_4_7_2_b1);
1081   TEST_CLAUSE(21_4_7_2_b2);
1082   TEST_CLAUSE(21_4_7_2_c);
1083   TEST_CLAUSE(21_4_7_2_c1);
1084   TEST_CLAUSE(21_4_7_2_c2);
1085   TEST_CLAUSE(21_4_7_2_d);
1086   TEST_CLAUSE(21_4_7_3_a);
1087   TEST_CLAUSE(21_4_7_3_b);
1088   TEST_CLAUSE(21_4_7_3_c);
1089   TEST_CLAUSE(21_4_7_3_d);
1090   TEST_CLAUSE(21_4_7_4_a);
1091   TEST_CLAUSE(21_4_7_4_b);
1092   TEST_CLAUSE(21_4_7_4_c);
1093   TEST_CLAUSE(21_4_7_4_d);
1094   TEST_CLAUSE(21_4_7_5_a);
1095   TEST_CLAUSE(21_4_7_5_b);
1096   TEST_CLAUSE(21_4_7_5_c);
1097   TEST_CLAUSE(21_4_7_5_d);
1098   TEST_CLAUSE(21_4_7_6_a);
1099   TEST_CLAUSE(21_4_7_6_b);
1100   TEST_CLAUSE(21_4_7_6_c);
1101   TEST_CLAUSE(21_4_7_6_d);
1102   TEST_CLAUSE(21_4_7_7_a);
1103   TEST_CLAUSE(21_4_7_7_b);
1104   TEST_CLAUSE(21_4_7_7_c);
1105   TEST_CLAUSE(21_4_7_7_d);
1106   TEST_CLAUSE(21_4_7_8);
1107   TEST_CLAUSE(21_4_7_9_a);
1108   TEST_CLAUSE(21_4_7_9_b);
1109   TEST_CLAUSE(21_4_7_9_c);
1110   TEST_CLAUSE(21_4_7_9_d);
1111   TEST_CLAUSE(21_4_7_9_e);
1112   TEST_CLAUSE(21_4_8_1_a);
1113   TEST_CLAUSE(21_4_8_1_b);
1114   TEST_CLAUSE(21_4_8_1_c);
1115   TEST_CLAUSE(21_4_8_1_d);
1116   TEST_CLAUSE(21_4_8_1_e);
1117   TEST_CLAUSE(21_4_8_1_f);
1118   TEST_CLAUSE(21_4_8_1_g);
1119   TEST_CLAUSE(21_4_8_1_h);
1120   TEST_CLAUSE(21_4_8_1_i);
1121   TEST_CLAUSE(21_4_8_1_j);
1122   TEST_CLAUSE(21_4_8_1_k);
1123   TEST_CLAUSE(21_4_8_1_l);
1124   TEST_CLAUSE(21_4_8_9_a);
1125 }
1126
1127 TEST(FBString, testGetline) {
1128   string s1 = "\
1129 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan \n\
1130 elit ut urna consectetur in sagittis mi auctor. Nulla facilisi. In nec \n\
1131 dolor leo, vitae imperdiet neque. Donec ut erat mauris, a faucibus \n\
1132 elit. Integer consectetur gravida augue, sit amet mattis mauris auctor \n\
1133 sed. Morbi congue libero eu nunc sodales adipiscing. In lectus nunc, \n\
1134 vulputate a fringilla at, venenatis quis justo. Proin eu velit \n\
1135 nibh. Maecenas vitae tellus eros. Pellentesque habitant morbi \n\
1136 tristique senectus et netus et malesuada fames ac turpis \n\
1137 egestas. Vivamus faucibus feugiat consequat. Donec fermentum neque sit \n\
1138 amet ligula suscipit porta. Phasellus facilisis felis in purus luctus \n\
1139 quis posuere leo tempor. Nam nunc purus, luctus a pharetra ut, \n\
1140 placerat at dui. Donec imperdiet, diam quis convallis pulvinar, dui \n\
1141 est commodo lorem, ut tincidunt diam nibh et nibh. Maecenas nec velit \n\
1142 massa, ut accumsan magna. Donec imperdiet tempor nisi et \n\
1143 laoreet. Phasellus lectus quam, ultricies ut tincidunt in, dignissim \n\
1144 id eros. Mauris vulputate tortor nec neque pellentesque sagittis quis \n\
1145 sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam.";
1146
1147   vector<fbstring> v;
1148   boost::split(v, s1, boost::is_any_of("\n"));
1149   {
1150     istringstream input(s1);
1151     fbstring line;
1152     FOR_EACH (i, v) {
1153       EXPECT_TRUE(!getline(input, line).fail());
1154       EXPECT_EQ(line, *i);
1155     }
1156   }
1157 }
1158
1159 TEST(FBString, testMoveCtor) {
1160   // Move constructor. Make sure we allocate a large string, so the
1161   // small string optimization doesn't kick in.
1162   auto size = random(100, 2000);
1163   fbstring s(size, 'a');
1164   fbstring test = std::move(s);
1165   EXPECT_TRUE(s.empty());
1166   EXPECT_EQ(size, test.size());
1167 }
1168
1169 TEST(FBString, testMoveAssign) {
1170   // Move constructor. Make sure we allocate a large string, so the
1171   // small string optimization doesn't kick in.
1172   auto size = random(100, 2000);
1173   fbstring s(size, 'a');
1174   fbstring test;
1175   test = std::move(s);
1176   EXPECT_TRUE(s.empty());
1177   EXPECT_EQ(size, test.size());
1178 }
1179
1180 TEST(FBString, testMoveOperatorPlusLhs) {
1181   // Make sure we allocate a large string, so the
1182   // small string optimization doesn't kick in.
1183   auto size1 = random(100, 2000);
1184   auto size2 = random(100, 2000);
1185   fbstring s1(size1, 'a');
1186   fbstring s2(size2, 'b');
1187   fbstring test;
1188   test = std::move(s1) + s2;
1189   EXPECT_TRUE(s1.empty());
1190   EXPECT_EQ(size1 + size2, test.size());
1191 }
1192
1193 TEST(FBString, testMoveOperatorPlusRhs) {
1194   // Make sure we allocate a large string, so the
1195   // small string optimization doesn't kick in.
1196   auto size1 = random(100, 2000);
1197   auto size2 = random(100, 2000);
1198   fbstring s1(size1, 'a');
1199   fbstring s2(size2, 'b');
1200   fbstring test;
1201   test = s1 + std::move(s2);
1202   EXPECT_EQ(size1 + size2, test.size());
1203 }
1204
1205 // The GNU C++ standard library throws an std::logic_error when an std::string
1206 // is constructed with a null pointer. Verify that we mirror this behavior.
1207 //
1208 // N.B. We behave this way even if the C++ library being used is something
1209 //      other than libstdc++. Someday if we deem it important to present
1210 //      identical undefined behavior for other platforms, we can re-visit this.
1211 TEST(FBString, testConstructionFromLiteralZero) {
1212   EXPECT_THROW(fbstring s(0), std::logic_error);
1213 }
1214
1215 TEST(FBString, testFixedBugs) {
1216   { // D479397
1217     fbstring str(1337, 'f');
1218     fbstring cp = str;
1219     cp.clear();
1220     cp.c_str();
1221     EXPECT_EQ(str.front(), 'f');
1222   }
1223   { // D481173
1224     fbstring str(1337, 'f');
1225     for (int i = 0; i < 2; ++i) {
1226       fbstring cp = str;
1227       cp[1] = 'b';
1228       EXPECT_EQ(cp.c_str()[cp.size()], '\0');
1229       cp.push_back('?');
1230     }
1231   }
1232   { // D580267
1233     {
1234       fbstring str(1337, 'f');
1235       fbstring cp = str;
1236       cp.push_back('f');
1237     }
1238     {
1239       fbstring str(1337, 'f');
1240       fbstring cp = str;
1241       cp += "bb";
1242     }
1243   }
1244   { // D661622
1245     folly::basic_fbstring<wchar_t> s;
1246     EXPECT_EQ(0, s.size());
1247   }
1248   { // D785057
1249     fbstring str(1337, 'f');
1250     std::swap(str, str);
1251     EXPECT_EQ(1337, str.size());
1252   }
1253   { // D1012196, --allocator=malloc
1254     fbstring str(128, 'f');
1255     str.clear();  // Empty medium string.
1256     fbstring copy(str);  // Medium string of 0 capacity.
1257     copy.push_back('b');
1258     EXPECT_GE(copy.capacity(), 1);
1259   }
1260   { // D2813713
1261     fbstring s1("a");
1262     s1.reserve(8); // Trigger the optimized code path.
1263     auto test1 = '\0' + std::move(s1);
1264     EXPECT_EQ(2, test1.size());
1265
1266     fbstring s2(1, '\0');
1267     s2.reserve(8);
1268     auto test2 = "a" + std::move(s2);
1269     EXPECT_EQ(2, test2.size());
1270   }
1271   { // D3698862
1272     EXPECT_EQ(fbstring().find(fbstring(), 4), fbstring::npos);
1273   }
1274   if (usingJEMalloc()) { // D4355440
1275     fbstring str(1337, 'f');
1276     str.reserve(3840);
1277     EXPECT_NE(str.capacity(), 3840);
1278
1279     struct {
1280       std::atomic<size_t> refCount_;
1281     } dummyRefCounted;
1282     EXPECT_EQ(
1283         str.capacity(),
1284         goodMallocSize(3840) - sizeof(dummyRefCounted) - sizeof(char));
1285   }
1286 }
1287
1288 TEST(FBString, findWithNpos) {
1289   fbstring fbstr("localhost:80");
1290   EXPECT_EQ(fbstring::npos, fbstr.find(":", fbstring::npos));
1291 }
1292
1293 TEST(FBString, testHash) {
1294   fbstring a;
1295   fbstring b;
1296   a.push_back(0);
1297   a.push_back(1);
1298   b.push_back(0);
1299   b.push_back(2);
1300   std::hash<fbstring> hashfunc;
1301   EXPECT_NE(hashfunc(a), hashfunc(b));
1302 }
1303
1304 #if FOLLY_HAVE_WCHAR_SUPPORT
1305 TEST(FBString, testHashChar16) {
1306   using u16fbstring = folly::basic_fbstring<char16_t>;
1307   u16fbstring a;
1308   u16fbstring b;
1309   a.push_back(0);
1310   a.push_back(1);
1311   b.push_back(0);
1312   b.push_back(2);
1313   std::hash<u16fbstring> hashfunc;
1314   EXPECT_NE(hashfunc(a), hashfunc(b));
1315 }
1316 #endif
1317
1318 TEST(FBString, testFrontBack) {
1319   fbstring str("hello");
1320   EXPECT_EQ(str.front(), 'h');
1321   EXPECT_EQ(str.back(), 'o');
1322   str.front() = 'H';
1323   EXPECT_EQ(str.front(), 'H');
1324   str.back() = 'O';
1325   EXPECT_EQ(str.back(), 'O');
1326   EXPECT_EQ(str, "HellO");
1327 }
1328
1329 TEST(FBString, noexcept) {
1330   EXPECT_TRUE(noexcept(fbstring()));
1331   fbstring x;
1332   EXPECT_FALSE(noexcept(fbstring(x)));
1333   EXPECT_TRUE(noexcept(fbstring(std::move(x))));
1334   fbstring y;
1335   EXPECT_FALSE(noexcept(y = x));
1336   EXPECT_TRUE(noexcept(y = std::move(x)));
1337 }
1338
1339 TEST(FBString, iomanip) {
1340   stringstream ss;
1341   fbstring fbstr("Hello");
1342
1343   ss << setw(6) << fbstr;
1344   EXPECT_EQ(ss.str(), " Hello");
1345   ss.str("");
1346
1347   ss << left << setw(6) << fbstr;
1348   EXPECT_EQ(ss.str(), "Hello ");
1349   ss.str("");
1350
1351   ss << right << setw(6) << fbstr;
1352   EXPECT_EQ(ss.str(), " Hello");
1353   ss.str("");
1354
1355   ss << setw(4) << fbstr;
1356   EXPECT_EQ(ss.str(), "Hello");
1357   ss.str("");
1358
1359   ss << setfill('^') << setw(6) << fbstr;
1360   EXPECT_EQ(ss.str(), "^Hello");
1361   ss.str("");
1362 }
1363
1364 TEST(FBString, rvalueIterators) {
1365   // you cannot take &* of a move-iterator, so use that for testing
1366   fbstring s = "base";
1367   fbstring r = "hello";
1368   r.replace(r.begin(), r.end(),
1369       make_move_iterator(s.begin()), make_move_iterator(s.end()));
1370   EXPECT_EQ("base", r);
1371
1372   // The following test is probably not required by the standard.
1373   // i.e. this could be in the realm of undefined behavior.
1374   fbstring b = "123abcXYZ";
1375   auto ait = b.begin() + 3;
1376   auto Xit = b.begin() + 6;
1377   b.replace(ait, b.end(), b.begin(), Xit);
1378   EXPECT_EQ("123123abc", b); // if things go wrong, you'd get "123123123"
1379 }
1380
1381 TEST(FBString, moveTerminator) {
1382   // The source of a move must remain in a valid state
1383   fbstring s(100, 'x'); // too big to be in-situ
1384   fbstring k;
1385   k = std::move(s);
1386
1387   EXPECT_EQ(0, s.size());
1388   EXPECT_EQ('\0', *s.c_str());
1389 }
1390
1391 namespace {
1392 /*
1393  * t8968589: Clang 3.7 refused to compile w/ certain constructors (specifically
1394  * those that were "explicit" and had a defaulted parameter, if they were used
1395  * in structs which were default-initialized).  Exercise these just to ensure
1396  * they compile.
1397  *
1398  * In diff D2632953 the old constructor:
1399  *   explicit basic_fbstring(const A& a = A()) noexcept;
1400  *
1401  * was split into these two, as a workaround:
1402  *   basic_fbstring() noexcept;
1403  *   explicit basic_fbstring(const A& a) noexcept;
1404  */
1405
1406 struct TestStructDefaultAllocator {
1407   folly::basic_fbstring<char> stringMember;
1408 };
1409
1410 template <class A>
1411 struct TestStructWithAllocator {
1412   folly::basic_fbstring<char, std::char_traits<char>, A> stringMember;
1413 };
1414
1415 std::atomic<size_t> allocatorConstructedCount(0);
1416 struct TestStructStringAllocator : std::allocator<char> {
1417   TestStructStringAllocator() {
1418     ++ allocatorConstructedCount;
1419   }
1420 };
1421
1422 } // namespace
1423
1424 TEST(FBStringCtorTest, DefaultInitStructDefaultAlloc) {
1425   TestStructDefaultAllocator t1 { };
1426   EXPECT_TRUE(t1.stringMember.empty());
1427 }
1428
1429 TEST(FBStringCtorTest, DefaultInitStructAlloc) {
1430   EXPECT_EQ(allocatorConstructedCount.load(), 0);
1431   TestStructWithAllocator<TestStructStringAllocator> t2;
1432   EXPECT_TRUE(t2.stringMember.empty());
1433   EXPECT_EQ(allocatorConstructedCount.load(), 1);
1434 }
1435
1436 TEST(FBStringCtorTest, NullZeroConstruction) {
1437   char* p = nullptr;
1438   int n = 0;
1439   folly::fbstring f(p, n);
1440   EXPECT_EQ(f.size(), 0);
1441 }
1442
1443 // Tests for the comparison operators. I use EXPECT_TRUE rather than EXPECT_LE
1444 // because what's under test is the operator rather than the relation between
1445 // the objects.
1446
1447 TEST(FBString, compareToStdString) {
1448   using folly::fbstring;
1449   using namespace std::string_literals;
1450   auto stdA = "a"s;
1451   auto stdB = "b"s;
1452   fbstring fbA("a");
1453   fbstring fbB("b");
1454   EXPECT_TRUE(stdA == fbA);
1455   EXPECT_TRUE(fbB == stdB);
1456   EXPECT_TRUE(stdA != fbB);
1457   EXPECT_TRUE(fbA != stdB);
1458   EXPECT_TRUE(stdA < fbB);
1459   EXPECT_TRUE(fbA < stdB);
1460   EXPECT_TRUE(stdB > fbA);
1461   EXPECT_TRUE(fbB > stdA);
1462   EXPECT_TRUE(stdA <= fbB);
1463   EXPECT_TRUE(fbA <= stdB);
1464   EXPECT_TRUE(stdA <= fbA);
1465   EXPECT_TRUE(fbA <= stdA);
1466   EXPECT_TRUE(stdB >= fbA);
1467   EXPECT_TRUE(fbB >= stdA);
1468   EXPECT_TRUE(stdB >= fbB);
1469   EXPECT_TRUE(fbB >= stdB);
1470 }
1471
1472 TEST(U16FBString, compareToStdU16String) {
1473   using folly::basic_fbstring;
1474   using namespace std::string_literals;
1475   auto stdA = u"a"s;
1476   auto stdB = u"b"s;
1477   basic_fbstring<char16_t> fbA(u"a");
1478   basic_fbstring<char16_t> fbB(u"b");
1479   EXPECT_TRUE(stdA == fbA);
1480   EXPECT_TRUE(fbB == stdB);
1481   EXPECT_TRUE(stdA != fbB);
1482   EXPECT_TRUE(fbA != stdB);
1483   EXPECT_TRUE(stdA < fbB);
1484   EXPECT_TRUE(fbA < stdB);
1485   EXPECT_TRUE(stdB > fbA);
1486   EXPECT_TRUE(fbB > stdA);
1487   EXPECT_TRUE(stdA <= fbB);
1488   EXPECT_TRUE(fbA <= stdB);
1489   EXPECT_TRUE(stdA <= fbA);
1490   EXPECT_TRUE(fbA <= stdA);
1491   EXPECT_TRUE(stdB >= fbA);
1492   EXPECT_TRUE(fbB >= stdA);
1493   EXPECT_TRUE(stdB >= fbB);
1494   EXPECT_TRUE(fbB >= stdB);
1495 }
1496
1497 TEST(U32FBString, compareToStdU32String) {
1498   using folly::basic_fbstring;
1499   using namespace std::string_literals;
1500   auto stdA = U"a"s;
1501   auto stdB = U"b"s;
1502   basic_fbstring<char32_t> fbA(U"a");
1503   basic_fbstring<char32_t> fbB(U"b");
1504   EXPECT_TRUE(stdA == fbA);
1505   EXPECT_TRUE(fbB == stdB);
1506   EXPECT_TRUE(stdA != fbB);
1507   EXPECT_TRUE(fbA != stdB);
1508   EXPECT_TRUE(stdA < fbB);
1509   EXPECT_TRUE(fbA < stdB);
1510   EXPECT_TRUE(stdB > fbA);
1511   EXPECT_TRUE(fbB > stdA);
1512   EXPECT_TRUE(stdA <= fbB);
1513   EXPECT_TRUE(fbA <= stdB);
1514   EXPECT_TRUE(stdA <= fbA);
1515   EXPECT_TRUE(fbA <= stdA);
1516   EXPECT_TRUE(stdB >= fbA);
1517   EXPECT_TRUE(fbB >= stdA);
1518   EXPECT_TRUE(stdB >= fbB);
1519   EXPECT_TRUE(fbB >= stdB);
1520 }
1521
1522 TEST(WFBString, compareToStdWString) {
1523   using folly::basic_fbstring;
1524   using namespace std::string_literals;
1525   auto stdA = L"a"s;
1526   auto stdB = L"b"s;
1527   basic_fbstring<wchar_t> fbA(L"a");
1528   basic_fbstring<wchar_t> fbB(L"b");
1529   EXPECT_TRUE(stdA == fbA);
1530   EXPECT_TRUE(fbB == stdB);
1531   EXPECT_TRUE(stdA != fbB);
1532   EXPECT_TRUE(fbA != stdB);
1533   EXPECT_TRUE(stdA < fbB);
1534   EXPECT_TRUE(fbA < stdB);
1535   EXPECT_TRUE(stdB > fbA);
1536   EXPECT_TRUE(fbB > stdA);
1537   EXPECT_TRUE(stdA <= fbB);
1538   EXPECT_TRUE(fbA <= stdB);
1539   EXPECT_TRUE(stdA <= fbA);
1540   EXPECT_TRUE(fbA <= stdA);
1541   EXPECT_TRUE(stdB >= fbA);
1542   EXPECT_TRUE(fbB >= stdA);
1543   EXPECT_TRUE(stdB >= fbB);
1544   EXPECT_TRUE(fbB >= stdB);
1545 }
1546
1547 // Same again, but with a more challenging input - a common prefix and different
1548 // lengths.
1549
1550 TEST(FBString, compareToStdStringLong) {
1551   using folly::fbstring;
1552   using namespace std::string_literals;
1553   auto stdA = "1234567890a"s;
1554   auto stdB = "1234567890ab"s;
1555   fbstring fbA("1234567890a");
1556   fbstring fbB("1234567890ab");
1557   EXPECT_TRUE(stdA == fbA);
1558   EXPECT_TRUE(fbB == stdB);
1559   EXPECT_TRUE(stdA != fbB);
1560   EXPECT_TRUE(fbA != stdB);
1561   EXPECT_TRUE(stdA < fbB);
1562   EXPECT_TRUE(fbA < stdB);
1563   EXPECT_TRUE(stdB > fbA);
1564   EXPECT_TRUE(fbB > stdA);
1565   EXPECT_TRUE(stdA <= fbB);
1566   EXPECT_TRUE(fbA <= stdB);
1567   EXPECT_TRUE(stdA <= fbA);
1568   EXPECT_TRUE(fbA <= stdA);
1569   EXPECT_TRUE(stdB >= fbA);
1570   EXPECT_TRUE(fbB >= stdA);
1571   EXPECT_TRUE(stdB >= fbB);
1572   EXPECT_TRUE(fbB >= stdB);
1573 }
1574
1575 TEST(U16FBString, compareToStdU16StringLong) {
1576   using folly::basic_fbstring;
1577   using namespace std::string_literals;
1578   auto stdA = u"1234567890a"s;
1579   auto stdB = u"1234567890ab"s;
1580   basic_fbstring<char16_t> fbA(u"1234567890a");
1581   basic_fbstring<char16_t> fbB(u"1234567890ab");
1582   EXPECT_TRUE(stdA == fbA);
1583   EXPECT_TRUE(fbB == stdB);
1584   EXPECT_TRUE(stdA != fbB);
1585   EXPECT_TRUE(fbA != stdB);
1586   EXPECT_TRUE(stdA < fbB);
1587   EXPECT_TRUE(fbA < stdB);
1588   EXPECT_TRUE(stdB > fbA);
1589   EXPECT_TRUE(fbB > stdA);
1590   EXPECT_TRUE(stdA <= fbB);
1591   EXPECT_TRUE(fbA <= stdB);
1592   EXPECT_TRUE(stdA <= fbA);
1593   EXPECT_TRUE(fbA <= stdA);
1594   EXPECT_TRUE(stdB >= fbA);
1595   EXPECT_TRUE(fbB >= stdA);
1596   EXPECT_TRUE(stdB >= fbB);
1597   EXPECT_TRUE(fbB >= stdB);
1598 }
1599
1600 #if FOLLY_HAVE_WCHAR_SUPPORT
1601 TEST(U32FBString, compareToStdU32StringLong) {
1602   using folly::basic_fbstring;
1603   using namespace std::string_literals;
1604   auto stdA = U"1234567890a"s;
1605   auto stdB = U"1234567890ab"s;
1606   basic_fbstring<char32_t> fbA(U"1234567890a");
1607   basic_fbstring<char32_t> fbB(U"1234567890ab");
1608   EXPECT_TRUE(stdA == fbA);
1609   EXPECT_TRUE(fbB == stdB);
1610   EXPECT_TRUE(stdA != fbB);
1611   EXPECT_TRUE(fbA != stdB);
1612   EXPECT_TRUE(stdA < fbB);
1613   EXPECT_TRUE(fbA < stdB);
1614   EXPECT_TRUE(stdB > fbA);
1615   EXPECT_TRUE(fbB > stdA);
1616   EXPECT_TRUE(stdA <= fbB);
1617   EXPECT_TRUE(fbA <= stdB);
1618   EXPECT_TRUE(stdA <= fbA);
1619   EXPECT_TRUE(fbA <= stdA);
1620   EXPECT_TRUE(stdB >= fbA);
1621   EXPECT_TRUE(fbB >= stdA);
1622   EXPECT_TRUE(stdB >= fbB);
1623   EXPECT_TRUE(fbB >= stdB);
1624 }
1625
1626 TEST(WFBString, compareToStdWStringLong) {
1627   using folly::basic_fbstring;
1628   using namespace std::string_literals;
1629   auto stdA = L"1234567890a"s;
1630   auto stdB = L"1234567890ab"s;
1631   basic_fbstring<wchar_t> fbA(L"1234567890a");
1632   basic_fbstring<wchar_t> fbB(L"1234567890ab");
1633   EXPECT_TRUE(stdA == fbA);
1634   EXPECT_TRUE(fbB == stdB);
1635   EXPECT_TRUE(stdA != fbB);
1636   EXPECT_TRUE(fbA != stdB);
1637   EXPECT_TRUE(stdA < fbB);
1638   EXPECT_TRUE(fbA < stdB);
1639   EXPECT_TRUE(stdB > fbA);
1640   EXPECT_TRUE(fbB > stdA);
1641   EXPECT_TRUE(stdA <= fbB);
1642   EXPECT_TRUE(fbA <= stdB);
1643   EXPECT_TRUE(stdA <= fbA);
1644   EXPECT_TRUE(fbA <= stdA);
1645   EXPECT_TRUE(stdB >= fbA);
1646   EXPECT_TRUE(fbB >= stdA);
1647   EXPECT_TRUE(stdB >= fbB);
1648   EXPECT_TRUE(fbB >= stdB);
1649 }
1650 #endif