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