/*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2015 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 <atomic>
#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/Portability.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;
}
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);
+ const size_t pos = random(0, test.size());
String before(test.data(), test.size());
String s(test.c_str() + pos);
String after(test.data(), test.size());
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,
}
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(
Num2String(test, test.find(str, random(0, test.size())));
}
+template <class String> void clause11_21_4_7_2_a1(String & test) {
+ String str = String(test).substr(
+ random(0, test.size()),
+ random(0, test.size()));
+ Num2String(test, test.find(str, random(0, test.size())));
+}
+
+template <class String> void clause11_21_4_7_2_a2(String & test) {
+ auto const& cTest = test;
+ String str = cTest.substr(
+ random(0, test.size()),
+ random(0, test.size()));
+ Num2String(test, test.find(str, random(0, test.size())));
+}
+
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);
random(0, str.size())));
}
+template <class String> void clause11_21_4_7_2_b1(String & test) {
+ auto from = random(0, test.size());
+ auto length = random(0, test.size() - from);
+ String str = String(test).substr(from, length);
+ Num2String(test, test.find(str.c_str(),
+ random(0, test.size()),
+ random(0, str.size())));
+}
+
+template <class String> void clause11_21_4_7_2_b2(String & test) {
+ auto from = random(0, test.size());
+ auto length = random(0, test.size() - from);
+ const auto& cTest = test;
+ String str = cTest.substr(from, length);
+ Num2String(test, test.find(str.c_str(),
+ random(0, test.size()),
+ random(0, str.size())));
+}
+
template <class String> void clause11_21_4_7_2_c(String & test) {
String str = test.substr(
random(0, test.size()),
random(0, test.size())));
}
+template <class String> void clause11_21_4_7_2_c1(String & test) {
+ String str = String(test).substr(
+ random(0, test.size()),
+ random(0, test.size()));
+ Num2String(test, test.find(str.c_str(),
+ random(0, test.size())));
+}
+
+template <class String> void clause11_21_4_7_2_c2(String & test) {
+ const auto& cTest = test;
+ String str = cTest.substr(
+ random(0, test.size()),
+ random(0, test.size()));
+ Num2String(test, test.find(str.c_str(),
+ random(0, test.size())));
+}
+
template <class String> void clause11_21_4_7_2_d(String & test) {
Num2String(test, test.find(
random('a', 'z'),
}
template <class String> void clause11_21_4_8_1_b(String & test) {
+ String s1;
+ randomString(&s1, maxString);
+ String s2;
+ randomString(&s2, maxString);
+ test = move(s1) + s2;
+}
+
+template <class String> void clause11_21_4_8_1_c(String & test) {
+ String s1;
+ randomString(&s1, maxString);
+ String s2;
+ randomString(&s2, maxString);
+ test = s1 + move(s2);
+}
+
+template <class String> void clause11_21_4_8_1_d(String & test) {
+ String s1;
+ randomString(&s1, maxString);
+ String s2;
+ randomString(&s2, maxString);
+ test = move(s1) + move(s2);
+}
+
+template <class String> void clause11_21_4_8_1_e(String & test) {
String s;
randomString(&s, maxString);
String s1;
test = s.c_str() + s1;
}
-template <class String> void clause11_21_4_8_1_c(String & test) {
+template <class String> void clause11_21_4_8_1_f(String & test) {
+ String s;
+ randomString(&s, maxString);
+ String s1;
+ randomString(&s1, maxString);
+ test = s.c_str() + move(s1);
+}
+
+template <class String> void clause11_21_4_8_1_g(String & test) {
String s;
randomString(&s, maxString);
test = typename String::value_type(random('a', 'z')) + s;
}
-template <class String> void clause11_21_4_8_1_d(String & test) {
+template <class String> void clause11_21_4_8_1_h(String & test) {
+ String s;
+ randomString(&s, maxString);
+ test = typename String::value_type(random('a', 'z')) + move(s);
+}
+
+template <class String> void clause11_21_4_8_1_i(String & test) {
String s;
randomString(&s, maxString);
String s1;
test = s + s1.c_str();
}
-template <class String> void clause11_21_4_8_1_e(String & test) {
+template <class String> void clause11_21_4_8_1_j(String & test) {
String s;
randomString(&s, maxString);
String s1;
randomString(&s1, maxString);
- test = s + s1.c_str();
+ test = move(s) + s1.c_str();
}
-template <class String> void clause11_21_4_8_1_f(String & test) {
+template <class String> void clause11_21_4_8_1_k(String & test) {
String s;
randomString(&s, maxString);
test = s + typename String::value_type(random('a', 'z'));
}
+template <class String> void clause11_21_4_8_1_l(String & test) {
+ String s;
+ randomString(&s, maxString);
+ String s1;
+ randomString(&s1, maxString);
+ test = move(s) + s1.c_str();
+}
+
// Numbering here is from C++11
template <class String> void clause11_21_4_8_9_a(String & test) {
basic_stringstream<typename String::value_type> stst(test.c_str());
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);
TEST_CLAUSE(21_4_7_1);
TEST_CLAUSE(21_4_7_2_a);
+ TEST_CLAUSE(21_4_7_2_a1);
+ TEST_CLAUSE(21_4_7_2_a2);
TEST_CLAUSE(21_4_7_2_b);
+ TEST_CLAUSE(21_4_7_2_b1);
+ TEST_CLAUSE(21_4_7_2_b2);
TEST_CLAUSE(21_4_7_2_c);
+ TEST_CLAUSE(21_4_7_2_c1);
+ TEST_CLAUSE(21_4_7_2_c2);
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_8_1_d);
TEST_CLAUSE(21_4_8_1_e);
TEST_CLAUSE(21_4_8_1_f);
+ TEST_CLAUSE(21_4_8_1_g);
+ TEST_CLAUSE(21_4_8_1_h);
+ TEST_CLAUSE(21_4_8_1_i);
+ TEST_CLAUSE(21_4_8_1_j);
+ TEST_CLAUSE(21_4_8_1_k);
+ TEST_CLAUSE(21_4_8_1_l);
TEST_CLAUSE(21_4_8_9_a);
}
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;
copy.push_back('b');
EXPECT_GE(copy.capacity(), 1);
}
+ { // D2813713
+ fbstring s1("a");
+ s1.reserve(8); // Trigger the optimized code path.
+ auto test1 = '\0' + std::move(s1);
+ EXPECT_EQ(2, test1.size());
+
+ fbstring s2(1, '\0');
+ s2.reserve(8);
+ auto test2 = "a" + std::move(s2);
+ EXPECT_EQ(2, test2.size());
+ }
}
TEST(FBString, findWithNpos) {
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);
- return RUN_ALL_TESTS();
+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());
+}
+
+namespace {
+/*
+ * t8968589: Clang 3.7 refused to compile w/ certain constructors (specifically
+ * those that were "explicit" and had a defaulted parameter, if they were used
+ * in structs which were default-initialized). Exercise these just to ensure
+ * they compile.
+ *
+ * In diff D2632953 the old constructor:
+ * explicit basic_fbstring(const A& a = A()) noexcept;
+ *
+ * was split into these two, as a workaround:
+ * basic_fbstring() noexcept;
+ * explicit basic_fbstring(const A& a) noexcept;
+ */
+
+struct TestStructDefaultAllocator {
+ folly::basic_fbstring<char> stringMember;
+};
+
+template <class A>
+struct TestStructWithAllocator {
+ folly::basic_fbstring<char, std::char_traits<char>, A> stringMember;
+};
+
+std::atomic<size_t> allocatorConstructedCount(0);
+struct TestStructStringAllocator : std::allocator<char> {
+ TestStructStringAllocator() {
+ ++ allocatorConstructedCount;
+ }
+};
+
+} // anon namespace
+
+TEST(FBStringCtorTest, DefaultInitStructDefaultAlloc) {
+ TestStructDefaultAllocator t1 { };
+ EXPECT_TRUE(t1.stringMember.empty());
+}
+
+TEST(FBStringCtorTest, DefaultInitStructAlloc) {
+ EXPECT_EQ(allocatorConstructedCount.load(), 0);
+ TestStructWithAllocator<TestStructStringAllocator> t2;
+ EXPECT_TRUE(t2.stringMember.empty());
+ EXPECT_EQ(allocatorConstructedCount.load(), 1);
}