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