diff options
author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/string_ut.cpp |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/string_ut.cpp')
-rw-r--r-- | util/generic/string_ut.cpp | 1270 |
1 files changed, 1270 insertions, 0 deletions
diff --git a/util/generic/string_ut.cpp b/util/generic/string_ut.cpp new file mode 100644 index 00000000000..ac82e9091db --- /dev/null +++ b/util/generic/string_ut.cpp @@ -0,0 +1,1270 @@ +#include "deque.h" +#include "strbuf.h" +#include "string_ut.h" +#include "vector.h" +#include "yexception.h" + +#include <util/charset/wide.h> +#include <util/str_stl.h> +#include <util/stream/output.h> +#include <util/string/subst.h> + +#include <string> +#include <sstream> +#include <algorithm> +#include <stdexcept> + +#ifdef TSTRING_IS_STD_STRING +static_assert(sizeof(TString) == sizeof(std::string), "expect sizeof(TString) == sizeof(std::string)"); +#else +static_assert(sizeof(TString) == sizeof(const char*), "expect sizeof(TString) == sizeof(const char*)"); +#endif + +class TStringTestZero: public TTestBase { + UNIT_TEST_SUITE(TStringTestZero); + UNIT_TEST(TestZero); + UNIT_TEST_SUITE_END(); + +public: + void TestZero() { + const char data[] = "abc\0def\0"; + TString s(data, sizeof(data)); + UNIT_ASSERT(s.size() == sizeof(data)); + UNIT_ASSERT(s.StartsWith(s)); + UNIT_ASSERT(s.EndsWith(s)); + UNIT_ASSERT(s.Contains('\0')); + + const char raw_def[] = "def"; + const char raw_zero[] = "\0"; + TString def(raw_def, sizeof(raw_def) - 1); + TString zero(raw_zero, sizeof(raw_zero) - 1); + UNIT_ASSERT_EQUAL(4, s.find(raw_def)); + UNIT_ASSERT_EQUAL(4, s.find(def)); + UNIT_ASSERT_EQUAL(4, s.find_first_of(raw_def)); + UNIT_ASSERT_EQUAL(3, s.find_first_of(zero)); + UNIT_ASSERT_EQUAL(7, s.find_first_not_of(def, 4)); + + const char nonSubstring[] = "def\0ghi"; + UNIT_ASSERT_EQUAL(TString::npos, s.find(TString(nonSubstring, sizeof(nonSubstring)))); + + TString copy = s; + copy.replace(copy.size() - 1, 1, "z"); + UNIT_ASSERT(s != copy); + copy.replace(copy.size() - 1, 1, "\0", 0, 1); + UNIT_ASSERT(s == copy); + + TString prefix(data, 5); + UNIT_ASSERT(s.StartsWith(prefix)); + UNIT_ASSERT(s != prefix); + UNIT_ASSERT(s > prefix); + UNIT_ASSERT(s > s.data()); + UNIT_ASSERT(s == TString(s.data(), s.size())); + UNIT_ASSERT(data < s); + + s.remove(5); + UNIT_ASSERT(s == prefix); + } +}; + +UNIT_TEST_SUITE_REGISTRATION(TStringTestZero); + +template <typename TStringType, typename TTestData> +class TStringStdTestImpl { + using TChar = typename TStringType::char_type; + using TTraits = typename TStringType::traits_type; + using TView = std::basic_string_view<TChar, TTraits>; + + TTestData Data_; + +protected: + void Constructor() { + // @todo use UNIT_TEST_EXCEPTION + try { + TStringType s((size_t)-1, *Data_.a()); + UNIT_ASSERT(false); + } catch (const std::length_error&) { + UNIT_ASSERT(true); + } catch (...) { + //Expected exception is length_error: + UNIT_ASSERT(false); + } + } + + void reserve() { +#if 0 + TStringType s; + // @todo use UNIT_TEST_EXCEPTION + try { + s.reserve(s.max_size() + 1); + UNIT_ASSERT(false); + } catch (const std::length_error&) { + UNIT_ASSERT(true); + } catch (...) { + //Expected exception is length_error: + UNIT_ASSERT(false); + } + + // Non-shared behaviour - never shrink + + s.reserve(256); + #ifndef TSTRING_IS_STD_STRING + const auto* data = s.data(); + + UNIT_ASSERT(s.capacity() >= 256); + + s.reserve(128); + + UNIT_ASSERT(s.capacity() >= 256 && s.data() == data); + #endif + + s.resize(64, 'x'); + s.reserve(10); + + #ifdef TSTRING_IS_STD_STRING + UNIT_ASSERT(s.capacity() >= 64); + #else + UNIT_ASSERT(s.capacity() >= 256 && s.data() == data); + #endif + + #ifndef TSTRING_IS_STD_STRING + // Shared behaviour - always reallocate, just as much as requisted + + TStringType holder = s; + + UNIT_ASSERT(s.capacity() >= 256); + + s.reserve(128); + + UNIT_ASSERT(s.capacity() >= 128 && s.capacity() < 256 && s.data() != data); + UNIT_ASSERT(s.IsDetached()); + + s.resize(64, 'x'); + data = s.data(); + holder = s; + + s.reserve(10); + + UNIT_ASSERT(s.capacity() >= 64 && s.capacity() < 128 && s.data() != data); + UNIT_ASSERT(s.IsDetached()); + #endif +#endif + } + + void short_string() { + TStringType const ref_short_str1(Data_.str1()), ref_short_str2(Data_.str2()); + TStringType short_str1(ref_short_str1), short_str2(ref_short_str2); + TStringType const ref_long_str1(Data_.str__________________________________________________1()); + TStringType const ref_long_str2(Data_.str__________________________________________________2()); + TStringType long_str1(ref_long_str1), long_str2(ref_long_str2); + + UNIT_ASSERT(short_str1 == ref_short_str1); + UNIT_ASSERT(long_str1 == ref_long_str1); + + { + TStringType str1(short_str1); + str1 = long_str1; + UNIT_ASSERT(str1 == ref_long_str1); + } + + { + TStringType str1(long_str1); + str1 = short_str1; + UNIT_ASSERT(str1 == ref_short_str1); + } + + { + short_str1.swap(short_str2); + UNIT_ASSERT((short_str1 == ref_short_str2) && (short_str2 == ref_short_str1)); + short_str1.swap(short_str2); + } + + { + long_str1.swap(long_str2); + UNIT_ASSERT((long_str1 == ref_long_str2) && (long_str2 == ref_long_str1)); + long_str1.swap(long_str2); + } + + { + short_str1.swap(long_str1); + UNIT_ASSERT((short_str1 == ref_long_str1) && (long_str1 == ref_short_str1)); + short_str1.swap(long_str1); + } + + { + long_str1.swap(short_str1); + UNIT_ASSERT((short_str1 == ref_long_str1) && (long_str1 == ref_short_str1)); + long_str1.swap(short_str1); + } + + { + //This is to test move constructor + TVector<TStringType> str_vect; + + str_vect.push_back(short_str1); + str_vect.push_back(long_str1); + str_vect.push_back(short_str2); + str_vect.push_back(long_str2); + + UNIT_ASSERT(str_vect[0] == ref_short_str1); + UNIT_ASSERT(str_vect[1] == ref_long_str1); + UNIT_ASSERT(str_vect[2] == ref_short_str2); + UNIT_ASSERT(str_vect[3] == ref_long_str2); + } + } + + void erase() { + TChar const* c_str = Data_.Hello_World(); + TStringType str(c_str); + UNIT_ASSERT(str == c_str); + + str.erase(str.begin() + 1, str.end() - 1); // Erase all but first and last. + + size_t i; + for (i = 0; i < str.size(); ++i) { + switch (i) { + case 0: + UNIT_ASSERT(str[i] == *Data_.H()); + break; + + case 1: + UNIT_ASSERT(str[i] == *Data_.d()); + break; + + default: + UNIT_ASSERT(false); + } + } + + str.insert(1, c_str); + str.erase(str.begin()); // Erase first element. + str.erase(str.end() - 1); // Erase last element. + UNIT_ASSERT(str == c_str); + str.clear(); // Erase all. + UNIT_ASSERT(str.empty()); + + str = c_str; + UNIT_ASSERT(str == c_str); + + str.erase(1, str.size() - 1); // Erase all but first and last. + for (i = 0; i < str.size(); i++) { + switch (i) { + case 0: + UNIT_ASSERT(str[i] == *Data_.H()); + break; + + case 1: + UNIT_ASSERT(str[i] == *Data_.d()); + break; + + default: + UNIT_ASSERT(false); + } + } + + str.erase(1); + UNIT_ASSERT(str == Data_.H()); + } + + void data() { + TStringType xx; + + // ISO-IEC-14882:1998(E), 21.3.6, paragraph 3 + UNIT_ASSERT(xx.data() != nullptr); + } + + void c_str() { + TStringType low(Data_._2004_01_01()); + TStringType xx; + TStringType yy; + + // ISO-IEC-14882:1998(E), 21.3.6, paragraph 1 + UNIT_ASSERT(*(yy.c_str()) == 0); + + // Blocks A and B should follow each other. + // Block A: + xx = Data_._123456(); + xx += low; + UNIT_ASSERT(xx.c_str() == TView(Data_._1234562004_01_01())); + // End of block A + + // Block B: + xx = Data_._1234(); + xx += Data_._5(); + UNIT_ASSERT(xx.c_str() == TView(Data_._12345())); + // End of block B + } + + void null_char_of_empty() { + const TStringType s; + + UNIT_ASSERT(s[s.size()] == 0); + } + + void null_char() { + // ISO/IEC 14882:1998(E), ISO/IEC 14882:2003(E), 21.3.4 ('... the const version') + const TStringType s(Data_._123456()); + + UNIT_ASSERT(s[s.size()] == 0); + } + + // Allowed since C++17, see http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2475 + void null_char_assignment_to_subscript_of_empty() { + TStringType s; + +#ifdef TSTRING_IS_STD_STRING + using reference = volatile typename TStringType::value_type&; +#else + using reference = typename TStringType::reference; +#endif + reference trailing_zero = s[s.size()]; + trailing_zero = 0; + UNIT_ASSERT(trailing_zero == 0); + } + + // Allowed since C++17, see http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2475 + void null_char_assignment_to_subscript_of_nonempty() { + TStringType s(Data_._123456()); + +#ifdef TSTRING_IS_STD_STRING + using reference = volatile typename TStringType::value_type&; +#else + using reference = typename TStringType::reference; +#endif + reference trailing_zero = s[s.size()]; + trailing_zero = 0; + UNIT_ASSERT(trailing_zero == 0); + } + +#ifndef TSTRING_IS_STD_STRING + // Dereferencing string end() is not allowed by C++ standard as of C++20, avoid using in real code. + void null_char_assignment_to_end_of_empty() { + TStringType s; + + volatile auto& trailing_zero = *(s.begin() + s.size()); + trailing_zero = 0; + UNIT_ASSERT(trailing_zero == 0); + } + + // Dereferencing string end() is not allowed by C++ standard as of C++20, avoid using in real code. + void null_char_assignment_to_end_of_nonempty() { + TStringType s(Data_._123456()); + + volatile auto& trailing_zero = *(s.begin() + s.size()); + trailing_zero = 0; + UNIT_ASSERT(trailing_zero == 0); + } +#endif + + void insert() { + TStringType strorg = Data_.This_is_test_string_for_string_calls(); + TStringType str; + + // In case of reallocation there is no auto reference problem + // so we reserve a big enough TStringType to be sure to test this + // particular point. + + str.reserve(100); + str = strorg; + + //test self insertion: + str.insert(10, str.c_str() + 5, 15); + UNIT_ASSERT(str == Data_.This_is_teis_test_string_st_string_for_string_calls()); + + str = strorg; + str.insert(15, str.c_str() + 5, 25); + UNIT_ASSERT(str == Data_.This_is_test_stis_test_string_for_stringring_for_string_calls()); + + str = strorg; + str.insert(0, str.c_str() + str.size() - 4, 4); + UNIT_ASSERT(str == Data_.allsThis_is_test_string_for_string_calls()); + + str = strorg; + str.insert(0, str.c_str() + str.size() / 2 - 1, str.size() / 2 + 1); + UNIT_ASSERT(str == Data_.ng_for_string_callsThis_is_test_string_for_string_calls()); + + str = strorg; + typename TStringType::iterator b = str.begin(); + typename TStringType::const_iterator s = str.begin() + str.size() / 2 - 1; + typename TStringType::const_iterator e = str.end(); + str.insert(b, s, e); + UNIT_ASSERT(str == Data_.ng_for_string_callsThis_is_test_string_for_string_calls()); + +#if 0 + // AV + str = strorg; + str.insert(str.begin(), str.begin() + str.size() / 2 - 1, str.end()); + UNIT_ASSERT(str == Data.ng_for_string_callsThis_is_test_string_for_string_calls()); +#endif + + TStringType str0; + str0.insert(str0.begin(), 5, *Data_._0()); + UNIT_ASSERT(str0 == Data_._00000()); + + TStringType str1; + { + typename TStringType::size_type pos = 0, nb = 2; + str1.insert(pos, nb, *Data_._1()); + } + UNIT_ASSERT(str1 == Data_._11()); + + str0.insert(0, str1); + UNIT_ASSERT(str0 == Data_._1100000()); + + TStringType str2(Data_._2345()); + str0.insert(str0.size(), str2, 1, 2); + UNIT_ASSERT(str0 == Data_._110000034()); + + str1.insert(str1.begin() + 1, 2, *Data_._2()); + UNIT_ASSERT(str1 == Data_._1221()); + + str1.insert(2, Data_._333333(), 3); + UNIT_ASSERT(str1 == Data_._1233321()); + + str1.insert(4, Data_._4444()); + UNIT_ASSERT(str1 == Data_._12334444321()); + + str1.insert(str1.begin() + 6, *Data_._5()); + UNIT_ASSERT(str1 == Data_._123344544321()); + } + + void resize() { + TStringType s; + + s.resize(0); + + UNIT_ASSERT(*s.c_str() == 0); + + s = Data_._1234567(); + + s.resize(0); + UNIT_ASSERT(*s.c_str() == 0); + + s = Data_._1234567(); + s.resize(1); + UNIT_ASSERT(s.size() == 1); + UNIT_ASSERT(*s.c_str() == *Data_._1()); + UNIT_ASSERT(*(s.c_str() + 1) == 0); + + s = Data_._1234567(); +#if 0 + s.resize(10); +#else + s.resize(10, 0); +#endif + UNIT_ASSERT(s.size() == 10); + UNIT_ASSERT(s[6] == *Data_._7()); + UNIT_ASSERT(s[7] == 0); + UNIT_ASSERT(s[8] == 0); + UNIT_ASSERT(s[9] == 0); + } + + void find() { + TStringType s(Data_.one_two_three_one_two_three()); + + UNIT_ASSERT(s.find(Data_.one()) == 0); + UNIT_ASSERT(s.find(*Data_.t()) == 4); + UNIT_ASSERT(s.find(*Data_.t(), 5) == 8); + + UNIT_ASSERT(s.find(Data_.four()) == TStringType::npos); + UNIT_ASSERT(s.find(Data_.one(), TStringType::npos) == TStringType::npos); + UNIT_ASSERT(s.find_first_of(Data_.abcde()) == 2); + UNIT_ASSERT(s.find_first_not_of(Data_.enotw_()) == 9); + } + + void capacity() { + TStringType s; + + UNIT_ASSERT(s.capacity() < s.max_size()); + UNIT_ASSERT(s.capacity() >= s.size()); + + for (int i = 0; i < 18; ++i) { + s += ' '; + + UNIT_ASSERT(s.capacity() > 0); + UNIT_ASSERT(s.capacity() < s.max_size()); + UNIT_ASSERT(s.capacity() >= s.size()); + } + } + + void assign() { + TStringType s; + TChar const* cstr = Data_.test_string_for_assign(); + + s.assign(cstr, cstr + 22); + UNIT_ASSERT(s == Data_.test_string_for_assign()); + + TStringType s2(Data_.other_test_string()); + s.assign(s2); + UNIT_ASSERT(s == s2); + + static TStringType str1; + static TStringType str2; + + // short TStringType optim: + str1 = Data_._123456(); + // longer than short TStringType: + str2 = Data_._1234567890123456789012345678901234567890(); + + UNIT_ASSERT(str1[5] == *Data_._6()); + UNIT_ASSERT(str2[29] == *Data_._0()); + } + + void copy() { + TStringType s(Data_.foo()); + TChar dest[4]; + dest[0] = dest[1] = dest[2] = dest[3] = 1; + s.copy(dest, 4); + int pos = 0; + UNIT_ASSERT(dest[pos++] == *Data_.f()); + UNIT_ASSERT(dest[pos++] == *Data_.o()); + UNIT_ASSERT(dest[pos++] == *Data_.o()); + UNIT_ASSERT(dest[pos++] == 1); + + dest[0] = dest[1] = dest[2] = dest[3] = 1; + s.copy(dest, 4, 2); + pos = 0; + UNIT_ASSERT(dest[pos++] == *Data_.o()); + UNIT_ASSERT(dest[pos++] == 1); + + // @todo use UNIT_TEST_EXCEPTION + try { + s.copy(dest, 4, 5); + UNIT_ASSERT(!"expected std::out_of_range"); + } catch (const std::out_of_range&) { + UNIT_ASSERT(true); + } catch (...) { + UNIT_ASSERT(!"expected std::out_of_range"); + } + } + + void cbegin_cend() { + const char helloThere[] = "Hello there"; + TString s = helloThere; + size_t index = 0; + for (auto it = s.cbegin(); s.cend() != it; ++it, ++index) { + UNIT_ASSERT_VALUES_EQUAL(helloThere[index], *it); + } + } + + void compare() { + TStringType str1(Data_.abcdef()); + TStringType str2; + + str2 = Data_.abcdef(); + UNIT_ASSERT(str1.compare(str2) == 0); + UNIT_ASSERT(str1.compare(str2.data(), str2.size()) == 0); + str2 = Data_.abcde(); + UNIT_ASSERT(str1.compare(str2) > 0); + UNIT_ASSERT(str1.compare(str2.data(), str2.size()) > 0); + str2 = Data_.abcdefg(); + UNIT_ASSERT(str1.compare(str2) < 0); + UNIT_ASSERT(str1.compare(str2.data(), str2.size()) < 0); + + UNIT_ASSERT(str1.compare(Data_.abcdef()) == 0); + UNIT_ASSERT(str1.compare(Data_.abcde()) > 0); + UNIT_ASSERT(str1.compare(Data_.abcdefg()) < 0); + + str2 = Data_.cde(); + UNIT_ASSERT(str1.compare(2, 3, str2) == 0); + str2 = Data_.cd(); + UNIT_ASSERT(str1.compare(2, 3, str2) > 0); + str2 = Data_.cdef(); + UNIT_ASSERT(str1.compare(2, 3, str2) < 0); + + str2 = Data_.abcdef(); + UNIT_ASSERT(str1.compare(2, 3, str2, 2, 3) == 0); + UNIT_ASSERT(str1.compare(2, 3, str2, 2, 2) > 0); + UNIT_ASSERT(str1.compare(2, 3, str2, 2, 4) < 0); + + UNIT_ASSERT(str1.compare(2, 3, Data_.cdefgh(), 3) == 0); + UNIT_ASSERT(str1.compare(2, 3, Data_.cdefgh(), 2) > 0); + UNIT_ASSERT(str1.compare(2, 3, Data_.cdefgh(), 4) < 0); + } + + void find_last_of() { + // 21.3.6.4 + TStringType s(Data_.one_two_three_one_two_three()); + + UNIT_ASSERT(s.find_last_of(Data_.abcde()) == 26); + UNIT_ASSERT(s.find_last_of(TStringType(Data_.abcde())) == 26); + + TStringType test(Data_.aba()); + + UNIT_ASSERT(test.find_last_of(Data_.a(), 2, 1) == 2); + UNIT_ASSERT(test.find_last_of(Data_.a(), 1, 1) == 0); + UNIT_ASSERT(test.find_last_of(Data_.a(), 0, 1) == 0); + + UNIT_ASSERT(test.find_last_of(*Data_.a(), 2) == 2); + UNIT_ASSERT(test.find_last_of(*Data_.a(), 1) == 0); + UNIT_ASSERT(test.find_last_of(*Data_.a(), 0) == 0); + } +#if 0 + void rfind() { + // 21.3.6.2 + TStringType s(Data.one_two_three_one_two_three()); + + UNIT_ASSERT(s.rfind(Data.two()) == 18); + UNIT_ASSERT(s.rfind(Data.two(), 0) == TStringType::npos); + UNIT_ASSERT(s.rfind(Data.two(), 11) == 4); + UNIT_ASSERT(s.rfind(*Data.w()) == 19); + + TStringType test(Data.aba()); + + UNIT_ASSERT(test.rfind(Data.a(), 2, 1) == 2); + UNIT_ASSERT(test.rfind(Data.a(), 1, 1) == 0); + UNIT_ASSERT(test.rfind(Data.a(), 0, 1) == 0); + + UNIT_ASSERT(test.rfind(*Data.a(), 2) == 2); + UNIT_ASSERT(test.rfind(*Data.a(), 1) == 0); + UNIT_ASSERT(test.rfind(*Data.a(), 0) == 0); + } +#endif + void find_last_not_of() { + // 21.3.6.6 + TStringType s(Data_.one_two_three_one_two_three()); + + UNIT_ASSERT(s.find_last_not_of(Data_.ehortw_()) == 15); + + TStringType test(Data_.aba()); + + UNIT_ASSERT(test.find_last_not_of(Data_.a(), 2, 1) == 1); + UNIT_ASSERT(test.find_last_not_of(Data_.b(), 2, 1) == 2); + UNIT_ASSERT(test.find_last_not_of(Data_.a(), 1, 1) == 1); + UNIT_ASSERT(test.find_last_not_of(Data_.b(), 1, 1) == 0); + UNIT_ASSERT(test.find_last_not_of(Data_.a(), 0, 1) == TStringType::npos); + UNIT_ASSERT(test.find_last_not_of(Data_.b(), 0, 1) == 0); + + UNIT_ASSERT(test.find_last_not_of(*Data_.a(), 2) == 1); + UNIT_ASSERT(test.find_last_not_of(*Data_.b(), 2) == 2); + UNIT_ASSERT(test.find_last_not_of(*Data_.a(), 1) == 1); + UNIT_ASSERT(test.find_last_not_of(*Data_.b(), 1) == 0); + UNIT_ASSERT(test.find_last_not_of(*Data_.a(), 0) == TStringType::npos); + UNIT_ASSERT(test.find_last_not_of(*Data_.b(), 0) == 0); + } +#if 0 + void replace() { + // This test case is for the non template basic_TString::replace method, + // this is why we play with the const iterators and reference to guaranty + // that the right method is called. + + const TStringType v(Data._78()); + TStringType s(Data._123456()); + TStringType const& cs = s; + + typename TStringType::iterator i = s.begin() + 1; + s.replace(i, i + 3, v.begin(), v.end()); + UNIT_ASSERT(s == Data._17856()); + + s = Data._123456(); + i = s.begin() + 1; + s.replace(i, i + 1, v.begin(), v.end()); + UNIT_ASSERT(s == Data._1783456()); + + s = Data._123456(); + i = s.begin() + 1; + typename TStringType::const_iterator ci = s.begin() + 1; + s.replace(i, i + 3, ci + 3, cs.end()); + UNIT_ASSERT(s == Data._15656()); + + s = Data._123456(); + i = s.begin() + 1; + ci = s.begin() + 1; + s.replace(i, i + 3, ci, ci + 2); + UNIT_ASSERT(s == Data._12356()); + + s = Data._123456(); + i = s.begin() + 1; + ci = s.begin() + 1; + s.replace(i, i + 3, ci + 1, cs.end()); + UNIT_ASSERT(s == Data._1345656()); + + s = Data._123456(); + i = s.begin(); + ci = s.begin() + 1; + s.replace(i, i, ci, ci + 1); + UNIT_ASSERT(s == Data._2123456()); + + s = Data._123456(); + s.replace(s.begin() + 4, s.end(), cs.begin(), cs.end()); + UNIT_ASSERT(s == Data._1234123456()); + + // This is the test for the template replace method. + + s = Data._123456(); + typename TStringType::iterator b = s.begin() + 4; + typename TStringType::iterator e = s.end(); + typename TStringType::const_iterator rb = s.begin(); + typename TStringType::const_iterator re = s.end(); + s.replace(b, e, rb, re); + UNIT_ASSERT(s == Data._1234123456()); + + s = Data._123456(); + s.replace(s.begin() + 4, s.end(), s.begin(), s.end()); + UNIT_ASSERT(s == Data._1234123456()); + + TStringType strorg(Data.This_is_test_StringT_for_StringT_calls()); + TStringType str = strorg; + str.replace(5, 15, str.c_str(), 10); + UNIT_ASSERT(str == Data.This_This_is_tefor_StringT_calls()); + + str = strorg; + str.replace(5, 5, str.c_str(), 10); + UNIT_ASSERT(str == Data.This_This_is_test_StringT_for_StringT_calls()); + + #if !defined(STLPORT) || defined(_STLP_MEMBER_TEMPLATES) + deque<TChar> cdeque; + cdeque.push_back(*Data.I()); + str.replace(str.begin(), str.begin() + 11, cdeque.begin(), cdeque.end()); + UNIT_ASSERT(str == Data.Is_test_StringT_for_StringT_calls()); + #endif + } +#endif +}; // TStringStdTestImpl + +class TStringTest: public TTestBase, private TStringTestImpl<TString, TTestData<char>> { +public: + UNIT_TEST_SUITE(TStringTest); + UNIT_TEST(TestMaxSize); + UNIT_TEST(TestConstructors); + UNIT_TEST(TestReplace); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(TestRefCount); +#endif + UNIT_TEST(TestFind); + UNIT_TEST(TestContains); + UNIT_TEST(TestOperators); + UNIT_TEST(TestMulOperators); + UNIT_TEST(TestFuncs); + UNIT_TEST(TestUtils); + UNIT_TEST(TestEmpty); + UNIT_TEST(TestJoin); + UNIT_TEST(TestCopy); + UNIT_TEST(TestStrCpy); + UNIT_TEST(TestPrefixSuffix); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(TestCharRef); +#endif + UNIT_TEST(TestBack) + UNIT_TEST(TestFront) + UNIT_TEST(TestIterators); + UNIT_TEST(TestReverseIterators); + UNIT_TEST(TestAppendUtf16) + UNIT_TEST(TestFillingAssign) + UNIT_TEST(TestStdStreamApi) + //UNIT_TEST(TestOperatorsCI); must fail + UNIT_TEST_SUITE_END(); + + void TestAppendUtf16() { + TString appended = TString("А роза упала").AppendUtf16(u" на лапу Азора"); + UNIT_ASSERT(appended == "А роза упала на лапу Азора"); + } + + void TestFillingAssign() { + TString s("abc"); + s.assign(5, 'a'); + UNIT_ASSERT_VALUES_EQUAL(s, "aaaaa"); + } + + void TestStdStreamApi() { + const TString data = "abracadabra"; + std::stringstream ss; + ss << data; + + UNIT_ASSERT_VALUES_EQUAL(data, ss.str()); + + ss << '\n' + << data << std::endl; + + TString read = "xxx"; + ss >> read; + UNIT_ASSERT_VALUES_EQUAL(read, data); + } +}; + +UNIT_TEST_SUITE_REGISTRATION(TStringTest); + +class TWideStringTest: public TTestBase, private TStringTestImpl<TUtf16String, TTestData<wchar16>> { +public: + UNIT_TEST_SUITE(TWideStringTest); + UNIT_TEST(TestConstructors); + UNIT_TEST(TestReplace); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(TestRefCount); +#endif + UNIT_TEST(TestFind); + UNIT_TEST(TestContains); + UNIT_TEST(TestOperators); + UNIT_TEST(TestLetOperator) + UNIT_TEST(TestMulOperators); + UNIT_TEST(TestFuncs); + UNIT_TEST(TestUtils); + UNIT_TEST(TestEmpty); + UNIT_TEST(TestJoin); + UNIT_TEST(TestCopy); + UNIT_TEST(TestStrCpy); + UNIT_TEST(TestPrefixSuffix); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(TestCharRef); +#endif + UNIT_TEST(TestBack); + UNIT_TEST(TestFront) + UNIT_TEST(TestDecodingMethods); + UNIT_TEST(TestIterators); + UNIT_TEST(TestReverseIterators); + UNIT_TEST(TestStringLiterals); + UNIT_TEST_SUITE_END(); + +private: + void TestDecodingMethods() { + UNIT_ASSERT(TUtf16String::FromAscii("").empty()); + UNIT_ASSERT(TUtf16String::FromAscii("abc") == ASCIIToWide("abc")); + + const char* text = "123kx83abcd ej)#$%ddja&%J&"; + TUtf16String wtext = ASCIIToWide(text); + + UNIT_ASSERT(wtext == TUtf16String::FromAscii(text)); + + TString strtext(text); + UNIT_ASSERT(wtext == TUtf16String::FromAscii(strtext)); + + TStringBuf strbuftext(text); + UNIT_ASSERT(wtext == TUtf16String::FromAscii(strbuftext)); + + UNIT_ASSERT(wtext.substr(5) == TUtf16String::FromAscii(text + 5)); + + const wchar16 wideCyrillicAlphabet[] = { + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x00}; + + TUtf16String strWide(wideCyrillicAlphabet); + TString strUtf8 = WideToUTF8(strWide); + + UNIT_ASSERT(strWide == TUtf16String::FromUtf8(strUtf8.c_str())); + UNIT_ASSERT(strWide == TUtf16String::FromUtf8(strUtf8)); + UNIT_ASSERT(strWide == TUtf16String::FromUtf8(TStringBuf(strUtf8))); + + // assign + + TUtf16String s1; + s1.AssignAscii("1234"); + UNIT_ASSERT(s1 == ASCIIToWide("1234")); + + s1.AssignUtf8(strUtf8); + UNIT_ASSERT(s1 == strWide); + + s1.AssignAscii(text); + UNIT_ASSERT(s1 == wtext); + + // append + + TUtf16String s2; + TUtf16String testAppend = strWide; + s2.AppendUtf8(strUtf8); + UNIT_ASSERT(testAppend == s2); + + testAppend += ' '; + s2.AppendAscii(" "); + UNIT_ASSERT(testAppend == s2); + + testAppend += '_'; + s2.AppendUtf8("_"); + UNIT_ASSERT(testAppend == s2); + + testAppend += wtext; + s2.AppendAscii(text); + UNIT_ASSERT(testAppend == s2); + + testAppend += wtext; + s2.AppendUtf8(text); + UNIT_ASSERT(testAppend == s2); + } + + void TestLetOperator() { + TUtf16String str; + + str = wchar16('X'); + UNIT_ASSERT(str == TUtf16String::FromAscii("X")); + + const TUtf16String hello = TUtf16String::FromAscii("hello"); + str = hello.data(); + UNIT_ASSERT(str == hello); + + str = hello; + UNIT_ASSERT(str == hello); + } + + void TestStringLiterals() { + TUtf16String s1 = u"hello"; + UNIT_ASSERT_VALUES_EQUAL(s1, TUtf16String::FromAscii("hello")); + + TUtf16String s2 = u"привет"; + UNIT_ASSERT_VALUES_EQUAL(s2, TUtf16String::FromUtf8("привет")); + } +}; + +UNIT_TEST_SUITE_REGISTRATION(TWideStringTest); + +class TUtf32StringTest: public TTestBase, private TStringTestImpl<TUtf32String, TTestData<wchar32>> { +public: + UNIT_TEST_SUITE(TUtf32StringTest); + UNIT_TEST(TestConstructors); + UNIT_TEST(TestReplace); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(TestRefCount); +#endif + UNIT_TEST(TestFind); + UNIT_TEST(TestContains); + UNIT_TEST(TestOperators); + UNIT_TEST(TestLetOperator) + UNIT_TEST(TestMulOperators); + UNIT_TEST(TestFuncs); + UNIT_TEST(TestUtils); + UNIT_TEST(TestEmpty); + UNIT_TEST(TestJoin); + UNIT_TEST(TestCopy); + UNIT_TEST(TestStrCpy); + UNIT_TEST(TestPrefixSuffix); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(TestCharRef); +#endif + UNIT_TEST(TestBack); + UNIT_TEST(TestFront) + UNIT_TEST(TestDecodingMethods); + UNIT_TEST(TestDecodingMethodsMixedStr); + UNIT_TEST(TestIterators); + UNIT_TEST(TestReverseIterators); + UNIT_TEST(TestStringLiterals); + UNIT_TEST_SUITE_END(); + +private: + void TestDecodingMethods() { + UNIT_ASSERT(TUtf32String::FromAscii("").empty()); + UNIT_ASSERT(TUtf32String::FromAscii("abc") == ASCIIToUTF32("abc")); + + const char* text = "123kx83abcd ej)#$%ddja&%J&"; + TUtf32String wtext = ASCIIToUTF32(text); + + UNIT_ASSERT(wtext == TUtf32String::FromAscii(text)); + + TString strtext(text); + UNIT_ASSERT(wtext == TUtf32String::FromAscii(strtext)); + + TStringBuf strbuftext(text); + UNIT_ASSERT(wtext == TUtf32String::FromAscii(strbuftext)); + + UNIT_ASSERT(wtext.substr(5) == TUtf32String::FromAscii(text + 5)); + + const wchar32 wideCyrillicAlphabet[] = { + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x00}; + + TUtf32String strWide(wideCyrillicAlphabet); + TString strUtf8 = WideToUTF8(strWide); + + UNIT_ASSERT(strWide == TUtf32String::FromUtf8(strUtf8.c_str())); + UNIT_ASSERT(strWide == TUtf32String::FromUtf8(strUtf8)); + UNIT_ASSERT(strWide == TUtf32String::FromUtf8(TStringBuf(strUtf8))); + + // assign + + TUtf32String s1; + s1.AssignAscii("1234"); + UNIT_ASSERT(s1 == ASCIIToUTF32("1234")); + + s1.AssignUtf8(strUtf8); + UNIT_ASSERT(s1 == strWide); + + s1.AssignAscii(text); + UNIT_ASSERT(s1 == wtext); + + // append + + TUtf32String s2; + TUtf32String testAppend = strWide; + s2.AppendUtf8(strUtf8); + UNIT_ASSERT(testAppend == s2); + + testAppend += ' '; + s2.AppendAscii(" "); + UNIT_ASSERT(testAppend == s2); + + testAppend += '_'; + s2.AppendUtf8("_"); + UNIT_ASSERT(testAppend == s2); + + testAppend += wtext; + s2.AppendAscii(text); + UNIT_ASSERT(testAppend == s2); + + testAppend += wtext; + s2.AppendUtf8(text); + + UNIT_ASSERT(testAppend == s2); + } + + void TestDecodingMethodsMixedStr() { + UNIT_ASSERT(TUtf32String::FromAscii("").empty()); + UNIT_ASSERT(TUtf32String::FromAscii("abc") == ASCIIToUTF32("abc")); + + const char* text = "123kx83abcd ej)#$%ddja&%J&"; + TUtf32String wtext = ASCIIToUTF32(text); + + UNIT_ASSERT(wtext == TUtf32String::FromAscii(text)); + + TString strtext(text); + UNIT_ASSERT(wtext == TUtf32String::FromAscii(strtext)); + + TStringBuf strbuftext(text); + UNIT_ASSERT(wtext == TUtf32String::FromAscii(strbuftext)); + + UNIT_ASSERT(wtext.substr(5) == TUtf32String::FromAscii(text + 5)); + + const wchar32 cyrilicAndLatinWide[] = { + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + wchar32('z'), + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + wchar32('z'), + 0x00}; + + TUtf32String strWide(cyrilicAndLatinWide); + TString strUtf8 = WideToUTF8(strWide); + + UNIT_ASSERT(strWide == TUtf32String::FromUtf8(strUtf8.c_str())); + UNIT_ASSERT(strWide == TUtf32String::FromUtf8(strUtf8)); + UNIT_ASSERT(strWide == UTF8ToUTF32<true>(strUtf8)); + UNIT_ASSERT(strWide == UTF8ToUTF32<false>(strUtf8)); + UNIT_ASSERT(strWide == TUtf32String::FromUtf8(TStringBuf(strUtf8))); + + // assign + + TUtf32String s1; + s1.AssignAscii("1234"); + UNIT_ASSERT(s1 == ASCIIToUTF32("1234")); + + s1.AssignUtf8(strUtf8); + UNIT_ASSERT(s1 == strWide); + + s1.AssignAscii(text); + UNIT_ASSERT(s1 == wtext); + + // append + + TUtf32String s2; + TUtf32String testAppend = strWide; + s2.AppendUtf16(UTF8ToWide(strUtf8)); + UNIT_ASSERT(testAppend == s2); + + testAppend += ' '; + s2.AppendAscii(" "); + UNIT_ASSERT(testAppend == s2); + + testAppend += '_'; + s2.AppendUtf8("_"); + UNIT_ASSERT(testAppend == s2); + + testAppend += wtext; + s2.AppendAscii(text); + UNIT_ASSERT(testAppend == s2); + + testAppend += wtext; + s2.AppendUtf8(text); + + UNIT_ASSERT(testAppend == s2); + } + + void TestLetOperator() { + TUtf32String str; + + str = wchar32('X'); + UNIT_ASSERT(str == TUtf32String::FromAscii("X")); + + const TUtf32String hello = TUtf32String::FromAscii("hello"); + str = hello.data(); + UNIT_ASSERT(str == hello); + + str = hello; + UNIT_ASSERT(str == hello); + } + + void TestStringLiterals() { + TUtf32String s1 = U"hello"; + UNIT_ASSERT_VALUES_EQUAL(s1, TUtf32String::FromAscii("hello")); + + TUtf32String s2 = U"привет"; + UNIT_ASSERT_VALUES_EQUAL(s2, TUtf32String::FromUtf8("привет")); + } +}; + +UNIT_TEST_SUITE_REGISTRATION(TUtf32StringTest); + +class TStringStdTest: public TTestBase, private TStringStdTestImpl<TString, TTestData<char>> { +public: + UNIT_TEST_SUITE(TStringStdTest); + UNIT_TEST(Constructor); + UNIT_TEST(reserve); + UNIT_TEST(short_string); + UNIT_TEST(erase); + UNIT_TEST(data); + UNIT_TEST(c_str); + UNIT_TEST(null_char_of_empty); + UNIT_TEST(null_char); + UNIT_TEST(null_char_assignment_to_subscript_of_empty); + UNIT_TEST(null_char_assignment_to_subscript_of_nonempty); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(null_char_assignment_to_end_of_empty); + UNIT_TEST(null_char_assignment_to_end_of_nonempty); +#endif + UNIT_TEST(insert); + UNIT_TEST(resize); + UNIT_TEST(find); + UNIT_TEST(capacity); + UNIT_TEST(assign); + UNIT_TEST(copy); + UNIT_TEST(cbegin_cend); + UNIT_TEST(compare); + UNIT_TEST(find_last_of); +#if 0 + UNIT_TEST(rfind); + UNIT_TEST(replace); +#endif + UNIT_TEST(find_last_not_of); + UNIT_TEST_SUITE_END(); +}; + +UNIT_TEST_SUITE_REGISTRATION(TStringStdTest); + +class TWideStringStdTest: public TTestBase, private TStringStdTestImpl<TUtf16String, TTestData<wchar16>> { +public: + UNIT_TEST_SUITE(TWideStringStdTest); + UNIT_TEST(Constructor); + UNIT_TEST(reserve); + UNIT_TEST(short_string); + UNIT_TEST(erase); + UNIT_TEST(data); + UNIT_TEST(c_str); + UNIT_TEST(null_char_of_empty); + UNIT_TEST(null_char); + UNIT_TEST(null_char_assignment_to_subscript_of_empty); + UNIT_TEST(null_char_assignment_to_subscript_of_nonempty); +#ifndef TSTRING_IS_STD_STRING + UNIT_TEST(null_char_assignment_to_end_of_empty); + UNIT_TEST(null_char_assignment_to_end_of_nonempty); +#endif + UNIT_TEST(insert); + UNIT_TEST(resize); + UNIT_TEST(find); + UNIT_TEST(capacity); + UNIT_TEST(assign); + UNIT_TEST(copy); + UNIT_TEST(cbegin_cend); + UNIT_TEST(compare); + UNIT_TEST(find_last_of); +#if 0 + UNIT_TEST(rfind); + UNIT_TEST(replace); +#endif + UNIT_TEST(find_last_not_of); + UNIT_TEST_SUITE_END(); +}; + +UNIT_TEST_SUITE_REGISTRATION(TWideStringStdTest); + +Y_UNIT_TEST_SUITE(TStringConversionTest) { + Y_UNIT_TEST(ConversionToStdStringTest) { + TString abra = "cadabra"; + std::string stdAbra = abra; + UNIT_ASSERT_VALUES_EQUAL(stdAbra, "cadabra"); + } + + Y_UNIT_TEST(ConversionToStdStringViewTest) { + TString abra = "cadabra"; + std::string_view stdAbra = abra; + UNIT_ASSERT_VALUES_EQUAL(stdAbra, "cadabra"); + } +} + +Y_UNIT_TEST_SUITE(HashFunctorTests) { + Y_UNIT_TEST(TestTransparency) { + THash<TString> h; + const char* ptr = "a"; + const TStringBuf strbuf = ptr; + const TString str = ptr; + const std::string stdStr = ptr; + UNIT_ASSERT_VALUES_EQUAL(h(ptr), h(strbuf)); + UNIT_ASSERT_VALUES_EQUAL(h(ptr), h(str)); + UNIT_ASSERT_VALUES_EQUAL(h(ptr), h(stdStr)); + } +} + +#if !defined(TSTRING_IS_STD_STRING) +Y_UNIT_TEST_SUITE(StdNonConformant) { + Y_UNIT_TEST(TestEraseNoThrow) { + TString x; + + LegacyErase(x, 10); + } + + Y_UNIT_TEST(TestReplaceNoThrow) { + TString x; + + LegacyReplace(x, 0, 0, "1"); + + UNIT_ASSERT_VALUES_EQUAL(x, "1"); + + LegacyReplace(x, 10, 0, "1"); + + UNIT_ASSERT_VALUES_EQUAL(x, "1"); + } + + Y_UNIT_TEST(TestNoAlias) { + TString s = "x"; + + s.AppendNoAlias("abc", 3); + + UNIT_ASSERT_VALUES_EQUAL(s, "xabc"); + UNIT_ASSERT_VALUES_EQUAL(TString(s.c_str()), "xabc"); + } +} +#endif + +Y_UNIT_TEST_SUITE(Interop) { + static void Mutate(std::string& s) { + s += "y"; + } + + static void Mutate(TString& s) { + Mutate(MutRef(s)); + } + + Y_UNIT_TEST(TestMutate) { + TString x = "x"; + + Mutate(x); + + UNIT_ASSERT_VALUES_EQUAL(x, "xy"); + } + + static std::string TransformStd(const std::string& s) { + return s + "y"; + } + + static TString Transform(const TString& s) { + return TransformStd(s); + } + + Y_UNIT_TEST(TestTransform) { + UNIT_ASSERT_VALUES_EQUAL(Transform(TString("x")), "xy"); + } + + Y_UNIT_TEST(TestTemp) { + UNIT_ASSERT_VALUES_EQUAL("x" + ConstRef(TString("y")), "xy"); + } +} |