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