Codemod: use #include angle brackets in folly and thrift
[folly.git] / folly / test / FBStringTest.cpp
index ede69e6a26393a65b09321b48b80796536849daa..8133b0167b9db8138e4d9666e1cba74554caa53d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 //
 // Author: andrei.alexandrescu@fb.com
 
-#include "folly/FBString.h"
+#include <folly/FBString.h>
 
 #include <cstdlib>
 
 #include <list>
 #include <fstream>
+#include <iomanip>
 #include <boost/algorithm/string.hpp>
 #include <boost/random.hpp>
 #include <gtest/gtest.h>
 
 #include <gflags/gflags.h>
 
-#include "folly/Foreach.h"
-#include "folly/Random.h"
-#include "folly/Conv.h"
+#include <folly/Foreach.h>
+#include <folly/Portability.h>
+#include <folly/Random.h>
+#include <folly/Conv.h>
 
 using namespace std;
 using namespace folly;
@@ -525,10 +527,11 @@ template <class String> void clause11_21_4_6_6(String & test) {
                random(0, maxString), random('a', 'z'));
   pos = random(0, test.size());
   if (avoidAliasing) {
+    auto newString = String(test);
     test.replace(
       test.begin() + pos,
       test.begin() + pos + random(0, test.size() - pos),
-      String(test));
+      newString);
   } else {
     test.replace(
       test.begin() + pos,
@@ -537,10 +540,11 @@ template <class String> void clause11_21_4_6_6(String & test) {
   }
   pos = random(0, test.size());
   if (avoidAliasing) {
+    auto newString = String(test);
     test.replace(
       test.begin() + pos,
       test.begin() + pos + random(0, test.size() - pos),
-      String(test).c_str(),
+      newString.c_str(),
       test.size() - random(0, test.size()));
   } else {
     test.replace(
@@ -885,36 +889,47 @@ TEST(FBString, testAllClauses) {
   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);                                     \
-      clause11_##x(r);                                                \
-      rng = RandomT(localSeed);                                     \
-      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;
+
+  auto l = [&](const char * const clause,
+               void(*f_string)(std::string&),
+               void(*f_fbstring)(folly::fbstring&),
+               void(*f_wfbstring)(folly::basic_fbstring<wchar_t>&)) {
+    do {
+      if (1) {} else EXPECT_TRUE(1) << "Testing clause " << clause;
+      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);
+      f_string(r);
+      rng = RandomT(localSeed);
+      f_fbstring(c);
+      EXPECT_EQ(r, c)
+        << "Lengths: " << r.size() << " vs. " << c.size()
+        << "\nReference: '" << r << "'"
+        << "\nActual:    '" << c.data()[0] << "'";
+      rng = RandomT(localSeed);
+      f_wfbstring(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);
+  };
+
+#define TEST_CLAUSE(x) \
+  l(#x, \
+    clause11_##x<std::string>, \
+    clause11_##x<folly::fbstring>, \
+    clause11_##x<folly::basic_fbstring<wchar_t>>);
+
   TEST_CLAUSE(21_4_2_a);
   TEST_CLAUSE(21_4_2_b);
   TEST_CLAUSE(21_4_2_c);
@@ -1028,7 +1043,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);
     }
   }
@@ -1081,22 +1096,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) {
@@ -1107,7 +1114,7 @@ TEST(FBString, testFixedBugs) {
     cp.c_str();
     EXPECT_EQ(str.front(), 'f');
   }
-  { // D481173, --extra-cxxflags=-DFBSTRING_CONSERVATIVE
+  { // D481173
     fbstring str(1337, 'f');
     for (int i = 0; i < 2; ++i) {
       fbstring cp = str;
@@ -1137,8 +1144,19 @@ TEST(FBString, testFixedBugs) {
     std::swap(str, str);
     EXPECT_EQ(1337, str.size());
   }
+  { // D1012196, --allocator=malloc
+    fbstring str(128, 'f');
+    str.clear();  // Empty medium string.
+    fbstring copy(str);  // Medium string of 0 capacity.
+    copy.push_back('b');
+    EXPECT_GE(copy.capacity(), 1);
+  }
 }
 
+TEST(FBString, findWithNpos) {
+  fbstring fbstr("localhost:80");
+  EXPECT_EQ(fbstring::npos, fbstr.find(":", fbstring::npos));
+}
 
 TEST(FBString, testHash) {
   fbstring a;
@@ -1162,6 +1180,71 @@ 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
+}
+
+TEST(FBString, iomanip) {
+  stringstream ss;
+  fbstring fbstr("Hello");
+
+  ss << setw(6) << fbstr;
+  EXPECT_EQ(ss.str(), " Hello");
+  ss.str("");
+
+  ss << left << setw(6) << fbstr;
+  EXPECT_EQ(ss.str(), "Hello ");
+  ss.str("");
+
+  ss << right << setw(6) << fbstr;
+  EXPECT_EQ(ss.str(), " Hello");
+  ss.str("");
+
+  ss << setw(4) << fbstr;
+  EXPECT_EQ(ss.str(), "Hello");
+  ss.str("");
+
+  ss << setfill('^') << setw(6) << fbstr;
+  EXPECT_EQ(ss.str(), "^Hello");
+  ss.str("");
+}
+
+TEST(FBString, rvalueIterators) {
+  // you cannot take &* of a move-iterator, so use that for testing
+  fbstring s = "base";
+  fbstring r = "hello";
+  r.replace(r.begin(), r.end(),
+      make_move_iterator(s.begin()), make_move_iterator(s.end()));
+  EXPECT_EQ("base", r);
+
+  // The following test is probably not required by the standard.
+  // i.e. this could be in the realm of undefined behavior.
+  fbstring b = "123abcXYZ";
+  auto ait = b.begin() + 3;
+  auto Xit = b.begin() + 6;
+  b.replace(ait, b.end(), b.begin(), Xit);
+  EXPECT_EQ("123123abc", b); // if things go wrong, you'd get "123123123"
+}
+
+TEST(FBString, moveTerminator) {
+  // The source of a move must remain in a valid state
+  fbstring s(100, 'x'); // too big to be in-situ
+  fbstring k;
+  k = std::move(s);
+
+  EXPECT_EQ(0, s.size());
+  EXPECT_EQ('\0', *s.c_str());
+}
+
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   google::ParseCommandLineFlags(&argc, &argv, true);