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