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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors