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