#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');
}
};