]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tests/testSBuf.cc
Add SBuf::push_back() (#1621)
[thirdparty/squid.git] / src / tests / testSBuf.cc
CommitLineData
4e0938ef 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
4e0938ef
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
412da427 9#include "squid.h"
4685b0c4 10#include "base/CharacterSet.h"
ae022809
FC
11#include "base/TextException.h"
12#include "compat/cppunit.h"
13#include "event.h"
a0c227a9 14#include "HttpReply.h"
ae022809 15#include "MemObject.h"
5218815a 16#include "sbuf/Algorithms.h"
a471b119 17#include "sbuf/SBuf.h"
58d8264f 18#include "sbuf/Stream.h"
323547b0 19#include "tests/SBufFindTest.h"
7f861c77
AJ
20#include "unitTestMain.h"
21
1cca3b78 22#include <algorithm>
412da427
FC
23#include <iostream>
24#include <stdexcept>
bf7550ff 25#include <unordered_map>
412da427 26
ae022809
FC
27/*
28 * test the SBuf functionalities
29 */
30
31class TestSBuf : public CPPUNIT_NS::TestFixture
32{
33 CPPUNIT_TEST_SUITE(TestSBuf);
34 CPPUNIT_TEST(testSBufConstructDestruct);
35 CPPUNIT_TEST(testSBufConstructDestructAfterMemInit);
36 CPPUNIT_TEST(testSBufLength);
37 CPPUNIT_TEST(testEqualityTest);
38 CPPUNIT_TEST(testStartsWith);
39 CPPUNIT_TEST(testAppendSBuf);
40 CPPUNIT_TEST(testAppendCString);
41 CPPUNIT_TEST(testAppendStdString);
42 CPPUNIT_TEST(testAppendf);
43 CPPUNIT_TEST(testSubscriptOp);
44 CPPUNIT_TEST_EXCEPTION(testSubscriptOpFail, TextException);
45 CPPUNIT_TEST(testComparisons);
46 CPPUNIT_TEST(testConsume);
47 CPPUNIT_TEST(testRawContent);
48 CPPUNIT_TEST(testRawSpace);
49 CPPUNIT_TEST(testChop);
50 CPPUNIT_TEST(testChomp);
51 CPPUNIT_TEST(testSubstr);
52 CPPUNIT_TEST(testFindChar);
53 CPPUNIT_TEST(testFindSBuf);
54 CPPUNIT_TEST(testRFindChar);
55 CPPUNIT_TEST(testRFindSBuf);
56 CPPUNIT_TEST(testFindFirstOf);
57 CPPUNIT_TEST(testFindFirstNotOf);
58 CPPUNIT_TEST(testPrintf);
59 CPPUNIT_TEST(testCopy);
60 CPPUNIT_TEST(testStringOps);
61 CPPUNIT_TEST(testGrow);
62 CPPUNIT_TEST(testReserve);
63 CPPUNIT_TEST(testSBufStream);
64 CPPUNIT_TEST(testAutoFind);
65 CPPUNIT_TEST(testStdStringOps);
66 CPPUNIT_TEST(testIterators);
67 CPPUNIT_TEST(testSBufHash);
1cca3b78 68 CPPUNIT_TEST(testStdAlgorithm);
ae022809
FC
69 // CPPUNIT_TEST( testDumpStats ); //fake test, to print alloc stats
70 CPPUNIT_TEST_SUITE_END();
71
72protected:
73 void commonInit();
74 void testSBufConstructDestruct();
75 void testSBufConstructDestructAfterMemInit();
76 void testEqualityTest();
77 void testAppendSBuf();
78 void testAppendCString();
79 void testAppendStdString();
80 void testAppendf();
81 void testPrintf();
82 void testSubscriptOp();
83 void testSubscriptOpFail();
84 void testDumpStats();
85 void testComparisons();
86 void testConsume();
87 void testRawContent();
88 void testRawSpace();
89 void testChop();
90 void testChomp();
91 void testSubstr();
92 void testTailCopy();
93 void testSBufLength();
94 void testFindChar();
95 void testFindSBuf();
96 void testRFindChar();
97 void testRFindSBuf();
98 void testSearchFail();
99 void testCopy();
100 void testStringOps();
101 void testGrow();
102 void testReserve();
103 void testStartsWith();
104 void testSBufStream();
105 void testFindFirstOf();
106 void testFindFirstNotOf();
107 void testAutoFind();
108 void testStdStringOps();
109 void testIterators();
110 void testSBufHash();
1cca3b78 111 void testStdAlgorithm();
ae022809 112};
41e9c9f0 113CPPUNIT_TEST_SUITE_REGISTRATION( TestSBuf );
412da427
FC
114
115/* let this test link sanely */
412da427 116void
8b082ed9 117eventAdd(const char *, EVH *, void *, double, int, bool)
412da427
FC
118{}
119int64_t
120MemObject::endOffset() const
121{ return 0; }
122/* end of stubs */
123
124// test string
963caaa7
AR
125static const char fox[] = "The quick brown fox jumped over the lazy dog";
126static const char fox1[] = "The quick brown fox ";
127static const char fox2[] = "jumped over the lazy dog";
412da427
FC
128
129// TEST: globals variables (default/empty and with contents) are
130// created outside and before any unit tests and memory subsystem
131// initialization. Check for correct constructor operation.
132SBuf empty_sbuf;
133SBuf literal("The quick brown fox jumped over the lazy dog");
134
135void
41e9c9f0 136TestSBuf::testSBufConstructDestruct()
412da427
FC
137{
138 /* NOTE: Do not initialize memory here because we need
139 * to test correct operation before and after Mem::Init
140 */
141
142 // XXX: partial demo below of how to do constructor unit-test. use scope to ensure each test
143 // is working on local-scope variables constructed fresh for the test, and destructed when
144 // scope exists. use nested scopes to test destructor affects on copied data (MemBlob etc)
145
146 // TEST: default constructor (implicit destructor non-crash test)
147 // test accessors on empty SBuf.
148 {
149 SBuf s1;
50827187 150 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
7cbd3256
FC
151 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
152 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
153 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
412da427
FC
154 }
155
156 // TEST: copy-construct NULL string (implicit destructor non-crash test)
157 {
aee3523a 158 SBuf s1(nullptr);
50827187 159 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
7cbd3256
FC
160 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
161 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
162 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
412da427
FC
163 }
164
165 // TEST: copy-construct empty string (implicit destructor non-crash test)
166 {
167 SBuf s1("");
50827187 168 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
7cbd3256
FC
169 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
170 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
171 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
a1fb178b
AJ
172 }
173
412da427
FC
174 // TEST: copy-construct from a SBuf
175 {
176 SBuf s1(empty_sbuf);
50827187 177 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
7cbd3256
FC
178 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
179 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
180 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
412da427
FC
181
182 SBuf s5(literal);
7cbd3256 183 CPPUNIT_ASSERT_EQUAL(literal,s5);
412da427 184 SBuf s6(fox);
7cbd3256 185 CPPUNIT_ASSERT_EQUAL(literal,s6);
412da427
FC
186 // XXX: other state checks. expected result of calling any state accessor on s4 ?
187 }
188
189 // TEST: check that COW doesn't happen upon copy-construction
190 {
191 SBuf s1(empty_sbuf), s2(s1);
192 CPPUNIT_ASSERT_EQUAL(s1.rawContent(), s2.rawContent());
193 SBuf s3(literal), s4(literal);
194 CPPUNIT_ASSERT_EQUAL(s3.rawContent(), s4.rawContent());
195 }
196
197 // TEST: sub-string copy
198 {
7cbd3256 199 SBuf s1=SBuf(fox+4), s2(fox);
412da427
FC
200 SBuf s3=s2.substr(4,s2.length()); //n is out-of-bounds
201 CPPUNIT_ASSERT_EQUAL(s1,s3);
7cbd3256 202 SBuf s4=SBuf(fox,4);
412da427
FC
203 s3=s2.substr(0,4);
204 CPPUNIT_ASSERT_EQUAL(s4,s3);
205 }
206
496a9e97
FC
207 // TEST: go via std::string adapter.
208 {
209 std::string str(fox);
210 SBuf s1(str);
7cbd3256 211 CPPUNIT_ASSERT_EQUAL(literal,s1);
496a9e97 212 }
412da427
FC
213}
214
215void
41e9c9f0 216TestSBuf::testSBufConstructDestructAfterMemInit()
412da427
FC
217{
218 Mem::Init();
219 testSBufConstructDestruct();
412da427
FC
220}
221
222void
41e9c9f0 223TestSBuf::testEqualityTest()
412da427
FC
224{
225 SBuf s1(fox),s2(fox);
226 CPPUNIT_ASSERT_EQUAL(s1,s1); //self-equality
227 CPPUNIT_ASSERT_EQUAL(s1,s2); //same contents
228 s2.assign("The quick brown fox jumped over the lazy doe");
229 CPPUNIT_ASSERT(!(s1 == s2)); //same length, different contents
230 s2.assign("foo");
231 CPPUNIT_ASSERT(!(s1 == s2)); //different length and contents
232 CPPUNIT_ASSERT(s1 != s2); //while we're ready, let's test inequality
233 s2.clear();
234 CPPUNIT_ASSERT(!(s1 == s2)); //null and not-null
235 CPPUNIT_ASSERT(s1 != s2); //while we're ready, let's test inequality
236 s1.clear();
237 CPPUNIT_ASSERT_EQUAL(s1,s2); //null and null
238}
239
240void
41e9c9f0 241TestSBuf::testAppendSBuf()
412da427 242{
5534a101
AR
243 const SBuf appendix(fox1);
244 const char * const rawAppendix = appendix.rawContent();
37ef8293 245
5534a101
AR
246 // check whether the optimization that prevents copying when append()ing to
247 // default-constructed SBuf actually works
248 SBuf s0;
249 s0.append(appendix);
250 CPPUNIT_ASSERT_EQUAL(s0.rawContent(), appendix.rawContent());
251 CPPUNIT_ASSERT_EQUAL(s0, appendix);
37ef8293 252
5534a101
AR
253 // paranoid: check that the above code can actually detect copies
254 SBuf s1(fox1);
255 s1.append(appendix);
256 CPPUNIT_ASSERT(s1.rawContent() != appendix.rawContent());
257 CPPUNIT_ASSERT(s1 != appendix);
258 CPPUNIT_ASSERT_EQUAL(rawAppendix, appendix.rawContent());
412da427
FC
259}
260
261void
41e9c9f0 262TestSBuf::testPrintf()
412da427
FC
263{
264 SBuf s1,s2;
265 s1.Printf("%s:%d:%03.3f","fox",10,12345.67);
266 s2.assign("fox:10:12345.670");
267 CPPUNIT_ASSERT_EQUAL(s1,s2);
268}
269
270void
41e9c9f0 271TestSBuf::testAppendCString()
412da427
FC
272{
273 SBuf s1(fox1);
274 s1.append(fox2);
275 CPPUNIT_ASSERT_EQUAL(s1,literal);
276}
277
278void
41e9c9f0 279TestSBuf::testAppendStdString()
412da427 280{
7cbd3256
FC
281 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
282 {
283 SBuf alpha(alphabet), s;
284 s.append(alphabet,5).append(alphabet+5);
285 CPPUNIT_ASSERT_EQUAL(alpha,s);
286 }
287 {
288 SBuf s;
289 std::string control;
290 s.append(alphabet,5).append("\0",1).append(alphabet+6,SBuf::npos);
291 control.append(alphabet,5).append(1,'\0').append(alphabet,6,std::string::npos);
292 SBuf scontrol(control); // we need this to test the equality. sigh.
293 CPPUNIT_ASSERT_EQUAL(scontrol,s);
294 }
295 {
296 const char *alphazero="abcdefghijk\0mnopqrstuvwxyz";
297 SBuf s(alphazero,26);
298 std::string str(alphazero,26);
299 CPPUNIT_ASSERT_EQUAL(0,memcmp(str.data(),s.rawContent(),26));
300 }
412da427
FC
301}
302
303void
41e9c9f0 304TestSBuf::testAppendf()
412da427
FC
305{
306 SBuf s1,s2;
307 s1.appendf("%s:%d:%03.2f",fox,1234,1234.56);
308 s2.assign("The quick brown fox jumped over the lazy dog:1234:1234.56");
8aa34dad 309 CPPUNIT_ASSERT_EQUAL(s2,s1);
412da427
FC
310}
311
312void
41e9c9f0 313TestSBuf::testDumpStats()
412da427
FC
314{
315 SBuf::GetStats().dump(std::cout);
316 MemBlob::GetStats().dump(std::cout);
317 std::cout << "sizeof(SBuf): " << sizeof(SBuf) << std::endl;
318 std::cout << "sizeof(MemBlob): " << sizeof(MemBlob) << std::endl;
319}
320
321void
41e9c9f0 322TestSBuf::testSubscriptOp()
412da427
FC
323{
324 SBuf chg(literal);
325 CPPUNIT_ASSERT_EQUAL(chg[5],'u');
326 chg.setAt(5,'e');
327 CPPUNIT_ASSERT_EQUAL(literal[5],'u');
328 CPPUNIT_ASSERT_EQUAL(chg[5],'e');
412da427
FC
329}
330
331// note: can't use cppunit's CPPUNIT_TEST_EXCEPTION because TextException asserts, and
332// so the test can't be properly completed.
333void
41e9c9f0 334TestSBuf::testSubscriptOpFail()
412da427
FC
335{
336 char c;
496a9e97 337 c=literal.at(literal.length()); //out of bounds by 1
412da427
FC
338 //notreached
339 std::cout << c << std::endl;
340}
341
342static int sign(int v)
343{
344 if (v < 0)
345 return -1;
346 if (v>0)
347 return 1;
348 return 0;
349}
350
1284f77c
AJ
351static void
352testComparisonStdFull(const char *left, const char *right)
353{
354 if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(SBuf(right))))
355 std::cerr << std::endl << " cmp(SBuf) npos " << left << " ?= " << right << std::endl;
356 CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(SBuf(right))));
357
358 if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(right)))
359 std::cerr << std::endl << " cmp(char*) npos " << left << " ?= " << right << std::endl;
360 CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(right)));
361
362 if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(SBuf(right))))
363 std::cerr << std::endl << " caseCmp(SBuf) npos " << left << " ?= " << right << std::endl;
364 CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(SBuf(right))));
365
366 if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(right)))
367 std::cerr << std::endl << " caseCmp(char*) npos " << left << " ?= " << right << std::endl;
368 CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(right)));
369}
370
371static void
372testComparisonStdN(const char *left, const char *right, const size_t n)
373{
374 if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(SBuf(right), n)))
375 std::cerr << std::endl << " cmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
376 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(SBuf(right), n)));
377
378 if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(right, n)))
379 std::cerr << std::endl << " cmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
380 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(right, n)));
381
382 if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(SBuf(right), n)))
383 std::cerr << std::endl << " caseCmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
384 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(SBuf(right), n)));
385
386 if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(right, n)))
387 std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
388 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(right, n)));
389}
390
391static void
392testComparisonStdOneWay(const char *left, const char *right)
393{
394 testComparisonStdFull(left, right);
395 const size_t maxN = 2 + min(strlen(left), strlen(right));
396 for (size_t n = 0; n <= maxN; ++n) {
397 testComparisonStdN(left, right, n);
398 }
399}
400
401static void
402testComparisonStd(const char *s1, const char *s2)
403{
404 testComparisonStdOneWay(s1, s2);
405 testComparisonStdOneWay(s2, s1);
406}
407
412da427 408void
41e9c9f0 409TestSBuf::testComparisons()
412da427
FC
410{
411 //same length
412 SBuf s1("foo"),s2("foe");
7cbd3256
FC
413 CPPUNIT_ASSERT(s1.cmp(s2)>0);
414 CPPUNIT_ASSERT(s1.caseCmp(s2)>0);
415 CPPUNIT_ASSERT(s2.cmp(s1)<0);
416 CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
417 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
412da427
FC
418 CPPUNIT_ASSERT(s1 > s2);
419 CPPUNIT_ASSERT(s2 < s1);
7cbd3256 420 CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
412da427
FC
421 //different lengths
422 s1.assign("foo");
423 s2.assign("foof");
7cbd3256
FC
424 CPPUNIT_ASSERT(s1.cmp(s2)<0);
425 CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
412da427 426 CPPUNIT_ASSERT(s1 < s2);
7cbd3256
FC
427 // specifying the max-length and overhanging size
428 CPPUNIT_ASSERT_EQUAL(1,SBuf("foolong").caseCmp(SBuf("foo"), 5));
429 // case-insensive comaprison
430 s1 = "foo";
431 s2 = "fOo";
432 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
433 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
434 // \0-clenliness test
435 s1.assign("f\0oo",4);
436 s2.assign("f\0Oo",4);
df7283c0 437 CPPUNIT_ASSERT(s1.cmp(s2) > 0);
7cbd3256
FC
438 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
439 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,3));
440 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
441 CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
1284f77c
AJ
442
443 testComparisonStd("foo", "fooz");
444 testComparisonStd("foo", "foo");
445 testComparisonStd("foo", "f");
446 testComparisonStd("foo", "bar");
447
448 testComparisonStd("foo", "FOOZ");
449 testComparisonStd("foo", "FOO");
450 testComparisonStd("foo", "F");
451
452 testComparisonStdOneWay("", "");
453
454 // rare case C-string input matching SBuf with N>strlen(s)
455 {
456 char *right = xstrdup("foo34567890123456789012345678");
457 SBuf left("fooZYXWVUTSRQPONMLKJIHGFEDCBA");
458 // is 3 bytes in length. NEVER more.
459 right[3] = '\0';
460 left.setAt(3, '\0');
461
462 // pick another spot to truncate at if something goes horribly wrong.
463 right[14] = '\0';
464 left.setAt(14, '\0');
465
466 const SBuf::size_type maxN = 20 + min(left.length(), static_cast<SBuf::size_type>(strlen(right)));
467 for (SBuf::size_type n = 0; n <= maxN; ++n) {
468 if (sign(strncmp(left.rawContent(), right, n)) != sign(left.cmp(right, n)) )
469 std::cerr << std::endl << " cmp(char*) " << n << ' ' << left << " ?= " << right;
470 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left.rawContent(), right, n)), sign(left.cmp(right, n)));
471 if (sign(strncasecmp(left.rawContent(), right, n)) != sign(left.caseCmp(right, n)))
472 std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << left << " ?= " << right;
473 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left.rawContent(), right, n)), sign(left.caseCmp(right, n)));
474 }
475 xfree(right);
476 }
412da427
FC
477}
478
479void
41e9c9f0 480TestSBuf::testConsume()
412da427
FC
481{
482 SBuf s1(literal),s2,s3;
483 s2=s1.consume(4);
484 s3.assign("The ");
485 CPPUNIT_ASSERT_EQUAL(s2,s3);
486 s3.assign("quick brown fox jumped over the lazy dog");
487 CPPUNIT_ASSERT_EQUAL(s1,s3);
488 s1.consume(40);
489 CPPUNIT_ASSERT_EQUAL(s1,SBuf());
490}
491
492void
41e9c9f0 493TestSBuf::testRawContent()
412da427
FC
494{
495 SBuf s1(literal);
496 SBuf s2(s1);
497 s2.append("foo");
498 const char *foo;
499 foo = s1.rawContent();
7cbd3256 500 CPPUNIT_ASSERT_EQUAL(0,strncmp(fox,foo,s1.length()));
412da427
FC
501 foo = s1.c_str();
502 CPPUNIT_ASSERT(!strcmp(fox,foo));
503}
504
505void
41e9c9f0 506TestSBuf::testRawSpace()
412da427
FC
507{
508 SBuf s1(literal);
509 SBuf s2(fox1);
672337d1 510 char *rb=s2.rawAppendStart(strlen(fox2)+1);
496a9e97 511 strcpy(rb,fox2);
672337d1 512 s2.rawAppendFinish(rb, strlen(fox2));
412da427
FC
513 CPPUNIT_ASSERT_EQUAL(s1,s2);
514}
515
516void
41e9c9f0 517TestSBuf::testChop()
412da427
FC
518{
519 SBuf s1(literal),s2;
520 s1.chop(4,5);
521 s2.assign("quick");
522 CPPUNIT_ASSERT_EQUAL(s1,s2);
523 s1=literal;
524 s2.clear();
525 s1.chop(5,0);
526 CPPUNIT_ASSERT_EQUAL(s1,s2);
496a9e97
FC
527 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
528 SBuf a(alphabet);
529 std::string s(alphabet); // TODO
f53969cc 530 { //regular chopping
496a9e97
FC
531 SBuf b(a);
532 b.chop(3,3);
533 SBuf ref("def");
534 CPPUNIT_ASSERT_EQUAL(ref,b);
535 }
f53969cc 536 { // chop at end
496a9e97
FC
537 SBuf b(a);
538 b.chop(b.length()-3);
539 SBuf ref("xyz");
540 CPPUNIT_ASSERT_EQUAL(ref,b);
541 }
f53969cc 542 { // chop at beginning
496a9e97
FC
543 SBuf b(a);
544 b.chop(0,3);
545 SBuf ref("abc");
546 CPPUNIT_ASSERT_EQUAL(ref,b);
547 }
f53969cc 548 { // chop to zero length
496a9e97
FC
549 SBuf b(a);
550 b.chop(5,0);
551 SBuf ref("");
552 CPPUNIT_ASSERT_EQUAL(ref,b);
553 }
f53969cc 554 { // chop beyond end (at npos)
496a9e97
FC
555 SBuf b(a);
556 b.chop(SBuf::npos,4);
557 SBuf ref("");
558 CPPUNIT_ASSERT_EQUAL(ref,b);
559 }
f53969cc 560 { // chop beyond end
496a9e97
FC
561 SBuf b(a);
562 b.chop(b.length()+2,4);
563 SBuf ref("");
564 CPPUNIT_ASSERT_EQUAL(ref,b);
565 }
f53969cc 566 { // null-chop
496a9e97
FC
567 SBuf b(a);
568 b.chop(0,b.length());
569 SBuf ref(a);
570 CPPUNIT_ASSERT_EQUAL(ref,b);
571 }
f53969cc 572 { // overflow chopped area
496a9e97
FC
573 SBuf b(a);
574 b.chop(b.length()-3,b.length());
575 SBuf ref("xyz");
576 CPPUNIT_ASSERT_EQUAL(ref,b);
577 }
412da427
FC
578}
579
580void
41e9c9f0 581TestSBuf::testChomp()
412da427
FC
582{
583 SBuf s1("complete string");
584 SBuf s2(s1);
585 s2.trim(SBuf(" ,"));
586 CPPUNIT_ASSERT_EQUAL(s1,s2);
587 s2.assign(" complete string ,");
588 s2.trim(SBuf(" ,"));
589 CPPUNIT_ASSERT_EQUAL(s1,s2);
590 s1.assign(", complete string ,");
591 s2=s1;
592 s2.trim(SBuf(" "));
593 CPPUNIT_ASSERT_EQUAL(s1,s2);
594}
595
a452bc8b 596// inspired by SBufFindTest; to be expanded.
496a9e97
FC
597class SBufSubstrAutoTest
598{
599 SBuf fullString, sb;
600 std::string fullReference, str;
62842d40
FC
601public:
602 void performEqualityTest() {
496a9e97
FC
603 SBuf ref(str);
604 CPPUNIT_ASSERT_EQUAL(ref,sb);
605 }
62842d40 606 SBufSubstrAutoTest() : fullString(fox), fullReference(fox) {
496a9e97
FC
607 for (int offset=fullString.length()-1; offset >= 0; --offset ) {
608 for (int length=fullString.length()-1-offset; length >= 0; --length) {
609 sb=fullString.substr(offset,length);
610 str=fullReference.substr(offset,length);
611 performEqualityTest();
612 }
613 }
614 }
615};
616
412da427 617void
41e9c9f0 618TestSBuf::testSubstr()
412da427
FC
619{
620 SBuf s1(literal),s2,s3;
621 s2=s1.substr(4,5);
622 s3.assign("quick");
623 CPPUNIT_ASSERT_EQUAL(s2,s3);
624 s1.chop(4,5);
625 CPPUNIT_ASSERT_EQUAL(s1,s2);
496a9e97 626 SBufSubstrAutoTest sat; // work done in the constructor
412da427
FC
627}
628
629void
41e9c9f0 630TestSBuf::testFindChar()
412da427
FC
631{
632 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
633 SBuf s1(alphabet);
634 SBuf::size_type idx;
635 SBuf::size_type nposResult=SBuf::npos;
636
637 // FORWARD SEARCH
638 // needle in haystack
639 idx=s1.find('d');
50827187 640 CPPUNIT_ASSERT_EQUAL(3U,idx);
7cbd3256 641 CPPUNIT_ASSERT_EQUAL('d',s1[idx]);
412da427
FC
642
643 // needle not present in haystack
644 idx=s1.find(' '); //fails
645 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
646
647 // search in portion
50827187
FC
648 idx=s1.find('e',3U);
649 CPPUNIT_ASSERT_EQUAL(4U,idx);
412da427
FC
650
651 // char not in searched portion
50827187 652 idx=s1.find('e',5U);
412da427
FC
653 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
654
655 // invalid start position
656 idx=s1.find('d',SBuf::npos);
657 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
658
412da427
FC
659 // search outside of haystack
660 idx=s1.find('d',s1.length()+1);
661 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
662
663 // REVERSE SEARCH
664 // needle in haystack
665 idx=s1.rfind('d');
50827187 666 CPPUNIT_ASSERT_EQUAL(3U, idx);
412da427
FC
667 CPPUNIT_ASSERT_EQUAL('d', s1[idx]);
668
669 // needle not present in haystack
670 idx=s1.rfind(' '); //fails
671 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
672
673 // search in portion
674 idx=s1.rfind('e',5);
50827187 675 CPPUNIT_ASSERT_EQUAL(4U,idx);
412da427
FC
676
677 // char not in searched portion
678 idx=s1.rfind('e',3);
679 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
680
412da427
FC
681 // overlong haystack specification
682 idx=s1.rfind('d',s1.length()+1);
50827187 683 CPPUNIT_ASSERT_EQUAL(3U,idx);
412da427
FC
684}
685
686void
41e9c9f0 687TestSBuf::testFindSBuf()
412da427
FC
688{
689 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
690 SBuf haystack(alphabet);
691 SBuf::size_type idx;
692 SBuf::size_type nposResult=SBuf::npos;
693
694 // FORWARD search
695 // needle in haystack
696 idx = haystack.find(SBuf("def"));
50827187 697 CPPUNIT_ASSERT_EQUAL(3U,idx);
412da427
FC
698
699 idx = haystack.find(SBuf("xyz"));
50827187 700 CPPUNIT_ASSERT_EQUAL(23U,idx);
412da427
FC
701
702 // needle not in haystack, no initial char match
703 idx = haystack.find(SBuf(" eq"));
704 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
705
706 // needle not in haystack, initial sequence match
707 idx = haystack.find(SBuf("deg"));
708 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
709
710 // needle past end of haystack
711 idx = haystack.find(SBuf("xyz1"));
712 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
713
714 // search in portion: needle not in searched part
715 idx = haystack.find(SBuf("def"),7);
716 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
717
718 // search in portion: overhang
719 idx = haystack.find(SBuf("def"),4);
720 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
721
722 // invalid start position
723 idx = haystack.find(SBuf("def"),SBuf::npos);
724 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
725
412da427
FC
726 // needle bigger than haystack
727 idx = SBuf("def").find(haystack);
728 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
729
730 // search in a double-matching haystack
731 {
732 SBuf h2=haystack;
733 h2.append(haystack);
734
735 idx = h2.find(SBuf("def"));
50827187 736 CPPUNIT_ASSERT_EQUAL(3U,idx);
412da427
FC
737
738 idx = h2.find(SBuf("xyzab"));
50827187 739 CPPUNIT_ASSERT_EQUAL(23U,idx);
412da427
FC
740 }
741
412da427
FC
742 // REVERSE search
743 // needle in haystack
744 idx = haystack.rfind(SBuf("def"));
50827187 745 CPPUNIT_ASSERT_EQUAL(3U,idx);
412da427
FC
746
747 idx = haystack.rfind(SBuf("xyz"));
50827187 748 CPPUNIT_ASSERT_EQUAL(23U,idx);
412da427
FC
749
750 // needle not in haystack, no initial char match
751 idx = haystack.rfind(SBuf(" eq"));
752 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
753
754 // needle not in haystack, initial sequence match
755 idx = haystack.rfind(SBuf("deg"));
756 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
757
758 // needle past end of haystack
759 idx = haystack.rfind(SBuf("xyz1"));
760 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
761
762 // search in portion: needle in searched part
763 idx = haystack.rfind(SBuf("def"),7);
50827187 764 CPPUNIT_ASSERT_EQUAL(3U, idx);
412da427
FC
765
766 // search in portion: needle not in searched part
767 idx = haystack.rfind(SBuf("mno"),3);
768 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
769
770 // search in portion: overhang
771 idx = haystack.rfind(SBuf("def"),4);
50827187 772 CPPUNIT_ASSERT_EQUAL(3U, idx);
412da427
FC
773
774 // npos start position
775 idx = haystack.rfind(SBuf("def"),SBuf::npos);
50827187 776 CPPUNIT_ASSERT_EQUAL(3U, idx);
412da427
FC
777
778 // needle bigger than haystack
779 idx = SBuf("def").rfind(haystack);
780 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
781
782 // search in a double-matching haystack
783 {
784 SBuf h2=haystack;
785 h2.append(haystack);
786
787 idx = h2.rfind(SBuf("def"));
50827187 788 CPPUNIT_ASSERT_EQUAL(29U,idx);
412da427
FC
789
790 idx = h2.find(SBuf("xyzab"));
50827187 791 CPPUNIT_ASSERT_EQUAL(23U,idx);
412da427
FC
792 }
793}
794
795void
41e9c9f0 796TestSBuf::testRFindChar()
412da427
FC
797{
798 SBuf s1(literal);
799 SBuf::size_type idx;
800 idx=s1.rfind(' ');
50827187 801 CPPUNIT_ASSERT_EQUAL(40U,idx);
412da427
FC
802 CPPUNIT_ASSERT_EQUAL(' ',s1[idx]);
803}
804
805void
41e9c9f0 806TestSBuf::testRFindSBuf()
412da427
FC
807{
808 SBuf haystack(literal),afox("fox");
809 SBuf goobar("goobar");
810 SBuf::size_type idx;
811
812 // corner case: search for a zero-length SBuf
813 idx=haystack.rfind(SBuf(""));
814 CPPUNIT_ASSERT_EQUAL(haystack.length(),idx);
815
816 // corner case: search for a needle longer than the haystack
817 idx=afox.rfind(SBuf(" "));
7cbd3256 818 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
412da427
FC
819
820 idx=haystack.rfind(SBuf("fox"));
50827187 821 CPPUNIT_ASSERT_EQUAL(16U,idx);
412da427
FC
822
823 // needle not found, no match for first char
824 idx=goobar.rfind(SBuf("foo"));
7cbd3256 825 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
412da427
FC
826
827 // needle not found, match for first char but no match for SBuf
828 idx=haystack.rfind(SBuf("foe"));
7cbd3256 829 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
412da427
FC
830
831 SBuf g("g"); //match at the last char
832 idx=haystack.rfind(g);
50827187 833 CPPUNIT_ASSERT_EQUAL(43U,idx);
412da427
FC
834 CPPUNIT_ASSERT_EQUAL('g',haystack[idx]);
835
836 idx=haystack.rfind(SBuf("The"));
50827187 837 CPPUNIT_ASSERT_EQUAL(0U,idx);
412da427
FC
838
839 haystack.append("The");
840 idx=haystack.rfind(SBuf("The"));
50827187 841 CPPUNIT_ASSERT_EQUAL(44U,idx);
412da427
FC
842
843 //partial match
844 haystack="The quick brown fox";
845 SBuf needle("foxy lady");
846 idx=haystack.rfind(needle);
7cbd3256 847 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
412da427
FC
848}
849
850void
41e9c9f0 851TestSBuf::testSBufLength()
412da427
FC
852{
853 SBuf s(fox);
7cbd3256 854 CPPUNIT_ASSERT_EQUAL(strlen(fox),(size_t)s.length());
412da427
FC
855}
856
ff1eb053 857void
41e9c9f0 858TestSBuf::testCopy()
412da427
FC
859{
860 char buf[40]; //shorter than literal()
861 SBuf s(fox1),s2;
7cbd3256
FC
862 CPPUNIT_ASSERT_EQUAL(s.length(),s.copy(buf,40));
863 CPPUNIT_ASSERT_EQUAL(0,strncmp(s.rawContent(),buf,s.length()));
412da427 864 s=literal;
50827187 865 CPPUNIT_ASSERT_EQUAL(40U,s.copy(buf,40));
7cbd3256 866 s2.assign(buf,40);
412da427 867 s.chop(0,40);
7cbd3256 868 CPPUNIT_ASSERT_EQUAL(s2,s);
412da427
FC
869}
870
ff1eb053 871void
41e9c9f0 872TestSBuf::testStringOps()
412da427 873{
37cf7314 874 SBuf sng(ToLower(literal)),
f53969cc 875 ref("the quick brown fox jumped over the lazy dog");
412da427
FC
876 CPPUNIT_ASSERT_EQUAL(ref,sng);
877 sng=literal;
7cbd3256
FC
878 CPPUNIT_ASSERT_EQUAL(0,sng.compare(ref,caseInsensitive));
879 // max-size comparison
880 CPPUNIT_ASSERT_EQUAL(0,ref.compare(SBuf("THE"),caseInsensitive,3));
881 CPPUNIT_ASSERT_EQUAL(1,ref.compare(SBuf("THE"),caseInsensitive,6));
882 CPPUNIT_ASSERT_EQUAL(0,SBuf("the").compare(SBuf("THE"),caseInsensitive,6));
412da427
FC
883}
884
ff1eb053 885void
41e9c9f0 886TestSBuf::testGrow()
412da427
FC
887{
888 SBuf t;
889 t.assign("foo");
890 const char *ref=t.rawContent();
891 t.reserveCapacity(10240);
892 const char *match=t.rawContent();
893 CPPUNIT_ASSERT(match!=ref);
894 ref=match;
895 t.append(literal).append(literal).append(literal).append(literal).append(literal);
896 t.append(t).append(t).append(t).append(t).append(t);
7cbd3256 897 CPPUNIT_ASSERT_EQUAL(ref,match);
412da427
FC
898}
899
41dd1b86 900void
41e9c9f0 901TestSBuf::testReserve()
41dd1b86
AJ
902{
903 SBufReservationRequirements requirements;
61beade2 904 // use unusual numbers to ensure we do not hit a lucky boundary situation
41dd1b86
AJ
905 requirements.minSpace = 10;
906 requirements.idealSpace = 82;
907 requirements.maxCapacity = 259;
908 requirements.allowShared = true;
909
910 // for each possible starting buffer length within the capacity
911 for (SBuf::size_type startLength = 0; startLength <= requirements.maxCapacity; ++startLength) {
912 std::cerr << ".";
913 SBuf b;
914 b.reserveCapacity(startLength);
915 CPPUNIT_ASSERT_EQUAL(b.length(), static_cast<unsigned int>(0));
916 CPPUNIT_ASSERT_EQUAL(b.spaceSize(), startLength);
917
918 // check that it never grows outside capacity.
919 // do 5 excess cycles to check that.
920 for (SBuf::size_type filled = 0; filled < requirements.maxCapacity +5; ++filled) {
921 CPPUNIT_ASSERT_EQUAL(b.length(), min(filled, requirements.maxCapacity));
41dd1b86
AJ
922 auto x = b.reserve(requirements);
923 // the amount of space advertized must not cause users to exceed capacity
924 CPPUNIT_ASSERT(x <= requirements.maxCapacity - filled);
925 CPPUNIT_ASSERT(b.spaceSize() <= requirements.maxCapacity - filled);
926 // the total size of buffer must not cause users to exceed capacity
927 CPPUNIT_ASSERT(b.length() + b.spaceSize() <= requirements.maxCapacity);
928 if (x > 0)
929 b.append('X');
930 }
931 }
ecf0d881
AR
932
933 // the minimal space requirement should overwrite idealSpace preferences
934 requirements.minSpace = 10;
935 for (const int delta: {-1,0,+1}) {
936 requirements.idealSpace = requirements.minSpace + delta;
937 SBuf buffer;
938 buffer.reserve(requirements);
939 CPPUNIT_ASSERT(buffer.spaceSize() >= requirements.minSpace);
940 }
963caaa7
AR
941
942 // TODO: Decide whether to encapsulate the (nearly identical) code of the
943 // gap-related test cases below into a function, obscuring each case logic a
944 // little, but facilitating new test cases (and removing code duplication).
945
946 { // reserveSpace() uses the trailing space before the front gap
947 SBuf buffer(fox);
948
949 // assure there is some trailing space
950 buffer.reserveSpace(1);
951 CPPUNIT_ASSERT(buffer.spaceSize() > 0);
952
953 // create a leading gap and (weak-)check that it was created
954 const auto gap = 1U; // the smallest gap may be the most challenging
955 CPPUNIT_ASSERT(gap < buffer.length());
956 const void *gapEnd = buffer.rawContent() + gap;
957 buffer.consume(gap);
958 CPPUNIT_ASSERT_EQUAL(gapEnd, static_cast<const void*>(buffer.rawContent()));
959
960 const auto before = SBuf::GetStats();
961 const auto beforeSpaceSize = buffer.spaceSize();
962 const void * const beforePosition = buffer.rawContent();
963 buffer.reserveSpace(beforeSpaceSize);
964 const auto after = SBuf::GetStats();
965 const void * const afterPosition = buffer.rawContent();
966 CPPUNIT_ASSERT_EQUAL(before.cowAvoided + 1, after.cowAvoided);
967 CPPUNIT_ASSERT_EQUAL(before.cowShift, after.cowShift);
968 CPPUNIT_ASSERT_EQUAL(before.cowJustAlloc, after.cowJustAlloc);
969 CPPUNIT_ASSERT_EQUAL(before.cowAllocCopy, after.cowAllocCopy);
970 CPPUNIT_ASSERT_EQUAL(beforeSpaceSize, buffer.spaceSize());
971 CPPUNIT_ASSERT_EQUAL(beforePosition, afterPosition);
972 CPPUNIT_ASSERT(strcmp(fox + gap, buffer.c_str()) == 0);
973 }
974
975 { // reserveSpace() uses the front gap when the trailing space is not enough
976 SBuf buffer(fox);
977
978 // assure there is some trailing space to keep the test case challenging
979 buffer.reserveSpace(1);
980 CPPUNIT_ASSERT(buffer.spaceSize() > 0);
981 const void * const initialStorage = buffer.rawContent();
982
983 // create a leading gap and (weak-)check that it was created
984 const auto gap = 1U; // the smallest gap may be the most challenging
985 CPPUNIT_ASSERT(gap < buffer.length());
986 const void *gapEnd = buffer.rawContent() + gap;
987 buffer.consume(gap);
988 CPPUNIT_ASSERT_EQUAL(gapEnd, static_cast<const void*>(buffer.rawContent()));
989
990 const auto before = SBuf::GetStats();
991 const auto beforeSpaceSize = buffer.spaceSize();
992 buffer.reserveSpace(beforeSpaceSize + gap); // force (entire) gap use
993 const auto after = SBuf::GetStats();
994 const void * const afterStorage = buffer.rawContent();
995 CPPUNIT_ASSERT_EQUAL(before.cowAvoided, after.cowAvoided);
996 CPPUNIT_ASSERT_EQUAL(before.cowShift + 1, after.cowShift);
997 CPPUNIT_ASSERT_EQUAL(before.cowJustAlloc, after.cowJustAlloc);
998 CPPUNIT_ASSERT_EQUAL(before.cowAllocCopy, after.cowAllocCopy);
999 CPPUNIT_ASSERT_EQUAL(initialStorage, afterStorage);
1000 CPPUNIT_ASSERT(beforeSpaceSize + gap <= buffer.spaceSize());
1001 CPPUNIT_ASSERT(strcmp(fox + gap, buffer.c_str()) == 0);
1002 }
1003
1004 { // reserveSpace() uses the entire front gap when using the front gap
1005 SBuf buffer(fox);
1006
1007 // assure there is some trailing space to keep the test case challenging
1008 buffer.reserveSpace(1);
1009 CPPUNIT_ASSERT(buffer.spaceSize() > 0);
1010 const void * const initialStorage = buffer.rawContent();
1011
1012 // create a leading gap and (weak-)check that it was created
1013 const auto gap = 2U; // the smallest extra gap may be the most challenging
1014 CPPUNIT_ASSERT(gap < buffer.length());
1015 const void *gapEnd = buffer.rawContent() + gap;
1016 buffer.consume(gap);
1017 CPPUNIT_ASSERT_EQUAL(gapEnd, static_cast<const void*>(buffer.rawContent()));
1018
1019 const auto before = SBuf::GetStats();
1020 const auto beforeSpaceSize = buffer.spaceSize();
1021 buffer.reserveSpace(beforeSpaceSize + 1); // force (minimal) gap use
1022 const auto after = SBuf::GetStats();
1023 const void * const afterStorage = buffer.rawContent();
1024 CPPUNIT_ASSERT_EQUAL(before.cowAvoided, after.cowAvoided);
1025 CPPUNIT_ASSERT_EQUAL(before.cowShift + 1, after.cowShift);
1026 CPPUNIT_ASSERT_EQUAL(before.cowJustAlloc, after.cowJustAlloc);
1027 CPPUNIT_ASSERT_EQUAL(before.cowAllocCopy, after.cowAllocCopy);
1028 CPPUNIT_ASSERT_EQUAL(initialStorage, afterStorage);
1029 CPPUNIT_ASSERT(beforeSpaceSize + gap <= buffer.spaceSize());
1030 CPPUNIT_ASSERT(strcmp(fox + gap, buffer.c_str()) == 0);
1031 }
41dd1b86
AJ
1032}
1033
ff1eb053 1034void
41e9c9f0 1035TestSBuf::testStartsWith()
412da427
FC
1036{
1037 static SBuf casebuf("THE QUICK");
1038 CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1)));
1039 CPPUNIT_ASSERT(!SBuf("The quick brown").startsWith(SBuf(fox1))); //too short
7cbd3256 1040 CPPUNIT_ASSERT(!literal.startsWith(SBuf(fox2))); //different contents
412da427 1041
7cbd3256 1042 // case-insensitive checks
412da427 1043 CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
37cf7314 1044 casebuf=ToUpper(SBuf(fox1));
412da427
FC
1045 CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
1046 CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1),caseInsensitive));
1047 casebuf = "tha quick";
7cbd3256 1048 CPPUNIT_ASSERT_EQUAL(false,literal.startsWith(casebuf,caseInsensitive));
412da427
FC
1049}
1050
ff1eb053 1051void
41e9c9f0 1052TestSBuf::testSBufStream()
412da427
FC
1053{
1054 SBuf b("const.string, int 10 and a float 10.5");
1055 SBufStream ss;
1056 ss << "const.string, int " << 10 << " and a float " << 10.5;
1057 SBuf o=ss.buf();
1058 CPPUNIT_ASSERT_EQUAL(b,o);
1059 ss.clearBuf();
1060 o=ss.buf();
1061 CPPUNIT_ASSERT_EQUAL(SBuf(),o);
1062 SBuf f1(fox1);
1063 SBufStream ss2(f1);
1064 ss2 << fox2;
1065 CPPUNIT_ASSERT_EQUAL(ss2.buf(),literal);
1066 CPPUNIT_ASSERT_EQUAL(f1,SBuf(fox1));
1067}
1068
ff1eb053 1069void
41e9c9f0 1070TestSBuf::testFindFirstOf()
412da427
FC
1071{
1072 SBuf haystack(literal);
1073 SBuf::size_type idx;
1074
1075 // not found
810a5427 1076 idx=haystack.findFirstOf(CharacterSet("t1","ADHRWYP"));
7cbd3256 1077 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
412da427
FC
1078
1079 // found at beginning
810a5427 1080 idx=haystack.findFirstOf(CharacterSet("t2","THANDF"));
50827187 1081 CPPUNIT_ASSERT_EQUAL(0U,idx);
412da427
FC
1082
1083 //found at end of haystack
810a5427 1084 idx=haystack.findFirstOf(CharacterSet("t3","QWERYVg"));
412da427
FC
1085 CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx);
1086
1087 //found in the middle of haystack
810a5427 1088 idx=haystack.findFirstOf(CharacterSet("t4","QWERqYV"));
50827187 1089 CPPUNIT_ASSERT_EQUAL(4U,idx);
412da427
FC
1090}
1091
3c1106a0 1092void
41e9c9f0 1093TestSBuf::testFindFirstNotOf()
3c1106a0
FC
1094{
1095 SBuf haystack(literal);
1096 SBuf::size_type idx;
1097
1098 // all chars from the set
810a5427 1099 idx=haystack.findFirstNotOf(CharacterSet("t1",literal.c_str()));
c8046ec7 1100 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
3c1106a0
FC
1101
1102 // found at beginning
810a5427 1103 idx=haystack.findFirstNotOf(CharacterSet("t2","a"));
3c1106a0
FC
1104 CPPUNIT_ASSERT_EQUAL(0U,idx);
1105
1106 //found at end of haystack
810a5427 1107 idx=haystack.findFirstNotOf(CharacterSet("t3",literal.substr(0,literal.length()-1).c_str()));
3c1106a0
FC
1108 CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx);
1109
1110 //found in the middle of haystack
810a5427 1111 idx=haystack.findFirstNotOf(CharacterSet("t4","The"));
3c1106a0
FC
1112 CPPUNIT_ASSERT_EQUAL(3U,idx);
1113}
1114
ff1eb053 1115void
41e9c9f0 1116TestSBuf::testAutoFind()
412da427
FC
1117{
1118 SBufFindTest test;
1119 test.run();
1120}
7cbd3256 1121
ff1eb053 1122void
41e9c9f0 1123TestSBuf::testStdStringOps()
7cbd3256
FC
1124{
1125 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
1126 std::string astr(alphabet);
1127 SBuf sb(alphabet);
1128 CPPUNIT_ASSERT_EQUAL(astr,sb.toStdString());
1129}
f53969cc 1130
8a3e1749 1131void
41e9c9f0 1132TestSBuf::testIterators()
8a3e1749
FC
1133{
1134 SBuf text("foo"), text2("foo");
1135 CPPUNIT_ASSERT(text.begin() == text.begin());
1136 CPPUNIT_ASSERT(text.begin() != text.end());
1137 CPPUNIT_ASSERT(text.begin() != text2.begin());
1138 {
1139 auto i = text.begin();
02620563 1140 auto e = text.end();
8a3e1749
FC
1141 CPPUNIT_ASSERT_EQUAL('f', *i);
1142 CPPUNIT_ASSERT(i != e);
1143 ++i;
1144 CPPUNIT_ASSERT_EQUAL('o', *i);
1145 CPPUNIT_ASSERT(i != e);
1146 ++i;
1147 CPPUNIT_ASSERT_EQUAL('o', *i);
1148 CPPUNIT_ASSERT(i != e);
1149 ++i;
1150 CPPUNIT_ASSERT(i == e);
1151 }
1152 {
1153 auto i = text.rbegin();
1154 auto e = text.rend();
1155 CPPUNIT_ASSERT_EQUAL('o', *i);
1156 CPPUNIT_ASSERT(i != e);
1157 ++i;
1158 CPPUNIT_ASSERT_EQUAL('o', *i);
1159 CPPUNIT_ASSERT(i != e);
1160 ++i;
1161 CPPUNIT_ASSERT_EQUAL('f', *i);
1162 CPPUNIT_ASSERT(i != e);
1163 ++i;
1164 CPPUNIT_ASSERT(i == e);
1165 }
1166}
0d37e60b 1167
bf7550ff 1168void
41e9c9f0 1169TestSBuf::testSBufHash()
bf7550ff
FC
1170{
1171 // same SBuf must have same hash
1172 auto hasher=std::hash<SBuf>();
1173 CPPUNIT_ASSERT_EQUAL(hasher(literal),hasher(literal));
1174
1175 // same content must have same hash
1176 CPPUNIT_ASSERT_EQUAL(hasher(literal),hasher(SBuf(fox)));
1177 CPPUNIT_ASSERT_EQUAL(hasher(SBuf(fox)),hasher(SBuf(fox)));
1178
2f8abb64 1179 //different content should have different hash
bf7550ff
FC
1180 CPPUNIT_ASSERT(hasher(SBuf(fox)) != hasher(SBuf(fox1)));
1181
1182 {
1183 std::unordered_map<SBuf, int> um;
1184 um[SBuf("one")] = 1;
1185 um[SBuf("two")] = 2;
1186
1187 auto i = um.find(SBuf("one"));
1188 CPPUNIT_ASSERT(i != um.end());
1189 CPPUNIT_ASSERT(i->second == 1);
1190
1191 i = um.find(SBuf("eleventy"));
1192 CPPUNIT_ASSERT(i == um.end());
bf7550ff
FC
1193 }
1194}
132d9943 1195
1cca3b78
FC
1196void
1197TestSBuf::testStdAlgorithm()
1198{
1199 {
1200 SBuf src(fox), dst;
1201 std::copy(src.begin(), src.end(), std::back_inserter(dst));
1202 CPPUNIT_ASSERT_EQUAL(src, dst);
1203 }
1204
1205 {
1206 SBuf src(fox), dst;
1207 std::copy_if(src.begin(), src.end(), std::back_inserter(dst),
1208 [](char c) { return c != 'o'; });
1209 CPPUNIT_ASSERT_EQUAL(SBuf("The quick brwn fx jumped ver the lazy dg"), dst);
1210 }
1211}
1212
53a5a6de
AR
1213int
1214main(int argc, char *argv[])
1215{
1216 return TestProgram().run(argc, argv);
1217}
1218