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