]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testSBuf.cc
Sync with trunk rev.13542
[thirdparty/squid.git] / src / tests / testSBuf.cc
1 #include "squid.h"
2 #include "base/CharacterSet.h"
3 #include "Mem.h"
4 #include "SBuf.h"
5 #include "SBufFindTest.h"
6 #include "SBufStream.h"
7 #include "SquidString.h"
8 #include "testSBuf.h"
9
10 #include <iostream>
11 #include <stdexcept>
12
13 CPPUNIT_TEST_SUITE_REGISTRATION( testSBuf );
14
15 /* let this test link sanely */
16 #include "event.h"
17 #include "MemObject.h"
18 void
19 eventAdd(const char *name, EVH * func, void *arg, double when, int, bool cbdata)
20 {}
21 int64_t
22 MemObject::endOffset() const
23 { return 0; }
24 /* end of stubs */
25
26 // test string
27 static char fox[]="The quick brown fox jumped over the lazy dog";
28 static char fox1[]="The quick brown fox ";
29 static char fox2[]="jumped over the lazy dog";
30
31 // TEST: globals variables (default/empty and with contents) are
32 // created outside and before any unit tests and memory subsystem
33 // initialization. Check for correct constructor operation.
34 SBuf empty_sbuf;
35 SBuf literal("The quick brown fox jumped over the lazy dog");
36
37 void
38 testSBuf::testSBufConstructDestruct()
39 {
40 /* NOTE: Do not initialize memory here because we need
41 * to test correct operation before and after Mem::Init
42 */
43
44 // XXX: partial demo below of how to do constructor unit-test. use scope to ensure each test
45 // is working on local-scope variables constructed fresh for the test, and destructed when
46 // scope exists. use nested scopes to test destructor affects on copied data (MemBlob etc)
47
48 // TEST: default constructor (implicit destructor non-crash test)
49 // test accessors on empty SBuf.
50 {
51 SBuf s1;
52 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
53 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
54 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
55 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
56 }
57
58 // TEST: copy-construct NULL string (implicit destructor non-crash test)
59 {
60 SBuf s1(NULL);
61 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
62 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
63 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
64 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
65 }
66
67 // TEST: copy-construct empty string (implicit destructor non-crash test)
68 {
69 SBuf s1("");
70 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
71 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
72 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
73 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
74 }
75
76 // TEST: copy-construct from a SBuf
77 {
78 SBuf s1(empty_sbuf);
79 CPPUNIT_ASSERT_EQUAL(0U,s1.length());
80 CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
81 CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
82 CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
83
84 SBuf s5(literal);
85 CPPUNIT_ASSERT_EQUAL(literal,s5);
86 SBuf s6(fox);
87 CPPUNIT_ASSERT_EQUAL(literal,s6);
88 // XXX: other state checks. expected result of calling any state accessor on s4 ?
89 }
90
91 // TEST: check that COW doesn't happen upon copy-construction
92 {
93 SBuf s1(empty_sbuf), s2(s1);
94 CPPUNIT_ASSERT_EQUAL(s1.rawContent(), s2.rawContent());
95 SBuf s3(literal), s4(literal);
96 CPPUNIT_ASSERT_EQUAL(s3.rawContent(), s4.rawContent());
97 }
98
99 // TEST: sub-string copy
100 {
101 SBuf s1=SBuf(fox+4), s2(fox);
102 SBuf s3=s2.substr(4,s2.length()); //n is out-of-bounds
103 CPPUNIT_ASSERT_EQUAL(s1,s3);
104 SBuf s4=SBuf(fox,4);
105 s3=s2.substr(0,4);
106 CPPUNIT_ASSERT_EQUAL(s4,s3);
107 }
108
109 // TEST: go via SquidString adapters.
110 {
111 String str(fox);
112 SBuf s1(str);
113 CPPUNIT_ASSERT_EQUAL(literal,s1);
114 }
115
116 // TEST: go via std::string adapter.
117 {
118 std::string str(fox);
119 SBuf s1(str);
120 CPPUNIT_ASSERT_EQUAL(literal,s1);
121 }
122 }
123
124 void
125 testSBuf::testSBufConstructDestructAfterMemInit()
126 {
127 Mem::Init();
128 testSBufConstructDestruct();
129 }
130
131 void
132 testSBuf::testEqualityTest()
133 {
134 SBuf s1(fox),s2(fox);
135 CPPUNIT_ASSERT_EQUAL(s1,s1); //self-equality
136 CPPUNIT_ASSERT_EQUAL(s1,s2); //same contents
137 s2.assign("The quick brown fox jumped over the lazy doe");
138 CPPUNIT_ASSERT(!(s1 == s2)); //same length, different contents
139 s2.assign("foo");
140 CPPUNIT_ASSERT(!(s1 == s2)); //different length and contents
141 CPPUNIT_ASSERT(s1 != s2); //while we're ready, let's test inequality
142 s2.clear();
143 CPPUNIT_ASSERT(!(s1 == s2)); //null and not-null
144 CPPUNIT_ASSERT(s1 != s2); //while we're ready, let's test inequality
145 s1.clear();
146 CPPUNIT_ASSERT_EQUAL(s1,s2); //null and null
147 }
148
149 void
150 testSBuf::testAppendSBuf()
151 {
152 SBuf s1(fox1),s2(fox2);
153 s1.append(s2);
154 CPPUNIT_ASSERT_EQUAL(s1,literal);
155 }
156
157 void
158 testSBuf::testPrintf()
159 {
160 SBuf s1,s2;
161 s1.Printf("%s:%d:%03.3f","fox",10,12345.67);
162 s2.assign("fox:10:12345.670");
163 CPPUNIT_ASSERT_EQUAL(s1,s2);
164 }
165
166 void
167 testSBuf::testAppendCString()
168 {
169 SBuf s1(fox1);
170 s1.append(fox2);
171 CPPUNIT_ASSERT_EQUAL(s1,literal);
172 }
173
174 void
175 testSBuf::testAppendStdString()
176 {
177 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
178 {
179 SBuf alpha(alphabet), s;
180 s.append(alphabet,5).append(alphabet+5);
181 CPPUNIT_ASSERT_EQUAL(alpha,s);
182 }
183 {
184 SBuf s;
185 std::string control;
186 s.append(alphabet,5).append("\0",1).append(alphabet+6,SBuf::npos);
187 control.append(alphabet,5).append(1,'\0').append(alphabet,6,std::string::npos);
188 SBuf scontrol(control); // we need this to test the equality. sigh.
189 CPPUNIT_ASSERT_EQUAL(scontrol,s);
190 }
191 {
192 const char *alphazero="abcdefghijk\0mnopqrstuvwxyz";
193 SBuf s(alphazero,26);
194 std::string str(alphazero,26);
195 CPPUNIT_ASSERT_EQUAL(0,memcmp(str.data(),s.rawContent(),26));
196 }
197 }
198
199 void
200 testSBuf::testAppendf()
201 {
202 SBuf s1,s2;
203 s1.appendf("%s:%d:%03.2f",fox,1234,1234.56);
204 s2.assign("The quick brown fox jumped over the lazy dog:1234:1234.56");
205 CPPUNIT_ASSERT_EQUAL(s2,s1);
206 }
207
208 void
209 testSBuf::testDumpStats()
210 {
211 SBuf::GetStats().dump(std::cout);
212 MemBlob::GetStats().dump(std::cout);
213 std::cout << "sizeof(SBuf): " << sizeof(SBuf) << std::endl;
214 std::cout << "sizeof(MemBlob): " << sizeof(MemBlob) << std::endl;
215 }
216
217 void
218 testSBuf::testSubscriptOp()
219 {
220 SBuf chg(literal);
221 CPPUNIT_ASSERT_EQUAL(chg[5],'u');
222 chg.setAt(5,'e');
223 CPPUNIT_ASSERT_EQUAL(literal[5],'u');
224 CPPUNIT_ASSERT_EQUAL(chg[5],'e');
225 }
226
227 // note: can't use cppunit's CPPUNIT_TEST_EXCEPTION because TextException asserts, and
228 // so the test can't be properly completed.
229 void
230 testSBuf::testSubscriptOpFail()
231 {
232 char c;
233 c=literal.at(literal.length()); //out of bounds by 1
234 //notreached
235 std::cout << c << std::endl;
236 }
237
238 static int sign(int v)
239 {
240 if (v < 0)
241 return -1;
242 if (v>0)
243 return 1;
244 return 0;
245 }
246
247 static void
248 testComparisonStdFull(const char *left, const char *right)
249 {
250 if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(SBuf(right))))
251 std::cerr << std::endl << " cmp(SBuf) npos " << left << " ?= " << right << std::endl;
252 CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(SBuf(right))));
253
254 if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(right)))
255 std::cerr << std::endl << " cmp(char*) npos " << left << " ?= " << right << std::endl;
256 CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(right)));
257
258 if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(SBuf(right))))
259 std::cerr << std::endl << " caseCmp(SBuf) npos " << left << " ?= " << right << std::endl;
260 CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(SBuf(right))));
261
262 if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(right)))
263 std::cerr << std::endl << " caseCmp(char*) npos " << left << " ?= " << right << std::endl;
264 CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(right)));
265 }
266
267 static void
268 testComparisonStdN(const char *left, const char *right, const size_t n)
269 {
270 if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(SBuf(right), n)))
271 std::cerr << std::endl << " cmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
272 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(SBuf(right), n)));
273
274 if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(right, n)))
275 std::cerr << std::endl << " cmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
276 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(right, n)));
277
278 if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(SBuf(right), n)))
279 std::cerr << std::endl << " caseCmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
280 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(SBuf(right), n)));
281
282 if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(right, n)))
283 std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
284 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(right, n)));
285 }
286
287 static void
288 testComparisonStdOneWay(const char *left, const char *right)
289 {
290 testComparisonStdFull(left, right);
291 const size_t maxN = 2 + min(strlen(left), strlen(right));
292 for (size_t n = 0; n <= maxN; ++n) {
293 testComparisonStdN(left, right, n);
294 }
295 }
296
297 static void
298 testComparisonStd(const char *s1, const char *s2)
299 {
300 testComparisonStdOneWay(s1, s2);
301 testComparisonStdOneWay(s2, s1);
302 }
303
304 void
305 testSBuf::testComparisons()
306 {
307 //same length
308 SBuf s1("foo"),s2("foe");
309 CPPUNIT_ASSERT(s1.cmp(s2)>0);
310 CPPUNIT_ASSERT(s1.caseCmp(s2)>0);
311 CPPUNIT_ASSERT(s2.cmp(s1)<0);
312 CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
313 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
314 CPPUNIT_ASSERT(s1 > s2);
315 CPPUNIT_ASSERT(s2 < s1);
316 CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
317 //different lengths
318 s1.assign("foo");
319 s2.assign("foof");
320 CPPUNIT_ASSERT(s1.cmp(s2)<0);
321 CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
322 CPPUNIT_ASSERT(s1 < s2);
323 // specifying the max-length and overhanging size
324 CPPUNIT_ASSERT_EQUAL(1,SBuf("foolong").caseCmp(SBuf("foo"), 5));
325 // case-insensive comaprison
326 s1 = "foo";
327 s2 = "fOo";
328 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
329 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
330 // \0-clenliness test
331 s1.assign("f\0oo",4);
332 s2.assign("f\0Oo",4);
333 CPPUNIT_ASSERT(s1.cmp(s2) > 0);
334 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
335 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,3));
336 CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
337 CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
338
339 testComparisonStd("foo", "fooz");
340 testComparisonStd("foo", "foo");
341 testComparisonStd("foo", "f");
342 testComparisonStd("foo", "bar");
343
344 testComparisonStd("foo", "FOOZ");
345 testComparisonStd("foo", "FOO");
346 testComparisonStd("foo", "F");
347
348 testComparisonStdOneWay("", "");
349
350 // rare case C-string input matching SBuf with N>strlen(s)
351 {
352 char *right = xstrdup("foo34567890123456789012345678");
353 SBuf left("fooZYXWVUTSRQPONMLKJIHGFEDCBA");
354 // is 3 bytes in length. NEVER more.
355 right[3] = '\0';
356 left.setAt(3, '\0');
357
358 // pick another spot to truncate at if something goes horribly wrong.
359 right[14] = '\0';
360 left.setAt(14, '\0');
361
362 const SBuf::size_type maxN = 20 + min(left.length(), static_cast<SBuf::size_type>(strlen(right)));
363 for (SBuf::size_type n = 0; n <= maxN; ++n) {
364 if (sign(strncmp(left.rawContent(), right, n)) != sign(left.cmp(right, n)) )
365 std::cerr << std::endl << " cmp(char*) " << n << ' ' << left << " ?= " << right;
366 CPPUNIT_ASSERT_EQUAL(sign(strncmp(left.rawContent(), right, n)), sign(left.cmp(right, n)));
367 if (sign(strncasecmp(left.rawContent(), right, n)) != sign(left.caseCmp(right, n)))
368 std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << left << " ?= " << right;
369 CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left.rawContent(), right, n)), sign(left.caseCmp(right, n)));
370 }
371 xfree(right);
372 }
373 }
374
375 void
376 testSBuf::testConsume()
377 {
378 SBuf s1(literal),s2,s3;
379 s2=s1.consume(4);
380 s3.assign("The ");
381 CPPUNIT_ASSERT_EQUAL(s2,s3);
382 s3.assign("quick brown fox jumped over the lazy dog");
383 CPPUNIT_ASSERT_EQUAL(s1,s3);
384 s1.consume(40);
385 CPPUNIT_ASSERT_EQUAL(s1,SBuf());
386 }
387
388 void
389 testSBuf::testRawContent()
390 {
391 SBuf s1(literal);
392 SBuf s2(s1);
393 s2.append("foo");
394 const char *foo;
395 foo = s1.rawContent();
396 CPPUNIT_ASSERT_EQUAL(0,strncmp(fox,foo,s1.length()));
397 foo = s1.c_str();
398 CPPUNIT_ASSERT(!strcmp(fox,foo));
399 }
400
401 void
402 testSBuf::testRawSpace()
403 {
404 SBuf s1(literal);
405 SBuf s2(fox1);
406 SBuf::size_type sz=s2.length();
407 char *rb=s2.rawSpace(strlen(fox2)+1);
408 strcpy(rb,fox2);
409 s2.forceSize(sz+strlen(fox2));
410 CPPUNIT_ASSERT_EQUAL(s1,s2);
411 }
412
413 void
414 testSBuf::testChop()
415 {
416 SBuf s1(literal),s2;
417 s1.chop(4,5);
418 s2.assign("quick");
419 CPPUNIT_ASSERT_EQUAL(s1,s2);
420 s1=literal;
421 s2.clear();
422 s1.chop(5,0);
423 CPPUNIT_ASSERT_EQUAL(s1,s2);
424 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
425 SBuf a(alphabet);
426 std::string s(alphabet); // TODO
427 { //regular chopping
428 SBuf b(a);
429 b.chop(3,3);
430 SBuf ref("def");
431 CPPUNIT_ASSERT_EQUAL(ref,b);
432 }
433 { // chop at end
434 SBuf b(a);
435 b.chop(b.length()-3);
436 SBuf ref("xyz");
437 CPPUNIT_ASSERT_EQUAL(ref,b);
438 }
439 { // chop at beginning
440 SBuf b(a);
441 b.chop(0,3);
442 SBuf ref("abc");
443 CPPUNIT_ASSERT_EQUAL(ref,b);
444 }
445 { // chop to zero length
446 SBuf b(a);
447 b.chop(5,0);
448 SBuf ref("");
449 CPPUNIT_ASSERT_EQUAL(ref,b);
450 }
451 { // chop beyond end (at npos)
452 SBuf b(a);
453 b.chop(SBuf::npos,4);
454 SBuf ref("");
455 CPPUNIT_ASSERT_EQUAL(ref,b);
456 }
457 { // chop beyond end
458 SBuf b(a);
459 b.chop(b.length()+2,4);
460 SBuf ref("");
461 CPPUNIT_ASSERT_EQUAL(ref,b);
462 }
463 { // null-chop
464 SBuf b(a);
465 b.chop(0,b.length());
466 SBuf ref(a);
467 CPPUNIT_ASSERT_EQUAL(ref,b);
468 }
469 { // overflow chopped area
470 SBuf b(a);
471 b.chop(b.length()-3,b.length());
472 SBuf ref("xyz");
473 CPPUNIT_ASSERT_EQUAL(ref,b);
474 }
475 }
476
477 void
478 testSBuf::testChomp()
479 {
480 SBuf s1("complete string");
481 SBuf s2(s1);
482 s2.trim(SBuf(" ,"));
483 CPPUNIT_ASSERT_EQUAL(s1,s2);
484 s2.assign(" complete string ,");
485 s2.trim(SBuf(" ,"));
486 CPPUNIT_ASSERT_EQUAL(s1,s2);
487 s1.assign(", complete string ,");
488 s2=s1;
489 s2.trim(SBuf(" "));
490 CPPUNIT_ASSERT_EQUAL(s1,s2);
491 }
492
493 // inspired by SBufFindTest; to be expanded.
494 class SBufSubstrAutoTest
495 {
496 SBuf fullString, sb;
497 std::string fullReference, str;
498 public:
499 void performEqualityTest() {
500 SBuf ref(str);
501 CPPUNIT_ASSERT_EQUAL(ref,sb);
502 }
503 SBufSubstrAutoTest() : fullString(fox), fullReference(fox) {
504 for (int offset=fullString.length()-1; offset >= 0; --offset ) {
505 for (int length=fullString.length()-1-offset; length >= 0; --length) {
506 sb=fullString.substr(offset,length);
507 str=fullReference.substr(offset,length);
508 performEqualityTest();
509 }
510 }
511 }
512 };
513
514 void
515 testSBuf::testSubstr()
516 {
517 SBuf s1(literal),s2,s3;
518 s2=s1.substr(4,5);
519 s3.assign("quick");
520 CPPUNIT_ASSERT_EQUAL(s2,s3);
521 s1.chop(4,5);
522 CPPUNIT_ASSERT_EQUAL(s1,s2);
523 SBufSubstrAutoTest sat; // work done in the constructor
524 }
525
526 void
527 testSBuf::testFindChar()
528 {
529 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
530 SBuf s1(alphabet);
531 SBuf::size_type idx;
532 SBuf::size_type nposResult=SBuf::npos;
533
534 // FORWARD SEARCH
535 // needle in haystack
536 idx=s1.find('d');
537 CPPUNIT_ASSERT_EQUAL(3U,idx);
538 CPPUNIT_ASSERT_EQUAL('d',s1[idx]);
539
540 // needle not present in haystack
541 idx=s1.find(' '); //fails
542 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
543
544 // search in portion
545 idx=s1.find('e',3U);
546 CPPUNIT_ASSERT_EQUAL(4U,idx);
547
548 // char not in searched portion
549 idx=s1.find('e',5U);
550 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
551
552 // invalid start position
553 idx=s1.find('d',SBuf::npos);
554 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
555
556 // search outside of haystack
557 idx=s1.find('d',s1.length()+1);
558 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
559
560 // REVERSE SEARCH
561 // needle in haystack
562 idx=s1.rfind('d');
563 CPPUNIT_ASSERT_EQUAL(3U, idx);
564 CPPUNIT_ASSERT_EQUAL('d', s1[idx]);
565
566 // needle not present in haystack
567 idx=s1.rfind(' '); //fails
568 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
569
570 // search in portion
571 idx=s1.rfind('e',5);
572 CPPUNIT_ASSERT_EQUAL(4U,idx);
573
574 // char not in searched portion
575 idx=s1.rfind('e',3);
576 CPPUNIT_ASSERT_EQUAL(nposResult,idx);
577
578 // overlong haystack specification
579 idx=s1.rfind('d',s1.length()+1);
580 CPPUNIT_ASSERT_EQUAL(3U,idx);
581 }
582
583 void
584 testSBuf::testFindSBuf()
585 {
586 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
587 SBuf haystack(alphabet);
588 SBuf::size_type idx;
589 SBuf::size_type nposResult=SBuf::npos;
590
591 // FORWARD search
592 // needle in haystack
593 idx = haystack.find(SBuf("def"));
594 CPPUNIT_ASSERT_EQUAL(3U,idx);
595
596 idx = haystack.find(SBuf("xyz"));
597 CPPUNIT_ASSERT_EQUAL(23U,idx);
598
599 // needle not in haystack, no initial char match
600 idx = haystack.find(SBuf(" eq"));
601 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
602
603 // needle not in haystack, initial sequence match
604 idx = haystack.find(SBuf("deg"));
605 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
606
607 // needle past end of haystack
608 idx = haystack.find(SBuf("xyz1"));
609 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
610
611 // search in portion: needle not in searched part
612 idx = haystack.find(SBuf("def"),7);
613 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
614
615 // search in portion: overhang
616 idx = haystack.find(SBuf("def"),4);
617 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
618
619 // invalid start position
620 idx = haystack.find(SBuf("def"),SBuf::npos);
621 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
622
623 // needle bigger than haystack
624 idx = SBuf("def").find(haystack);
625 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
626
627 // search in a double-matching haystack
628 {
629 SBuf h2=haystack;
630 h2.append(haystack);
631
632 idx = h2.find(SBuf("def"));
633 CPPUNIT_ASSERT_EQUAL(3U,idx);
634
635 idx = h2.find(SBuf("xyzab"));
636 CPPUNIT_ASSERT_EQUAL(23U,idx);
637 }
638
639 // REVERSE search
640 // needle in haystack
641 idx = haystack.rfind(SBuf("def"));
642 CPPUNIT_ASSERT_EQUAL(3U,idx);
643
644 idx = haystack.rfind(SBuf("xyz"));
645 CPPUNIT_ASSERT_EQUAL(23U,idx);
646
647 // needle not in haystack, no initial char match
648 idx = haystack.rfind(SBuf(" eq"));
649 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
650
651 // needle not in haystack, initial sequence match
652 idx = haystack.rfind(SBuf("deg"));
653 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
654
655 // needle past end of haystack
656 idx = haystack.rfind(SBuf("xyz1"));
657 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
658
659 // search in portion: needle in searched part
660 idx = haystack.rfind(SBuf("def"),7);
661 CPPUNIT_ASSERT_EQUAL(3U, idx);
662
663 // search in portion: needle not in searched part
664 idx = haystack.rfind(SBuf("mno"),3);
665 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
666
667 // search in portion: overhang
668 idx = haystack.rfind(SBuf("def"),4);
669 CPPUNIT_ASSERT_EQUAL(3U, idx);
670
671 // npos start position
672 idx = haystack.rfind(SBuf("def"),SBuf::npos);
673 CPPUNIT_ASSERT_EQUAL(3U, idx);
674
675 // needle bigger than haystack
676 idx = SBuf("def").rfind(haystack);
677 CPPUNIT_ASSERT_EQUAL(nposResult, idx);
678
679 // search in a double-matching haystack
680 {
681 SBuf h2=haystack;
682 h2.append(haystack);
683
684 idx = h2.rfind(SBuf("def"));
685 CPPUNIT_ASSERT_EQUAL(29U,idx);
686
687 idx = h2.find(SBuf("xyzab"));
688 CPPUNIT_ASSERT_EQUAL(23U,idx);
689 }
690 }
691
692 void
693 testSBuf::testRFindChar()
694 {
695 SBuf s1(literal);
696 SBuf::size_type idx;
697 idx=s1.rfind(' ');
698 CPPUNIT_ASSERT_EQUAL(40U,idx);
699 CPPUNIT_ASSERT_EQUAL(' ',s1[idx]);
700 }
701
702 void
703 testSBuf::testRFindSBuf()
704 {
705 SBuf haystack(literal),afox("fox");
706 SBuf goobar("goobar");
707 SBuf::size_type idx;
708
709 // corner case: search for a zero-length SBuf
710 idx=haystack.rfind(SBuf(""));
711 CPPUNIT_ASSERT_EQUAL(haystack.length(),idx);
712
713 // corner case: search for a needle longer than the haystack
714 idx=afox.rfind(SBuf(" "));
715 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
716
717 idx=haystack.rfind(SBuf("fox"));
718 CPPUNIT_ASSERT_EQUAL(16U,idx);
719
720 // needle not found, no match for first char
721 idx=goobar.rfind(SBuf("foo"));
722 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
723
724 // needle not found, match for first char but no match for SBuf
725 idx=haystack.rfind(SBuf("foe"));
726 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
727
728 SBuf g("g"); //match at the last char
729 idx=haystack.rfind(g);
730 CPPUNIT_ASSERT_EQUAL(43U,idx);
731 CPPUNIT_ASSERT_EQUAL('g',haystack[idx]);
732
733 idx=haystack.rfind(SBuf("The"));
734 CPPUNIT_ASSERT_EQUAL(0U,idx);
735
736 haystack.append("The");
737 idx=haystack.rfind(SBuf("The"));
738 CPPUNIT_ASSERT_EQUAL(44U,idx);
739
740 //partial match
741 haystack="The quick brown fox";
742 SBuf needle("foxy lady");
743 idx=haystack.rfind(needle);
744 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
745 }
746
747 void
748 testSBuf::testSBufLength()
749 {
750 SBuf s(fox);
751 CPPUNIT_ASSERT_EQUAL(strlen(fox),(size_t)s.length());
752 }
753
754 void
755 testSBuf::testScanf()
756 {
757 SBuf s1;
758 char s[128];
759 int i;
760 float f;
761 int rv;
762 s1.assign("string , 123 , 123.50");
763 rv=s1.scanf("%s , %d , %f",s,&i,&f);
764 CPPUNIT_ASSERT_EQUAL(3,rv);
765 CPPUNIT_ASSERT_EQUAL(0,strcmp(s,"string"));
766 CPPUNIT_ASSERT_EQUAL(123,i);
767 CPPUNIT_ASSERT_EQUAL(static_cast<float>(123.5),f);
768 }
769
770 void
771 testSBuf::testCopy()
772 {
773 char buf[40]; //shorter than literal()
774 SBuf s(fox1),s2;
775 CPPUNIT_ASSERT_EQUAL(s.length(),s.copy(buf,40));
776 CPPUNIT_ASSERT_EQUAL(0,strncmp(s.rawContent(),buf,s.length()));
777 s=literal;
778 CPPUNIT_ASSERT_EQUAL(40U,s.copy(buf,40));
779 s2.assign(buf,40);
780 s.chop(0,40);
781 CPPUNIT_ASSERT_EQUAL(s2,s);
782 }
783
784 void
785 testSBuf::testStringOps()
786 {
787 SBuf sng(ToLower(literal)),
788 ref("the quick brown fox jumped over the lazy dog");
789 CPPUNIT_ASSERT_EQUAL(ref,sng);
790 sng=literal;
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));
796 }
797
798 void
799 testSBuf::testGrow()
800 {
801 SBuf t;
802 t.assign("foo");
803 const char *ref=t.rawContent();
804 t.reserveCapacity(10240);
805 const char *match=t.rawContent();
806 CPPUNIT_ASSERT(match!=ref);
807 ref=match;
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);
811 }
812
813 void
814 testSBuf::testStartsWith()
815 {
816 static SBuf casebuf("THE QUICK");
817 CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1)));
818 CPPUNIT_ASSERT(!SBuf("The quick brown").startsWith(SBuf(fox1))); //too short
819 CPPUNIT_ASSERT(!literal.startsWith(SBuf(fox2))); //different contents
820
821 // case-insensitive checks
822 CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
823 casebuf=ToUpper(SBuf(fox1));
824 CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
825 CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1),caseInsensitive));
826 casebuf = "tha quick";
827 CPPUNIT_ASSERT_EQUAL(false,literal.startsWith(casebuf,caseInsensitive));
828 }
829
830 void
831 testSBuf::testSBufStream()
832 {
833 SBuf b("const.string, int 10 and a float 10.5");
834 SBufStream ss;
835 ss << "const.string, int " << 10 << " and a float " << 10.5;
836 SBuf o=ss.buf();
837 CPPUNIT_ASSERT_EQUAL(b,o);
838 ss.clearBuf();
839 o=ss.buf();
840 CPPUNIT_ASSERT_EQUAL(SBuf(),o);
841 SBuf f1(fox1);
842 SBufStream ss2(f1);
843 ss2 << fox2;
844 CPPUNIT_ASSERT_EQUAL(ss2.buf(),literal);
845 CPPUNIT_ASSERT_EQUAL(f1,SBuf(fox1));
846 }
847
848 void
849 testSBuf::testFindFirstOf()
850 {
851 SBuf haystack(literal);
852 SBuf::size_type idx;
853
854 // not found
855 idx=haystack.findFirstOf(CharacterSet("t1","ADHRWYP"));
856 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
857
858 // found at beginning
859 idx=haystack.findFirstOf(CharacterSet("t2","THANDF"));
860 CPPUNIT_ASSERT_EQUAL(0U,idx);
861
862 //found at end of haystack
863 idx=haystack.findFirstOf(CharacterSet("t3","QWERYVg"));
864 CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx);
865
866 //found in the middle of haystack
867 idx=haystack.findFirstOf(CharacterSet("t4","QWERqYV"));
868 CPPUNIT_ASSERT_EQUAL(4U,idx);
869 }
870
871 void
872 testSBuf::testFindFirstNotOf()
873 {
874 SBuf haystack(literal);
875 SBuf::size_type idx;
876
877 // all chars from the set
878 idx=haystack.findFirstNotOf(CharacterSet("t1",literal.c_str()));
879 CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
880
881 // found at beginning
882 idx=haystack.findFirstNotOf(CharacterSet("t2","a"));
883 CPPUNIT_ASSERT_EQUAL(0U,idx);
884
885 //found at end of haystack
886 idx=haystack.findFirstNotOf(CharacterSet("t3",literal.substr(0,literal.length()-1).c_str()));
887 CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx);
888
889 //found in the middle of haystack
890 idx=haystack.findFirstNotOf(CharacterSet("t4","The"));
891 CPPUNIT_ASSERT_EQUAL(3U,idx);
892 }
893
894 void
895 testSBuf::testAutoFind()
896 {
897 SBufFindTest test;
898 test.run();
899 }
900
901 void
902 testSBuf::testStdStringOps()
903 {
904 const char *alphabet="abcdefghijklmnopqrstuvwxyz";
905 std::string astr(alphabet);
906 SBuf sb(alphabet);
907 CPPUNIT_ASSERT_EQUAL(astr,sb.toStdString());
908 }