]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/tests/testSBuf.cc
renamed sbuf/SBufAlgos.h to sbuf/Algorithms.h
[thirdparty/squid.git] / src / tests / testSBuf.cc
index 41cc334a3b2e045429207876cf8a8f451140e9f7..feb9e9ba1ef2222d2731f42961454d006b77165d 100644 (file)
@@ -1,13 +1,23 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
 #include "squid.h"
-#include "Mem.h"
-#include "SBuf.h"
-#include "SBufStream.h"
-#include "SquidString.h"
-#include "testSBuf.h"
-#include "SBufFindTest.h"
+#include "base/CharacterSet.h"
+#include "sbuf/SBuf.h"
+#include "sbuf/Algorithms.h"
+#include "sbuf/SBufStream.h"
+#include "tests/SBufFindTest.h"
+#include "tests/testSBuf.h"
+#include "unitTestMain.h"
 
 #include <iostream>
 #include <stdexcept>
+#include <unordered_map>
 
 CPPUNIT_TEST_SUITE_REGISTRATION( testSBuf );
 
@@ -48,7 +58,7 @@ testSBuf::testSBufConstructDestruct()
     //  test accessors on empty SBuf.
     {
         SBuf s1;
-        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(0U,s1.length());
         CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
         CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
         CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
@@ -57,7 +67,7 @@ testSBuf::testSBufConstructDestruct()
     // TEST: copy-construct NULL string (implicit destructor non-crash test)
     {
         SBuf s1(NULL);
-        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(0U,s1.length());
         CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
         CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
         CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
@@ -66,7 +76,7 @@ testSBuf::testSBufConstructDestruct()
     // TEST: copy-construct empty string (implicit destructor non-crash test)
     {
         SBuf s1("");
-        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(0U,s1.length());
         CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
         CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
         CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
@@ -75,7 +85,7 @@ testSBuf::testSBufConstructDestruct()
     // TEST: copy-construct from a SBuf
     {
         SBuf s1(empty_sbuf);
-        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(0U,s1.length());
         CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
         CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
         CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
@@ -105,13 +115,6 @@ testSBuf::testSBufConstructDestruct()
         CPPUNIT_ASSERT_EQUAL(s4,s3);
     }
 
-    // TEST: go via SquidString adapters.
-    {
-        String str(fox);
-        SBuf s1(str);
-        CPPUNIT_ASSERT_EQUAL(literal,s1);
-    }
-
     // TEST: go via std::string adapter.
     {
         std::string str(fox);
@@ -201,7 +204,7 @@ testSBuf::testAppendf()
     SBuf s1,s2;
     s1.appendf("%s:%d:%03.2f",fox,1234,1234.56);
     s2.assign("The quick brown fox jumped over the lazy dog:1234:1234.56");
-    CPPUNIT_ASSERT_EQUAL(s1,s2);
+    CPPUNIT_ASSERT_EQUAL(s2,s1);
 }
 
 void
@@ -243,6 +246,63 @@ static int sign(int v)
     return 0;
 }
 
+static void
+testComparisonStdFull(const char *left, const char *right)
+{
+    if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(SBuf(right))))
+        std::cerr << std::endl << " cmp(SBuf) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(SBuf(right))));
+
+    if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(right)))
+        std::cerr << std::endl << " cmp(char*) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(right)));
+
+    if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(SBuf(right))))
+        std::cerr << std::endl << " caseCmp(SBuf) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(SBuf(right))));
+
+    if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(right)))
+        std::cerr << std::endl << " caseCmp(char*) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(right)));
+}
+
+static void
+testComparisonStdN(const char *left, const char *right, const size_t n)
+{
+    if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(SBuf(right), n)))
+        std::cerr << std::endl << " cmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(SBuf(right), n)));
+
+    if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(right, n)))
+        std::cerr << std::endl << " cmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(right, n)));
+
+    if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(SBuf(right), n)))
+        std::cerr << std::endl << " caseCmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(SBuf(right), n)));
+
+    if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(right, n)))
+        std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(right, n)));
+}
+
+static void
+testComparisonStdOneWay(const char *left, const char *right)
+{
+    testComparisonStdFull(left, right);
+    const size_t maxN = 2 + min(strlen(left), strlen(right));
+    for (size_t n = 0; n <= maxN; ++n) {
+        testComparisonStdN(left, right, n);
+    }
+}
+
+static void
+testComparisonStd(const char *s1, const char *s2)
+{
+    testComparisonStdOneWay(s1, s2);
+    testComparisonStdOneWay(s2, s1);
+}
+
 void
 testSBuf::testComparisons()
 {
@@ -272,11 +332,46 @@ testSBuf::testComparisons()
     // \0-clenliness test
     s1.assign("f\0oo",4);
     s2.assign("f\0Oo",4);
-    CPPUNIT_ASSERT_EQUAL(1,s1.cmp(s2));
+    CPPUNIT_ASSERT(s1.cmp(s2) > 0);
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,3));
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
     CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
+
+    testComparisonStd("foo", "fooz");
+    testComparisonStd("foo", "foo");
+    testComparisonStd("foo", "f");
+    testComparisonStd("foo", "bar");
+
+    testComparisonStd("foo", "FOOZ");
+    testComparisonStd("foo", "FOO");
+    testComparisonStd("foo", "F");
+
+    testComparisonStdOneWay("", "");
+
+    // rare case C-string input matching SBuf with N>strlen(s)
+    {
+        char *right = xstrdup("foo34567890123456789012345678");
+        SBuf left("fooZYXWVUTSRQPONMLKJIHGFEDCBA");
+        // is 3 bytes in length. NEVER more.
+        right[3] = '\0';
+        left.setAt(3, '\0');
+
+        // pick another spot to truncate at if something goes horribly wrong.
+        right[14] = '\0';
+        left.setAt(14, '\0');
+
+        const SBuf::size_type maxN = 20 + min(left.length(), static_cast<SBuf::size_type>(strlen(right)));
+        for (SBuf::size_type n = 0; n <= maxN; ++n) {
+            if (sign(strncmp(left.rawContent(), right, n)) != sign(left.cmp(right, n)) )
+                std::cerr << std::endl << " cmp(char*) " << n << ' ' << left << " ?= " << right;
+            CPPUNIT_ASSERT_EQUAL(sign(strncmp(left.rawContent(), right, n)), sign(left.cmp(right, n)));
+            if (sign(strncasecmp(left.rawContent(), right, n)) != sign(left.caseCmp(right, n)))
+                std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << left << " ?= " << right;
+            CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left.rawContent(), right, n)), sign(left.caseCmp(right, n)));
+        }
+        xfree(right);
+    }
 }
 
 void
@@ -331,49 +426,49 @@ testSBuf::testChop()
     const char *alphabet="abcdefghijklmnopqrstuvwxyz";
     SBuf a(alphabet);
     std::string s(alphabet); // TODO
-    { //regular chopping
+    {   //regular chopping
         SBuf b(a);
         b.chop(3,3);
         SBuf ref("def");
         CPPUNIT_ASSERT_EQUAL(ref,b);
     }
-    { // chop at end
+    {   // chop at end
         SBuf b(a);
         b.chop(b.length()-3);
         SBuf ref("xyz");
         CPPUNIT_ASSERT_EQUAL(ref,b);
     }
-    { // chop at beginning
+    {   // chop at beginning
         SBuf b(a);
         b.chop(0,3);
         SBuf ref("abc");
         CPPUNIT_ASSERT_EQUAL(ref,b);
     }
-    { // chop to zero length
+    {   // chop to zero length
         SBuf b(a);
         b.chop(5,0);
         SBuf ref("");
         CPPUNIT_ASSERT_EQUAL(ref,b);
     }
-    { // chop beyond end (at npos)
+    {   // chop beyond end (at npos)
         SBuf b(a);
         b.chop(SBuf::npos,4);
         SBuf ref("");
         CPPUNIT_ASSERT_EQUAL(ref,b);
     }
-    { // chop beyond end
+    {   // chop beyond end
         SBuf b(a);
         b.chop(b.length()+2,4);
         SBuf ref("");
         CPPUNIT_ASSERT_EQUAL(ref,b);
     }
-    { // null-chop
+    {   // null-chop
         SBuf b(a);
         b.chop(0,b.length());
         SBuf ref(a);
         CPPUNIT_ASSERT_EQUAL(ref,b);
     }
-    { // overflow chopped area
+    {   // overflow chopped area
         SBuf b(a);
         b.chop(b.length()-3,b.length());
         SBuf ref("xyz");
@@ -397,7 +492,7 @@ testSBuf::testChomp()
     CPPUNIT_ASSERT_EQUAL(s1,s2);
 }
 
-// inspired to SBufFindTest; to be expanded.
+// inspired by SBufFindTest; to be expanded.
 class SBufSubstrAutoTest
 {
     SBuf fullString, sb;
@@ -441,7 +536,7 @@ testSBuf::testFindChar()
     // FORWARD SEARCH
     // needle in haystack
     idx=s1.find('d');
-    CPPUNIT_ASSERT_EQUAL(3,idx);
+    CPPUNIT_ASSERT_EQUAL(3U,idx);
     CPPUNIT_ASSERT_EQUAL('d',s1[idx]);
 
     // needle not present in haystack
@@ -449,21 +544,17 @@ testSBuf::testFindChar()
     CPPUNIT_ASSERT_EQUAL(nposResult,idx);
 
     // search in portion
-    idx=s1.find('e',3);
-    CPPUNIT_ASSERT_EQUAL(4,idx);
+    idx=s1.find('e',3U);
+    CPPUNIT_ASSERT_EQUAL(4U,idx);
 
     // char not in searched portion
-    idx=s1.find('e',5);
+    idx=s1.find('e',5U);
     CPPUNIT_ASSERT_EQUAL(nposResult,idx);
 
     // invalid start position
     idx=s1.find('d',SBuf::npos);
     CPPUNIT_ASSERT_EQUAL(nposResult,idx);
 
-    // invalid start position
-    idx=s1.find('d', -5);
-    CPPUNIT_ASSERT_EQUAL(3, idx);
-
     // search outside of haystack
     idx=s1.find('d',s1.length()+1);
     CPPUNIT_ASSERT_EQUAL(nposResult,idx);
@@ -471,7 +562,7 @@ testSBuf::testFindChar()
     // REVERSE SEARCH
     // needle in haystack
     idx=s1.rfind('d');
-    CPPUNIT_ASSERT_EQUAL(3, idx);
+    CPPUNIT_ASSERT_EQUAL(3U, idx);
     CPPUNIT_ASSERT_EQUAL('d', s1[idx]);
 
     // needle not present in haystack
@@ -480,19 +571,15 @@ testSBuf::testFindChar()
 
     // search in portion
     idx=s1.rfind('e',5);
-    CPPUNIT_ASSERT_EQUAL(4,idx);
+    CPPUNIT_ASSERT_EQUAL(4U,idx);
 
     // char not in searched portion
     idx=s1.rfind('e',3);
     CPPUNIT_ASSERT_EQUAL(nposResult,idx);
 
-    // invalid start position
-    idx=s1.rfind('d', -5);
-    CPPUNIT_ASSERT_EQUAL(nposResult,idx);
-
     // overlong haystack specification
     idx=s1.rfind('d',s1.length()+1);
-    CPPUNIT_ASSERT_EQUAL(3,idx);
+    CPPUNIT_ASSERT_EQUAL(3U,idx);
 }
 
 void
@@ -506,10 +593,10 @@ testSBuf::testFindSBuf()
     // FORWARD search
     // needle in haystack
     idx = haystack.find(SBuf("def"));
-    CPPUNIT_ASSERT_EQUAL(3,idx);
+    CPPUNIT_ASSERT_EQUAL(3U,idx);
 
     idx = haystack.find(SBuf("xyz"));
-    CPPUNIT_ASSERT_EQUAL(23,idx);
+    CPPUNIT_ASSERT_EQUAL(23U,idx);
 
     // needle not in haystack, no initial char match
     idx = haystack.find(SBuf(" eq"));
@@ -535,10 +622,6 @@ testSBuf::testFindSBuf()
     idx = haystack.find(SBuf("def"),SBuf::npos);
     CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 
-    // invalid start position: negative
-    idx = haystack.find(SBuf("def"),-5);
-    CPPUNIT_ASSERT_EQUAL(3, idx);
-
     // needle bigger than haystack
     idx = SBuf("def").find(haystack);
     CPPUNIT_ASSERT_EQUAL(nposResult, idx);
@@ -549,19 +632,19 @@ testSBuf::testFindSBuf()
         h2.append(haystack);
 
         idx = h2.find(SBuf("def"));
-        CPPUNIT_ASSERT_EQUAL(3,idx);
+        CPPUNIT_ASSERT_EQUAL(3U,idx);
 
         idx = h2.find(SBuf("xyzab"));
-        CPPUNIT_ASSERT_EQUAL(23,idx);
+        CPPUNIT_ASSERT_EQUAL(23U,idx);
     }
 
     // REVERSE search
     // needle in haystack
     idx = haystack.rfind(SBuf("def"));
-    CPPUNIT_ASSERT_EQUAL(3,idx);
+    CPPUNIT_ASSERT_EQUAL(3U,idx);
 
     idx = haystack.rfind(SBuf("xyz"));
-    CPPUNIT_ASSERT_EQUAL(23,idx);
+    CPPUNIT_ASSERT_EQUAL(23U,idx);
 
     // needle not in haystack, no initial char match
     idx = haystack.rfind(SBuf(" eq"));
@@ -577,7 +660,7 @@ testSBuf::testFindSBuf()
 
     // search in portion: needle in searched part
     idx = haystack.rfind(SBuf("def"),7);
-    CPPUNIT_ASSERT_EQUAL(3, idx);
+    CPPUNIT_ASSERT_EQUAL(3U, idx);
 
     // search in portion: needle not in searched part
     idx = haystack.rfind(SBuf("mno"),3);
@@ -585,15 +668,11 @@ testSBuf::testFindSBuf()
 
     // search in portion: overhang
     idx = haystack.rfind(SBuf("def"),4);
-    CPPUNIT_ASSERT_EQUAL(3, idx);
+    CPPUNIT_ASSERT_EQUAL(3U, idx);
 
     // npos start position
     idx = haystack.rfind(SBuf("def"),SBuf::npos);
-    CPPUNIT_ASSERT_EQUAL(3, idx);
-
-    // invalid start position: negative
-    idx = haystack.rfind(SBuf("def"),-5);
-    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
+    CPPUNIT_ASSERT_EQUAL(3U, idx);
 
     // needle bigger than haystack
     idx = SBuf("def").rfind(haystack);
@@ -605,10 +684,10 @@ testSBuf::testFindSBuf()
         h2.append(haystack);
 
         idx = h2.rfind(SBuf("def"));
-        CPPUNIT_ASSERT_EQUAL(29,idx);
+        CPPUNIT_ASSERT_EQUAL(29U,idx);
 
         idx = h2.find(SBuf("xyzab"));
-        CPPUNIT_ASSERT_EQUAL(23,idx);
+        CPPUNIT_ASSERT_EQUAL(23U,idx);
     }
 }
 
@@ -618,7 +697,7 @@ testSBuf::testRFindChar()
     SBuf s1(literal);
     SBuf::size_type idx;
     idx=s1.rfind(' ');
-    CPPUNIT_ASSERT_EQUAL(40,idx);
+    CPPUNIT_ASSERT_EQUAL(40U,idx);
     CPPUNIT_ASSERT_EQUAL(' ',s1[idx]);
 }
 
@@ -638,7 +717,7 @@ testSBuf::testRFindSBuf()
     CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
 
     idx=haystack.rfind(SBuf("fox"));
-    CPPUNIT_ASSERT_EQUAL(16,idx);
+    CPPUNIT_ASSERT_EQUAL(16U,idx);
 
     // needle not found, no match for first char
     idx=goobar.rfind(SBuf("foo"));
@@ -650,15 +729,15 @@ testSBuf::testRFindSBuf()
 
     SBuf g("g"); //match at the last char
     idx=haystack.rfind(g);
-    CPPUNIT_ASSERT_EQUAL(43,idx);
+    CPPUNIT_ASSERT_EQUAL(43U,idx);
     CPPUNIT_ASSERT_EQUAL('g',haystack[idx]);
 
     idx=haystack.rfind(SBuf("The"));
-    CPPUNIT_ASSERT_EQUAL(0,idx);
+    CPPUNIT_ASSERT_EQUAL(0U,idx);
 
     haystack.append("The");
     idx=haystack.rfind(SBuf("The"));
-    CPPUNIT_ASSERT_EQUAL(44,idx);
+    CPPUNIT_ASSERT_EQUAL(44U,idx);
 
     //partial match
     haystack="The quick brown fox";
@@ -690,23 +769,25 @@ testSBuf::testScanf()
     CPPUNIT_ASSERT_EQUAL(static_cast<float>(123.5),f);
 }
 
-void testSBuf::testCopy()
+void
+testSBuf::testCopy()
 {
     char buf[40]; //shorter than literal()
     SBuf s(fox1),s2;
     CPPUNIT_ASSERT_EQUAL(s.length(),s.copy(buf,40));
     CPPUNIT_ASSERT_EQUAL(0,strncmp(s.rawContent(),buf,s.length()));
     s=literal;
-    CPPUNIT_ASSERT_EQUAL(40,s.copy(buf,40));
+    CPPUNIT_ASSERT_EQUAL(40U,s.copy(buf,40));
     s2.assign(buf,40);
     s.chop(0,40);
     CPPUNIT_ASSERT_EQUAL(s2,s);
 }
 
-void testSBuf::testStringOps()
+void
+testSBuf::testStringOps()
 {
-    SBuf sng(literal.toLower()),
-    ref("the quick brown fox jumped over the lazy dog");
+    SBuf sng(ToLower(literal)),
+         ref("the quick brown fox jumped over the lazy dog");
     CPPUNIT_ASSERT_EQUAL(ref,sng);
     sng=literal;
     CPPUNIT_ASSERT_EQUAL(0,sng.compare(ref,caseInsensitive));
@@ -716,7 +797,8 @@ void testSBuf::testStringOps()
     CPPUNIT_ASSERT_EQUAL(0,SBuf("the").compare(SBuf("THE"),caseInsensitive,6));
 }
 
-void testSBuf::testGrow()
+void
+testSBuf::testGrow()
 {
     SBuf t;
     t.assign("foo");
@@ -730,7 +812,8 @@ void testSBuf::testGrow()
     CPPUNIT_ASSERT_EQUAL(ref,match);
 }
 
-void testSBuf::testStartsWith()
+void
+testSBuf::testStartsWith()
 {
     static SBuf casebuf("THE QUICK");
     CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1)));
@@ -739,14 +822,15 @@ void testSBuf::testStartsWith()
 
     // case-insensitive checks
     CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
-    casebuf=SBuf(fox1).toUpper();
+    casebuf=ToUpper(SBuf(fox1));
     CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
     CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1),caseInsensitive));
     casebuf = "tha quick";
     CPPUNIT_ASSERT_EQUAL(false,literal.startsWith(casebuf,caseInsensitive));
 }
 
-void testSBuf::testSBufStream()
+void
+testSBuf::testSBufStream()
 {
     SBuf b("const.string, int 10 and a float 10.5");
     SBufStream ss;
@@ -763,38 +847,130 @@ void testSBuf::testSBufStream()
     CPPUNIT_ASSERT_EQUAL(f1,SBuf(fox1));
 }
 
-void testSBuf::testFindFirstOf()
+void
+testSBuf::testFindFirstOf()
 {
     SBuf haystack(literal);
     SBuf::size_type idx;
 
     // not found
-    idx=haystack.find_first_of(SBuf("ADHRWYP"));
+    idx=haystack.findFirstOf(CharacterSet("t1","ADHRWYP"));
     CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
 
     // found at beginning
-    idx=haystack.find_first_of(SBuf("THANDF"));
-    CPPUNIT_ASSERT_EQUAL(0,idx);
+    idx=haystack.findFirstOf(CharacterSet("t2","THANDF"));
+    CPPUNIT_ASSERT_EQUAL(0U,idx);
 
     //found at end of haystack
-    idx=haystack.find_first_of(SBuf("QWERYVg"));
+    idx=haystack.findFirstOf(CharacterSet("t3","QWERYVg"));
     CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx);
 
     //found in the middle of haystack
-    idx=haystack.find_first_of(SBuf("QWERqYV"));
-    CPPUNIT_ASSERT_EQUAL(4,idx);
+    idx=haystack.findFirstOf(CharacterSet("t4","QWERqYV"));
+    CPPUNIT_ASSERT_EQUAL(4U,idx);
 }
 
-void testSBuf::testAutoFind()
+void
+testSBuf::testFindFirstNotOf()
+{
+    SBuf haystack(literal);
+    SBuf::size_type idx;
+
+    // all chars from the set
+    idx=haystack.findFirstNotOf(CharacterSet("t1",literal.c_str()));
+    CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
+
+    // found at beginning
+    idx=haystack.findFirstNotOf(CharacterSet("t2","a"));
+    CPPUNIT_ASSERT_EQUAL(0U,idx);
+
+    //found at end of haystack
+    idx=haystack.findFirstNotOf(CharacterSet("t3",literal.substr(0,literal.length()-1).c_str()));
+    CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx);
+
+    //found in the middle of haystack
+    idx=haystack.findFirstNotOf(CharacterSet("t4","The"));
+    CPPUNIT_ASSERT_EQUAL(3U,idx);
+}
+
+void
+testSBuf::testAutoFind()
 {
     SBufFindTest test;
     test.run();
 }
 
-void testSBuf::testStdStringOps()
+void
+testSBuf::testStdStringOps()
 {
     const char *alphabet="abcdefghijklmnopqrstuvwxyz";
     std::string astr(alphabet);
     SBuf sb(alphabet);
     CPPUNIT_ASSERT_EQUAL(astr,sb.toStdString());
 }
+
+void
+testSBuf::testIterators()
+{
+    SBuf text("foo"), text2("foo");
+    CPPUNIT_ASSERT(text.begin() == text.begin());
+    CPPUNIT_ASSERT(text.begin() != text.end());
+    CPPUNIT_ASSERT(text.begin() != text2.begin());
+    {
+        auto i = text.begin();
+        auto e = text.end();
+        CPPUNIT_ASSERT_EQUAL('f', *i);
+        CPPUNIT_ASSERT(i != e);
+        ++i;
+        CPPUNIT_ASSERT_EQUAL('o', *i);
+        CPPUNIT_ASSERT(i != e);
+        ++i;
+        CPPUNIT_ASSERT_EQUAL('o', *i);
+        CPPUNIT_ASSERT(i != e);
+        ++i;
+        CPPUNIT_ASSERT(i == e);
+    }
+    {
+        auto i = text.rbegin();
+        auto e = text.rend();
+        CPPUNIT_ASSERT_EQUAL('o', *i);
+        CPPUNIT_ASSERT(i != e);
+        ++i;
+        CPPUNIT_ASSERT_EQUAL('o', *i);
+        CPPUNIT_ASSERT(i != e);
+        ++i;
+        CPPUNIT_ASSERT_EQUAL('f', *i);
+        CPPUNIT_ASSERT(i != e);
+        ++i;
+        CPPUNIT_ASSERT(i == e);
+    }
+}
+
+void
+testSBuf::testSBufHash()
+{
+    // same SBuf must have same hash
+    auto hasher=std::hash<SBuf>();
+    CPPUNIT_ASSERT_EQUAL(hasher(literal),hasher(literal));
+
+    // same content must have same hash
+    CPPUNIT_ASSERT_EQUAL(hasher(literal),hasher(SBuf(fox)));
+    CPPUNIT_ASSERT_EQUAL(hasher(SBuf(fox)),hasher(SBuf(fox)));
+
+    //differen content should have different hash
+    CPPUNIT_ASSERT(hasher(SBuf(fox)) != hasher(SBuf(fox1)));
+
+    {
+        std::unordered_map<SBuf, int> um;
+        um[SBuf("one")] = 1;
+        um[SBuf("two")] = 2;
+
+        auto i = um.find(SBuf("one"));
+        CPPUNIT_ASSERT(i != um.end());
+        CPPUNIT_ASSERT(i->second == 1);
+
+        i = um.find(SBuf("eleventy"));
+        CPPUNIT_ASSERT(i == um.end());
+    }
+}
+