2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
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.
10 #include "base/CharacterSet.h"
11 #include "HttpRequest.h"
12 #include "sbuf/Algorithms.h"
13 #include "sbuf/SBuf.h"
14 #include "sbuf/Stream.h"
15 #include "tests/SBufFindTest.h"
16 #include "tests/testSBuf.h"
17 #include "unitTestMain.h"
21 #include <unordered_map>
23 CPPUNIT_TEST_SUITE_REGISTRATION( testSBuf
);
25 /* let this test link sanely */
27 #include "MemObject.h"
29 eventAdd(const char *name
, EVH
* func
, void *arg
, double when
, int, bool cbdata
)
32 MemObject::endOffset() const
37 static char fox
[]="The quick brown fox jumped over the lazy dog";
38 static char fox1
[]="The quick brown fox ";
39 static char fox2
[]="jumped over the lazy dog";
41 // TEST: globals variables (default/empty and with contents) are
42 // created outside and before any unit tests and memory subsystem
43 // initialization. Check for correct constructor operation.
45 SBuf
literal("The quick brown fox jumped over the lazy dog");
48 testSBuf::testSBufConstructDestruct()
50 /* NOTE: Do not initialize memory here because we need
51 * to test correct operation before and after Mem::Init
54 // XXX: partial demo below of how to do constructor unit-test. use scope to ensure each test
55 // is working on local-scope variables constructed fresh for the test, and destructed when
56 // scope exists. use nested scopes to test destructor affects on copied data (MemBlob etc)
58 // TEST: default constructor (implicit destructor non-crash test)
59 // test accessors on empty SBuf.
62 CPPUNIT_ASSERT_EQUAL(0U,s1
.length());
63 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1
);
64 CPPUNIT_ASSERT_EQUAL(empty_sbuf
,s1
);
65 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1
.c_str()));
68 // TEST: copy-construct NULL string (implicit destructor non-crash test)
71 CPPUNIT_ASSERT_EQUAL(0U,s1
.length());
72 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1
);
73 CPPUNIT_ASSERT_EQUAL(empty_sbuf
,s1
);
74 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1
.c_str()));
77 // TEST: copy-construct empty string (implicit destructor non-crash test)
80 CPPUNIT_ASSERT_EQUAL(0U,s1
.length());
81 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1
);
82 CPPUNIT_ASSERT_EQUAL(empty_sbuf
,s1
);
83 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1
.c_str()));
86 // TEST: copy-construct from a SBuf
89 CPPUNIT_ASSERT_EQUAL(0U,s1
.length());
90 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1
);
91 CPPUNIT_ASSERT_EQUAL(empty_sbuf
,s1
);
92 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1
.c_str()));
95 CPPUNIT_ASSERT_EQUAL(literal
,s5
);
97 CPPUNIT_ASSERT_EQUAL(literal
,s6
);
98 // XXX: other state checks. expected result of calling any state accessor on s4 ?
101 // TEST: check that COW doesn't happen upon copy-construction
103 SBuf
s1(empty_sbuf
), s2(s1
);
104 CPPUNIT_ASSERT_EQUAL(s1
.rawContent(), s2
.rawContent());
105 SBuf
s3(literal
), s4(literal
);
106 CPPUNIT_ASSERT_EQUAL(s3
.rawContent(), s4
.rawContent());
109 // TEST: sub-string copy
111 SBuf s1
=SBuf(fox
+4), s2(fox
);
112 SBuf s3
=s2
.substr(4,s2
.length()); //n is out-of-bounds
113 CPPUNIT_ASSERT_EQUAL(s1
,s3
);
116 CPPUNIT_ASSERT_EQUAL(s4
,s3
);
119 // TEST: go via std::string adapter.
121 std::string
str(fox
);
123 CPPUNIT_ASSERT_EQUAL(literal
,s1
);
128 testSBuf::testSBufConstructDestructAfterMemInit()
131 testSBufConstructDestruct();
135 testSBuf::testEqualityTest()
137 SBuf
s1(fox
),s2(fox
);
138 CPPUNIT_ASSERT_EQUAL(s1
,s1
); //self-equality
139 CPPUNIT_ASSERT_EQUAL(s1
,s2
); //same contents
140 s2
.assign("The quick brown fox jumped over the lazy doe");
141 CPPUNIT_ASSERT(!(s1
== s2
)); //same length, different contents
143 CPPUNIT_ASSERT(!(s1
== s2
)); //different length and contents
144 CPPUNIT_ASSERT(s1
!= s2
); //while we're ready, let's test inequality
146 CPPUNIT_ASSERT(!(s1
== s2
)); //null and not-null
147 CPPUNIT_ASSERT(s1
!= s2
); //while we're ready, let's test inequality
149 CPPUNIT_ASSERT_EQUAL(s1
,s2
); //null and null
153 testSBuf::testAppendSBuf()
155 const SBuf
appendix(fox1
);
156 const char * const rawAppendix
= appendix
.rawContent();
158 // check whether the optimization that prevents copying when append()ing to
159 // default-constructed SBuf actually works
162 CPPUNIT_ASSERT_EQUAL(s0
.rawContent(), appendix
.rawContent());
163 CPPUNIT_ASSERT_EQUAL(s0
, appendix
);
165 // paranoid: check that the above code can actually detect copies
168 CPPUNIT_ASSERT(s1
.rawContent() != appendix
.rawContent());
169 CPPUNIT_ASSERT(s1
!= appendix
);
170 CPPUNIT_ASSERT_EQUAL(rawAppendix
, appendix
.rawContent());
174 testSBuf::testPrintf()
177 s1
.Printf("%s:%d:%03.3f","fox",10,12345.67);
178 s2
.assign("fox:10:12345.670");
179 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
183 testSBuf::testAppendCString()
187 CPPUNIT_ASSERT_EQUAL(s1
,literal
);
191 testSBuf::testAppendStdString()
193 const char *alphabet
="abcdefghijklmnopqrstuvwxyz";
195 SBuf
alpha(alphabet
), s
;
196 s
.append(alphabet
,5).append(alphabet
+5);
197 CPPUNIT_ASSERT_EQUAL(alpha
,s
);
202 s
.append(alphabet
,5).append("\0",1).append(alphabet
+6,SBuf::npos
);
203 control
.append(alphabet
,5).append(1,'\0').append(alphabet
,6,std::string::npos
);
204 SBuf
scontrol(control
); // we need this to test the equality. sigh.
205 CPPUNIT_ASSERT_EQUAL(scontrol
,s
);
208 const char *alphazero
="abcdefghijk\0mnopqrstuvwxyz";
209 SBuf
s(alphazero
,26);
210 std::string
str(alphazero
,26);
211 CPPUNIT_ASSERT_EQUAL(0,memcmp(str
.data(),s
.rawContent(),26));
216 testSBuf::testAppendf()
219 s1
.appendf("%s:%d:%03.2f",fox
,1234,1234.56);
220 s2
.assign("The quick brown fox jumped over the lazy dog:1234:1234.56");
221 CPPUNIT_ASSERT_EQUAL(s2
,s1
);
225 testSBuf::testDumpStats()
227 SBuf::GetStats().dump(std::cout
);
228 MemBlob::GetStats().dump(std::cout
);
229 std::cout
<< "sizeof(SBuf): " << sizeof(SBuf
) << std::endl
;
230 std::cout
<< "sizeof(MemBlob): " << sizeof(MemBlob
) << std::endl
;
234 testSBuf::testSubscriptOp()
237 CPPUNIT_ASSERT_EQUAL(chg
[5],'u');
239 CPPUNIT_ASSERT_EQUAL(literal
[5],'u');
240 CPPUNIT_ASSERT_EQUAL(chg
[5],'e');
243 // note: can't use cppunit's CPPUNIT_TEST_EXCEPTION because TextException asserts, and
244 // so the test can't be properly completed.
246 testSBuf::testSubscriptOpFail()
249 c
=literal
.at(literal
.length()); //out of bounds by 1
251 std::cout
<< c
<< std::endl
;
254 static int sign(int v
)
264 testComparisonStdFull(const char *left
, const char *right
)
266 if (sign(strcmp(left
, right
)) != sign(SBuf(left
).cmp(SBuf(right
))))
267 std::cerr
<< std::endl
<< " cmp(SBuf) npos " << left
<< " ?= " << right
<< std::endl
;
268 CPPUNIT_ASSERT_EQUAL(sign(strcmp(left
, right
)), sign(SBuf(left
).cmp(SBuf(right
))));
270 if (sign(strcmp(left
, right
)) != sign(SBuf(left
).cmp(right
)))
271 std::cerr
<< std::endl
<< " cmp(char*) npos " << left
<< " ?= " << right
<< std::endl
;
272 CPPUNIT_ASSERT_EQUAL(sign(strcmp(left
, right
)), sign(SBuf(left
).cmp(right
)));
274 if (sign(strcasecmp(left
, right
)) != sign(SBuf(left
).caseCmp(SBuf(right
))))
275 std::cerr
<< std::endl
<< " caseCmp(SBuf) npos " << left
<< " ?= " << right
<< std::endl
;
276 CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left
, right
)), sign(SBuf(left
).caseCmp(SBuf(right
))));
278 if (sign(strcasecmp(left
, right
)) != sign(SBuf(left
).caseCmp(right
)))
279 std::cerr
<< std::endl
<< " caseCmp(char*) npos " << left
<< " ?= " << right
<< std::endl
;
280 CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left
, right
)), sign(SBuf(left
).caseCmp(right
)));
284 testComparisonStdN(const char *left
, const char *right
, const size_t n
)
286 if (sign(strncmp(left
, right
, n
)) != sign(SBuf(left
).cmp(SBuf(right
), n
)))
287 std::cerr
<< std::endl
<< " cmp(SBuf) " << n
<< ' ' << left
<< " ?= " << right
<< std::endl
;
288 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left
, right
, n
)), sign(SBuf(left
).cmp(SBuf(right
), n
)));
290 if (sign(strncmp(left
, right
, n
)) != sign(SBuf(left
).cmp(right
, n
)))
291 std::cerr
<< std::endl
<< " cmp(char*) " << n
<< ' ' << SBuf(left
) << " ?= " << right
<< std::endl
;
292 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left
, right
, n
)), sign(SBuf(left
).cmp(right
, n
)));
294 if (sign(strncasecmp(left
, right
, n
)) != sign(SBuf(left
).caseCmp(SBuf(right
), n
)))
295 std::cerr
<< std::endl
<< " caseCmp(SBuf) " << n
<< ' ' << left
<< " ?= " << right
<< std::endl
;
296 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left
, right
, n
)), sign(SBuf(left
).caseCmp(SBuf(right
), n
)));
298 if (sign(strncasecmp(left
, right
, n
)) != sign(SBuf(left
).caseCmp(right
, n
)))
299 std::cerr
<< std::endl
<< " caseCmp(char*) " << n
<< ' ' << SBuf(left
) << " ?= " << right
<< std::endl
;
300 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left
, right
, n
)), sign(SBuf(left
).caseCmp(right
, n
)));
304 testComparisonStdOneWay(const char *left
, const char *right
)
306 testComparisonStdFull(left
, right
);
307 const size_t maxN
= 2 + min(strlen(left
), strlen(right
));
308 for (size_t n
= 0; n
<= maxN
; ++n
) {
309 testComparisonStdN(left
, right
, n
);
314 testComparisonStd(const char *s1
, const char *s2
)
316 testComparisonStdOneWay(s1
, s2
);
317 testComparisonStdOneWay(s2
, s1
);
321 testSBuf::testComparisons()
324 SBuf
s1("foo"),s2("foe");
325 CPPUNIT_ASSERT(s1
.cmp(s2
)>0);
326 CPPUNIT_ASSERT(s1
.caseCmp(s2
)>0);
327 CPPUNIT_ASSERT(s2
.cmp(s1
)<0);
328 CPPUNIT_ASSERT_EQUAL(0,s1
.cmp(s2
,2));
329 CPPUNIT_ASSERT_EQUAL(0,s1
.caseCmp(s2
,2));
330 CPPUNIT_ASSERT(s1
> s2
);
331 CPPUNIT_ASSERT(s2
< s1
);
332 CPPUNIT_ASSERT_EQUAL(sign(s1
.cmp(s2
)),sign(strcmp(s1
.c_str(),s2
.c_str())));
336 CPPUNIT_ASSERT(s1
.cmp(s2
)<0);
337 CPPUNIT_ASSERT_EQUAL(sign(s1
.cmp(s2
)),sign(strcmp(s1
.c_str(),s2
.c_str())));
338 CPPUNIT_ASSERT(s1
< s2
);
339 // specifying the max-length and overhanging size
340 CPPUNIT_ASSERT_EQUAL(1,SBuf("foolong").caseCmp(SBuf("foo"), 5));
341 // case-insensive comaprison
344 CPPUNIT_ASSERT_EQUAL(0,s1
.caseCmp(s2
));
345 CPPUNIT_ASSERT_EQUAL(0,s1
.caseCmp(s2
,2));
346 // \0-clenliness test
347 s1
.assign("f\0oo",4);
348 s2
.assign("f\0Oo",4);
349 CPPUNIT_ASSERT(s1
.cmp(s2
) > 0);
350 CPPUNIT_ASSERT_EQUAL(0,s1
.caseCmp(s2
));
351 CPPUNIT_ASSERT_EQUAL(0,s1
.caseCmp(s2
,3));
352 CPPUNIT_ASSERT_EQUAL(0,s1
.caseCmp(s2
,2));
353 CPPUNIT_ASSERT_EQUAL(0,s1
.cmp(s2
,2));
355 testComparisonStd("foo", "fooz");
356 testComparisonStd("foo", "foo");
357 testComparisonStd("foo", "f");
358 testComparisonStd("foo", "bar");
360 testComparisonStd("foo", "FOOZ");
361 testComparisonStd("foo", "FOO");
362 testComparisonStd("foo", "F");
364 testComparisonStdOneWay("", "");
366 // rare case C-string input matching SBuf with N>strlen(s)
368 char *right
= xstrdup("foo34567890123456789012345678");
369 SBuf
left("fooZYXWVUTSRQPONMLKJIHGFEDCBA");
370 // is 3 bytes in length. NEVER more.
374 // pick another spot to truncate at if something goes horribly wrong.
376 left
.setAt(14, '\0');
378 const SBuf::size_type maxN
= 20 + min(left
.length(), static_cast<SBuf::size_type
>(strlen(right
)));
379 for (SBuf::size_type n
= 0; n
<= maxN
; ++n
) {
380 if (sign(strncmp(left
.rawContent(), right
, n
)) != sign(left
.cmp(right
, n
)) )
381 std::cerr
<< std::endl
<< " cmp(char*) " << n
<< ' ' << left
<< " ?= " << right
;
382 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left
.rawContent(), right
, n
)), sign(left
.cmp(right
, n
)));
383 if (sign(strncasecmp(left
.rawContent(), right
, n
)) != sign(left
.caseCmp(right
, n
)))
384 std::cerr
<< std::endl
<< " caseCmp(char*) " << n
<< ' ' << left
<< " ?= " << right
;
385 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left
.rawContent(), right
, n
)), sign(left
.caseCmp(right
, n
)));
392 testSBuf::testConsume()
394 SBuf
s1(literal
),s2
,s3
;
397 CPPUNIT_ASSERT_EQUAL(s2
,s3
);
398 s3
.assign("quick brown fox jumped over the lazy dog");
399 CPPUNIT_ASSERT_EQUAL(s1
,s3
);
401 CPPUNIT_ASSERT_EQUAL(s1
,SBuf());
405 testSBuf::testRawContent()
411 foo
= s1
.rawContent();
412 CPPUNIT_ASSERT_EQUAL(0,strncmp(fox
,foo
,s1
.length()));
414 CPPUNIT_ASSERT(!strcmp(fox
,foo
));
418 testSBuf::testRawSpace()
422 SBuf::size_type sz
=s2
.length();
423 char *rb
=s2
.rawSpace(strlen(fox2
)+1);
425 s2
.forceSize(sz
+strlen(fox2
));
426 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
435 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
439 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
440 const char *alphabet
="abcdefghijklmnopqrstuvwxyz";
442 std::string
s(alphabet
); // TODO
447 CPPUNIT_ASSERT_EQUAL(ref
,b
);
451 b
.chop(b
.length()-3);
453 CPPUNIT_ASSERT_EQUAL(ref
,b
);
455 { // chop at beginning
459 CPPUNIT_ASSERT_EQUAL(ref
,b
);
461 { // chop to zero length
465 CPPUNIT_ASSERT_EQUAL(ref
,b
);
467 { // chop beyond end (at npos)
469 b
.chop(SBuf::npos
,4);
471 CPPUNIT_ASSERT_EQUAL(ref
,b
);
475 b
.chop(b
.length()+2,4);
477 CPPUNIT_ASSERT_EQUAL(ref
,b
);
481 b
.chop(0,b
.length());
483 CPPUNIT_ASSERT_EQUAL(ref
,b
);
485 { // overflow chopped area
487 b
.chop(b
.length()-3,b
.length());
489 CPPUNIT_ASSERT_EQUAL(ref
,b
);
494 testSBuf::testChomp()
496 SBuf
s1("complete string");
499 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
500 s2
.assign(" complete string ,");
502 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
503 s1
.assign(", complete string ,");
506 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
509 // inspired by SBufFindTest; to be expanded.
510 class SBufSubstrAutoTest
513 std::string fullReference
, str
;
515 void performEqualityTest() {
517 CPPUNIT_ASSERT_EQUAL(ref
,sb
);
519 SBufSubstrAutoTest() : fullString(fox
), fullReference(fox
) {
520 for (int offset
=fullString
.length()-1; offset
>= 0; --offset
) {
521 for (int length
=fullString
.length()-1-offset
; length
>= 0; --length
) {
522 sb
=fullString
.substr(offset
,length
);
523 str
=fullReference
.substr(offset
,length
);
524 performEqualityTest();
531 testSBuf::testSubstr()
533 SBuf
s1(literal
),s2
,s3
;
536 CPPUNIT_ASSERT_EQUAL(s2
,s3
);
538 CPPUNIT_ASSERT_EQUAL(s1
,s2
);
539 SBufSubstrAutoTest sat
; // work done in the constructor
543 testSBuf::testFindChar()
545 const char *alphabet
="abcdefghijklmnopqrstuvwxyz";
548 SBuf::size_type nposResult
=SBuf::npos
;
551 // needle in haystack
553 CPPUNIT_ASSERT_EQUAL(3U,idx
);
554 CPPUNIT_ASSERT_EQUAL('d',s1
[idx
]);
556 // needle not present in haystack
557 idx
=s1
.find(' '); //fails
558 CPPUNIT_ASSERT_EQUAL(nposResult
,idx
);
562 CPPUNIT_ASSERT_EQUAL(4U,idx
);
564 // char not in searched portion
566 CPPUNIT_ASSERT_EQUAL(nposResult
,idx
);
568 // invalid start position
569 idx
=s1
.find('d',SBuf::npos
);
570 CPPUNIT_ASSERT_EQUAL(nposResult
,idx
);
572 // search outside of haystack
573 idx
=s1
.find('d',s1
.length()+1);
574 CPPUNIT_ASSERT_EQUAL(nposResult
,idx
);
577 // needle in haystack
579 CPPUNIT_ASSERT_EQUAL(3U, idx
);
580 CPPUNIT_ASSERT_EQUAL('d', s1
[idx
]);
582 // needle not present in haystack
583 idx
=s1
.rfind(' '); //fails
584 CPPUNIT_ASSERT_EQUAL(nposResult
,idx
);
588 CPPUNIT_ASSERT_EQUAL(4U,idx
);
590 // char not in searched portion
592 CPPUNIT_ASSERT_EQUAL(nposResult
,idx
);
594 // overlong haystack specification
595 idx
=s1
.rfind('d',s1
.length()+1);
596 CPPUNIT_ASSERT_EQUAL(3U,idx
);
600 testSBuf::testFindSBuf()
602 const char *alphabet
="abcdefghijklmnopqrstuvwxyz";
603 SBuf
haystack(alphabet
);
605 SBuf::size_type nposResult
=SBuf::npos
;
608 // needle in haystack
609 idx
= haystack
.find(SBuf("def"));
610 CPPUNIT_ASSERT_EQUAL(3U,idx
);
612 idx
= haystack
.find(SBuf("xyz"));
613 CPPUNIT_ASSERT_EQUAL(23U,idx
);
615 // needle not in haystack, no initial char match
616 idx
= haystack
.find(SBuf(" eq"));
617 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
619 // needle not in haystack, initial sequence match
620 idx
= haystack
.find(SBuf("deg"));
621 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
623 // needle past end of haystack
624 idx
= haystack
.find(SBuf("xyz1"));
625 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
627 // search in portion: needle not in searched part
628 idx
= haystack
.find(SBuf("def"),7);
629 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
631 // search in portion: overhang
632 idx
= haystack
.find(SBuf("def"),4);
633 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
635 // invalid start position
636 idx
= haystack
.find(SBuf("def"),SBuf::npos
);
637 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
639 // needle bigger than haystack
640 idx
= SBuf("def").find(haystack
);
641 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
643 // search in a double-matching haystack
648 idx
= h2
.find(SBuf("def"));
649 CPPUNIT_ASSERT_EQUAL(3U,idx
);
651 idx
= h2
.find(SBuf("xyzab"));
652 CPPUNIT_ASSERT_EQUAL(23U,idx
);
656 // needle in haystack
657 idx
= haystack
.rfind(SBuf("def"));
658 CPPUNIT_ASSERT_EQUAL(3U,idx
);
660 idx
= haystack
.rfind(SBuf("xyz"));
661 CPPUNIT_ASSERT_EQUAL(23U,idx
);
663 // needle not in haystack, no initial char match
664 idx
= haystack
.rfind(SBuf(" eq"));
665 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
667 // needle not in haystack, initial sequence match
668 idx
= haystack
.rfind(SBuf("deg"));
669 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
671 // needle past end of haystack
672 idx
= haystack
.rfind(SBuf("xyz1"));
673 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
675 // search in portion: needle in searched part
676 idx
= haystack
.rfind(SBuf("def"),7);
677 CPPUNIT_ASSERT_EQUAL(3U, idx
);
679 // search in portion: needle not in searched part
680 idx
= haystack
.rfind(SBuf("mno"),3);
681 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
683 // search in portion: overhang
684 idx
= haystack
.rfind(SBuf("def"),4);
685 CPPUNIT_ASSERT_EQUAL(3U, idx
);
687 // npos start position
688 idx
= haystack
.rfind(SBuf("def"),SBuf::npos
);
689 CPPUNIT_ASSERT_EQUAL(3U, idx
);
691 // needle bigger than haystack
692 idx
= SBuf("def").rfind(haystack
);
693 CPPUNIT_ASSERT_EQUAL(nposResult
, idx
);
695 // search in a double-matching haystack
700 idx
= h2
.rfind(SBuf("def"));
701 CPPUNIT_ASSERT_EQUAL(29U,idx
);
703 idx
= h2
.find(SBuf("xyzab"));
704 CPPUNIT_ASSERT_EQUAL(23U,idx
);
709 testSBuf::testRFindChar()
714 CPPUNIT_ASSERT_EQUAL(40U,idx
);
715 CPPUNIT_ASSERT_EQUAL(' ',s1
[idx
]);
719 testSBuf::testRFindSBuf()
721 SBuf
haystack(literal
),afox("fox");
722 SBuf
goobar("goobar");
725 // corner case: search for a zero-length SBuf
726 idx
=haystack
.rfind(SBuf(""));
727 CPPUNIT_ASSERT_EQUAL(haystack
.length(),idx
);
729 // corner case: search for a needle longer than the haystack
730 idx
=afox
.rfind(SBuf(" "));
731 CPPUNIT_ASSERT_EQUAL(SBuf::npos
,idx
);
733 idx
=haystack
.rfind(SBuf("fox"));
734 CPPUNIT_ASSERT_EQUAL(16U,idx
);
736 // needle not found, no match for first char
737 idx
=goobar
.rfind(SBuf("foo"));
738 CPPUNIT_ASSERT_EQUAL(SBuf::npos
,idx
);
740 // needle not found, match for first char but no match for SBuf
741 idx
=haystack
.rfind(SBuf("foe"));
742 CPPUNIT_ASSERT_EQUAL(SBuf::npos
,idx
);
744 SBuf
g("g"); //match at the last char
745 idx
=haystack
.rfind(g
);
746 CPPUNIT_ASSERT_EQUAL(43U,idx
);
747 CPPUNIT_ASSERT_EQUAL('g',haystack
[idx
]);
749 idx
=haystack
.rfind(SBuf("The"));
750 CPPUNIT_ASSERT_EQUAL(0U,idx
);
752 haystack
.append("The");
753 idx
=haystack
.rfind(SBuf("The"));
754 CPPUNIT_ASSERT_EQUAL(44U,idx
);
757 haystack
="The quick brown fox";
758 SBuf
needle("foxy lady");
759 idx
=haystack
.rfind(needle
);
760 CPPUNIT_ASSERT_EQUAL(SBuf::npos
,idx
);
764 testSBuf::testSBufLength()
767 CPPUNIT_ASSERT_EQUAL(strlen(fox
),(size_t)s
.length());
773 char buf
[40]; //shorter than literal()
775 CPPUNIT_ASSERT_EQUAL(s
.length(),s
.copy(buf
,40));
776 CPPUNIT_ASSERT_EQUAL(0,strncmp(s
.rawContent(),buf
,s
.length()));
778 CPPUNIT_ASSERT_EQUAL(40U,s
.copy(buf
,40));
781 CPPUNIT_ASSERT_EQUAL(s2
,s
);
785 testSBuf::testStringOps()
787 SBuf
sng(ToLower(literal
)),
788 ref("the quick brown fox jumped over the lazy dog");
789 CPPUNIT_ASSERT_EQUAL(ref
,sng
);
791 CPPUNIT_ASSERT_EQUAL(0,sng
.compare(ref
,caseInsensitive
));
792 // max-size comparison
793 CPPUNIT_ASSERT_EQUAL(0,ref
.compare(SBuf("THE"),caseInsensitive
,3));
794 CPPUNIT_ASSERT_EQUAL(1,ref
.compare(SBuf("THE"),caseInsensitive
,6));
795 CPPUNIT_ASSERT_EQUAL(0,SBuf("the").compare(SBuf("THE"),caseInsensitive
,6));
803 const char *ref
=t
.rawContent();
804 t
.reserveCapacity(10240);
805 const char *match
=t
.rawContent();
806 CPPUNIT_ASSERT(match
!=ref
);
808 t
.append(literal
).append(literal
).append(literal
).append(literal
).append(literal
);
809 t
.append(t
).append(t
).append(t
).append(t
).append(t
);
810 CPPUNIT_ASSERT_EQUAL(ref
,match
);
814 testSBuf::testReserve()
816 SBufReservationRequirements requirements
;
817 // use unusual numbers to ensure we dont hit a lucky boundary situation
818 requirements
.minSpace
= 10;
819 requirements
.idealSpace
= 82;
820 requirements
.maxCapacity
= 259;
821 requirements
.allowShared
= true;
823 // for each possible starting buffer length within the capacity
824 for (SBuf::size_type startLength
= 0; startLength
<= requirements
.maxCapacity
; ++startLength
) {
827 b
.reserveCapacity(startLength
);
828 CPPUNIT_ASSERT_EQUAL(b
.length(), static_cast<unsigned int>(0));
829 CPPUNIT_ASSERT_EQUAL(b
.spaceSize(), startLength
);
831 // check that it never grows outside capacity.
832 // do 5 excess cycles to check that.
833 for (SBuf::size_type filled
= 0; filled
< requirements
.maxCapacity
+5; ++filled
) {
834 CPPUNIT_ASSERT_EQUAL(b
.length(), min(filled
, requirements
.maxCapacity
));
835 auto x
= b
.reserve(requirements
);
836 // the amount of space advertized must not cause users to exceed capacity
837 CPPUNIT_ASSERT(x
<= requirements
.maxCapacity
- filled
);
838 CPPUNIT_ASSERT(b
.spaceSize() <= requirements
.maxCapacity
- filled
);
839 // the total size of buffer must not cause users to exceed capacity
840 CPPUNIT_ASSERT(b
.length() + b
.spaceSize() <= requirements
.maxCapacity
);
846 // the minimal space requirement should overwrite idealSpace preferences
847 requirements
.minSpace
= 10;
848 for (const int delta
: {-1,0,+1}) {
849 requirements
.idealSpace
= requirements
.minSpace
+ delta
;
851 buffer
.reserve(requirements
);
852 CPPUNIT_ASSERT(buffer
.spaceSize() >= requirements
.minSpace
);
857 testSBuf::testStartsWith()
859 static SBuf
casebuf("THE QUICK");
860 CPPUNIT_ASSERT(literal
.startsWith(SBuf(fox1
)));
861 CPPUNIT_ASSERT(!SBuf("The quick brown").startsWith(SBuf(fox1
))); //too short
862 CPPUNIT_ASSERT(!literal
.startsWith(SBuf(fox2
))); //different contents
864 // case-insensitive checks
865 CPPUNIT_ASSERT(literal
.startsWith(casebuf
,caseInsensitive
));
866 casebuf
=ToUpper(SBuf(fox1
));
867 CPPUNIT_ASSERT(literal
.startsWith(casebuf
,caseInsensitive
));
868 CPPUNIT_ASSERT(literal
.startsWith(SBuf(fox1
),caseInsensitive
));
869 casebuf
= "tha quick";
870 CPPUNIT_ASSERT_EQUAL(false,literal
.startsWith(casebuf
,caseInsensitive
));
874 testSBuf::testSBufStream()
876 SBuf
b("const.string, int 10 and a float 10.5");
878 ss
<< "const.string, int " << 10 << " and a float " << 10.5;
880 CPPUNIT_ASSERT_EQUAL(b
,o
);
883 CPPUNIT_ASSERT_EQUAL(SBuf(),o
);
887 CPPUNIT_ASSERT_EQUAL(ss2
.buf(),literal
);
888 CPPUNIT_ASSERT_EQUAL(f1
,SBuf(fox1
));
892 testSBuf::testFindFirstOf()
894 SBuf
haystack(literal
);
898 idx
=haystack
.findFirstOf(CharacterSet("t1","ADHRWYP"));
899 CPPUNIT_ASSERT_EQUAL(SBuf::npos
,idx
);
901 // found at beginning
902 idx
=haystack
.findFirstOf(CharacterSet("t2","THANDF"));
903 CPPUNIT_ASSERT_EQUAL(0U,idx
);
905 //found at end of haystack
906 idx
=haystack
.findFirstOf(CharacterSet("t3","QWERYVg"));
907 CPPUNIT_ASSERT_EQUAL(haystack
.length()-1,idx
);
909 //found in the middle of haystack
910 idx
=haystack
.findFirstOf(CharacterSet("t4","QWERqYV"));
911 CPPUNIT_ASSERT_EQUAL(4U,idx
);
915 testSBuf::testFindFirstNotOf()
917 SBuf
haystack(literal
);
920 // all chars from the set
921 idx
=haystack
.findFirstNotOf(CharacterSet("t1",literal
.c_str()));
922 CPPUNIT_ASSERT_EQUAL(SBuf::npos
,idx
);
924 // found at beginning
925 idx
=haystack
.findFirstNotOf(CharacterSet("t2","a"));
926 CPPUNIT_ASSERT_EQUAL(0U,idx
);
928 //found at end of haystack
929 idx
=haystack
.findFirstNotOf(CharacterSet("t3",literal
.substr(0,literal
.length()-1).c_str()));
930 CPPUNIT_ASSERT_EQUAL(haystack
.length()-1,idx
);
932 //found in the middle of haystack
933 idx
=haystack
.findFirstNotOf(CharacterSet("t4","The"));
934 CPPUNIT_ASSERT_EQUAL(3U,idx
);
938 testSBuf::testAutoFind()
945 testSBuf::testStdStringOps()
947 const char *alphabet
="abcdefghijklmnopqrstuvwxyz";
948 std::string
astr(alphabet
);
950 CPPUNIT_ASSERT_EQUAL(astr
,sb
.toStdString());
954 testSBuf::testIterators()
956 SBuf
text("foo"), text2("foo");
957 CPPUNIT_ASSERT(text
.begin() == text
.begin());
958 CPPUNIT_ASSERT(text
.begin() != text
.end());
959 CPPUNIT_ASSERT(text
.begin() != text2
.begin());
961 auto i
= text
.begin();
963 CPPUNIT_ASSERT_EQUAL('f', *i
);
964 CPPUNIT_ASSERT(i
!= e
);
966 CPPUNIT_ASSERT_EQUAL('o', *i
);
967 CPPUNIT_ASSERT(i
!= e
);
969 CPPUNIT_ASSERT_EQUAL('o', *i
);
970 CPPUNIT_ASSERT(i
!= e
);
972 CPPUNIT_ASSERT(i
== e
);
975 auto i
= text
.rbegin();
976 auto e
= text
.rend();
977 CPPUNIT_ASSERT_EQUAL('o', *i
);
978 CPPUNIT_ASSERT(i
!= e
);
980 CPPUNIT_ASSERT_EQUAL('o', *i
);
981 CPPUNIT_ASSERT(i
!= e
);
983 CPPUNIT_ASSERT_EQUAL('f', *i
);
984 CPPUNIT_ASSERT(i
!= e
);
986 CPPUNIT_ASSERT(i
== e
);
991 testSBuf::testSBufHash()
993 // same SBuf must have same hash
994 auto hasher
=std::hash
<SBuf
>();
995 CPPUNIT_ASSERT_EQUAL(hasher(literal
),hasher(literal
));
997 // same content must have same hash
998 CPPUNIT_ASSERT_EQUAL(hasher(literal
),hasher(SBuf(fox
)));
999 CPPUNIT_ASSERT_EQUAL(hasher(SBuf(fox
)),hasher(SBuf(fox
)));
1001 //differen content should have different hash
1002 CPPUNIT_ASSERT(hasher(SBuf(fox
)) != hasher(SBuf(fox1
)));
1005 std::unordered_map
<SBuf
, int> um
;
1006 um
[SBuf("one")] = 1;
1007 um
[SBuf("two")] = 2;
1009 auto i
= um
.find(SBuf("one"));
1010 CPPUNIT_ASSERT(i
!= um
.end());
1011 CPPUNIT_ASSERT(i
->second
== 1);
1013 i
= um
.find(SBuf("eleventy"));
1014 CPPUNIT_ASSERT(i
== um
.end());