#pragma once #include "string.h" #include <library/cpp/testing/unittest/registar.h> #include <util/string/reverse.h> template <typename CharT, size_t N> struct TCharBuffer { CharT Data[N]; //! copies characters from string to the internal buffer without any conversion //! @param s a string that must contain only characters less than 0x7F explicit TCharBuffer(const char* s) { // copy all symbols including null terminated symbol for (size_t i = 0; i < N; ++i) { Data[i] = s[i]; } } const CharT* GetData() const { return Data; } }; template <> struct TCharBuffer<char, 0> { const char* Data; //! stores pointer to string explicit TCharBuffer(const char* s) : Data(s) { } const char* GetData() const { return Data; } }; #define DECLARE_AND_RETURN_BUFFER(s) \ static TCharBuffer<CharT, sizeof(s)> buf(s); \ return buf.GetData(); //! @attention this class can process characters less than 0x7F only (the low half of ASCII table) template <typename CharT> struct TTestData { // words const CharT* str1() { DECLARE_AND_RETURN_BUFFER("str1"); } const CharT* str2() { DECLARE_AND_RETURN_BUFFER("str2"); } const CharT* str__________________________________________________1() { DECLARE_AND_RETURN_BUFFER("str 1"); } const CharT* str__________________________________________________2() { DECLARE_AND_RETURN_BUFFER("str 2"); } const CharT* one() { DECLARE_AND_RETURN_BUFFER("one"); } const CharT* two() { DECLARE_AND_RETURN_BUFFER("two"); } const CharT* three() { DECLARE_AND_RETURN_BUFFER("three"); } const CharT* thrii() { DECLARE_AND_RETURN_BUFFER("thrii"); } const CharT* four() { DECLARE_AND_RETURN_BUFFER("four"); } const CharT* enotw_() { DECLARE_AND_RETURN_BUFFER("enotw "); } const CharT* foo() { DECLARE_AND_RETURN_BUFFER("foo"); } const CharT* abcdef() { DECLARE_AND_RETURN_BUFFER("abcdef"); } const CharT* abcdefg() { DECLARE_AND_RETURN_BUFFER("abcdefg"); } const CharT* aba() { DECLARE_AND_RETURN_BUFFER("aba"); } const CharT* hr() { DECLARE_AND_RETURN_BUFFER("hr"); } const CharT* hrt() { DECLARE_AND_RETURN_BUFFER("hrt"); } const CharT* thr() { DECLARE_AND_RETURN_BUFFER("thr"); } const CharT* tw() { DECLARE_AND_RETURN_BUFFER("tw"); } const CharT* ow() { DECLARE_AND_RETURN_BUFFER("ow"); } const CharT* opq() { DECLARE_AND_RETURN_BUFFER("opq"); } const CharT* xyz() { DECLARE_AND_RETURN_BUFFER("xyz"); } const CharT* abc() { DECLARE_AND_RETURN_BUFFER("abc"); } const CharT* abcd() { DECLARE_AND_RETURN_BUFFER("abcd"); } const CharT* abcde() { DECLARE_AND_RETURN_BUFFER("abcde"); } const CharT* abcc() { DECLARE_AND_RETURN_BUFFER("abcc"); } const CharT* abce() { DECLARE_AND_RETURN_BUFFER("abce"); } const CharT* qwe() { DECLARE_AND_RETURN_BUFFER("qwe"); } const CharT* cd() { DECLARE_AND_RETURN_BUFFER("cd"); } const CharT* cde() { DECLARE_AND_RETURN_BUFFER("cde"); } const CharT* cdef() { DECLARE_AND_RETURN_BUFFER("cdef"); } const CharT* cdefgh() { DECLARE_AND_RETURN_BUFFER("cdefgh"); } const CharT* ehortw_() { DECLARE_AND_RETURN_BUFFER("ehortw "); } const CharT* fg() { DECLARE_AND_RETURN_BUFFER("fg"); } const CharT* abcdefgh() { DECLARE_AND_RETURN_BUFFER("abcdefgh"); } // phrases const CharT* Hello_World() { DECLARE_AND_RETURN_BUFFER("Hello World"); } const CharT* This_is_test_string_for_string_calls() { DECLARE_AND_RETURN_BUFFER("This is test string for string calls"); } const CharT* This_is_teis_test_string_st_string_for_string_calls() { DECLARE_AND_RETURN_BUFFER("This is teis test string st string for string calls"); } const CharT* This_is_test_stis_test_string_for_stringring_for_string_calls() { DECLARE_AND_RETURN_BUFFER("This is test stis test string for stringring for string calls"); } const CharT* allsThis_is_test_string_for_string_calls() { DECLARE_AND_RETURN_BUFFER("allsThis is test string for string calls"); } const CharT* ng_for_string_callsThis_is_test_string_for_string_calls() { DECLARE_AND_RETURN_BUFFER("ng for string callsThis is test string for string calls"); } const CharT* one_two_three_one_two_three() { DECLARE_AND_RETURN_BUFFER("one two three one two three"); } const CharT* test_string_for_assign() { DECLARE_AND_RETURN_BUFFER("test string for assign"); } const CharT* other_test_string() { DECLARE_AND_RETURN_BUFFER("other test string"); } const CharT* This_This_is_tefor_string_calls() { DECLARE_AND_RETURN_BUFFER("This This is tefor string calls"); } const CharT* This_This_is_test_string_for_string_calls() { DECLARE_AND_RETURN_BUFFER("This This is test string for string calls"); } const CharT* _0123456x() { DECLARE_AND_RETURN_BUFFER("0123456x"); } const CharT* _0123456xy() { DECLARE_AND_RETURN_BUFFER("0123456xy"); } const CharT* _0123456xyz() { DECLARE_AND_RETURN_BUFFER("0123456xyz"); } const CharT* _0123456xyzZ() { DECLARE_AND_RETURN_BUFFER("0123456xyzZ"); } const CharT* _0123456xyzZ0() { DECLARE_AND_RETURN_BUFFER("0123456xyzZ0"); } const CharT* abc0123456xyz() { DECLARE_AND_RETURN_BUFFER("abc0123456xyz"); } const CharT* BCabc0123456xyz() { DECLARE_AND_RETURN_BUFFER("BCabc0123456xyz"); } const CharT* qweBCabc0123456xyz() { DECLARE_AND_RETURN_BUFFER("qweBCabc0123456xyz"); } const CharT* _1qweBCabc0123456xyz() { DECLARE_AND_RETURN_BUFFER("1qweBCabc0123456xyz"); } const CharT* _01abc23456() { DECLARE_AND_RETURN_BUFFER("01abc23456"); } const CharT* _01ABCabc23456() { DECLARE_AND_RETURN_BUFFER("01ABCabc23456"); } const CharT* ABC() { DECLARE_AND_RETURN_BUFFER("ABC"); } const CharT* ABCD() { DECLARE_AND_RETURN_BUFFER("ABCD"); } const CharT* QWE() { DECLARE_AND_RETURN_BUFFER("QWE"); } const CharT* XYZ() { DECLARE_AND_RETURN_BUFFER("XYZ"); } const CharT* W01ABCabc23456() { DECLARE_AND_RETURN_BUFFER("W01ABCabc23456"); } const CharT* abcd456() { DECLARE_AND_RETURN_BUFFER("abcd456"); } const CharT* abcdABCD() { DECLARE_AND_RETURN_BUFFER("abcdABCD"); } const CharT* abcdABC123() { DECLARE_AND_RETURN_BUFFER("abcdABC123"); } const CharT* z123z123() { DECLARE_AND_RETURN_BUFFER("z123z123"); } const CharT* ASDF1234QWER() { DECLARE_AND_RETURN_BUFFER("ASDF1234QWER"); } const CharT* asdf1234qwer() { DECLARE_AND_RETURN_BUFFER("asdf1234qwer"); } const CharT* asDF1234qWEr() { DECLARE_AND_RETURN_BUFFER("asDF1234qWEr"); } const CharT* AsDF1234qWEr() { DECLARE_AND_RETURN_BUFFER("AsDF1234qWEr"); } const CharT* Asdf1234qwer() { DECLARE_AND_RETURN_BUFFER("Asdf1234qwer"); } const CharT* Asdf1234qwerWWWW() { DECLARE_AND_RETURN_BUFFER("Asdf1234qwerWWWW"); } const CharT* Asdf() { DECLARE_AND_RETURN_BUFFER("Asdf"); } const CharT* orig() { DECLARE_AND_RETURN_BUFFER("orig"); } const CharT* fdfdsfds() { DECLARE_AND_RETURN_BUFFER("fdfdsfds"); } // numbers const CharT* _0() { DECLARE_AND_RETURN_BUFFER("0"); } const CharT* _00() { DECLARE_AND_RETURN_BUFFER("00"); } const CharT* _0000000000() { DECLARE_AND_RETURN_BUFFER("0000000000"); } const CharT* _00000() { DECLARE_AND_RETURN_BUFFER("00000"); } const CharT* _0123() { DECLARE_AND_RETURN_BUFFER("0123"); } const CharT* _01230123() { DECLARE_AND_RETURN_BUFFER("01230123"); } const CharT* _01234() { DECLARE_AND_RETURN_BUFFER("01234"); } const CharT* _0123401234() { DECLARE_AND_RETURN_BUFFER("0123401234"); } const CharT* _012345() { DECLARE_AND_RETURN_BUFFER("012345"); } const CharT* _0123456() { DECLARE_AND_RETURN_BUFFER("0123456"); } const CharT* _1() { DECLARE_AND_RETURN_BUFFER("1"); } const CharT* _11() { DECLARE_AND_RETURN_BUFFER("11"); } const CharT* _1100000() { DECLARE_AND_RETURN_BUFFER("1100000"); } const CharT* _110000034() { DECLARE_AND_RETURN_BUFFER("110000034"); } const CharT* _12() { DECLARE_AND_RETURN_BUFFER("12"); } const CharT* _123() { DECLARE_AND_RETURN_BUFFER("123"); } const CharT* _1233321() { DECLARE_AND_RETURN_BUFFER("1233321"); } const CharT* _1221() { DECLARE_AND_RETURN_BUFFER("1221"); } const CharT* _1234123456() { DECLARE_AND_RETURN_BUFFER("1234123456"); } const CharT* _12334444321() { DECLARE_AND_RETURN_BUFFER("12334444321"); } const CharT* _123344544321() { DECLARE_AND_RETURN_BUFFER("123344544321"); } const CharT* _1234567890123456789012345678901234567890() { DECLARE_AND_RETURN_BUFFER("1234567890123456789012345678901234567890"); } const CharT* _1234() { DECLARE_AND_RETURN_BUFFER("1234"); } const CharT* _12345() { DECLARE_AND_RETURN_BUFFER("12345"); } const CharT* _123456() { DECLARE_AND_RETURN_BUFFER("123456"); } const CharT* _1234567() { DECLARE_AND_RETURN_BUFFER("1234567"); } const CharT* _1234561234() { DECLARE_AND_RETURN_BUFFER("1234561234"); } const CharT* _12356() { DECLARE_AND_RETURN_BUFFER("12356"); } const CharT* _1345656() { DECLARE_AND_RETURN_BUFFER("1345656"); } const CharT* _15656() { DECLARE_AND_RETURN_BUFFER("15656"); } const CharT* _17856() { DECLARE_AND_RETURN_BUFFER("17856"); } const CharT* _1783456() { DECLARE_AND_RETURN_BUFFER("1783456"); } const CharT* _2() { DECLARE_AND_RETURN_BUFFER("2"); } const CharT* _2123456() { DECLARE_AND_RETURN_BUFFER("2123456"); } const CharT* _23() { DECLARE_AND_RETURN_BUFFER("23"); } const CharT* _2345() { DECLARE_AND_RETURN_BUFFER("2345"); } const CharT* _3() { DECLARE_AND_RETURN_BUFFER("3"); } const CharT* _345() { DECLARE_AND_RETURN_BUFFER("345"); } const CharT* _3456() { DECLARE_AND_RETURN_BUFFER("3456"); } const CharT* _333333() { DECLARE_AND_RETURN_BUFFER("333333"); } const CharT* _389() { DECLARE_AND_RETURN_BUFFER("389"); } const CharT* _4294967295() { DECLARE_AND_RETURN_BUFFER("4294967295"); } const CharT* _4444() { DECLARE_AND_RETURN_BUFFER("4444"); } const CharT* _5() { DECLARE_AND_RETURN_BUFFER("5"); } const CharT* _6() { DECLARE_AND_RETURN_BUFFER("6"); } const CharT* _6543210() { DECLARE_AND_RETURN_BUFFER("6543210"); } const CharT* _7() { DECLARE_AND_RETURN_BUFFER("7"); } const CharT* _78() { DECLARE_AND_RETURN_BUFFER("78"); } const CharT* _2004_01_01() { DECLARE_AND_RETURN_BUFFER("2004-01-01"); } const CharT* _1234562004_01_01() { DECLARE_AND_RETURN_BUFFER("1234562004-01-01"); } const CharT* _0123456_12345() { DECLARE_AND_RETURN_BUFFER("0123456_12345"); } // letters const CharT* a() { DECLARE_AND_RETURN_BUFFER("a"); } const CharT* b() { DECLARE_AND_RETURN_BUFFER("b"); } const CharT* c() { DECLARE_AND_RETURN_BUFFER("c"); } const CharT* d() { DECLARE_AND_RETURN_BUFFER("d"); } const CharT* e() { DECLARE_AND_RETURN_BUFFER("e"); } const CharT* f() { DECLARE_AND_RETURN_BUFFER("f"); } const CharT* h() { DECLARE_AND_RETURN_BUFFER("h"); } const CharT* o() { DECLARE_AND_RETURN_BUFFER("o"); } const CharT* p() { DECLARE_AND_RETURN_BUFFER("p"); } const CharT* q() { DECLARE_AND_RETURN_BUFFER("q"); } const CharT* r() { DECLARE_AND_RETURN_BUFFER("r"); } const CharT* s() { DECLARE_AND_RETURN_BUFFER("s"); } const CharT* t() { DECLARE_AND_RETURN_BUFFER("t"); } const CharT* w() { DECLARE_AND_RETURN_BUFFER("w"); } const CharT* x() { DECLARE_AND_RETURN_BUFFER("x"); } const CharT* y() { DECLARE_AND_RETURN_BUFFER("y"); } const CharT* z() { DECLARE_AND_RETURN_BUFFER("z"); } const CharT* H() { DECLARE_AND_RETURN_BUFFER("H"); } const CharT* I() { DECLARE_AND_RETURN_BUFFER("I"); } const CharT* W() { DECLARE_AND_RETURN_BUFFER("W"); } const CharT* Space() { DECLARE_AND_RETURN_BUFFER(" "); } const CharT* Empty() { DECLARE_AND_RETURN_BUFFER(""); } size_t HashOf_0123456() { return 0; } }; template <> size_t TTestData<char>::HashOf_0123456() { return 1229863857ul; } template <> size_t TTestData<wchar16>::HashOf_0123456() { return 2775195331ul; } template <class TStringType, typename TTestData> class TStringTestImpl { protected: using char_type = typename TStringType::char_type; using traits_type = typename TStringType::traits_type; TTestData Data; public: void TestMaxSize() { const size_t badMaxVal = TStringType{}.max_size() + 1; TStringType s; UNIT_CHECK_GENERATED_EXCEPTION(s.reserve(badMaxVal), std::length_error); } void TestConstructors() { TStringType s0(nullptr); UNIT_ASSERT(s0.size() == 0); UNIT_ASSERT_EQUAL(s0, TStringType()); TStringType s; TStringType s1(*Data._0()); TStringType s2(Data._0()); UNIT_ASSERT(s1 == s2); TStringType fromZero(0); UNIT_ASSERT_VALUES_EQUAL(fromZero.size(), 0u); TStringType fromChar(char_type('a')); UNIT_ASSERT_VALUES_EQUAL(fromChar.size(), 1u); UNIT_ASSERT_VALUES_EQUAL(fromChar[0], char_type('a')); #ifndef TSTRING_IS_STD_STRING TStringType s3 = TStringType::Uninitialized(10); UNIT_ASSERT(s3.size() == 10); #endif TStringType s4(Data._0123456(), 1, 3); UNIT_ASSERT(s4 == Data._123()); TStringType s5(5, *Data._0()); UNIT_ASSERT(s5 == Data._00000()); TStringType s6(Data._0123456()); UNIT_ASSERT(s6 == Data._0123456()); TStringType s7(s6); UNIT_ASSERT(s7 == s6); #ifndef TSTRING_IS_STD_STRING UNIT_ASSERT(s7.c_str() == s6.c_str()); #endif TStringType s8(s7, 1, 3); UNIT_ASSERT(s8 == Data._123()); TStringType s9(*Data._1()); UNIT_ASSERT(s9 == Data._1()); TStringType s10(Reserve(100)); UNIT_ASSERT(s10.empty()); UNIT_ASSERT(s10.capacity() >= 100); } void TestReplace() { TStringType s(Data._0123456()); UNIT_ASSERT(s.copy() == Data._0123456()); // append family s.append(Data.x()); UNIT_ASSERT(s == Data._0123456x()); #ifdef TSTRING_IS_STD_STRING s.append(Data.xyz() + 1, 1); #else s.append(Data.xyz(), 1, 1); #endif UNIT_ASSERT(s == Data._0123456xy()); s.append(TStringType(Data.z())); UNIT_ASSERT(s == Data._0123456xyz()); s.append(TStringType(Data.XYZ()), 2, 1); UNIT_ASSERT(s == Data._0123456xyzZ()); s.append(*Data._0()); UNIT_ASSERT(s == Data._0123456xyzZ0()); // prepend family s = Data._0123456xyz(); s.prepend(TStringType(Data.abc())); UNIT_ASSERT(s == Data.abc0123456xyz()); s.prepend(TStringType(Data.ABC()), 1, 2); UNIT_ASSERT(s == Data.BCabc0123456xyz()); s.prepend(Data.qwe()); UNIT_ASSERT(s == Data.qweBCabc0123456xyz()); s.prepend(*Data._1()); UNIT_ASSERT(s == Data._1qweBCabc0123456xyz()); // substr s = Data.abc0123456xyz(); s = s.substr(3, 7); UNIT_ASSERT(s == Data._0123456()); // insert family s.insert(2, Data.abc()); UNIT_ASSERT(s == Data._01abc23456()); s.insert(2, TStringType(Data.ABC())); UNIT_ASSERT(s == Data._01ABCabc23456()); s.insert(0, TStringType(Data.QWE()), 1, 1); UNIT_ASSERT(s == Data.W01ABCabc23456()); // replace family s = Data._01abc23456(); s.replace(0, 7, Data.abcd()); UNIT_ASSERT(s == Data.abcd456()); s.replace(4, 3, TStringType(Data.ABCD())); UNIT_ASSERT(s == Data.abcdABCD()); s.replace(7, 10, TStringType(Data._01234()), 1, 3); UNIT_ASSERT(s == Data.abcdABC123()); UNIT_ASSERT(Data.abcdABC123() == s); // remove, erase s.remove(4); UNIT_ASSERT(s == Data.abcd()); s.erase(3); UNIT_ASSERT(s == Data.abc()); // Read access s = Data._012345(); UNIT_ASSERT(s.at(1) == *Data._1()); UNIT_ASSERT(s[1] == *Data._1()); UNIT_ASSERT(s.at(s.size()) == 0); UNIT_ASSERT(s[s.size()] == 0); } #ifndef TSTRING_IS_STD_STRING void TestRefCount() { using TStr = TStringType; struct TestStroka: public TStr { using TStr::TStr; // un-protect using TStr::RefCount; }; TestStroka s1(Data.orig()); UNIT_ASSERT_EQUAL(s1.RefCount() == 1, true); TestStroka s2(s1); UNIT_ASSERT_EQUAL(s1.RefCount() == 2, true); UNIT_ASSERT_EQUAL(s2.RefCount() == 2, true); UNIT_ASSERT_EQUAL(s1.c_str() == s2.c_str(), true); // the same pointer char_type* beg = s2.begin(); UNIT_ASSERT_EQUAL(s1 == beg, true); UNIT_ASSERT_EQUAL(s1.RefCount() == 1, true); UNIT_ASSERT_EQUAL(s2.RefCount() == 1, true); UNIT_ASSERT_EQUAL(s1.c_str() == s2.c_str(), false); } #endif // Find family void TestFind() { const TStringType s(Data._0123456_12345()); const TStringType s2(Data._0123()); UNIT_ASSERT(s.find(Data._345()) == 3); UNIT_ASSERT(s.find(Data._345(), 5) == 10); UNIT_ASSERT(s.find(Data._345(), 20) == TStringType::npos); UNIT_ASSERT(s.find(*Data._3()) == 3); UNIT_ASSERT(s.find(TStringType(Data._345())) == 3); UNIT_ASSERT(s.find(TStringType(Data._345()), 2) == 3); UNIT_ASSERT(s.find_first_of(TStringType(Data._389())) == 3); UNIT_ASSERT(s.find_first_of(Data._389()) == 3); UNIT_ASSERT(s.find_first_of(Data._389(), s.size()) == TStringType::npos); UNIT_ASSERT(s.find_first_not_of(Data._123()) == 0); UNIT_ASSERT(s.find_first_of('6') == 6); UNIT_ASSERT(s.find_first_of('1', 2) == 8); UNIT_ASSERT(s.find_first_not_of('0') == 1); UNIT_ASSERT(s.find_first_not_of('1', 1) == 2); const TStringType rs = Data._0123401234(); UNIT_ASSERT(rs.rfind(*Data._3()) == 8); const TStringType empty; UNIT_ASSERT(empty.find(empty) == 0); UNIT_ASSERT(s.find(empty, 0) == 0); UNIT_ASSERT(s.find(empty, 1) == 1); UNIT_ASSERT(s.find(empty, s.length()) == s.length()); UNIT_ASSERT(s.find(empty, s.length() + 1) == TStringType::npos); UNIT_ASSERT(s.rfind(empty) == s.length()); UNIT_ASSERT(empty.rfind(empty) == 0); UNIT_ASSERT(empty.rfind(s) == TStringType::npos); UNIT_ASSERT(s2.rfind(s) == TStringType::npos); UNIT_ASSERT(s.rfind(s2) == 0); UNIT_ASSERT(s.rfind(TStringType(Data._345())) == 10); UNIT_ASSERT(s.rfind(TStringType(Data._345()), 13) == 10); UNIT_ASSERT(s.rfind(TStringType(Data._345()), 10) == 10); UNIT_ASSERT(s.rfind(TStringType(Data._345()), 9) == 3); UNIT_ASSERT(s.rfind(TStringType(Data._345()), 6) == 3); UNIT_ASSERT(s.rfind(TStringType(Data._345()), 3) == 3); UNIT_ASSERT(s.rfind(TStringType(Data._345()), 2) == TStringType::npos); } void TestContains() { const TStringType s(Data._0123456_12345()); const TStringType s2(Data._0123()); UNIT_ASSERT(s.Contains(Data._345())); UNIT_ASSERT(!s2.Contains(Data._345())); UNIT_ASSERT(s.Contains('1')); UNIT_ASSERT(!s.Contains('*')); TStringType empty; UNIT_ASSERT(s.Contains(empty)); UNIT_ASSERT(!empty.Contains(s)); UNIT_ASSERT(empty.Contains(empty)); UNIT_ASSERT(s.Contains(empty, s.length())); } // Operators void TestOperators() { TStringType s(Data._0123456()); // operator += s += TStringType(Data.x()); UNIT_ASSERT(s == Data._0123456x()); s += Data.y(); UNIT_ASSERT(s == Data._0123456xy()); s += *Data.z(); UNIT_ASSERT(s == Data._0123456xyz()); // operator + s = Data._0123456(); s = s + TStringType(Data.x()); UNIT_ASSERT(s == Data._0123456x()); s = s + Data.y(); UNIT_ASSERT(s == Data._0123456xy()); s = s + *Data.z(); UNIT_ASSERT(s == Data._0123456xyz()); // operator != s = Data._012345(); UNIT_ASSERT(s != TStringType(Data.xyz())); UNIT_ASSERT(s != Data.xyz()); UNIT_ASSERT(Data.xyz() != s); // operator < UNIT_ASSERT_EQUAL(s < TStringType(Data.xyz()), true); UNIT_ASSERT_EQUAL(s < Data.xyz(), true); UNIT_ASSERT_EQUAL(Data.xyz() < s, false); // operator <= UNIT_ASSERT_EQUAL(s <= TStringType(Data.xyz()), true); UNIT_ASSERT_EQUAL(s <= Data.xyz(), true); UNIT_ASSERT_EQUAL(Data.xyz() <= s, false); // operator > UNIT_ASSERT_EQUAL(s > TStringType(Data.xyz()), false); UNIT_ASSERT_EQUAL(s > Data.xyz(), false); UNIT_ASSERT_EQUAL(Data.xyz() > s, true); // operator >= UNIT_ASSERT_EQUAL(s >= TStringType(Data.xyz()), false); UNIT_ASSERT_EQUAL(s >= Data.xyz(), false); UNIT_ASSERT_EQUAL(Data.xyz() >= s, true); } void TestOperatorsCI() { TStringType s(Data.ABCD()); UNIT_ASSERT(s > Data.abc0123456xyz()); UNIT_ASSERT(s == Data.abcd()); using TCIStringBuf = TBasicStringBuf<char_type, traits_type>; UNIT_ASSERT(s > TCIStringBuf(Data.abc0123456xyz())); UNIT_ASSERT(TCIStringBuf(Data.abc0123456xyz()) < s); UNIT_ASSERT(s == TCIStringBuf(Data.abcd())); } void TestMulOperators() { { TStringType s(Data._0()); s *= 10; UNIT_ASSERT_EQUAL(s, TStringType(Data._0000000000())); } { TStringType s = TStringType(Data._0()) * 2; UNIT_ASSERT_EQUAL(s, TStringType(Data._00())); } } // Test any other functions void TestFuncs() { TStringType s(Data._0123456()); UNIT_ASSERT(s.c_str() == s.data()); // length() UNIT_ASSERT(s.length() == s.size()); UNIT_ASSERT(s.length() == traits_type::length(s.data())); // is_null() TStringType s1(Data.Empty()); UNIT_ASSERT(s1.is_null() == true); UNIT_ASSERT(s1.is_null() == s1.empty()); UNIT_ASSERT(s1.is_null() == !s1); TStringType s2(s); UNIT_ASSERT(s2 == s); // reverse() ReverseInPlace(s2); UNIT_ASSERT(s2 == Data._6543210()); // to_upper() s2 = Data.asdf1234qwer(); s2.to_upper(); UNIT_ASSERT(s2 == Data.ASDF1234QWER()); // to_lower() s2.to_lower(); UNIT_ASSERT(s2 == Data.asdf1234qwer()); // to_title() s2 = Data.asDF1234qWEr(); s2.to_title(); UNIT_ASSERT(s2 == Data.Asdf1234qwer()); s2 = Data.AsDF1234qWEr(); s2.to_title(); UNIT_ASSERT(s2 == Data.Asdf1234qwer()); // Friend functions s2 = Data.asdf1234qwer(); TStringType s3 = to_upper(s2); UNIT_ASSERT(s3 == Data.ASDF1234QWER()); s3 = to_lower(s2); UNIT_ASSERT(s3 == Data.asdf1234qwer()); s3 = to_title(s2); UNIT_ASSERT(s3 == Data.Asdf1234qwer()); s2 = s3; // resize family s2.resize(s2.size()); // without length change UNIT_ASSERT(s2 == Data.Asdf1234qwer()); s2.resize(s2.size() + 4, *Data.W()); UNIT_ASSERT(s2 == Data.Asdf1234qwerWWWW()); s2.resize(4); UNIT_ASSERT(s2 == Data.Asdf()); // assign family s2 = Data.asdf1234qwer(); s2.assign(s, 1, 3); UNIT_ASSERT(s2 == Data._123()); s2.assign(Data._0123456(), 4); UNIT_ASSERT(s2 == Data._0123()); s2.assign('1'); UNIT_ASSERT(s2 == Data._1()); s2.assign(Data._0123456()); UNIT_ASSERT(s2 == Data._0123456()); // hash() TStringType sS = s2; // type 'TStringType' is used as is ComputeHash(sS); /*size_t hash_val = sS.hash(); try { //UNIT_ASSERT(hash_val == Data.HashOf_0123456()); } catch (...) { Cerr << hash_val << Endl; throw; }*/ s2.assign(Data._0123456(), 2, 2); UNIT_ASSERT(s2 == Data._23()); //s2.reserve(); TStringType s5(Data.abcde()); s5.clear(); UNIT_ASSERT(s5 == Data.Empty()); } void TestUtils() { TStringType s; s = Data._01230123(); TStringType from = Data._0(); TStringType to = Data.z(); SubstGlobal(s, from, to); UNIT_ASSERT(s == Data.z123z123()); } void TestEmpty() { TStringType s; s = Data._2(); s = TStringType(Data.fdfdsfds(), (size_t)0, (size_t)0); UNIT_ASSERT(s.empty()); } void TestJoin() { UNIT_ASSERT_EQUAL(TStringType::Join(Data._12(), Data._3456()), Data._123456()); UNIT_ASSERT_EQUAL(TStringType::Join(Data._12(), TStringType(Data._3456())), Data._123456()); UNIT_ASSERT_EQUAL(TStringType::Join(TStringType(Data._12()), Data._3456()), Data._123456()); UNIT_ASSERT_EQUAL(TStringType::Join(Data._12(), Data._345(), Data._6()), Data._123456()); UNIT_ASSERT_EQUAL(TStringType::Join(Data._12(), TStringType(Data._345()), Data._6()), Data._123456()); UNIT_ASSERT_EQUAL(TStringType::Join(TStringType(Data._12()), TStringType(Data._345()), Data._6()), Data._123456()); UNIT_ASSERT_EQUAL(TStringType::Join(TStringType(Data.a()), Data.b(), TStringType(Data.cd()), TStringType(Data.e()), Data.fg(), TStringType(Data.h())), Data.abcdefgh()); UNIT_ASSERT_EQUAL(TStringType::Join(TStringType(Data.a()), static_cast<typename TStringType::char_type>('b'), TStringType(Data.cd()), TStringType(Data.e()), Data.fg(), TStringType(Data.h())), Data.abcdefgh()); } void TestCopy() { TStringType s(Data.abcd()); TStringType c = s.copy(); UNIT_ASSERT_EQUAL(s, c); UNIT_ASSERT(s.end() != c.end()); } void TestStrCpy() { { TStringType s(Data.abcd()); char_type data[5]; data[4] = 1; s.strcpy(data, 4); UNIT_ASSERT_EQUAL(data[0], *Data.a()); UNIT_ASSERT_EQUAL(data[1], *Data.b()); UNIT_ASSERT_EQUAL(data[2], *Data.c()); UNIT_ASSERT_EQUAL(data[3], 0); UNIT_ASSERT_EQUAL(data[4], 1); } { TStringType s(Data.abcd()); char_type data[5]; s.strcpy(data, 5); UNIT_ASSERT_EQUAL(data[0], *Data.a()); UNIT_ASSERT_EQUAL(data[1], *Data.b()); UNIT_ASSERT_EQUAL(data[2], *Data.c()); UNIT_ASSERT_EQUAL(data[3], *Data.d()); UNIT_ASSERT_EQUAL(data[4], 0); } } void TestPrefixSuffix() { const TStringType emptyStr; UNIT_ASSERT_EQUAL(emptyStr.StartsWith('x'), false); UNIT_ASSERT_EQUAL(emptyStr.EndsWith('x'), false); UNIT_ASSERT_EQUAL(emptyStr.StartsWith(0), false); UNIT_ASSERT_EQUAL(emptyStr.EndsWith(0), false); UNIT_ASSERT_EQUAL(emptyStr.StartsWith(emptyStr), true); UNIT_ASSERT_EQUAL(emptyStr.EndsWith(emptyStr), true); const char_type chars[] = {'h', 'e', 'l', 'l', 'o', 0}; const TStringType str(chars); UNIT_ASSERT_EQUAL(str.StartsWith('h'), true); UNIT_ASSERT_EQUAL(str.StartsWith('o'), false); UNIT_ASSERT_EQUAL(str.EndsWith('o'), true); UNIT_ASSERT_EQUAL(str.EndsWith('h'), false); UNIT_ASSERT_EQUAL(str.StartsWith(emptyStr), true); UNIT_ASSERT_EQUAL(str.EndsWith(emptyStr), true); } #ifndef TSTRING_IS_STD_STRING void TestCharRef() { const char_type abc[] = {'a', 'b', 'c', 0}; const char_type bbc[] = {'b', 'b', 'c', 0}; const char_type cbc[] = {'c', 'b', 'c', 0}; TStringType s0 = abc; TStringType s1 = s0; UNIT_ASSERT(!s0.IsDetached()); UNIT_ASSERT(!s1.IsDetached()); /* Read access shouldn't detach. */ UNIT_ASSERT_VALUES_EQUAL(s0[0], (ui8)'a'); UNIT_ASSERT(!s0.IsDetached()); UNIT_ASSERT(!s1.IsDetached()); /* Writing should detach. */ s1[0] = (ui8)'b'; TStringType s2 = s0; s0[0] = (ui8)'c'; UNIT_ASSERT_VALUES_EQUAL(s0, cbc); UNIT_ASSERT_VALUES_EQUAL(s1, bbc); UNIT_ASSERT_VALUES_EQUAL(s2, abc); UNIT_ASSERT(s0.IsDetached()); UNIT_ASSERT(s1.IsDetached()); UNIT_ASSERT(s2.IsDetached()); /* Accessing null terminator is OK. Note that writing into it is UB. */ UNIT_ASSERT_VALUES_EQUAL(s0[3], (ui8)'\0'); UNIT_ASSERT_VALUES_EQUAL(s1[3], (ui8)'\0'); UNIT_ASSERT_VALUES_EQUAL(s2[3], (ui8)'\0'); /* Assignment one char reference to another results in modification of underlying character */ { const char_type dark_eyed[] = {'d', 'a', 'r', 'k', '-', 'e', 'y', 'e', 'd', 0}; const char_type red_eared[] = {'r', 'e', 'd', '-', 'e', 'a', 'r', 'e', 'd', 0}; TStringType s0 = dark_eyed; TStringType s1 = TStringType::Uninitialized(s0.size()); for (size_t i = 0; i < s1.size(); ++i) { const size_t j = (3u * (i + 1u) ^ 1u) % s0.size(); s1[i] = s0[j]; } UNIT_ASSERT_VALUES_EQUAL(s1, red_eared); } } #endif void TestBack() { const char_type chars[] = {'f', 'o', 'o', 0}; TStringType str = chars; const TStringType constStr = str; UNIT_ASSERT_VALUES_EQUAL(constStr.back(), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(str.back(), (ui8)'o'); str.back() = 'r'; UNIT_ASSERT_VALUES_EQUAL(constStr.back(), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(str.back(), (ui8)'r'); } void TestFront() { const char_type chars[] = {'f', 'o', 'o', 0}; TStringType str = chars; const TStringType constStr = str; UNIT_ASSERT_VALUES_EQUAL(constStr.front(), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(str.front(), (ui8)'f'); str.front() = 'r'; UNIT_ASSERT_VALUES_EQUAL(constStr.front(), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(str.front(), (ui8)'r'); } void TestIterators() { const char_type chars[] = {'f', 'o', 0}; TStringType str = chars; const TStringType constStr = str; typename TStringType::const_iterator itBegin = str.begin(); typename TStringType::const_iterator itEnd = str.end(); typename TStringType::const_iterator citBegin = constStr.begin(); typename TStringType::const_iterator citEnd = constStr.end(); UNIT_ASSERT_VALUES_EQUAL(*itBegin, (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*citBegin, (ui8)'f'); str.front() = 'r'; UNIT_ASSERT_VALUES_EQUAL(*itBegin, (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*citBegin, (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(2, itEnd - itBegin); UNIT_ASSERT_VALUES_EQUAL(2, citEnd - citBegin); UNIT_ASSERT_VALUES_EQUAL(*(++itBegin), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*(++citBegin), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*(--itBegin), (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*(--citBegin), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*(itBegin++), (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*(citBegin++), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*itBegin, (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*citBegin, (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*(itBegin--), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*(citBegin--), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*itBegin, (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*citBegin, (ui8)'f'); } void TestReverseIterators() { const char_type chars[] = {'f', 'o', 0}; TStringType str = chars; const TStringType constStr = str; typename TStringType::reverse_iterator ritBegin = str.rbegin(); typename TStringType::reverse_iterator ritEnd = str.rend(); typename TStringType::const_reverse_iterator critBegin = constStr.rbegin(); typename TStringType::const_reverse_iterator critEnd = constStr.rend(); UNIT_ASSERT_VALUES_EQUAL(*ritBegin, (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*critBegin, (ui8)'o'); str.back() = (ui8)'r'; UNIT_ASSERT_VALUES_EQUAL(*ritBegin, (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*critBegin, (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(2, ritEnd - ritBegin); UNIT_ASSERT_VALUES_EQUAL(2, critEnd - critBegin); UNIT_ASSERT_VALUES_EQUAL(*(++ritBegin), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*(++critBegin), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*(--ritBegin), (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*(--critBegin), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*(ritBegin++), (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*(critBegin++), (ui8)'o'); UNIT_ASSERT_VALUES_EQUAL(*ritBegin, (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*critBegin, (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*(ritBegin--), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*(critBegin--), (ui8)'f'); UNIT_ASSERT_VALUES_EQUAL(*ritBegin, (ui8)'r'); UNIT_ASSERT_VALUES_EQUAL(*critBegin, (ui8)'o'); *ritBegin = (ui8)'e'; UNIT_ASSERT_VALUES_EQUAL(*ritBegin, (ui8)'e'); } };