IOBuf::getIov
[folly.git] / folly / test / FBStringTest.cpp
1 /*
2  * Copyright 2013 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 <cstdlib>
23
24 #include <list>
25 #include <fstream>
26 #include <boost/algorithm/string.hpp>
27 #include <boost/random.hpp>
28 #include <gtest/gtest.h>
29
30 #include <gflags/gflags.h>
31
32 #include "folly/Foreach.h"
33 #include "folly/Random.h"
34 #include "folly/Conv.h"
35
36 using namespace std;
37 using namespace folly;
38
39 static const int seed = folly::randomNumberSeed();
40 typedef boost::mt19937 RandomT;
41 static RandomT rng(seed);
42 static const size_t maxString = 100;
43 static const bool avoidAliasing = true;
44
45 template <class Integral1, class Integral2>
46 Integral2 random(Integral1 low, Integral2 up) {
47   boost::uniform_int<> range(low, up);
48   return range(rng);
49 }
50
51 template <class String>
52 void randomString(String* toFill, unsigned int maxSize = 1000) {
53   assert(toFill);
54   toFill->resize(random(0, maxSize));
55   FOR_EACH (i, *toFill) {
56     *i = random('a', 'z');
57   }
58 }
59
60 template <class String, class Integral>
61 void Num2String(String& str, Integral n) {
62
63   std::string tmp = folly::to<std::string>(n);
64   str = String(tmp.begin(), tmp.end());
65 }
66
67 std::list<char> RandomList(unsigned int maxSize) {
68   std::list<char> lst(random(0u, maxSize));
69   std::list<char>::iterator i = lst.begin();
70   for (; i != lst.end(); ++i) {
71     *i = random('a', 'z');
72  }
73   return lst;
74 }
75
76 ////////////////////////////////////////////////////////////////////////////////
77 // Tests begin here
78 ////////////////////////////////////////////////////////////////////////////////
79
80 template <class String> void clause_21_3_1_a(String & test) {
81   test.String::~String();
82   new(&test) String();
83 }
84 template <class String> void clause_21_3_1_b(String & test) {
85   // Copy constructor
86   const size_t pos = random(0, test.size());
87   String s(test, pos, random(0, (size_t)(test.size() - pos)));
88   test = s;
89 }
90 template <class String> void clause_21_3_1_c(String & test) {
91   // Constructor from char*, size_t
92   const size_t
93     pos = random(0, test.size()),
94     n = random(0, test.size() - pos);
95   String before(test.data(), test.size());
96   String s(test.c_str() + pos, n);
97   String after(test.data(), test.size());
98   EXPECT_EQ(before, after);
99
100   // Constructor from char*, char*
101   String s1(test.begin(), test.end());
102   EXPECT_EQ(test, s1);
103   String s2(test.data(), test.data() + test.size());
104   EXPECT_EQ(test, s2);
105
106   // Constructor from iterators
107   std::list<char> lst;
108   for (auto c : test) lst.push_back(c);
109   String s3(lst.begin(), lst.end());
110   EXPECT_EQ(test, s3);
111
112   // Constructor from wchar_t iterators
113   std::list<wchar_t> lst1;
114   for (auto c : test) lst1.push_back(c);
115   String s4(lst1.begin(), lst1.end());
116   EXPECT_EQ(test, s4);
117
118   // Constructor from wchar_t pointers
119   wchar_t t[20];
120   t[0] = 'a';
121   t[1] = 'b';
122   fbstring s5(t, t + 2);;
123   EXPECT_EQ("ab", s5);
124
125   test = s;
126 }
127 template <class String> void clause_21_3_1_d(String & test) {
128   // Assignment
129   auto size = random(0, 2000);
130   String s(size, '\0');
131   EXPECT_EQ(s.size(), size);
132   FOR_EACH_RANGE (i, 0, s.size()) {
133     s[i] = random('a', 'z');
134   }
135   test = s;
136 }
137 template <class String> void clause_21_3_1_e(String & test) {
138   // Assignment from char*
139   String s(random(0, 1000), '\0');
140   size_t i = 0;
141   for (; i != s.size(); ++i) {
142     s[i] = random('a', 'z');
143   }
144   test = s.c_str();
145 }
146 template <class String> void clause_21_3_1_f(String & test) {
147   // Aliased assign
148   const size_t pos = random(0, test.size());
149   if (avoidAliasing) {
150     test = String(test.c_str() + pos);
151   } else {
152     test = test.c_str() + pos;
153   }
154 }
155 template <class String> void clause_21_3_1_g(String & test) {
156   // Assignment from char
157   test = random('a', 'z');
158 }
159
160 template <class String> void clause_21_3_2(String & test) {
161   // Iterators. The code below should leave test unchanged
162   EXPECT_EQ(test.size(), test.end() - test.begin());
163   EXPECT_EQ(test.size(), test.rend() - test.rbegin());
164
165   auto s = test.size();
166   test.resize(test.end() - test.begin());
167   EXPECT_EQ(s, test.size());
168   test.resize(test.rend() - test.rbegin());
169   EXPECT_EQ(s, test.size());
170 }
171
172 template <class String> void clause_21_3_3(String & test) {
173   // exercise capacity, size, max_size
174   EXPECT_EQ(test.size(), test.length());
175   EXPECT_LE(test.size(), test.max_size());
176   EXPECT_LE(test.capacity(), test.max_size());
177   EXPECT_LE(test.size(), test.capacity());
178   // exercise empty
179   string empty("empty");
180   string notempty("not empty");
181   if (test.empty()) test = String(empty.begin(), empty.end());
182   else test = String(notempty.begin(), notempty.end());
183 }
184
185 template <class String> void clause_21_3_4(String & test) {
186   // exercise element access 21.3.4
187   if (!test.empty()) {
188     auto const i = random(0, test.size() - 1);
189     EXPECT_EQ(test[i], test.at(i));
190     test = test[i];
191   }
192 }
193
194 template <class String> void clause_21_3_5_a(String & test) {
195   // 21.3.5 modifiers (+=)
196   String test1;
197   randomString(&test1);
198   assert(test1.size() == char_traits
199       <typename String::value_type>::length(test1.c_str()));
200   auto len = test.size();
201   test += test1;
202   EXPECT_EQ(test.size(), test1.size() + len);
203   FOR_EACH_RANGE (i, 0, test1.size()) {
204     EXPECT_EQ(test[len + i], test1[i]);
205   }
206   // aliasing modifiers
207   String test2 = test;
208   auto dt = test2.data();
209   auto sz = test.c_str();
210   len = test.size();
211   EXPECT_EQ(memcmp(sz, dt, len), 0);
212   String copy(test.data(), test.size());
213   EXPECT_EQ(char_traits
214       <typename String::value_type>::length(test.c_str()), len);
215   test += test;
216   //test.append(test);
217   EXPECT_EQ(test.size(), 2 * len);
218   EXPECT_EQ(char_traits
219       <typename String::value_type>::length(test.c_str()), 2 * len);
220   FOR_EACH_RANGE (i, 0, len) {
221     EXPECT_EQ(test[i], copy[i]);
222     EXPECT_EQ(test[i], test[len + i]);
223   }
224   len = test.size();
225   EXPECT_EQ(char_traits
226       <typename String::value_type>::length(test.c_str()), len);
227   // more aliasing
228   auto const pos = random(0, test.size());
229   EXPECT_EQ(char_traits
230       <typename String::value_type>::length(test.c_str() + pos), len - pos);
231   if (avoidAliasing) {
232     String addMe(test.c_str() + pos);
233     EXPECT_EQ(addMe.size(), len - pos);
234     test += addMe;
235   } else {
236     test += test.c_str() + pos;
237   }
238   EXPECT_EQ(test.size(), 2 * len - pos);
239   // single char
240   len = test.size();
241   test += random('a', 'z');
242   EXPECT_EQ(test.size(), len + 1);
243 }
244
245 template <class String> void clause_21_3_5_b(String & test) {
246   // 21.3.5 modifiers (append, push_back)
247   String s;
248
249   // Test with a small string first
250   char c = random('a', 'z');
251   s.push_back(c);
252   EXPECT_EQ(s[s.size() - 1], c);
253   EXPECT_EQ(s.size(), 1);
254   s.resize(s.size() - 1);
255
256   randomString(&s, maxString);
257   test.append(s);
258   randomString(&s, maxString);
259   test.append(s, random(0, s.size()), random(0, maxString));
260   randomString(&s, maxString);
261   test.append(s.c_str(), random(0, s.size()));
262   randomString(&s, maxString);
263   test.append(s.c_str());
264   test.append(random(0, maxString), random('a', 'z'));
265   std::list<char> lst(RandomList(maxString));
266   test.append(lst.begin(), lst.end());
267   c = random('a', 'z');
268   test.push_back(c);
269   EXPECT_EQ(test[test.size() - 1], c);
270 }
271
272 template <class String> void clause_21_3_5_c(String & test) {
273   // assign
274   String s;
275   randomString(&s);
276   test.assign(s);
277 }
278
279 template <class String> void clause_21_3_5_d(String & test) {
280   // assign
281   String s;
282   randomString(&s, maxString);
283   test.assign(s, random(0, s.size()), random(0, maxString));
284 }
285
286 template <class String> void clause_21_3_5_e(String & test) {
287   // assign
288   String s;
289   randomString(&s, maxString);
290   test.assign(s.c_str(), random(0, s.size()));
291 }
292
293 template <class String> void clause_21_3_5_f(String & test) {
294   // assign
295   String s;
296   randomString(&s, maxString);
297   test.assign(s.c_str());
298 }
299
300 template <class String> void clause_21_3_5_g(String & test) {
301   // assign
302   String s;
303   randomString(&s, maxString);
304   test.assign(random(0, maxString), random('a', 'z'));
305 }
306
307 template <class String> void clause_21_3_5_h(String & test) {
308   // assign from bidirectional iterator
309   std::list<char> lst(RandomList(maxString));
310   test.assign(lst.begin(), lst.end());
311 }
312
313 template <class String> void clause_21_3_5_i(String & test) {
314   // assign from aliased source
315   test.assign(test);
316 }
317
318 template <class String> void clause_21_3_5_j(String & test) {
319   // assign from aliased source
320   test.assign(test, random(0, test.size()), random(0, maxString));
321 }
322
323 template <class String> void clause_21_3_5_k(String & test) {
324   // assign from aliased source
325   test.assign(test.c_str(), random(0, test.size()));
326 }
327
328 template <class String> void clause_21_3_5_l(String & test) {
329   // assign from aliased source
330   test.assign(test.c_str());
331 }
332
333 template <class String> void clause_21_3_5_m(String & test) {
334   // insert
335   String s;
336   randomString(&s, maxString);
337   test.insert(random(0, test.size()), s);
338   randomString(&s, maxString);
339   test.insert(random(0, test.size()),
340               s, random(0, s.size()),
341               random(0, maxString));
342   randomString(&s, maxString);
343   test.insert(random(0, test.size()),
344               s.c_str(), random(0, s.size()));
345   randomString(&s, maxString);
346   test.insert(random(0, test.size()), s.c_str());
347   test.insert(random(0, test.size()),
348               random(0, maxString), random('a', 'z'));
349   test.insert(test.begin() + random(0, test.size()),
350               random('a', 'z'));
351   std::list<char> lst(RandomList(maxString));
352   test.insert(test.begin() + random(0, test.size()),
353               lst.begin(), lst.end());
354 }
355
356 template <class String> void clause_21_3_5_n(String & test) {
357   // erase
358   if (!test.empty()) {
359     test.erase(random(0, test.size()), random(0, maxString));
360   }
361   if (!test.empty()) {
362     // TODO: is erase(end()) allowed?
363     test.erase(test.begin() + random(0, test.size() - 1));
364   }
365   if (!test.empty()) {
366     auto const i = test.begin() + random(0, test.size());
367     if (i != test.end()) {
368       test.erase(i, i + random(0, size_t(test.end() - i)));
369     }
370   }
371 }
372
373 template <class String> void clause_21_3_5_o(String & test) {
374   auto pos = random(0, test.size());
375   if (avoidAliasing) {
376     test.replace(pos, random(0, test.size() - pos),
377                  String(test));
378   } else {
379     test.replace(pos, random(0, test.size() - pos), test);
380   }
381   pos = random(0, test.size());
382   String s;
383   randomString(&s, maxString);
384   test.replace(pos, pos + random(0, test.size() - pos), s);
385   auto pos1 = random(0, test.size());
386   auto pos2 = random(0, test.size());
387   if (avoidAliasing) {
388     test.replace(pos1, pos1 + random(0, test.size() - pos1),
389                  String(test),
390                  pos2, pos2 + random(0, test.size() - pos2));
391   } else {
392     test.replace(pos1, pos1 + random(0, test.size() - pos1),
393                  test, pos2, pos2 + random(0, test.size() - pos2));
394   }
395   pos1 = random(0, test.size());
396   String str;
397   randomString(&str, maxString);
398   pos2 = random(0, str.size());
399   test.replace(pos1, pos1 + random(0, test.size() - pos1),
400                str, pos2, pos2 + random(0, str.size() - pos2));
401   pos = random(0, test.size());
402   if (avoidAliasing) {
403     test.replace(pos, random(0, test.size() - pos),
404                  String(test).c_str(), test.size());
405   } else {
406     test.replace(pos, random(0, test.size() - pos),
407                  test.c_str(), test.size());
408   }
409   pos = random(0, test.size());
410   randomString(&str, maxString);
411   test.replace(pos, pos + random(0, test.size() - pos),
412                str.c_str(), str.size());
413   pos = random(0, test.size());
414   randomString(&str, maxString);
415   test.replace(pos, pos + random(0, test.size() - pos),
416                str.c_str());
417   pos = random(0, test.size());
418   test.replace(pos, random(0, test.size() - pos),
419                random(0, maxString), random('a', 'z'));
420   pos = random(0, test.size());
421   if (avoidAliasing) {
422     test.replace(
423       test.begin() + pos,
424       test.begin() + pos + random(0, test.size() - pos),
425       String(test));
426   } else {
427     test.replace(
428       test.begin() + pos,
429       test.begin() + pos + random(0, test.size() - pos),
430       test);
431   }
432   pos = random(0, test.size());
433   if (avoidAliasing) {
434     test.replace(
435       test.begin() + pos,
436       test.begin() + pos + random(0, test.size() - pos),
437       String(test).c_str(),
438       test.size() - random(0, test.size()));
439   } else {
440     test.replace(
441       test.begin() + pos,
442       test.begin() + pos + random(0, test.size() - pos),
443       test.c_str(),
444       test.size() - random(0, test.size()));
445   }
446   pos = random(0, test.size());
447   auto const n = random(0, test.size() - pos);
448   typename String::iterator b = test.begin();
449   String str1;
450   randomString(&str1, maxString);
451   const String & str3 = str1;
452   const typename String::value_type* ss = str3.c_str();
453   test.replace(
454     b + pos,
455     b + pos + n,
456     ss);
457   pos = random(0, test.size());
458   test.replace(
459     test.begin() + pos,
460     test.begin() + pos + random(0, test.size() - pos),
461     random(0, maxString), random('a', 'z'));
462 }
463
464 template <class String> void clause_21_3_5_p(String & test) {
465   std::vector<typename String::value_type>
466     vec(random(0, maxString));
467   test.copy(
468     &vec[0],
469     vec.size(),
470     random(0, test.size()));
471 }
472
473 template <class String> void clause_21_3_5_q(String & test) {
474   String s;
475   randomString(&s, maxString);
476   s.swap(test);
477 }
478
479 template <class String> void clause_21_3_6_a(String & test) {
480   // 21.3.6 string operations
481   // exercise c_str() and data()
482   assert(test.c_str() == test.data());
483   // exercise get_allocator()
484   String s;
485   randomString(&s, maxString);
486   assert(test.get_allocator() == s.get_allocator());
487 }
488
489 template <class String> void clause_21_3_6_b(String & test) {
490   String str = test.substr(
491     random(0, test.size()),
492     random(0, test.size()));
493   Num2String(test, test.find(str, random(0, test.size())));
494 }
495
496 template <class String> void clause_21_3_6_c(String & test) {
497   auto from = random(0, test.size());
498   auto length = random(0, test.size() - from);
499   String str = test.substr(from, length);
500   Num2String(test, test.find(str.c_str(),
501                              random(0, test.size()),
502                              random(0, str.size())));
503 }
504
505 template <class String> void clause_21_3_6_d(String & test) {
506   String str = test.substr(
507     random(0, test.size()),
508     random(0, test.size()));
509   Num2String(test, test.find(str.c_str(),
510                              random(0, test.size())));
511 }
512
513 template <class String> void clause_21_3_6_e(String & test) {
514   Num2String(test, test.find(
515                random('a', 'z'),
516                random(0, test.size())));
517 }
518
519 template <class String> void clause_21_3_6_f(String & test) {
520   String str = test.substr(
521     random(0, test.size()),
522     random(0, test.size()));
523   Num2String(test, test.rfind(str, random(0, test.size())));
524 }
525
526 template <class String> void clause_21_3_6_g(String & test) {
527   String str = test.substr(
528     random(0, test.size()),
529     random(0, test.size()));
530   Num2String(test, test.rfind(str.c_str(),
531                               random(0, test.size()),
532                               random(0, str.size())));
533 }
534
535 template <class String> void clause_21_3_6_h(String & test) {
536   String str = test.substr(
537     random(0, test.size()),
538     random(0, test.size()));
539   Num2String(test, test.rfind(str.c_str(),
540                               random(0, test.size())));
541 }
542
543 template <class String> void clause_21_3_6_i(String & test) {
544   Num2String(test, test.rfind(
545                random('a', 'z'),
546                random(0, test.size())));
547 }
548
549 template <class String> void clause_21_3_6_j(String & test) {
550   String str;
551   randomString(&str, maxString);
552   Num2String(test, test.find_first_of(str,
553                                       random(0, test.size())));
554 }
555
556 template <class String> void clause_21_3_6_k(String & test) {
557   String str;
558   randomString(&str, maxString);
559   Num2String(test, test.find_first_of(str.c_str(),
560                                       random(0, test.size()),
561                                       random(0, str.size())));
562 }
563
564 template <class String> void clause_21_3_6_l(String & test) {
565   String str;
566   randomString(&str, maxString);
567   Num2String(test, test.find_first_of(str.c_str(),
568                                       random(0, test.size())));
569 }
570
571 template <class String> void clause_21_3_6_m(String & test) {
572   Num2String(test, test.find_first_of(
573                random('a', 'z'),
574                random(0, test.size())));
575 }
576
577 template <class String> void clause_21_3_6_n(String & test) {
578   String str;
579   randomString(&str, maxString);
580   Num2String(test, test.find_last_of(str,
581                                      random(0, test.size())));
582 }
583
584 template <class String> void clause_21_3_6_o(String & test) {
585   String str;
586   randomString(&str, maxString);
587   Num2String(test, test.find_last_of(str.c_str(),
588                                      random(0, test.size()),
589                                      random(0, str.size())));
590 }
591
592 template <class String> void clause_21_3_6_p(String & test) {
593   String str;
594   randomString(&str, maxString);
595   Num2String(test, test.find_last_of(str.c_str(),
596                                      random(0, test.size())));
597 }
598
599 template <class String> void clause_21_3_6_q(String & test) {
600   Num2String(test, test.find_last_of(
601                random('a', 'z'),
602                random(0, test.size())));
603 }
604
605 template <class String> void clause_21_3_6_r(String & test) {
606   String str;
607   randomString(&str, maxString);
608   Num2String(test, test.find_first_not_of(str,
609                                           random(0, test.size())));
610 }
611
612 template <class String> void clause_21_3_6_s(String & test) {
613   String str;
614   randomString(&str, maxString);
615   Num2String(test, test.find_first_not_of(str.c_str(),
616                                           random(0, test.size()),
617                                           random(0, str.size())));
618 }
619
620 template <class String> void clause_21_3_6_t(String & test) {
621   String str;
622   randomString(&str, maxString);
623   Num2String(test, test.find_first_not_of(str.c_str(),
624                                           random(0, test.size())));
625 }
626
627 template <class String> void clause_21_3_6_u(String & test) {
628   Num2String(test, test.find_first_not_of(
629                random('a', 'z'),
630                random(0, test.size())));
631 }
632
633 template <class String> void clause_21_3_6_v(String & test) {
634   String str;
635   randomString(&str, maxString);
636   Num2String(test, test.find_last_not_of(str,
637                                          random(0, test.size())));
638 }
639
640 template <class String> void clause_21_3_6_w(String & test) {
641   String str;
642   randomString(&str, maxString);
643   Num2String(test, test.find_last_not_of(str.c_str(),
644                                          random(0, test.size()),
645                                          random(0, str.size())));
646 }
647
648 template <class String> void clause_21_3_6_x(String & test) {
649   String str;
650   randomString(&str, maxString);
651   Num2String(test, test.find_last_not_of(str.c_str(),
652                                          random(0, test.size())));
653 }
654
655 template <class String> void clause_21_3_6_y(String & test) {
656   Num2String(test, test.find_last_not_of(
657                random('a', 'z'),
658                random(0, test.size())));
659 }
660
661 template <class String> void clause_21_3_6_z(String & test) {
662   test = test.substr(random(0, test.size()), random(0, test.size()));
663 }
664
665 template <class String> void clause_21_3_7_a(String & test) {
666   String s;
667   randomString(&s, maxString);
668   int tristate = test.compare(s);
669   if (tristate > 0) tristate = 1;
670   else if (tristate < 0) tristate = 2;
671   Num2String(test, tristate);
672 }
673
674 template <class String> void clause_21_3_7_b(String & test) {
675   String s;
676   randomString(&s, maxString);
677   int tristate = test.compare(
678     random(0, test.size()),
679     random(0, test.size()),
680     s);
681   if (tristate > 0) tristate = 1;
682   else if (tristate < 0) tristate = 2;
683   Num2String(test, tristate);
684 }
685
686 template <class String> void clause_21_3_7_c(String & test) {
687   String str;
688   randomString(&str, maxString);
689   int tristate = test.compare(
690     random(0, test.size()),
691     random(0, test.size()),
692     str,
693     random(0, str.size()),
694     random(0, str.size()));
695   if (tristate > 0) tristate = 1;
696   else if (tristate < 0) tristate = 2;
697   Num2String(test, tristate);
698 }
699
700 template <class String> void clause_21_3_7_d(String & test) {
701   String s;
702   randomString(&s, maxString);
703   int tristate = test.compare(s.c_str());
704   if (tristate > 0) tristate = 1;
705   else if (tristate < 0) tristate = 2;
706                 Num2String(test, tristate);
707 }
708
709 template <class String> void clause_21_3_7_e(String & test) {
710   String str;
711   randomString(&str, maxString);
712   int tristate = test.compare(
713     random(0, test.size()),
714     random(0, test.size()),
715     str.c_str(),
716     random(0, str.size()));
717   if (tristate > 0) tristate = 1;
718   else if (tristate < 0) tristate = 2;
719   Num2String(test, tristate);
720 }
721
722 template <class String> void clause_21_3_7_f(String & test) {
723   String s1;
724   randomString(&s1, maxString);
725   String s2;
726   randomString(&s2, maxString);
727   test = s1 + s2;
728 }
729
730 template <class String> void clause_21_3_7_g(String & test) {
731   String s;
732   randomString(&s, maxString);
733   String s1;
734   randomString(&s1, maxString);
735   test = s.c_str() + s1;
736 }
737
738 template <class String> void clause_21_3_7_h(String & test) {
739   String s;
740   randomString(&s, maxString);
741   test = typename String::value_type(random('a', 'z')) + s;
742 }
743
744 template <class String> void clause_21_3_7_i(String & test) {
745   String s;
746   randomString(&s, maxString);
747   String s1;
748   randomString(&s1, maxString);
749   test = s + s1.c_str();
750 }
751
752 template <class String> void clause_21_3_7_j(String & test) {
753   String s;
754   randomString(&s, maxString);
755   String s1;
756   randomString(&s1, maxString);
757   test = s + s1.c_str();
758 }
759
760 template <class String> void clause_21_3_7_k(String & test) {
761   String s;
762   randomString(&s, maxString);
763   test = s + typename String::value_type(random('a', 'z'));
764 }
765
766 // Numbering here is from C++11
767 template <class String> void clause_21_4_8_9_a(String & test) {
768   basic_stringstream<typename String::value_type> stst(test.c_str());
769   String str;
770   while (stst) {
771     stst >> str;
772     test += str + test;
773   }
774 }
775
776 TEST(FBString, testAllClauses) {
777   EXPECT_TRUE(1) << "Starting with seed: " << seed;
778   std::string r;
779   std::wstring wr;
780   folly::fbstring c;
781   folly::basic_fbstring<wchar_t> wc;
782 #define TEST_CLAUSE(x)                                              \
783   do {                                                              \
784       if (1) {} else EXPECT_TRUE(1) << "Testing clause " << #x;     \
785       randomString(&r);                                             \
786       c = r;                                                        \
787       EXPECT_EQ(c, r);                                              \
788       wr = std::wstring(r.begin(), r.end());                        \
789       wc = folly::basic_fbstring<wchar_t>(wr.c_str());              \
790       auto localSeed = seed + count;                                \
791       rng = RandomT(localSeed);                                     \
792       clause_##x(r);                                                \
793       rng = RandomT(localSeed);                                     \
794       clause_##x(c);                                                \
795       EXPECT_EQ(r, c)                                               \
796         << "Lengths: " << r.size() << " vs. " << c.size()           \
797         << "\nReference: '" << r << "'"                             \
798         << "\nActual:    '" << c.data()[0] << "'";                  \
799       rng = RandomT(localSeed);                                     \
800       clause_##x(wc);                                               \
801       int wret = wcslen(wc.c_str());                                \
802       char mb[wret+1];                                              \
803       int ret = wcstombs(mb, wc.c_str(), sizeof(mb));               \
804       if (ret == wret) mb[wret] = '\0';                             \
805       const char *mc = c.c_str();                                   \
806       std::string one(mb);                                          \
807       std::string two(mc);                                          \
808       EXPECT_EQ(one, two);                                          \
809     } while (++count % 100 != 0)
810
811   int count = 0;
812   TEST_CLAUSE(21_3_1_a);
813   TEST_CLAUSE(21_3_1_b);
814   TEST_CLAUSE(21_3_1_c);
815   TEST_CLAUSE(21_3_1_d);
816   TEST_CLAUSE(21_3_1_e);
817   TEST_CLAUSE(21_3_1_f);
818   TEST_CLAUSE(21_3_1_g);
819
820   TEST_CLAUSE(21_3_2);
821   TEST_CLAUSE(21_3_3);
822   TEST_CLAUSE(21_3_4);
823   TEST_CLAUSE(21_3_5_a);
824   TEST_CLAUSE(21_3_5_b);
825   TEST_CLAUSE(21_3_5_c);
826   TEST_CLAUSE(21_3_5_d);
827   TEST_CLAUSE(21_3_5_e);
828   TEST_CLAUSE(21_3_5_f);
829   TEST_CLAUSE(21_3_5_g);
830   TEST_CLAUSE(21_3_5_h);
831   TEST_CLAUSE(21_3_5_i);
832   TEST_CLAUSE(21_3_5_j);
833   TEST_CLAUSE(21_3_5_k);
834   TEST_CLAUSE(21_3_5_l);
835   TEST_CLAUSE(21_3_5_m);
836   TEST_CLAUSE(21_3_5_n);
837   TEST_CLAUSE(21_3_5_o);
838   TEST_CLAUSE(21_3_5_p);
839
840   TEST_CLAUSE(21_3_6_a);
841   TEST_CLAUSE(21_3_6_b);
842   TEST_CLAUSE(21_3_6_c);
843   TEST_CLAUSE(21_3_6_d);
844   TEST_CLAUSE(21_3_6_e);
845   TEST_CLAUSE(21_3_6_f);
846   TEST_CLAUSE(21_3_6_g);
847   TEST_CLAUSE(21_3_6_h);
848   TEST_CLAUSE(21_3_6_i);
849   TEST_CLAUSE(21_3_6_j);
850   TEST_CLAUSE(21_3_6_k);
851   TEST_CLAUSE(21_3_6_l);
852   TEST_CLAUSE(21_3_6_m);
853   TEST_CLAUSE(21_3_6_n);
854   TEST_CLAUSE(21_3_6_o);
855   TEST_CLAUSE(21_3_6_p);
856   TEST_CLAUSE(21_3_6_q);
857   TEST_CLAUSE(21_3_6_r);
858   TEST_CLAUSE(21_3_6_s);
859   TEST_CLAUSE(21_3_6_t);
860   TEST_CLAUSE(21_3_6_u);
861   TEST_CLAUSE(21_3_6_v);
862   TEST_CLAUSE(21_3_6_w);
863   TEST_CLAUSE(21_3_6_x);
864   TEST_CLAUSE(21_3_6_y);
865   TEST_CLAUSE(21_3_6_z);
866
867   TEST_CLAUSE(21_3_7_a);
868   TEST_CLAUSE(21_3_7_b);
869   TEST_CLAUSE(21_3_7_c);
870   TEST_CLAUSE(21_3_7_d);
871   TEST_CLAUSE(21_3_7_e);
872   TEST_CLAUSE(21_3_7_f);
873   TEST_CLAUSE(21_3_7_g);
874   TEST_CLAUSE(21_3_7_h);
875   TEST_CLAUSE(21_3_7_i);
876   TEST_CLAUSE(21_3_7_j);
877   TEST_CLAUSE(21_3_7_k);
878
879   TEST_CLAUSE(21_4_8_9_a);
880 }
881
882 TEST(FBString, testGetline) {
883   fbstring s1 = "\
884 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan \n\
885 elit ut urna consectetur in sagittis mi auctor. Nulla facilisi. In nec \n\
886 dolor leo, vitae imperdiet neque. Donec ut erat mauris, a faucibus \n\
887 elit. Integer consectetur gravida augue, sit amet mattis mauris auctor \n\
888 sed. Morbi congue libero eu nunc sodales adipiscing. In lectus nunc, \n\
889 vulputate a fringilla at, venenatis quis justo. Proin eu velit \n\
890 nibh. Maecenas vitae tellus eros. Pellentesque habitant morbi \n\
891 tristique senectus et netus et malesuada fames ac turpis \n\
892 egestas. Vivamus faucibus feugiat consequat. Donec fermentum neque sit \n\
893 amet ligula suscipit porta. Phasellus facilisis felis in purus luctus \n\
894 quis posuere leo tempor. Nam nunc purus, luctus a pharetra ut, \n\
895 placerat at dui. Donec imperdiet, diam quis convallis pulvinar, dui \n\
896 est commodo lorem, ut tincidunt diam nibh et nibh. Maecenas nec velit \n\
897 massa, ut accumsan magna. Donec imperdiet tempor nisi et \n\
898 laoreet. Phasellus lectus quam, ultricies ut tincidunt in, dignissim \n\
899 id eros. Mauris vulputate tortor nec neque pellentesque sagittis quis \n\
900 sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam.";
901   char f[] = "/tmp/fbstring_testing.XXXXXX";
902   int fd = mkstemp(f);
903   EXPECT_TRUE(fd > 0);
904   if (fd > 0) {
905     close(fd);  // Yeah
906     std::ofstream out(f);
907     if (!(out << s1)) {
908       EXPECT_TRUE(0) << "Couldn't write to temp file.";
909       return;
910     }
911   }
912   vector<fbstring> v;
913   boost::split(v, s1, boost::is_any_of("\n"));
914   {
915     ifstream input(f);
916     fbstring line;
917     FOR_EACH (i, v) {
918       EXPECT_TRUE(getline(input, line));
919       EXPECT_EQ(line, *i);
920     }
921   }
922   unlink(f);
923 }
924
925 TEST(FBString, testMoveCtor) {
926   // Move constructor. Make sure we allocate a large string, so the
927   // small string optimization doesn't kick in.
928   auto size = random(100, 2000);
929   fbstring s(size, 'a');
930   fbstring test = std::move(s);
931   EXPECT_TRUE(s.empty());
932   EXPECT_EQ(size, test.size());
933 }
934
935 TEST(FBString, testMoveAssign) {
936   // Move constructor. Make sure we allocate a large string, so the
937   // small string optimization doesn't kick in.
938   auto size = random(100, 2000);
939   fbstring s(size, 'a');
940   fbstring test;
941   test = std::move(s);
942   EXPECT_TRUE(s.empty());
943   EXPECT_EQ(size, test.size());
944 }
945
946 TEST(FBString, testMoveOperatorPlusLhs) {
947   // Make sure we allocate a large string, so the
948   // small string optimization doesn't kick in.
949   auto size1 = random(100, 2000);
950   auto size2 = random(100, 2000);
951   fbstring s1(size1, 'a');
952   fbstring s2(size2, 'b');
953   fbstring test;
954   test = std::move(s1) + s2;
955   EXPECT_TRUE(s1.empty());
956   EXPECT_EQ(size1 + size2, test.size());
957 }
958
959 TEST(FBString, testMoveOperatorPlusRhs) {
960   // Make sure we allocate a large string, so the
961   // small string optimization doesn't kick in.
962   auto size1 = random(100, 2000);
963   auto size2 = random(100, 2000);
964   fbstring s1(size1, 'a');
965   fbstring s2(size2, 'b');
966   fbstring test;
967   test = s1 + std::move(s2);
968   EXPECT_EQ(size1 + size2, test.size());
969 }
970
971 TEST(FBString, testConstructionFromLiteralZero) {
972   try {
973     std::string s(0);
974     EXPECT_TRUE(false);
975   } catch (const std::logic_error&) {
976   } catch (...) {
977     EXPECT_TRUE(false);
978   }
979
980   try {
981     fbstring s(0);
982     EXPECT_TRUE(false);
983   } catch (const std::logic_error& e) {
984   } catch (...) {
985     EXPECT_TRUE(false);
986   }
987 }
988
989 TEST(FBString, testFixedBugs) {
990   { // D479397
991     fbstring str(1337, 'f');
992     fbstring cp = str;
993     cp.clear();
994     cp.c_str();
995     EXPECT_EQ(str.front(), 'f');
996   }
997   { // D481173, --extra-cxxflags=-DFBSTRING_CONSERVATIVE
998     fbstring str(1337, 'f');
999     for (int i = 0; i < 2; ++i) {
1000       fbstring cp = str;
1001       cp[1] = 'b';
1002       EXPECT_EQ(cp.c_str()[cp.size()], '\0');
1003       cp.push_back('?');
1004     }
1005   }
1006   { // D580267
1007     {
1008       fbstring str(1337, 'f');
1009       fbstring cp = str;
1010       cp.push_back('f');
1011     }
1012     {
1013       fbstring str(1337, 'f');
1014       fbstring cp = str;
1015       cp += "bb";
1016     }
1017   }
1018   {
1019     // D661622
1020     folly::basic_fbstring<wchar_t> s;
1021     EXPECT_EQ(0, s.size());
1022   }
1023 }
1024
1025
1026 TEST(FBString, testHash) {
1027   fbstring a;
1028   fbstring b;
1029   a.push_back(0);
1030   a.push_back(1);
1031   b.push_back(0);
1032   b.push_back(2);
1033   std::hash<fbstring> hashfunc;
1034   EXPECT_NE(hashfunc(a), hashfunc(b));
1035 }
1036
1037 TEST(FBString, testFrontBack) {
1038   fbstring str("hello");
1039   EXPECT_EQ(str.front(), 'h');
1040   EXPECT_EQ(str.back(), 'o');
1041   str.front() = 'H';
1042   EXPECT_EQ(str.front(), 'H');
1043   str.back() = 'O';
1044   EXPECT_EQ(str.back(), 'O');
1045   EXPECT_EQ(str, "HellO");
1046 }
1047
1048 int main(int argc, char** argv) {
1049   testing::InitGoogleTest(&argc, argv);
1050   google::ParseCommandLineFlags(&argc, &argv, true);
1051   return RUN_ALL_TESTS();
1052 }