Only run FBString.testConstructionFromLiteralZero under GNU libstdc++
[folly.git] / folly / test / FBStringTest.cpp
index bd13a669441b1c6ad01add74e642f41070e1eeb4..6cd5d1fa559c3c394105c680ca1b2838bea94b20 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Facebook, Inc.
+ * Copyright 2013 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,7 +30,9 @@
 #include <gflags/gflags.h>
 
 #include "folly/Foreach.h"
+#include "folly/Portability.h"
 #include "folly/Random.h"
+#include "folly/Conv.h"
 
 using namespace std;
 using namespace folly;
@@ -58,9 +60,9 @@ void randomString(String* toFill, unsigned int maxSize = 1000) {
 
 template <class String, class Integral>
 void Num2String(String& str, Integral n) {
-  str.resize(30, '\0');
-  sprintf(&str[0], "%lu", static_cast<unsigned long>(n));
-  str.resize(strlen(str.c_str()));
+
+  std::string tmp = folly::to<std::string>(n);
+  str = String(tmp.begin(), tmp.end());
 }
 
 std::list<char> RandomList(unsigned int maxSize) {
@@ -76,55 +78,94 @@ std::list<char> RandomList(unsigned int maxSize) {
 // Tests begin here
 ////////////////////////////////////////////////////////////////////////////////
 
-template <class String> void clause_21_3_1_a(String & test) {
+template <class String> void clause11_21_4_2_a(String & test) {
   test.String::~String();
   new(&test) String();
 }
-template <class String> void clause_21_3_1_b(String & test) {
-  // Copy constructor
+template <class String> void clause11_21_4_2_b(String & test) {
+  String test2(test);
+  assert(test2 == test);
+}
+template <class String> void clause11_21_4_2_c(String & test) {
+  // Test move constructor. There is a more specialized test, see
+  // TEST(FBString, testMoveCtor)
+  String donor(test);
+  String test2(std::move(donor));
+  EXPECT_EQ(test2, test);
+  // Technically not required, but all implementations that actually
+  // support move will move large strings. Make a guess for 128 as the
+  // maximum small string optimization that's reasonable.
+  EXPECT_LE(donor.size(), 128);
+}
+template <class String> void clause11_21_4_2_d(String & test) {
+  // Copy constructor with position and length
   const size_t pos = random(0, test.size());
-  String s(test, pos, random(0, (size_t)(test.size() - pos)));
+  String s(test, pos, random(0, 9)
+           ? random(0, (size_t)(test.size() - pos))
+           : String::npos); // test for npos, too, in 10% of the cases
   test = s;
 }
-template <class String> void clause_21_3_1_c(String & test) {
+template <class String> void clause11_21_4_2_e(String & test) {
   // Constructor from char*, size_t
   const size_t
     pos = random(0, test.size()),
     n = random(0, test.size() - pos);
-  std::string before(test.data(), test.size());
+  String before(test.data(), test.size());
   String s(test.c_str() + pos, n);
-  std::string after(test.data(), test.size());
+  String after(test.data(), test.size());
   EXPECT_EQ(before, after);
-
+  test.swap(s);
+}
+template <class String> void clause11_21_4_2_f(String & test) {
+  // Constructor from char*
+  const size_t
+    pos = random(0, test.size()),
+    n = random(0, test.size() - pos);
+  String before(test.data(), test.size());
+  String s(test.c_str() + pos);
+  String after(test.data(), test.size());
+  EXPECT_EQ(before, after);
+  test.swap(s);
+}
+template <class String> void clause11_21_4_2_g(String & test) {
+  // Constructor from size_t, char
+  const size_t n = random(0, test.size());
+  const auto c = test.front();
+  test = String(n, c);
+}
+template <class String> void clause11_21_4_2_h(String & test) {
+  // Constructors from various iterator pairs
   // Constructor from char*, char*
   String s1(test.begin(), test.end());
   EXPECT_EQ(test, s1);
   String s2(test.data(), test.data() + test.size());
   EXPECT_EQ(test, s2);
-
-  // Constructor from iterators
+  // Constructor from other iterators
   std::list<char> lst;
   for (auto c : test) lst.push_back(c);
   String s3(lst.begin(), lst.end());
   EXPECT_EQ(test, s3);
-
   // Constructor from wchar_t iterators
   std::list<wchar_t> lst1;
   for (auto c : test) lst1.push_back(c);
   String s4(lst1.begin(), lst1.end());
   EXPECT_EQ(test, s4);
-
   // Constructor from wchar_t pointers
   wchar_t t[20];
   t[0] = 'a';
   t[1] = 'b';
-  String s5(t, t + 2);;
+  fbstring s5(t, t + 2);;
   EXPECT_EQ("ab", s5);
-
-  test = s;
 }
-template <class String> void clause_21_3_1_d(String & test) {
-  // Assignment
+template <class String> void clause11_21_4_2_i(String & test) {
+  // From initializer_list<char>
+  std::initializer_list<typename String::value_type>
+    il = { 'h', 'e', 'l', 'l', 'o' };
+  String s(il);
+  test.swap(s);
+}
+template <class String> void clause11_21_4_2_j(String & test) {
+  // Assignment from const String&
   auto size = random(0, 2000);
   String s(size, '\0');
   EXPECT_EQ(s.size(), size);
@@ -133,7 +174,20 @@ template <class String> void clause_21_3_1_d(String & test) {
   }
   test = s;
 }
-template <class String> void clause_21_3_1_e(String & test) {
+template <class String> void clause11_21_4_2_k(String & test) {
+  // Assignment from String&&
+  auto size = random(0, 2000);
+  String s(size, '\0');
+  EXPECT_EQ(s.size(), size);
+  FOR_EACH_RANGE (i, 0, s.size()) {
+    s[i] = random('a', 'z');
+  }
+  test = std::move(s);
+  if (typeid(String) == typeid(fbstring)) {
+    EXPECT_LE(s.size(), 128);
+  }
+}
+template <class String> void clause11_21_4_2_l(String & test) {
   // Assignment from char*
   String s(random(0, 1000), '\0');
   size_t i = 0;
@@ -142,7 +196,7 @@ template <class String> void clause_21_3_1_e(String & test) {
   }
   test = s.c_str();
 }
-template <class String> void clause_21_3_1_f(String & test) {
+template <class String> void clause11_21_4_2_lprime(String & test) {
   // Aliased assign
   const size_t pos = random(0, test.size());
   if (avoidAliasing) {
@@ -151,15 +205,23 @@ template <class String> void clause_21_3_1_f(String & test) {
     test = test.c_str() + pos;
   }
 }
-template <class String> void clause_21_3_1_g(String & test) {
+template <class String> void clause11_21_4_2_m(String & test) {
   // Assignment from char
   test = random('a', 'z');
 }
+template <class String> void clause11_21_4_2_n(String & test) {
+  // Assignment from initializer_list<char>
+  initializer_list<typename String::value_type>
+    il = { 'h', 'e', 'l', 'l', 'o' };
+  test = il;
+}
 
-template <class String> void clause_21_3_2(String & test) {
+template <class String> void clause11_21_4_3(String & test) {
   // Iterators. The code below should leave test unchanged
   EXPECT_EQ(test.size(), test.end() - test.begin());
   EXPECT_EQ(test.size(), test.rend() - test.rbegin());
+  EXPECT_EQ(test.size(), test.cend() - test.cbegin());
+  EXPECT_EQ(test.size(), test.crend() - test.crbegin());
 
   auto s = test.size();
   test.resize(test.end() - test.begin());
@@ -168,31 +230,44 @@ template <class String> void clause_21_3_2(String & test) {
   EXPECT_EQ(s, test.size());
 }
 
-template <class String> void clause_21_3_3(String & test) {
+template <class String> void clause11_21_4_4(String & test) {
   // exercise capacity, size, max_size
   EXPECT_EQ(test.size(), test.length());
   EXPECT_LE(test.size(), test.max_size());
   EXPECT_LE(test.capacity(), test.max_size());
   EXPECT_LE(test.size(), test.capacity());
+
+  // exercise shrink_to_fit. Nonbinding request so we can't really do
+  // much beyond calling it.
+  auto copy = test;
+  copy.reserve(copy.capacity() * 3);
+  copy.shrink_to_fit();
+  EXPECT_EQ(copy, test);
+
   // exercise empty
-  if (test.empty()) test = "empty";
-  else test = "not empty";
+  string empty("empty");
+  string notempty("not empty");
+  if (test.empty()) test = String(empty.begin(), empty.end());
+  else test = String(notempty.begin(), notempty.end());
 }
 
-template <class String> void clause_21_3_4(String & test) {
-  // exercise element access 21.3.4
+template <class String> void clause11_21_4_5(String & test) {
+  // exercise element access
   if (!test.empty()) {
+    EXPECT_EQ(test[0], test.front());
+    EXPECT_EQ(test[test.size() - 1], test.back());
     auto const i = random(0, test.size() - 1);
     EXPECT_EQ(test[i], test.at(i));
     test = test[i];
   }
 }
 
-template <class String> void clause_21_3_5_a(String & test) {
+template <class String> void clause11_21_4_6_1(String & test) {
   // 21.3.5 modifiers (+=)
   String test1;
   randomString(&test1);
-  assert(test1.size() == strlen(test1.c_str()));
+  assert(test1.size() == char_traits
+      <typename String::value_type>::length(test1.c_str()));
   auto len = test.size();
   test += test1;
   EXPECT_EQ(test.size(), test1.size() + len);
@@ -206,20 +281,24 @@ template <class String> void clause_21_3_5_a(String & test) {
   len = test.size();
   EXPECT_EQ(memcmp(sz, dt, len), 0);
   String copy(test.data(), test.size());
-  EXPECT_EQ(strlen(test.c_str()), len);
+  EXPECT_EQ(char_traits
+      <typename String::value_type>::length(test.c_str()), len);
   test += test;
   //test.append(test);
   EXPECT_EQ(test.size(), 2 * len);
-  EXPECT_EQ(strlen(test.c_str()), 2 * len);
+  EXPECT_EQ(char_traits
+      <typename String::value_type>::length(test.c_str()), 2 * len);
   FOR_EACH_RANGE (i, 0, len) {
     EXPECT_EQ(test[i], copy[i]);
     EXPECT_EQ(test[i], test[len + i]);
   }
   len = test.size();
-  EXPECT_EQ(strlen(test.c_str()), len);
+  EXPECT_EQ(char_traits
+      <typename String::value_type>::length(test.c_str()), len);
   // more aliasing
   auto const pos = random(0, test.size());
-  EXPECT_EQ(strlen(test.c_str() + pos), len - pos);
+  EXPECT_EQ(char_traits
+      <typename String::value_type>::length(test.c_str() + pos), len - pos);
   if (avoidAliasing) {
     String addMe(test.c_str() + pos);
     EXPECT_EQ(addMe.size(), len - pos);
@@ -232,9 +311,12 @@ template <class String> void clause_21_3_5_a(String & test) {
   len = test.size();
   test += random('a', 'z');
   EXPECT_EQ(test.size(), len + 1);
+  // initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  test += il;
 }
 
-template <class String> void clause_21_3_5_b(String & test) {
+template <class String> void clause11_21_4_6_2(String & test) {
   // 21.3.5 modifiers (append, push_back)
   String s;
 
@@ -259,70 +341,85 @@ template <class String> void clause_21_3_5_b(String & test) {
   c = random('a', 'z');
   test.push_back(c);
   EXPECT_EQ(test[test.size() - 1], c);
+  // initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  test.append(il);
 }
 
-template <class String> void clause_21_3_5_c(String & test) {
+template <class String> void clause11_21_4_6_3_a(String & test) {
   // assign
   String s;
   randomString(&s);
   test.assign(s);
+  EXPECT_EQ(test, s);
+  // move assign
+  test.assign(std::move(s));
+  if (typeid(String) == typeid(fbstring)) {
+    EXPECT_LE(s.size(), 128);
+  }
 }
 
-template <class String> void clause_21_3_5_d(String & test) {
+template <class String> void clause11_21_4_6_3_b(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(s, random(0, s.size()), random(0, maxString));
 }
 
-template <class String> void clause_21_3_5_e(String & test) {
+template <class String> void clause11_21_4_6_3_c(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(s.c_str(), random(0, s.size()));
 }
 
-template <class String> void clause_21_3_5_f(String & test) {
+template <class String> void clause11_21_4_6_3_d(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(s.c_str());
 }
 
-template <class String> void clause_21_3_5_g(String & test) {
+template <class String> void clause11_21_4_6_3_e(String & test) {
   // assign
   String s;
   randomString(&s, maxString);
   test.assign(random(0, maxString), random('a', 'z'));
 }
 
-template <class String> void clause_21_3_5_h(String & test) {
+template <class String> void clause11_21_4_6_3_f(String & test) {
   // assign from bidirectional iterator
   std::list<char> lst(RandomList(maxString));
   test.assign(lst.begin(), lst.end());
 }
 
-template <class String> void clause_21_3_5_i(String & test) {
+template <class String> void clause11_21_4_6_3_g(String & test) {
   // assign from aliased source
   test.assign(test);
 }
 
-template <class String> void clause_21_3_5_j(String & test) {
+template <class String> void clause11_21_4_6_3_h(String & test) {
   // assign from aliased source
   test.assign(test, random(0, test.size()), random(0, maxString));
 }
 
-template <class String> void clause_21_3_5_k(String & test) {
+template <class String> void clause11_21_4_6_3_i(String & test) {
   // assign from aliased source
   test.assign(test.c_str(), random(0, test.size()));
 }
 
-template <class String> void clause_21_3_5_l(String & test) {
+template <class String> void clause11_21_4_6_3_j(String & test) {
   // assign from aliased source
   test.assign(test.c_str());
 }
 
-template <class String> void clause_21_3_5_m(String & test) {
+template <class String> void clause11_21_4_6_3_k(String & test) {
+  // assign from initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  test.assign(il);
+}
+
+template <class String> void clause11_21_4_6_4(String & test) {
   // insert
   String s;
   randomString(&s, maxString);
@@ -338,15 +435,29 @@ template <class String> void clause_21_3_5_m(String & test) {
   test.insert(random(0, test.size()), s.c_str());
   test.insert(random(0, test.size()),
               random(0, maxString), random('a', 'z'));
-  test.insert(test.begin() + random(0, test.size()),
-              random('a', 'z'));
+  typename String::size_type pos = random(0, test.size());
+  typename String::iterator res =
+    test.insert(test.begin() + pos, random('a', 'z'));
+  EXPECT_EQ(res - test.begin(), pos);
   std::list<char> lst(RandomList(maxString));
-  test.insert(test.begin() + random(0, test.size()),
-              lst.begin(), lst.end());
+  pos = random(0, test.size());
+  // Uncomment below to see a bug in gcc
+  /*res = */test.insert(test.begin() + pos, lst.begin(), lst.end());
+  // insert from initializer_list
+  initializer_list<typename String::value_type> il { 'a', 'b', 'c' };
+  pos = random(0, test.size());
+  // Uncomment below to see a bug in gcc
+  /*res = */test.insert(test.begin() + pos, il);
+
+  // Test with actual input iterators
+  stringstream ss;
+  ss << "hello cruel world";
+  auto i = istream_iterator<char>(ss);
+  test.insert(test.begin(), i, istream_iterator<char>());
 }
 
-template <class String> void clause_21_3_5_n(String & test) {
-  // erase
+template <class String> void clause11_21_4_6_5(String & test) {
+  // erase and pop_back
   if (!test.empty()) {
     test.erase(random(0, test.size()), random(0, maxString));
   }
@@ -360,9 +471,13 @@ template <class String> void clause_21_3_5_n(String & test) {
       test.erase(i, i + random(0, size_t(test.end() - i)));
     }
   }
+  if (!test.empty()) {
+    // Can't test pop_back with std::string, doesn't support it yet.
+    //test.pop_back();
+  }
 }
 
-template <class String> void clause_21_3_5_o(String & test) {
+template <class String> void clause11_21_4_6_6(String & test) {
   auto pos = random(0, test.size());
   if (avoidAliasing) {
     test.replace(pos, random(0, test.size() - pos),
@@ -453,7 +568,7 @@ template <class String> void clause_21_3_5_o(String & test) {
     random(0, maxString), random('a', 'z'));
 }
 
-template <class String> void clause_21_3_5_p(String & test) {
+template <class String> void clause11_21_4_6_7(String & test) {
   std::vector<typename String::value_type>
     vec(random(0, maxString));
   test.copy(
@@ -462,13 +577,13 @@ template <class String> void clause_21_3_5_p(String & test) {
     random(0, test.size()));
 }
 
-template <class String> void clause_21_3_5_q(String & test) {
+template <class String> void clause11_21_4_6_8(String & test) {
   String s;
   randomString(&s, maxString);
   s.swap(test);
 }
 
-template <class String> void clause_21_3_6_a(String & test) {
+template <class String> void clause11_21_4_7_1(String & test) {
   // 21.3.6 string operations
   // exercise c_str() and data()
   assert(test.c_str() == test.data());
@@ -478,14 +593,14 @@ template <class String> void clause_21_3_6_a(String & test) {
   assert(test.get_allocator() == s.get_allocator());
 }
 
-template <class String> void clause_21_3_6_b(String & test) {
+template <class String> void clause11_21_4_7_2_a(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
   Num2String(test, test.find(str, random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_c(String & test) {
+template <class String> void clause11_21_4_7_2_b(String & test) {
   auto from = random(0, test.size());
   auto length = random(0, test.size() - from);
   String str = test.substr(from, length);
@@ -494,7 +609,7 @@ template <class String> void clause_21_3_6_c(String & test) {
                              random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_d(String & test) {
+template <class String> void clause11_21_4_7_2_c(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
@@ -502,20 +617,20 @@ template <class String> void clause_21_3_6_d(String & test) {
                              random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_e(String & test) {
+template <class String> void clause11_21_4_7_2_d(String & test) {
   Num2String(test, test.find(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_f(String & test) {
+template <class String> void clause11_21_4_7_3_a(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
   Num2String(test, test.rfind(str, random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_g(String & test) {
+template <class String> void clause11_21_4_7_3_b(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
@@ -524,7 +639,7 @@ template <class String> void clause_21_3_6_g(String & test) {
                               random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_h(String & test) {
+template <class String> void clause11_21_4_7_3_c(String & test) {
   String str = test.substr(
     random(0, test.size()),
     random(0, test.size()));
@@ -532,20 +647,20 @@ template <class String> void clause_21_3_6_h(String & test) {
                               random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_i(String & test) {
+template <class String> void clause11_21_4_7_3_d(String & test) {
   Num2String(test, test.rfind(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_j(String & test) {
+template <class String> void clause11_21_4_7_4_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_of(str,
                                       random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_k(String & test) {
+template <class String> void clause11_21_4_7_4_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_of(str.c_str(),
@@ -553,27 +668,27 @@ template <class String> void clause_21_3_6_k(String & test) {
                                       random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_l(String & test) {
+template <class String> void clause11_21_4_7_4_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_of(str.c_str(),
                                       random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_m(String & test) {
+template <class String> void clause11_21_4_7_4_d(String & test) {
   Num2String(test, test.find_first_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_n(String & test) {
+template <class String> void clause11_21_4_7_5_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_of(str,
                                      random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_o(String & test) {
+template <class String> void clause11_21_4_7_5_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_of(str.c_str(),
@@ -581,27 +696,27 @@ template <class String> void clause_21_3_6_o(String & test) {
                                      random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_p(String & test) {
+template <class String> void clause11_21_4_7_5_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_of(str.c_str(),
                                      random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_q(String & test) {
+template <class String> void clause11_21_4_7_5_d(String & test) {
   Num2String(test, test.find_last_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_r(String & test) {
+template <class String> void clause11_21_4_7_6_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_not_of(str,
                                           random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_s(String & test) {
+template <class String> void clause11_21_4_7_6_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_not_of(str.c_str(),
@@ -609,27 +724,27 @@ template <class String> void clause_21_3_6_s(String & test) {
                                           random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_t(String & test) {
+template <class String> void clause11_21_4_7_6_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_first_not_of(str.c_str(),
                                           random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_u(String & test) {
+template <class String> void clause11_21_4_7_6_d(String & test) {
   Num2String(test, test.find_first_not_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_v(String & test) {
+template <class String> void clause11_21_4_7_7_a(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_not_of(str,
                                          random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_w(String & test) {
+template <class String> void clause11_21_4_7_7_b(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_not_of(str.c_str(),
@@ -637,24 +752,24 @@ template <class String> void clause_21_3_6_w(String & test) {
                                          random(0, str.size())));
 }
 
-template <class String> void clause_21_3_6_x(String & test) {
+template <class String> void clause11_21_4_7_7_c(String & test) {
   String str;
   randomString(&str, maxString);
   Num2String(test, test.find_last_not_of(str.c_str(),
                                          random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_y(String & test) {
+template <class String> void clause11_21_4_7_7_d(String & test) {
   Num2String(test, test.find_last_not_of(
                random('a', 'z'),
                random(0, test.size())));
 }
 
-template <class String> void clause_21_3_6_z(String & test) {
+template <class String> void clause11_21_4_7_8(String & test) {
   test = test.substr(random(0, test.size()), random(0, test.size()));
 }
 
-template <class String> void clause_21_3_7_a(String & test) {
+template <class String> void clause11_21_4_7_9_a(String & test) {
   String s;
   randomString(&s, maxString);
   int tristate = test.compare(s);
@@ -663,7 +778,7 @@ template <class String> void clause_21_3_7_a(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_b(String & test) {
+template <class String> void clause11_21_4_7_9_b(String & test) {
   String s;
   randomString(&s, maxString);
   int tristate = test.compare(
@@ -675,7 +790,7 @@ template <class String> void clause_21_3_7_b(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_c(String & test) {
+template <class String> void clause11_21_4_7_9_c(String & test) {
   String str;
   randomString(&str, maxString);
   int tristate = test.compare(
@@ -689,7 +804,7 @@ template <class String> void clause_21_3_7_c(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_d(String & test) {
+template <class String> void clause11_21_4_7_9_d(String & test) {
   String s;
   randomString(&s, maxString);
   int tristate = test.compare(s.c_str());
@@ -698,7 +813,7 @@ template <class String> void clause_21_3_7_d(String & test) {
                 Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_e(String & test) {
+template <class String> void clause11_21_4_7_9_e(String & test) {
   String str;
   randomString(&str, maxString);
   int tristate = test.compare(
@@ -711,7 +826,7 @@ template <class String> void clause_21_3_7_e(String & test) {
   Num2String(test, tristate);
 }
 
-template <class String> void clause_21_3_7_f(String & test) {
+template <class String> void clause11_21_4_8_1_a(String & test) {
   String s1;
   randomString(&s1, maxString);
   String s2;
@@ -719,7 +834,7 @@ template <class String> void clause_21_3_7_f(String & test) {
   test = s1 + s2;
 }
 
-template <class String> void clause_21_3_7_g(String & test) {
+template <class String> void clause11_21_4_8_1_b(String & test) {
   String s;
   randomString(&s, maxString);
   String s1;
@@ -727,13 +842,13 @@ template <class String> void clause_21_3_7_g(String & test) {
   test = s.c_str() + s1;
 }
 
-template <class String> void clause_21_3_7_h(String & test) {
+template <class String> void clause11_21_4_8_1_c(String & test) {
   String s;
   randomString(&s, maxString);
   test = typename String::value_type(random('a', 'z')) + s;
 }
 
-template <class String> void clause_21_3_7_i(String & test) {
+template <class String> void clause11_21_4_8_1_d(String & test) {
   String s;
   randomString(&s, maxString);
   String s1;
@@ -741,7 +856,7 @@ template <class String> void clause_21_3_7_i(String & test) {
   test = s + s1.c_str();
 }
 
-template <class String> void clause_21_3_7_j(String & test) {
+template <class String> void clause11_21_4_8_1_e(String & test) {
   String s;
   randomString(&s, maxString);
   String s1;
@@ -749,18 +864,18 @@ template <class String> void clause_21_3_7_j(String & test) {
   test = s + s1.c_str();
 }
 
-template <class String> void clause_21_3_7_k(String & test) {
+template <class String> void clause11_21_4_8_1_f(String & test) {
   String s;
   randomString(&s, maxString);
   test = s + typename String::value_type(random('a', 'z'));
 }
 
 // Numbering here is from C++11
-template <class String> void clause_21_4_8_9_a(String & test) {
-  stringstream s("asd asdfjhuhdf    asdfasdf\tasdsdf");
+template <class String> void clause11_21_4_8_9_a(String & test) {
+  basic_stringstream<typename String::value_type> stst(test.c_str());
   String str;
-  while (s) {
-    s >> str;
+  while (stst) {
+    stst >> str;
     test += str + test;
   }
 }
@@ -768,92 +883,113 @@ template <class String> void clause_21_4_8_9_a(String & test) {
 TEST(FBString, testAllClauses) {
   EXPECT_TRUE(1) << "Starting with seed: " << seed;
   std::string r;
+  std::wstring wr;
   folly::fbstring c;
+  folly::basic_fbstring<wchar_t> wc;
 #define TEST_CLAUSE(x)                                              \
   do {                                                              \
       if (1) {} else EXPECT_TRUE(1) << "Testing clause " << #x;     \
       randomString(&r);                                             \
       c = r;                                                        \
       EXPECT_EQ(c, r);                                              \
+      wr = std::wstring(r.begin(), r.end());                        \
+      wc = folly::basic_fbstring<wchar_t>(wr.c_str());              \
       auto localSeed = seed + count;                                \
       rng = RandomT(localSeed);                                     \
-      clause_##x(r);                                                \
+      clause11_##x(r);                                                \
       rng = RandomT(localSeed);                                     \
-      clause_##x(c);                                                \
+      clause11_##x(c);                                                \
       EXPECT_EQ(r, c)                                               \
         << "Lengths: " << r.size() << " vs. " << c.size()           \
         << "\nReference: '" << r << "'"                             \
         << "\nActual:    '" << c.data()[0] << "'";                  \
+      rng = RandomT(localSeed);                                     \
+      clause11_##x(wc);                                               \
+      int wret = wcslen(wc.c_str());                                \
+      char mb[wret+1];                                              \
+      int ret = wcstombs(mb, wc.c_str(), sizeof(mb));               \
+      if (ret == wret) mb[wret] = '\0';                             \
+      const char *mc = c.c_str();                                   \
+      std::string one(mb);                                          \
+      std::string two(mc);                                          \
+      EXPECT_EQ(one, two);                                          \
     } while (++count % 100 != 0)
 
   int count = 0;
-  TEST_CLAUSE(21_3_1_a);
-  TEST_CLAUSE(21_3_1_b);
-  TEST_CLAUSE(21_3_1_c);
-  TEST_CLAUSE(21_3_1_d);
-  TEST_CLAUSE(21_3_1_e);
-  TEST_CLAUSE(21_3_1_f);
-  TEST_CLAUSE(21_3_1_g);
-
-  TEST_CLAUSE(21_3_2);
-  TEST_CLAUSE(21_3_3);
-  TEST_CLAUSE(21_3_4);
-  TEST_CLAUSE(21_3_5_a);
-  TEST_CLAUSE(21_3_5_b);
-  TEST_CLAUSE(21_3_5_c);
-  TEST_CLAUSE(21_3_5_d);
-  TEST_CLAUSE(21_3_5_e);
-  TEST_CLAUSE(21_3_5_f);
-  TEST_CLAUSE(21_3_5_g);
-  TEST_CLAUSE(21_3_5_h);
-  TEST_CLAUSE(21_3_5_i);
-  TEST_CLAUSE(21_3_5_j);
-  TEST_CLAUSE(21_3_5_k);
-  TEST_CLAUSE(21_3_5_l);
-  TEST_CLAUSE(21_3_5_m);
-  TEST_CLAUSE(21_3_5_n);
-  TEST_CLAUSE(21_3_5_o);
-  TEST_CLAUSE(21_3_5_p);
-
-  TEST_CLAUSE(21_3_6_a);
-  TEST_CLAUSE(21_3_6_b);
-  TEST_CLAUSE(21_3_6_c);
-  TEST_CLAUSE(21_3_6_d);
-  TEST_CLAUSE(21_3_6_e);
-  TEST_CLAUSE(21_3_6_f);
-  TEST_CLAUSE(21_3_6_g);
-  TEST_CLAUSE(21_3_6_h);
-  TEST_CLAUSE(21_3_6_i);
-  TEST_CLAUSE(21_3_6_j);
-  TEST_CLAUSE(21_3_6_k);
-  TEST_CLAUSE(21_3_6_l);
-  TEST_CLAUSE(21_3_6_m);
-  TEST_CLAUSE(21_3_6_n);
-  TEST_CLAUSE(21_3_6_o);
-  TEST_CLAUSE(21_3_6_p);
-  TEST_CLAUSE(21_3_6_q);
-  TEST_CLAUSE(21_3_6_r);
-  TEST_CLAUSE(21_3_6_s);
-  TEST_CLAUSE(21_3_6_t);
-  TEST_CLAUSE(21_3_6_u);
-  TEST_CLAUSE(21_3_6_v);
-  TEST_CLAUSE(21_3_6_w);
-  TEST_CLAUSE(21_3_6_x);
-  TEST_CLAUSE(21_3_6_y);
-  TEST_CLAUSE(21_3_6_z);
-
-  TEST_CLAUSE(21_3_7_a);
-  TEST_CLAUSE(21_3_7_b);
-  TEST_CLAUSE(21_3_7_c);
-  TEST_CLAUSE(21_3_7_d);
-  TEST_CLAUSE(21_3_7_e);
-  TEST_CLAUSE(21_3_7_f);
-  TEST_CLAUSE(21_3_7_g);
-  TEST_CLAUSE(21_3_7_h);
-  TEST_CLAUSE(21_3_7_i);
-  TEST_CLAUSE(21_3_7_j);
-  TEST_CLAUSE(21_3_7_k);
-
+  TEST_CLAUSE(21_4_2_a);
+  TEST_CLAUSE(21_4_2_b);
+  TEST_CLAUSE(21_4_2_c);
+  TEST_CLAUSE(21_4_2_d);
+  TEST_CLAUSE(21_4_2_e);
+  TEST_CLAUSE(21_4_2_f);
+  TEST_CLAUSE(21_4_2_g);
+  TEST_CLAUSE(21_4_2_h);
+  TEST_CLAUSE(21_4_2_i);
+  TEST_CLAUSE(21_4_2_j);
+  TEST_CLAUSE(21_4_2_k);
+  TEST_CLAUSE(21_4_2_l);
+  TEST_CLAUSE(21_4_2_lprime);
+  TEST_CLAUSE(21_4_2_m);
+  TEST_CLAUSE(21_4_2_n);
+  TEST_CLAUSE(21_4_3);
+  TEST_CLAUSE(21_4_4);
+  TEST_CLAUSE(21_4_5);
+  TEST_CLAUSE(21_4_6_1);
+  TEST_CLAUSE(21_4_6_2);
+  TEST_CLAUSE(21_4_6_3_a);
+  TEST_CLAUSE(21_4_6_3_b);
+  TEST_CLAUSE(21_4_6_3_c);
+  TEST_CLAUSE(21_4_6_3_d);
+  TEST_CLAUSE(21_4_6_3_e);
+  TEST_CLAUSE(21_4_6_3_f);
+  TEST_CLAUSE(21_4_6_3_g);
+  TEST_CLAUSE(21_4_6_3_h);
+  TEST_CLAUSE(21_4_6_3_i);
+  TEST_CLAUSE(21_4_6_3_j);
+  TEST_CLAUSE(21_4_6_3_k);
+  TEST_CLAUSE(21_4_6_4);
+  TEST_CLAUSE(21_4_6_5);
+  TEST_CLAUSE(21_4_6_6);
+  TEST_CLAUSE(21_4_6_7);
+  TEST_CLAUSE(21_4_6_8);
+  TEST_CLAUSE(21_4_7_1);
+
+  TEST_CLAUSE(21_4_7_2_a);
+  TEST_CLAUSE(21_4_7_2_b);
+  TEST_CLAUSE(21_4_7_2_c);
+  TEST_CLAUSE(21_4_7_2_d);
+  TEST_CLAUSE(21_4_7_3_a);
+  TEST_CLAUSE(21_4_7_3_b);
+  TEST_CLAUSE(21_4_7_3_c);
+  TEST_CLAUSE(21_4_7_3_d);
+  TEST_CLAUSE(21_4_7_4_a);
+  TEST_CLAUSE(21_4_7_4_b);
+  TEST_CLAUSE(21_4_7_4_c);
+  TEST_CLAUSE(21_4_7_4_d);
+  TEST_CLAUSE(21_4_7_5_a);
+  TEST_CLAUSE(21_4_7_5_b);
+  TEST_CLAUSE(21_4_7_5_c);
+  TEST_CLAUSE(21_4_7_5_d);
+  TEST_CLAUSE(21_4_7_6_a);
+  TEST_CLAUSE(21_4_7_6_b);
+  TEST_CLAUSE(21_4_7_6_c);
+  TEST_CLAUSE(21_4_7_6_d);
+  TEST_CLAUSE(21_4_7_7_a);
+  TEST_CLAUSE(21_4_7_7_b);
+  TEST_CLAUSE(21_4_7_7_c);
+  TEST_CLAUSE(21_4_7_7_d);
+  TEST_CLAUSE(21_4_7_8);
+  TEST_CLAUSE(21_4_7_9_a);
+  TEST_CLAUSE(21_4_7_9_b);
+  TEST_CLAUSE(21_4_7_9_c);
+  TEST_CLAUSE(21_4_7_9_d);
+  TEST_CLAUSE(21_4_7_9_e);
+  TEST_CLAUSE(21_4_8_1_a);
+  TEST_CLAUSE(21_4_8_1_b);
+  TEST_CLAUSE(21_4_8_1_c);
+  TEST_CLAUSE(21_4_8_1_d);
+  TEST_CLAUSE(21_4_8_1_e);
+  TEST_CLAUSE(21_4_8_1_f);
   TEST_CLAUSE(21_4_8_9_a);
 }
 
@@ -893,7 +1029,7 @@ sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam.";
     ifstream input(f);
     fbstring line;
     FOR_EACH (i, v) {
-      EXPECT_TRUE(getline(input, line));
+      EXPECT_TRUE(!getline(input, line).fail());
       EXPECT_EQ(line, *i);
     }
   }
@@ -946,22 +1082,14 @@ TEST(FBString, testMoveOperatorPlusRhs) {
   EXPECT_EQ(size1 + size2, test.size());
 }
 
+// The GNU C++ standard library throws an std::logic_error when an std::string
+// is constructed with a null pointer. Verify that we mirror this behavior.
+//
+// N.B. We behave this way even if the C++ library being used is something
+//      other than libstdc++. Someday if we deem it important to present
+//      identical undefined behavior for other platforms, we can re-visit this.
 TEST(FBString, testConstructionFromLiteralZero) {
-  try {
-    std::string s(0);
-    EXPECT_TRUE(false);
-  } catch (const std::logic_error&) {
-  } catch (...) {
-    EXPECT_TRUE(false);
-  }
-
-  try {
-    fbstring s(0);
-    EXPECT_TRUE(false);
-  } catch (const std::logic_error& e) {
-  } catch (...) {
-    EXPECT_TRUE(false);
-  }
+  EXPECT_THROW(fbstring s(0), std::logic_error);
 }
 
 TEST(FBString, testFixedBugs) {
@@ -993,6 +1121,15 @@ TEST(FBString, testFixedBugs) {
       cp += "bb";
     }
   }
+  { // D661622
+    folly::basic_fbstring<wchar_t> s;
+    EXPECT_EQ(0, s.size());
+  }
+  { // D785057
+    fbstring str(1337, 'f');
+    std::swap(str, str);
+    EXPECT_EQ(1337, str.size());
+  }
 }
 
 
@@ -1018,6 +1155,19 @@ TEST(FBString, testFrontBack) {
   EXPECT_EQ(str, "HellO");
 }
 
+TEST(FBString, noexcept) {
+  EXPECT_TRUE(noexcept(fbstring()));
+  // std::move is not marked noexcept in gcc 4.6, sigh
+#if __GNUC_PREREQ(4, 7)
+  fbstring x;
+  EXPECT_FALSE(noexcept(fbstring(x)));
+  EXPECT_TRUE(noexcept(fbstring(std::move(x))));
+  fbstring y;
+  EXPECT_FALSE(noexcept(y = x));
+  EXPECT_TRUE(noexcept(y = std::move(x)));
+#endif
+}
+
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   google::ParseCommandLineFlags(&argc, &argv, true);