X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2FFBStringTest.cpp;h=08e22608078df07217b1bb0da89120ffe40e2da7;hb=f2925b23df8d85ebca72d62a69f1282528c086de;hp=e6b021166d77eb6dca739b236fe84f9959d7a474;hpb=1ebbefe65734732a46cb6d6b3d9a9e800a415ac0;p=folly.git diff --git a/folly/test/FBStringTest.cpp b/folly/test/FBStringTest.cpp index e6b02116..08e22608 100644 --- a/folly/test/FBStringTest.cpp +++ b/folly/test/FBStringTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,25 +17,28 @@ // // Author: andrei.alexandrescu@fb.com -#include "folly/FBString.h" +#include +#include #include - +#include #include -#include +#include + #include #include -#include - -#include -#include "folly/Foreach.h" -#include "folly/Random.h" -#include "folly/Conv.h" +#include +#include +#include +#include +#include using namespace std; using namespace folly; +namespace { + static const int seed = folly::randomNumberSeed(); typedef boost::mt19937 RandomT; static RandomT rng(seed); @@ -72,22 +75,40 @@ std::list RandomList(unsigned int maxSize) { } return lst; } +} // namespace //////////////////////////////////////////////////////////////////////////////// // Tests begin here //////////////////////////////////////////////////////////////////////////////// -template void clause_21_3_1_a(String & test) { +template void clause11_21_4_2_a(String & test) { test.String::~String(); new(&test) String(); } -template void clause_21_3_1_b(String & test) { - // Copy constructor +template void clause11_21_4_2_b(String & test) { + String test2(test); + assert(test2 == test); +} +template 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 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 void clause_21_3_1_c(String & test) { +template void clause11_21_4_2_e(String & test) { // Constructor from char*, size_t const size_t pos = random(0, test.size()), @@ -96,36 +117,60 @@ template void clause_21_3_1_c(String & test) { String s(test.c_str() + pos, n); String after(test.data(), test.size()); EXPECT_EQ(before, after); - + test.swap(s); +} +template void clause11_21_4_2_f(String & test) { + // Constructor from char* + 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()); + EXPECT_EQ(before, after); + test.swap(s); +} +template 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 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 lst; - for (auto c : test) lst.push_back(c); + 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 lst1; - for (auto c : test) lst1.push_back(c); + 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'; fbstring s5(t, t + 2);; EXPECT_EQ("ab", s5); - - test = s; } -template void clause_21_3_1_d(String & test) { - // Assignment +template void clause11_21_4_2_i(String & test) { + // From initializer_list + std::initializer_list + il = { 'h', 'e', 'l', 'l', 'o' }; + String s(il); + test.swap(s); +} +template 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); @@ -134,7 +179,20 @@ template void clause_21_3_1_d(String & test) { } test = s; } -template void clause_21_3_1_e(String & test) { +template 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 void clause11_21_4_2_l(String & test) { // Assignment from char* String s(random(0, 1000), '\0'); size_t i = 0; @@ -143,7 +201,7 @@ template void clause_21_3_1_e(String & test) { } test = s.c_str(); } -template void clause_21_3_1_f(String & test) { +template void clause11_21_4_2_lprime(String & test) { // Aliased assign const size_t pos = random(0, test.size()); if (avoidAliasing) { @@ -152,15 +210,24 @@ template void clause_21_3_1_f(String & test) { test = test.c_str() + pos; } } -template void clause_21_3_1_g(String & test) { +template void clause11_21_4_2_m(String & test) { // Assignment from char - test = random('a', 'z'); + using value_type = typename String::value_type; + test = random(static_cast('a'), static_cast('z')); +} +template void clause11_21_4_2_n(String & test) { + // Assignment from initializer_list + initializer_list + il = { 'h', 'e', 'l', 'l', 'o' }; + test = il; } -template void clause_21_3_2(String & test) { +template 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()); @@ -169,29 +236,42 @@ template void clause_21_3_2(String & test) { EXPECT_EQ(s, test.size()); } -template void clause_21_3_3(String & test) { +template 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 string empty("empty"); string notempty("not empty"); - if (test.empty()) test = String(empty.begin(), empty.end()); - else test = String(notempty.begin(), notempty.end()); + if (test.empty()) { + test = String(empty.begin(), empty.end()); + } else { + test = String(notempty.begin(), notempty.end()); + } } -template void clause_21_3_4(String & test) { - // exercise element access 21.3.4 +template 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 void clause_21_3_5_a(String & test) { +template void clause11_21_4_6_1(String & test) { // 21.3.5 modifiers (+=) String test1; randomString(&test1); @@ -240,9 +320,12 @@ template 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 il { 'a', 'b', 'c' }; + test += il; } -template void clause_21_3_5_b(String & test) { +template void clause11_21_4_6_2(String & test) { // 21.3.5 modifiers (append, push_back) String s; @@ -267,70 +350,85 @@ template 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 il { 'a', 'b', 'c' }; + test.append(il); } -template void clause_21_3_5_c(String & test) { +template 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 void clause_21_3_5_d(String & test) { +template 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 void clause_21_3_5_e(String & test) { +template 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 void clause_21_3_5_f(String & test) { +template void clause11_21_4_6_3_d(String & test) { // assign String s; randomString(&s, maxString); test.assign(s.c_str()); } -template void clause_21_3_5_g(String & test) { +template void clause11_21_4_6_3_e(String & test) { // assign String s; randomString(&s, maxString); test.assign(random(0, maxString), random('a', 'z')); } -template void clause_21_3_5_h(String & test) { +template void clause11_21_4_6_3_f(String & test) { // assign from bidirectional iterator std::list lst(RandomList(maxString)); test.assign(lst.begin(), lst.end()); } -template void clause_21_3_5_i(String & test) { +template void clause11_21_4_6_3_g(String & test) { // assign from aliased source test.assign(test); } -template void clause_21_3_5_j(String & test) { +template void clause11_21_4_6_3_h(String & test) { // assign from aliased source test.assign(test, random(0, test.size()), random(0, maxString)); } -template void clause_21_3_5_k(String & test) { +template void clause11_21_4_6_3_i(String & test) { // assign from aliased source test.assign(test.c_str(), random(0, test.size())); } -template void clause_21_3_5_l(String & test) { +template void clause11_21_4_6_3_j(String & test) { // assign from aliased source test.assign(test.c_str()); } -template void clause_21_3_5_m(String & test) { +template void clause11_21_4_6_3_k(String & test) { + // assign from initializer_list + initializer_list il { 'a', 'b', 'c' }; + test.assign(il); +} + +template void clause11_21_4_6_4(String & test) { // insert String s; randomString(&s, maxString); @@ -346,15 +444,29 @@ template 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 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 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(ss); + test.insert(test.begin(), i, istream_iterator()); } -template void clause_21_3_5_n(String & test) { - // erase +template void clause11_21_4_6_5(String & test) { + // erase and pop_back if (!test.empty()) { test.erase(random(0, test.size()), random(0, maxString)); } @@ -368,9 +480,13 @@ template 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 void clause_21_3_5_o(String & test) { +template void clause11_21_4_6_6(String & test) { auto pos = random(0, test.size()); if (avoidAliasing) { test.replace(pos, random(0, test.size() - pos), @@ -419,10 +535,11 @@ template void clause_21_3_5_o(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, @@ -431,10 +548,11 @@ template void clause_21_3_5_o(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( @@ -461,39 +579,54 @@ template void clause_21_3_5_o(String & test) { random(0, maxString), random('a', 'z')); } -template void clause_21_3_5_p(String & test) { +template void clause11_21_4_6_7(String & test) { std::vector vec(random(0, maxString)); - test.copy( - &vec[0], - vec.size(), - random(0, test.size())); + if (vec.empty()) { + return; + } + test.copy(vec.data(), vec.size(), random(0, test.size())); } -template void clause_21_3_5_q(String & test) { +template void clause11_21_4_6_8(String & test) { String s; randomString(&s, maxString); s.swap(test); } -template void clause_21_3_6_a(String & test) { +template void clause11_21_4_7_1(String & test) { // 21.3.6 string operations // exercise c_str() and data() assert(test.c_str() == test.data()); // exercise get_allocator() String s; randomString(&s, maxString); - assert(test.get_allocator() == s.get_allocator()); + DCHECK(test.get_allocator() == s.get_allocator()); } -template void clause_21_3_6_b(String & test) { +template 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 void clause_21_3_6_c(String & test) { +template 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 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 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); @@ -502,7 +635,26 @@ template void clause_21_3_6_c(String & test) { random(0, str.size()))); } -template void clause_21_3_6_d(String & test) { +template 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 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 void clause11_21_4_7_2_c(String & test) { String str = test.substr( random(0, test.size()), random(0, test.size())); @@ -510,20 +662,37 @@ template void clause_21_3_6_d(String & test) { random(0, test.size()))); } -template void clause_21_3_6_e(String & test) { +template 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 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 void clause11_21_4_7_2_d(String & test) { Num2String(test, test.find( random('a', 'z'), random(0, test.size()))); } -template void clause_21_3_6_f(String & test) { +template 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 void clause_21_3_6_g(String & test) { +template void clause11_21_4_7_3_b(String & test) { String str = test.substr( random(0, test.size()), random(0, test.size())); @@ -532,7 +701,7 @@ template void clause_21_3_6_g(String & test) { random(0, str.size()))); } -template void clause_21_3_6_h(String & test) { +template void clause11_21_4_7_3_c(String & test) { String str = test.substr( random(0, test.size()), random(0, test.size())); @@ -540,20 +709,20 @@ template void clause_21_3_6_h(String & test) { random(0, test.size()))); } -template void clause_21_3_6_i(String & test) { +template void clause11_21_4_7_3_d(String & test) { Num2String(test, test.rfind( random('a', 'z'), random(0, test.size()))); } -template void clause_21_3_6_j(String & test) { +template 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 void clause_21_3_6_k(String & test) { +template void clause11_21_4_7_4_b(String & test) { String str; randomString(&str, maxString); Num2String(test, test.find_first_of(str.c_str(), @@ -561,27 +730,27 @@ template void clause_21_3_6_k(String & test) { random(0, str.size()))); } -template void clause_21_3_6_l(String & test) { +template 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 void clause_21_3_6_m(String & test) { +template void clause11_21_4_7_4_d(String & test) { Num2String(test, test.find_first_of( random('a', 'z'), random(0, test.size()))); } -template void clause_21_3_6_n(String & test) { +template 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 void clause_21_3_6_o(String & test) { +template void clause11_21_4_7_5_b(String & test) { String str; randomString(&str, maxString); Num2String(test, test.find_last_of(str.c_str(), @@ -589,27 +758,27 @@ template void clause_21_3_6_o(String & test) { random(0, str.size()))); } -template void clause_21_3_6_p(String & test) { +template 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 void clause_21_3_6_q(String & test) { +template void clause11_21_4_7_5_d(String & test) { Num2String(test, test.find_last_of( random('a', 'z'), random(0, test.size()))); } -template void clause_21_3_6_r(String & test) { +template 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 void clause_21_3_6_s(String & test) { +template void clause11_21_4_7_6_b(String & test) { String str; randomString(&str, maxString); Num2String(test, test.find_first_not_of(str.c_str(), @@ -617,27 +786,27 @@ template void clause_21_3_6_s(String & test) { random(0, str.size()))); } -template void clause_21_3_6_t(String & test) { +template 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 void clause_21_3_6_u(String & test) { +template void clause11_21_4_7_6_d(String & test) { Num2String(test, test.find_first_not_of( random('a', 'z'), random(0, test.size()))); } -template void clause_21_3_6_v(String & test) { +template 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 void clause_21_3_6_w(String & test) { +template void clause11_21_4_7_7_b(String & test) { String str; randomString(&str, maxString); Num2String(test, test.find_last_not_of(str.c_str(), @@ -645,45 +814,51 @@ template void clause_21_3_6_w(String & test) { random(0, str.size()))); } -template void clause_21_3_6_x(String & test) { +template 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 void clause_21_3_6_y(String & test) { +template void clause11_21_4_7_7_d(String & test) { Num2String(test, test.find_last_not_of( random('a', 'z'), random(0, test.size()))); } -template void clause_21_3_6_z(String & test) { +template void clause11_21_4_7_8(String & test) { test = test.substr(random(0, test.size()), random(0, test.size())); } -template void clause_21_3_7_a(String & test) { +template void clause11_21_4_7_9_a(String & test) { String s; randomString(&s, maxString); int tristate = test.compare(s); - if (tristate > 0) tristate = 1; - else if (tristate < 0) tristate = 2; + if (tristate > 0) { + tristate = 1; + } else if (tristate < 0) { + tristate = 2; + } Num2String(test, tristate); } -template void clause_21_3_7_b(String & test) { +template void clause11_21_4_7_9_b(String & test) { String s; randomString(&s, maxString); int tristate = test.compare( random(0, test.size()), random(0, test.size()), s); - if (tristate > 0) tristate = 1; - else if (tristate < 0) tristate = 2; + if (tristate > 0) { + tristate = 1; + } else if (tristate < 0) { + tristate = 2; + } Num2String(test, tristate); } -template void clause_21_3_7_c(String & test) { +template void clause11_21_4_7_9_c(String & test) { String str; randomString(&str, maxString); int tristate = test.compare( @@ -692,21 +867,27 @@ template void clause_21_3_7_c(String & test) { str, random(0, str.size()), random(0, str.size())); - if (tristate > 0) tristate = 1; - else if (tristate < 0) tristate = 2; + if (tristate > 0) { + tristate = 1; + } else if (tristate < 0) { + tristate = 2; + } Num2String(test, tristate); } -template void clause_21_3_7_d(String & test) { +template void clause11_21_4_7_9_d(String & test) { String s; randomString(&s, maxString); int tristate = test.compare(s.c_str()); - if (tristate > 0) tristate = 1; - else if (tristate < 0) tristate = 2; - Num2String(test, tristate); + if (tristate > 0) { + tristate = 1; + } else if (tristate < 0) { + tristate = 2; + } + Num2String(test, tristate); } -template void clause_21_3_7_e(String & test) { +template void clause11_21_4_7_9_e(String & test) { String str; randomString(&str, maxString); int tristate = test.compare( @@ -714,12 +895,15 @@ template void clause_21_3_7_e(String & test) { random(0, test.size()), str.c_str(), random(0, str.size())); - if (tristate > 0) tristate = 1; - else if (tristate < 0) tristate = 2; + if (tristate > 0) { + tristate = 1; + } else if (tristate < 0) { + tristate = 2; + } Num2String(test, tristate); } -template void clause_21_3_7_f(String & test) { +template void clause11_21_4_8_1_a(String & test) { String s1; randomString(&s1, maxString); String s2; @@ -727,7 +911,31 @@ template void clause_21_3_7_f(String & test) { test = s1 + s2; } -template void clause_21_3_7_g(String & test) { +template void clause11_21_4_8_1_b(String & test) { + String s1; + randomString(&s1, maxString); + String s2; + randomString(&s2, maxString); + test = move(s1) + s2; +} + +template void clause11_21_4_8_1_c(String & test) { + String s1; + randomString(&s1, maxString); + String s2; + randomString(&s2, maxString); + test = s1 + move(s2); +} + +template 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 void clause11_21_4_8_1_e(String & test) { String s; randomString(&s, maxString); String s1; @@ -735,13 +943,27 @@ template void clause_21_3_7_g(String & test) { test = s.c_str() + s1; } -template void clause_21_3_7_h(String & test) { +template 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 void clause11_21_4_8_1_g(String & test) { String s; randomString(&s, maxString); test = typename String::value_type(random('a', 'z')) + s; } -template void clause_21_3_7_i(String & test) { +template 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 void clause11_21_4_8_1_i(String & test) { String s; randomString(&s, maxString); String s1; @@ -749,22 +971,30 @@ template void clause_21_3_7_i(String & test) { test = s + s1.c_str(); } -template void clause_21_3_7_j(String & test) { +template 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 void clause_21_3_7_k(String & test) { +template void clause11_21_4_8_1_k(String & test) { String s; randomString(&s, maxString); test = s + typename String::value_type(random('a', 'z')); } +template 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 void clause_21_4_8_9_a(String & test) { +template void clause11_21_4_8_9_a(String & test) { basic_stringstream stst(test.c_str()); String str; while (stst) { @@ -776,111 +1006,153 @@ template 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; +#if FOLLY_HAVE_WCHAR_SUPPORT + std::wstring wr; folly::basic_fbstring 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(wr.c_str()); \ - auto localSeed = seed + count; \ - rng = RandomT(localSeed); \ - clause_##x(r); \ - rng = RandomT(localSeed); \ - clause_##x(c); \ - EXPECT_EQ(r, c) \ - << "Lengths: " << r.size() << " vs. " << c.size() \ - << "\nReference: '" << r << "'" \ - << "\nActual: '" << c.data()[0] << "'"; \ - rng = RandomT(localSeed); \ - clause_##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) - +#endif 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); + auto l = [&](const char * const clause, + void(*f_string)(std::string&), + void(*f_fbstring)(folly::fbstring&), + void(*f_wfbstring)(folly::basic_fbstring&)) { + do { + if (1) { + } else { + EXPECT_TRUE(1) << "Testing clause " << clause; + } + randomString(&r); + c = r; + EXPECT_EQ(c, r); +#if FOLLY_HAVE_WCHAR_SUPPORT + wr = std::wstring(r.begin(), r.end()); + wc = folly::basic_fbstring(wr.c_str()); +#endif + 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] << "'"; +#if FOLLY_HAVE_WCHAR_SUPPORT + rng = RandomT(localSeed); + f_wfbstring(wc); + int wret = wcslen(wc.c_str()); + auto mbv = std::vector(wret + 1); + auto mb = mbv.data(); + int ret = wcstombs(mb, wc.c_str(), wret + 1); + if (ret == wret) { + mb[wret] = '\0'; + } + const char *mc = c.c_str(); + std::string one(mb); + std::string two(mc); + EXPECT_EQ(one, two); +#endif + } while (++count % 100 != 0); + }; + +#define TEST_CLAUSE(x) \ + l(#x, \ + clause11_##x, \ + clause11_##x, \ + clause11_##x>); + + 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_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_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_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); } TEST(FBString, testGetline) { - fbstring s1 = "\ + string s1 = "\ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras accumsan \n\ elit ut urna consectetur in sagittis mi auctor. Nulla facilisi. In nec \n\ dolor leo, vitae imperdiet neque. Donec ut erat mauris, a faucibus \n\ @@ -898,28 +1170,17 @@ massa, ut accumsan magna. Donec imperdiet tempor nisi et \n\ laoreet. Phasellus lectus quam, ultricies ut tincidunt in, dignissim \n\ id eros. Mauris vulputate tortor nec neque pellentesque sagittis quis \n\ sed nisl. In diam lacus, lobortis ut posuere nec, ornare id quam."; - char f[] = "/tmp/fbstring_testing.XXXXXX"; - int fd = mkstemp(f); - EXPECT_TRUE(fd > 0); - if (fd > 0) { - close(fd); // Yeah - std::ofstream out(f); - if (!(out << s1)) { - EXPECT_TRUE(0) << "Couldn't write to temp file."; - return; - } - } + vector v; boost::split(v, s1, boost::is_any_of("\n")); { - ifstream input(f); + istringstream input(s1); fbstring line; FOR_EACH (i, v) { - EXPECT_TRUE(getline(input, line)); + EXPECT_TRUE(!getline(input, line).fail()); EXPECT_EQ(line, *i); } } - unlink(f); } TEST(FBString, testMoveCtor) { @@ -968,22 +1229,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(nullptr), std::logic_error); } TEST(FBString, testFixedBugs) { @@ -994,7 +1247,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; @@ -1015,13 +1268,54 @@ TEST(FBString, testFixedBugs) { cp += "bb"; } } - { - // D661622 + { // D661622 folly::basic_fbstring s; EXPECT_EQ(0, s.size()); } + { // D785057 + fbstring str(1337, 'f'); + 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); + } + { // 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()); + } + { // D3698862 + EXPECT_EQ(fbstring().find(fbstring(), 4), fbstring::npos); + } + if (usingJEMalloc()) { // D4355440 + fbstring str(1337, 'f'); + str.reserve(3840); + EXPECT_NE(str.capacity(), 3840); + + struct { + std::atomic refCount_; + } dummyRefCounted; + EXPECT_EQ( + str.capacity(), + goodMallocSize(3840) - sizeof(dummyRefCounted) - sizeof(char)); + } } +TEST(FBString, findWithNpos) { + fbstring fbstr("localhost:80"); + EXPECT_EQ(fbstring::npos, fbstr.find(":", fbstring::npos)); +} TEST(FBString, testHash) { fbstring a; @@ -1034,6 +1328,20 @@ TEST(FBString, testHash) { EXPECT_NE(hashfunc(a), hashfunc(b)); } +#if FOLLY_HAVE_WCHAR_SUPPORT +TEST(FBString, testHashChar16) { + using u16fbstring = folly::basic_fbstring; + u16fbstring a; + u16fbstring b; + a.push_back(0); + a.push_back(1); + b.push_back(0); + b.push_back(2); + std::hash hashfunc; + EXPECT_NE(hashfunc(a), hashfunc(b)); +} +#endif + TEST(FBString, testFrontBack) { fbstring str("hello"); EXPECT_EQ(str.front(), 'h'); @@ -1045,8 +1353,325 @@ TEST(FBString, testFrontBack) { EXPECT_EQ(str, "HellO"); } -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - google::ParseCommandLineFlags(&argc, &argv, true); - return RUN_ALL_TESTS(); +TEST(FBString, noexcept) { + EXPECT_TRUE(noexcept(fbstring())); + 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))); +} + +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 stringMember; +}; + +template +struct TestStructWithAllocator { + folly::basic_fbstring, A> stringMember; +}; + +std::atomic allocatorConstructedCount(0); +struct TestStructStringAllocator : std::allocator { + TestStructStringAllocator() { + ++ allocatorConstructedCount; + } +}; + +} // namespace + +TEST(FBStringCtorTest, DefaultInitStructDefaultAlloc) { + TestStructDefaultAllocator t1 { }; + EXPECT_TRUE(t1.stringMember.empty()); +} + +TEST(FBStringCtorTest, DefaultInitStructAlloc) { + EXPECT_EQ(allocatorConstructedCount.load(), 0); + TestStructWithAllocator t2; + EXPECT_TRUE(t2.stringMember.empty()); + EXPECT_EQ(allocatorConstructedCount.load(), 1); +} + +TEST(FBStringCtorTest, NullZeroConstruction) { + char* p = nullptr; + int n = 0; + folly::fbstring f(p, n); + EXPECT_EQ(f.size(), 0); +} + +// Tests for the comparison operators. I use EXPECT_TRUE rather than EXPECT_LE +// because what's under test is the operator rather than the relation between +// the objects. + +TEST(FBString, compareToStdString) { + using folly::fbstring; + using namespace std::string_literals; + auto stdA = "a"s; + auto stdB = "b"s; + fbstring fbA("a"); + fbstring fbB("b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(U16FBString, compareToStdU16String) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = u"a"s; + auto stdB = u"b"s; + basic_fbstring fbA(u"a"); + basic_fbstring fbB(u"b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(U32FBString, compareToStdU32String) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = U"a"s; + auto stdB = U"b"s; + basic_fbstring fbA(U"a"); + basic_fbstring fbB(U"b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(WFBString, compareToStdWString) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = L"a"s; + auto stdB = L"b"s; + basic_fbstring fbA(L"a"); + basic_fbstring fbB(L"b"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +// Same again, but with a more challenging input - a common prefix and different +// lengths. + +TEST(FBString, compareToStdStringLong) { + using folly::fbstring; + using namespace std::string_literals; + auto stdA = "1234567890a"s; + auto stdB = "1234567890ab"s; + fbstring fbA("1234567890a"); + fbstring fbB("1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(U16FBString, compareToStdU16StringLong) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = u"1234567890a"s; + auto stdB = u"1234567890ab"s; + basic_fbstring fbA(u"1234567890a"); + basic_fbstring fbB(u"1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +#if FOLLY_HAVE_WCHAR_SUPPORT +TEST(U32FBString, compareToStdU32StringLong) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = U"1234567890a"s; + auto stdB = U"1234567890ab"s; + basic_fbstring fbA(U"1234567890a"); + basic_fbstring fbB(U"1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} + +TEST(WFBString, compareToStdWStringLong) { + using folly::basic_fbstring; + using namespace std::string_literals; + auto stdA = L"1234567890a"s; + auto stdB = L"1234567890ab"s; + basic_fbstring fbA(L"1234567890a"); + basic_fbstring fbB(L"1234567890ab"); + EXPECT_TRUE(stdA == fbA); + EXPECT_TRUE(fbB == stdB); + EXPECT_TRUE(stdA != fbB); + EXPECT_TRUE(fbA != stdB); + EXPECT_TRUE(stdA < fbB); + EXPECT_TRUE(fbA < stdB); + EXPECT_TRUE(stdB > fbA); + EXPECT_TRUE(fbB > stdA); + EXPECT_TRUE(stdA <= fbB); + EXPECT_TRUE(fbA <= stdB); + EXPECT_TRUE(stdA <= fbA); + EXPECT_TRUE(fbA <= stdA); + EXPECT_TRUE(stdB >= fbA); + EXPECT_TRUE(fbB >= stdA); + EXPECT_TRUE(stdB >= fbB); + EXPECT_TRUE(fbB >= stdB); +} +#endif