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