fix flaky ConnectTFOTimeout and ConnectTFOFallbackTimeout tests
[folly.git] / folly / test / FBStringTest.cpp
1 /*
2  * Copyright 2016 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 #include <gtest/gtest.h>
31
32 #include <folly/Foreach.h>
33 #include <folly/Portability.h>
34 #include <folly/Random.h>
35 #include <folly/Conv.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 #ifndef __ANDROID__
988   // Disabled on Android: wchar support is not recommended and does not
989   // always behave as expected
990   std::wstring wr;
991   folly::basic_fbstring<wchar_t> wc;
992 #endif
993   int count = 0;
994
995   auto l = [&](const char * const clause,
996                void(*f_string)(std::string&),
997                void(*f_fbstring)(folly::fbstring&),
998                void(*f_wfbstring)(folly::basic_fbstring<wchar_t>&)) {
999     do {
1000       if (1) {} else EXPECT_TRUE(1) << "Testing clause " << clause;
1001       randomString(&r);
1002       c = r;
1003       EXPECT_EQ(c, r);
1004 #ifndef __ANDROID__
1005       wr = std::wstring(r.begin(), r.end());
1006       wc = folly::basic_fbstring<wchar_t>(wr.c_str());
1007 #endif
1008       auto localSeed = seed + count;
1009       rng = RandomT(localSeed);
1010       f_string(r);
1011       rng = RandomT(localSeed);
1012       f_fbstring(c);
1013       EXPECT_EQ(r, c)
1014         << "Lengths: " << r.size() << " vs. " << c.size()
1015         << "\nReference: '" << r << "'"
1016         << "\nActual:    '" << c.data()[0] << "'";
1017 #ifndef __ANDROID__
1018       rng = RandomT(localSeed);
1019       f_wfbstring(wc);
1020       int wret = wcslen(wc.c_str());
1021       auto mbv = std::vector<char>(wret + 1);
1022       auto mb = mbv.data();
1023       int ret = wcstombs(mb, wc.c_str(), wret + 1);
1024       if (ret == wret) mb[wret] = '\0';
1025       const char *mc = c.c_str();
1026       std::string one(mb);
1027       std::string two(mc);
1028       EXPECT_EQ(one, two);
1029 #endif
1030     } while (++count % 100 != 0);
1031   };
1032
1033 #define TEST_CLAUSE(x) \
1034   l(#x, \
1035     clause11_##x<std::string>, \
1036     clause11_##x<folly::fbstring>, \
1037     clause11_##x<folly::basic_fbstring<wchar_t>>);
1038
1039   TEST_CLAUSE(21_4_2_a);
1040   TEST_CLAUSE(21_4_2_b);
1041   TEST_CLAUSE(21_4_2_c);
1042   TEST_CLAUSE(21_4_2_d);
1043   TEST_CLAUSE(21_4_2_e);
1044   TEST_CLAUSE(21_4_2_f);
1045   TEST_CLAUSE(21_4_2_g);
1046   TEST_CLAUSE(21_4_2_h);
1047   TEST_CLAUSE(21_4_2_i);
1048   TEST_CLAUSE(21_4_2_j);
1049   TEST_CLAUSE(21_4_2_k);
1050   TEST_CLAUSE(21_4_2_l);
1051   TEST_CLAUSE(21_4_2_lprime);
1052   TEST_CLAUSE(21_4_2_m);
1053   TEST_CLAUSE(21_4_2_n);
1054   TEST_CLAUSE(21_4_3);
1055   TEST_CLAUSE(21_4_4);
1056   TEST_CLAUSE(21_4_5);
1057   TEST_CLAUSE(21_4_6_1);
1058   TEST_CLAUSE(21_4_6_2);
1059   TEST_CLAUSE(21_4_6_3_a);
1060   TEST_CLAUSE(21_4_6_3_b);
1061   TEST_CLAUSE(21_4_6_3_c);
1062   TEST_CLAUSE(21_4_6_3_d);
1063   TEST_CLAUSE(21_4_6_3_e);
1064   TEST_CLAUSE(21_4_6_3_f);
1065   TEST_CLAUSE(21_4_6_3_g);
1066   TEST_CLAUSE(21_4_6_3_h);
1067   TEST_CLAUSE(21_4_6_3_i);
1068   TEST_CLAUSE(21_4_6_3_j);
1069   TEST_CLAUSE(21_4_6_3_k);
1070   TEST_CLAUSE(21_4_6_4);
1071   TEST_CLAUSE(21_4_6_5);
1072   TEST_CLAUSE(21_4_6_6);
1073   TEST_CLAUSE(21_4_6_7);
1074   TEST_CLAUSE(21_4_6_8);
1075   TEST_CLAUSE(21_4_7_1);
1076
1077   TEST_CLAUSE(21_4_7_2_a);
1078   TEST_CLAUSE(21_4_7_2_a1);
1079   TEST_CLAUSE(21_4_7_2_a2);
1080   TEST_CLAUSE(21_4_7_2_b);
1081   TEST_CLAUSE(21_4_7_2_b1);
1082   TEST_CLAUSE(21_4_7_2_b2);
1083   TEST_CLAUSE(21_4_7_2_c);
1084   TEST_CLAUSE(21_4_7_2_c1);
1085   TEST_CLAUSE(21_4_7_2_c2);
1086   TEST_CLAUSE(21_4_7_2_d);
1087   TEST_CLAUSE(21_4_7_3_a);
1088   TEST_CLAUSE(21_4_7_3_b);
1089   TEST_CLAUSE(21_4_7_3_c);
1090   TEST_CLAUSE(21_4_7_3_d);
1091   TEST_CLAUSE(21_4_7_4_a);
1092   TEST_CLAUSE(21_4_7_4_b);
1093   TEST_CLAUSE(21_4_7_4_c);
1094   TEST_CLAUSE(21_4_7_4_d);
1095   TEST_CLAUSE(21_4_7_5_a);
1096   TEST_CLAUSE(21_4_7_5_b);
1097   TEST_CLAUSE(21_4_7_5_c);
1098   TEST_CLAUSE(21_4_7_5_d);
1099   TEST_CLAUSE(21_4_7_6_a);
1100   TEST_CLAUSE(21_4_7_6_b);
1101   TEST_CLAUSE(21_4_7_6_c);
1102   TEST_CLAUSE(21_4_7_6_d);
1103   TEST_CLAUSE(21_4_7_7_a);
1104   TEST_CLAUSE(21_4_7_7_b);
1105   TEST_CLAUSE(21_4_7_7_c);
1106   TEST_CLAUSE(21_4_7_7_d);
1107   TEST_CLAUSE(21_4_7_8);
1108   TEST_CLAUSE(21_4_7_9_a);
1109   TEST_CLAUSE(21_4_7_9_b);
1110   TEST_CLAUSE(21_4_7_9_c);
1111   TEST_CLAUSE(21_4_7_9_d);
1112   TEST_CLAUSE(21_4_7_9_e);
1113   TEST_CLAUSE(21_4_8_1_a);
1114   TEST_CLAUSE(21_4_8_1_b);
1115   TEST_CLAUSE(21_4_8_1_c);
1116   TEST_CLAUSE(21_4_8_1_d);
1117   TEST_CLAUSE(21_4_8_1_e);
1118   TEST_CLAUSE(21_4_8_1_f);
1119   TEST_CLAUSE(21_4_8_1_g);
1120   TEST_CLAUSE(21_4_8_1_h);
1121   TEST_CLAUSE(21_4_8_1_i);
1122   TEST_CLAUSE(21_4_8_1_j);
1123   TEST_CLAUSE(21_4_8_1_k);
1124   TEST_CLAUSE(21_4_8_1_l);
1125   TEST_CLAUSE(21_4_8_9_a);
1126 }
1127
1128 TEST(FBString, testGetline) {
1129   string s1 = "\
1130 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan \n\
1131 elit ut urna consectetur in sagittis mi auctor. Nulla facilisi. In nec \n\
1132 dolor leo, vitae imperdiet neque. Donec ut erat mauris, a faucibus \n\
1133 elit. Integer consectetur gravida augue, sit amet mattis mauris auctor \n\
1134 sed. Morbi congue libero eu nunc sodales adipiscing. In lectus nunc, \n\
1135 vulputate a fringilla at, venenatis quis justo. Proin eu velit \n\
1136 nibh. Maecenas vitae tellus eros. Pellentesque habitant morbi \n\
1137 tristique senectus et netus et malesuada fames ac turpis \n\
1138 egestas. Vivamus faucibus feugiat consequat. Donec fermentum neque sit \n\
1139 amet ligula suscipit porta. Phasellus facilisis felis in purus luctus \n\
1140 quis posuere leo tempor. Nam nunc purus, luctus a pharetra ut, \n\
1141 placerat at dui. Donec imperdiet, diam quis convallis pulvinar, dui \n\
1142 est commodo lorem, ut tincidunt diam nibh et nibh. Maecenas nec velit \n\
1143 massa, ut accumsan magna. Donec imperdiet tempor nisi et \n\
1144 laoreet. Phasellus lectus quam, ultricies ut tincidunt in, dignissim \n\
1145 id eros. Mauris vulputate tortor nec neque pellentesque sagittis quis \n\
1146 sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam.";
1147
1148   vector<fbstring> v;
1149   boost::split(v, s1, boost::is_any_of("\n"));
1150   {
1151     istringstream input(s1);
1152     fbstring line;
1153     FOR_EACH (i, v) {
1154       EXPECT_TRUE(!getline(input, line).fail());
1155       EXPECT_EQ(line, *i);
1156     }
1157   }
1158 }
1159
1160 TEST(FBString, testMoveCtor) {
1161   // Move constructor. Make sure we allocate a large string, so the
1162   // small string optimization doesn't kick in.
1163   auto size = random(100, 2000);
1164   fbstring s(size, 'a');
1165   fbstring test = std::move(s);
1166   EXPECT_TRUE(s.empty());
1167   EXPECT_EQ(size, test.size());
1168 }
1169
1170 TEST(FBString, testMoveAssign) {
1171   // Move constructor. Make sure we allocate a large string, so the
1172   // small string optimization doesn't kick in.
1173   auto size = random(100, 2000);
1174   fbstring s(size, 'a');
1175   fbstring test;
1176   test = std::move(s);
1177   EXPECT_TRUE(s.empty());
1178   EXPECT_EQ(size, test.size());
1179 }
1180
1181 TEST(FBString, testMoveOperatorPlusLhs) {
1182   // Make sure we allocate a large string, so the
1183   // small string optimization doesn't kick in.
1184   auto size1 = random(100, 2000);
1185   auto size2 = random(100, 2000);
1186   fbstring s1(size1, 'a');
1187   fbstring s2(size2, 'b');
1188   fbstring test;
1189   test = std::move(s1) + s2;
1190   EXPECT_TRUE(s1.empty());
1191   EXPECT_EQ(size1 + size2, test.size());
1192 }
1193
1194 TEST(FBString, testMoveOperatorPlusRhs) {
1195   // Make sure we allocate a large string, so the
1196   // small string optimization doesn't kick in.
1197   auto size1 = random(100, 2000);
1198   auto size2 = random(100, 2000);
1199   fbstring s1(size1, 'a');
1200   fbstring s2(size2, 'b');
1201   fbstring test;
1202   test = s1 + std::move(s2);
1203   EXPECT_EQ(size1 + size2, test.size());
1204 }
1205
1206 // The GNU C++ standard library throws an std::logic_error when an std::string
1207 // is constructed with a null pointer. Verify that we mirror this behavior.
1208 //
1209 // N.B. We behave this way even if the C++ library being used is something
1210 //      other than libstdc++. Someday if we deem it important to present
1211 //      identical undefined behavior for other platforms, we can re-visit this.
1212 TEST(FBString, testConstructionFromLiteralZero) {
1213   EXPECT_THROW(fbstring s(0), std::logic_error);
1214 }
1215
1216 TEST(FBString, testFixedBugs) {
1217   { // D479397
1218     fbstring str(1337, 'f');
1219     fbstring cp = str;
1220     cp.clear();
1221     cp.c_str();
1222     EXPECT_EQ(str.front(), 'f');
1223   }
1224   { // D481173
1225     fbstring str(1337, 'f');
1226     for (int i = 0; i < 2; ++i) {
1227       fbstring cp = str;
1228       cp[1] = 'b';
1229       EXPECT_EQ(cp.c_str()[cp.size()], '\0');
1230       cp.push_back('?');
1231     }
1232   }
1233   { // D580267
1234     {
1235       fbstring str(1337, 'f');
1236       fbstring cp = str;
1237       cp.push_back('f');
1238     }
1239     {
1240       fbstring str(1337, 'f');
1241       fbstring cp = str;
1242       cp += "bb";
1243     }
1244   }
1245   { // D661622
1246     folly::basic_fbstring<wchar_t> s;
1247     EXPECT_EQ(0, s.size());
1248   }
1249   { // D785057
1250     fbstring str(1337, 'f');
1251     std::swap(str, str);
1252     EXPECT_EQ(1337, str.size());
1253   }
1254   { // D1012196, --allocator=malloc
1255     fbstring str(128, 'f');
1256     str.clear();  // Empty medium string.
1257     fbstring copy(str);  // Medium string of 0 capacity.
1258     copy.push_back('b');
1259     EXPECT_GE(copy.capacity(), 1);
1260   }
1261   { // D2813713
1262     fbstring s1("a");
1263     s1.reserve(8); // Trigger the optimized code path.
1264     auto test1 = '\0' + std::move(s1);
1265     EXPECT_EQ(2, test1.size());
1266
1267     fbstring s2(1, '\0');
1268     s2.reserve(8);
1269     auto test2 = "a" + std::move(s2);
1270     EXPECT_EQ(2, test2.size());
1271   }
1272 }
1273
1274 TEST(FBString, findWithNpos) {
1275   fbstring fbstr("localhost:80");
1276   EXPECT_EQ(fbstring::npos, fbstr.find(":", fbstring::npos));
1277 }
1278
1279 TEST(FBString, testHash) {
1280   fbstring a;
1281   fbstring b;
1282   a.push_back(0);
1283   a.push_back(1);
1284   b.push_back(0);
1285   b.push_back(2);
1286   std::hash<fbstring> hashfunc;
1287   EXPECT_NE(hashfunc(a), hashfunc(b));
1288 }
1289
1290 TEST(FBString, testFrontBack) {
1291   fbstring str("hello");
1292   EXPECT_EQ(str.front(), 'h');
1293   EXPECT_EQ(str.back(), 'o');
1294   str.front() = 'H';
1295   EXPECT_EQ(str.front(), 'H');
1296   str.back() = 'O';
1297   EXPECT_EQ(str.back(), 'O');
1298   EXPECT_EQ(str, "HellO");
1299 }
1300
1301 TEST(FBString, noexcept) {
1302   EXPECT_TRUE(noexcept(fbstring()));
1303   fbstring x;
1304   EXPECT_FALSE(noexcept(fbstring(x)));
1305   EXPECT_TRUE(noexcept(fbstring(std::move(x))));
1306   fbstring y;
1307   EXPECT_FALSE(noexcept(y = x));
1308   EXPECT_TRUE(noexcept(y = std::move(x)));
1309 }
1310
1311 TEST(FBString, iomanip) {
1312   stringstream ss;
1313   fbstring fbstr("Hello");
1314
1315   ss << setw(6) << fbstr;
1316   EXPECT_EQ(ss.str(), " Hello");
1317   ss.str("");
1318
1319   ss << left << setw(6) << fbstr;
1320   EXPECT_EQ(ss.str(), "Hello ");
1321   ss.str("");
1322
1323   ss << right << setw(6) << fbstr;
1324   EXPECT_EQ(ss.str(), " Hello");
1325   ss.str("");
1326
1327   ss << setw(4) << fbstr;
1328   EXPECT_EQ(ss.str(), "Hello");
1329   ss.str("");
1330
1331   ss << setfill('^') << setw(6) << fbstr;
1332   EXPECT_EQ(ss.str(), "^Hello");
1333   ss.str("");
1334 }
1335
1336 TEST(FBString, rvalueIterators) {
1337   // you cannot take &* of a move-iterator, so use that for testing
1338   fbstring s = "base";
1339   fbstring r = "hello";
1340   r.replace(r.begin(), r.end(),
1341       make_move_iterator(s.begin()), make_move_iterator(s.end()));
1342   EXPECT_EQ("base", r);
1343
1344   // The following test is probably not required by the standard.
1345   // i.e. this could be in the realm of undefined behavior.
1346   fbstring b = "123abcXYZ";
1347   auto ait = b.begin() + 3;
1348   auto Xit = b.begin() + 6;
1349   b.replace(ait, b.end(), b.begin(), Xit);
1350   EXPECT_EQ("123123abc", b); // if things go wrong, you'd get "123123123"
1351 }
1352
1353 TEST(FBString, moveTerminator) {
1354   // The source of a move must remain in a valid state
1355   fbstring s(100, 'x'); // too big to be in-situ
1356   fbstring k;
1357   k = std::move(s);
1358
1359   EXPECT_EQ(0, s.size());
1360   EXPECT_EQ('\0', *s.c_str());
1361 }
1362
1363 namespace {
1364 /*
1365  * t8968589: Clang 3.7 refused to compile w/ certain constructors (specifically
1366  * those that were "explicit" and had a defaulted parameter, if they were used
1367  * in structs which were default-initialized).  Exercise these just to ensure
1368  * they compile.
1369  *
1370  * In diff D2632953 the old constructor:
1371  *   explicit basic_fbstring(const A& a = A()) noexcept;
1372  *
1373  * was split into these two, as a workaround:
1374  *   basic_fbstring() noexcept;
1375  *   explicit basic_fbstring(const A& a) noexcept;
1376  */
1377
1378 struct TestStructDefaultAllocator {
1379   folly::basic_fbstring<char> stringMember;
1380 };
1381
1382 template <class A>
1383 struct TestStructWithAllocator {
1384   folly::basic_fbstring<char, std::char_traits<char>, A> stringMember;
1385 };
1386
1387 std::atomic<size_t> allocatorConstructedCount(0);
1388 struct TestStructStringAllocator : std::allocator<char> {
1389   TestStructStringAllocator() {
1390     ++ allocatorConstructedCount;
1391   }
1392 };
1393
1394 }  // anon namespace
1395
1396 TEST(FBStringCtorTest, DefaultInitStructDefaultAlloc) {
1397   TestStructDefaultAllocator t1 { };
1398   EXPECT_TRUE(t1.stringMember.empty());
1399 }
1400
1401 TEST(FBStringCtorTest, DefaultInitStructAlloc) {
1402   EXPECT_EQ(allocatorConstructedCount.load(), 0);
1403   TestStructWithAllocator<TestStructStringAllocator> t2;
1404   EXPECT_TRUE(t2.stringMember.empty());
1405   EXPECT_EQ(allocatorConstructedCount.load(), 1);
1406 }