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