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