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