Skip to content

Commit 56b7326

Browse files
committed
#159 - Test CppStringT::replace() with char and wchar_t
Tested and validated; Fixed a few bugs, notably within methods find() and find_n() and within tests of find() and find_n()!
1 parent 6faba8d commit 56b7326

File tree

2 files changed

+149
-54
lines changed

2 files changed

+149
-54
lines changed

cpp-strings-tests/cpp-strings-tests.cpp

Lines changed: 130 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -171,45 +171,119 @@ namespace cppstringstests
171171

172172
TEST_METHOD(find)
173173
{
174+
size_t found_pos;
175+
174176
pcs::CppString test{ "ABC0123456789." };
175177
for (int c = 0; c <= 255; ++c) {
176178
char ch{ char(c) };
177179
Assert::AreEqual(test.MyBaseClass::find(ch), test.find(ch));
178-
Assert::AreEqual(test.substr(2).MyBaseClass::find(ch), test.find(ch, 2));
179-
Assert::AreEqual(test.substr(2,5).MyBaseClass::find(ch), test.find(ch, 2, 5+2-1));
180+
181+
found_pos = test.substr(2).MyBaseClass::find(ch);
182+
if (found_pos == pcs::CppString::npos)
183+
Assert::AreEqual(found_pos, test.find(ch, 2));
184+
else
185+
Assert::AreEqual(found_pos, test.find(ch, 2) - 2);
186+
187+
found_pos = test.substr(2, 5).MyBaseClass::find(ch);
188+
if (found_pos == pcs::CppString::npos)
189+
Assert::AreEqual(found_pos, test.find(ch, 2, pcs::CppString::size_type(5 + 2 - 1)));
190+
else
191+
Assert::AreEqual(found_pos, test.find(ch, 2, pcs::CppString::size_type(5 + 2 - 1)) - 2);
180192

181193
CppString s(ch);
182194
Assert::AreEqual(test.MyBaseClass::find(s), test.find(s));
183-
Assert::AreEqual(test.substr(2).MyBaseClass::find(s), test.find(s,2));
184-
Assert::AreEqual(test.substr(3, 5).MyBaseClass::find(s), test.find(s, 3, 5+3-1));
185-
186-
char str[2]{ ch, 0 };
187-
Assert::AreEqual(test.MyBaseClass::find(str), test.find(str));
188-
Assert::AreEqual(test.substr(2).MyBaseClass::find(str), test.find(str, 2));
189-
Assert::AreEqual(test.substr(3, 5).MyBaseClass::find(str), test.find(str, 3, 5+3-1));
195+
found_pos = test.substr(2).MyBaseClass::find(s);
196+
if (found_pos == pcs::CppString::npos)
197+
Assert::AreEqual(found_pos, test.find(s, 2));
198+
else
199+
Assert::AreEqual(found_pos, test.find(s, 2) - 2);
200+
201+
found_pos = test.substr(2, 5).MyBaseClass::find(s);
202+
if (found_pos == pcs::CppString::npos)
203+
Assert::AreEqual(found_pos, test.find(s, 2, pcs::CppString::size_type(5 + 2 - 1)));
204+
else
205+
Assert::AreEqual(found_pos, test.find(s, 2, pcs::CppString::size_type(5 + 2 - 1)) - 2);
206+
207+
if (c > 0) {
208+
char str[2]{ ch, 0 };
209+
Assert::AreEqual(test.MyBaseClass::find(str), test.find(str));
210+
211+
found_pos = test.substr(2).MyBaseClass::find(str);
212+
if (found_pos == pcs::CppString::npos)
213+
Assert::AreEqual(found_pos, test.find(str, 2));
214+
else
215+
Assert::AreEqual(found_pos, test.find(str, 2) - 2);
216+
217+
found_pos = test.substr(2, 5).MyBaseClass::find(str);
218+
if (found_pos == pcs::CppString::npos)
219+
Assert::AreEqual(found_pos, test.find(str, 2, pcs::CppString::size_type(5 + 2 - 1)));
220+
else
221+
Assert::AreEqual(found_pos, test.find(str, 2, pcs::CppString::size_type(5 + 2 - 1)) - 2);
222+
}
190223
}
224+
Assert::AreEqual(pcs::CppString::npos, test.find("A", 1));
225+
Assert::AreEqual(size_t(0), test.find(""));
226+
Assert::AreEqual(pcs::CppString::npos, test.find(".", 14));
227+
Assert::AreEqual(size_t(13), test.find(".", 13));
191228

192229
pcs::CppWString wtest{ L"ABC0123456789." };
193230
for (int wc = 0; wc <=0xffff; ++wc) {
194231
wchar_t wch{ wchar_t(wc) };
195-
Assert::AreEqual(wtest.MyBaseClass::find(wch), wtest.find(wch));
196-
Assert::AreEqual(wtest.substr(2).MyBaseClass::find(wch), wtest.find(wch, 2));
197-
Assert::AreEqual(wtest.substr(2, 5).MyBaseClass::find(wch), wtest.find(wch, 2, 5 + 2 - 1));
232+
233+
found_pos = wtest.substr(2).MyBaseClass::find(wch);
234+
if (found_pos == pcs::CppString::npos)
235+
Assert::AreEqual(found_pos, wtest.find(wch, 2));
236+
else
237+
Assert::AreEqual(found_pos, wtest.find(wch, 2) - 2);
238+
239+
found_pos = wtest.substr(2, 5).MyBaseClass::find(wch);
240+
if (found_pos == pcs::CppString::npos)
241+
Assert::AreEqual(found_pos, wtest.find(wch, 2, pcs::CppWString::size_type(5 + 2 - 1)));
242+
else
243+
Assert::AreEqual(found_pos, wtest.find(wch, 2, pcs::CppWString::size_type(5 + 2 - 1)) - 2);
198244

199245
CppWString ws(wch);
200246
Assert::AreEqual(wtest.MyBaseClass::find(ws), wtest.find(ws));
201-
Assert::AreEqual(wtest.substr(2).MyBaseClass::find(ws), wtest.find(ws, 2));
202-
Assert::AreEqual(wtest.substr(3, 5).MyBaseClass::find(ws), wtest.find(ws, 3, 5 + 3 - 1));
203247

204-
wchar_t wstr[2]{ wch, 0 };
205-
Assert::AreEqual(wtest.MyBaseClass::find(wstr), wtest.find(wstr));
206-
Assert::AreEqual(wtest.substr(2).MyBaseClass::find(wstr), wtest.find(wstr, 2));
207-
Assert::AreEqual(wtest.substr(3, 5).MyBaseClass::find(wstr), wtest.find(wstr, 3, 5 + 3 - 1));
248+
found_pos = wtest.substr(2).MyBaseClass::find(ws);
249+
if (found_pos == pcs::CppString::npos)
250+
Assert::AreEqual(found_pos, wtest.find(ws, 2));
251+
else
252+
Assert::AreEqual(found_pos, wtest.find(ws, 2) - 2);
253+
254+
found_pos = wtest.substr(2, 5).MyBaseClass::find(ws);
255+
if (found_pos == pcs::CppString::npos)
256+
Assert::AreEqual(found_pos, wtest.find(ws, 2, pcs::CppString::size_type(5 + 2 - 1)));
257+
else
258+
Assert::AreEqual(found_pos, wtest.find(ws, 2, pcs::CppString::size_type(5 + 2 - 1)) - 2);
259+
260+
261+
if (wc > 0) {
262+
wchar_t wstr[2]{ wch, 0 };
263+
Assert::AreEqual(wtest.MyBaseClass::find(wstr), wtest.find(wstr));
264+
265+
found_pos = wtest.substr(2).MyBaseClass::find(wstr);
266+
if (found_pos == pcs::CppString::npos)
267+
Assert::AreEqual(found_pos, wtest.find(wstr, 2));
268+
else
269+
Assert::AreEqual(found_pos, wtest.find(wstr, 2) - 2);
270+
271+
found_pos = wtest.substr(2, 5).MyBaseClass::find(wstr);
272+
if (found_pos == pcs::CppString::npos)
273+
Assert::AreEqual(found_pos, wtest.find(wstr, 2, pcs::CppString::size_type(5 + 2 - 1)));
274+
else
275+
Assert::AreEqual(found_pos, wtest.find(wstr, 2, pcs::CppString::size_type(5 + 2 - 1)) - 2);
276+
}
208277
}
278+
Assert::AreEqual(pcs::CppString::npos, wtest.find(L"A", 1));
279+
Assert::AreEqual(size_t(0), wtest.find(L""));
280+
Assert::AreEqual(pcs::CppString::npos, wtest.find(L".", 14));
281+
Assert::AreEqual(size_t(13), wtest.find(L".", 13));
209282
}
210283

211284
TEST_METHOD(find_n)
212285
{
286+
// notice: find_n() is fully tested via TEST_METHOD(find)
213287
pcs::CppString test{ "ABC0123456789." };
214288
for (int c = 0; c <= 255; ++c) {
215289
char ch{ char(c) };
@@ -910,5 +984,43 @@ namespace cppstringstests
910984
Assert::AreEqual(L"abbaba", L"abbabaabcd"cs.removesuffix(L"abcd").c_str());
911985
Assert::AreEqual(L"abcd", L"abcdab"cs.removesuffix(L"ab").c_str());
912986
}
987+
988+
989+
TEST_METHOD(replace)
990+
{
991+
pcs::CppString s("abbaa");
992+
Assert::AreEqual("abbaa", s.replace("e", "fff").c_str());
993+
Assert::AreEqual("AAbbAAAA", s.replace("a", "AA").c_str());
994+
Assert::AreEqual("aBBaa", s.replace("b", "B").c_str());
995+
996+
Assert::AreEqual("abbaa", s.replace("e", "fff", 0).c_str());
997+
Assert::AreEqual("abbaa", s.replace("a", "AA", 0).c_str());
998+
Assert::AreEqual("abbaa", s.replace("b", "B", 0).c_str());
999+
1000+
Assert::AreEqual("abbaa", s.replace("e", "fff", 1).c_str());
1001+
Assert::AreEqual("AAbbaa", s.replace("a", "AA", 1).c_str());
1002+
Assert::AreEqual("aBbaa", s.replace("b", "B", 1).c_str());
1003+
1004+
Assert::AreEqual("abbaa", s.replace("e", "fff", 2).c_str());
1005+
Assert::AreEqual("AAbbAAAA", s.replace("a", "AA", 3).c_str());
1006+
Assert::AreEqual("aBBaa", s.replace("b", "B", 5).c_str());
1007+
1008+
pcs::CppWString ws(L"abbaa");
1009+
Assert::AreEqual(L"abbaa", ws.replace(L"e", L"fff").c_str());
1010+
Assert::AreEqual(L"AAbbAAAA", ws.replace(L"a", L"AA").c_str());
1011+
Assert::AreEqual(L"aBBaa", ws.replace(L"b", L"B").c_str());
1012+
1013+
Assert::AreEqual(L"abbaa", ws.replace(L"e", L"fff", 0).c_str());
1014+
Assert::AreEqual(L"abbaa", ws.replace(L"a", L"AA", 0).c_str());
1015+
Assert::AreEqual(L"abbaa", ws.replace(L"b", L"B", 0).c_str());
1016+
1017+
Assert::AreEqual(L"abbaa", ws.replace(L"e", L"fff", 1).c_str());
1018+
Assert::AreEqual(L"AAbbaa", ws.replace(L"a", L"AA", 1).c_str());
1019+
Assert::AreEqual(L"aBbaa", ws.replace(L"b", L"B", 1).c_str());
1020+
1021+
Assert::AreEqual(L"abbaa", ws.replace(L"e", L"fff", 2).c_str());
1022+
Assert::AreEqual(L"AAbbAAAA", ws.replace(L"a", L"AA", 3).c_str());
1023+
Assert::AreEqual(L"aBBaa", ws.replace(L"b", L"B", 5).c_str());
1024+
}
9131025
};
9141026
}

cpp-strings/cppstrings.h

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -583,13 +583,12 @@ namespace pcs // i.e. "pythonic c++ strings"
583583
*/
584584
constexpr size_type find(const CppStringT& sub, const size_type start = 0, const size_type end = -1) const noexcept
585585
{
586-
size_type start_{ start };
587586
const size_type end_{ (end == -1) ? this->size() : end };
588587

589-
if (start_ > end_)
588+
if (start > end_)
590589
return CppStringT::npos;
591590
else
592-
return find_n(sub, start_, end_ - start_ + 1);
591+
return find_n(sub, start, end_ - start + 1);
593592
}
594593

595594
/** Returns the lowest index in the string where character ch is found within the slice str[start:end], or -1 (i.e. 'npos') if ch is not found.
@@ -642,12 +641,16 @@ namespace pcs // i.e. "pythonic c++ strings"
642641
*/
643642
inline constexpr size_type find_n(const CppStringT& sub, const size_type start, const size_type count) const noexcept
644643
{
644+
constexpr size_type npos{ CppStringT::npos };
645+
645646
try {
646-
CppStringT part{ this->substr(start, count) };
647-
return part.MyBaseClass::find(sub);
647+
const CppStringT sub_str{ this->substr(start, count) };
648+
const size_type found_pos{ sub_str.MyBaseClass::find(sub) };
649+
650+
return (found_pos == npos) ? npos : found_pos + start;
648651
}
649652
catch (...) {
650-
return CppStringT::npos;
653+
return npos;
651654
}
652655
}
653656

@@ -1049,7 +1052,7 @@ namespace pcs // i.e. "pythonic c++ strings"
10491052
* The separator between elements is the string to which this method is applied.
10501053
*/
10511054
template<class... NextCppStringsT>
1052-
inline CppStringT join(const CppStringT& first, const NextCppStringsT... others) const noexcept
1055+
inline CppStringT join(const CppStringT& first, const NextCppStringsT&... others) const noexcept
10531056
requires (sizeof...(others) > 0)
10541057
{
10551058
return first + *this + this->join(others...);
@@ -1182,43 +1185,23 @@ namespace pcs // i.e. "pythonic c++ strings"
11821185

11831186

11841187
//--- replace() ---------------------------------------
1185-
/** \brief Returns a copy of the string with all occurrences of substring old replaced by new. */
1186-
CppStringT replace(const CppStringT& old, const CppStringT& new_) const noexcept
1187-
{
1188-
if (!this->contains(old))
1189-
return *this;
1190-
1191-
CppStringT res{};
1192-
size_type last_index = 0;
1193-
size_type current_index = 0;
1194-
while ((current_index = this->find(old)) != CppStringT::npos) {
1195-
res += this->substr(last_index, current_index - last_index) + new_;
1196-
last_index = current_index;
1197-
}
1198-
1199-
if (last_index != this->size())
1200-
res += this->substr(last_index, this->size - last_index);
1201-
1202-
return res;
1203-
}
1204-
1205-
/** \brief Returns a copy of the string with first count occurrences of substring old replaced by new. */
1206-
CppStringT replace(const CppStringT& old, const CppStringT& new_, size_type count) const noexcept
1188+
/** \brief Returns a copy of the string with first count occurrences of substring 'old' replaced by 'new_'. */
1189+
CppStringT replace(const CppStringT& old, const CppStringT& new_, size_type count = -1) const noexcept
12071190
{
1208-
if (!this->contains(old) || count == 0)
1191+
if (old == new_ || old.empty())
12091192
return *this;
12101193

12111194
CppStringT res{};
1212-
size_type last_index = 0;
1195+
size_type prev_index = 0;
12131196
size_type current_index = 0;
1214-
while (count > 0 && (current_index = this->find(old)) != CppStringT::npos) {
1215-
res += this->substr(last_index, current_index - last_index) + new_;
1216-
last_index = current_index;
1197+
while (count > 0 && (current_index = this->find(old, prev_index)) != CppStringT::npos) {
1198+
res += this->substr(prev_index, current_index - prev_index) + new_;
1199+
prev_index = current_index + 1;
12171200
--count;
12181201
}
12191202

1220-
if (last_index != this->size())
1221-
res += this->substr(last_index, this->size - last_index);
1203+
if (prev_index < this->size())
1204+
res += this->substr(prev_index, this->size() - prev_index);
12221205

12231206
return res;
12241207
}

0 commit comments

Comments
 (0)