]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Merge from trunk
authorAmos Jeffries <squid3@treenet.co.nz>
Sun, 2 Jun 2013 15:43:09 +0000 (09:43 -0600)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 2 Jun 2013 15:43:09 +0000 (09:43 -0600)
1  2 
src/Makefile.am
src/tests/testSBuf.cc

diff --cc src/Makefile.am
index 2a5a5a95d65579b9d99cdf0a0fe8d3d6ce0d849f,8d1eac4011db2741b6c901e034b05d7982e096bd..61efca41177d428510742c7f76469fe907611100
@@@ -1093,9 -1089,9 +1094,10 @@@ check_PROGRAMS+=
        tests/testStore \
        tests/testString \
        tests/testURL \
 +      tests/testSBuf \
        tests/testConfigParser \
        tests/testStatHist \
+       tests/testVector \
        $(STORE_TESTS)
  
  ## NP: required to run the above list. check_PROGRAMS only builds the binaries...
index 09635580ef2ec9b99a2c59c9559a861bb5deee7e,0000000000000000000000000000000000000000..a70534c68abae67b03665940644673dfe4157f7d
mode 100644,000000..100644
--- /dev/null
@@@ -1,763 -1,0 +1,763 @@@
-         CPPUNIT_ASSERT_EQUAL(s1.length(),strlen(fox));
 +#include "squid.h"
 +#include "Mem.h"
 +#include "SBuf.h"
 +#include "SBufStream.h"
 +#include "SquidString.h"
 +#include "testSBuf.h"
 +#include "SBufFindTest.h"
 +
 +#include <iostream>
 +#include <stdexcept>
 +
 +CPPUNIT_TEST_SUITE_REGISTRATION( testSBuf );
 +
 +/* let this test link sanely */
 +#include "event.h"
 +#include "MemObject.h"
 +void
 +eventAdd(const char *name, EVH * func, void *arg, double when, int, bool cbdata)
 +{}
 +int64_t
 +MemObject::endOffset() const
 +{ return 0; }
 +/* end of stubs */
 +
 +// test string
 +static char fox[]="The quick brown fox jumped over the lazy dog";
 +static char fox1[]="The quick brown fox ";
 +static char fox2[]="jumped over the lazy dog";
 +
 +// TEST: globals variables (default/empty and with contents) are
 +//  created outside and before any unit tests and memory subsystem
 +//  initialization. Check for correct constructor operation.
 +SBuf empty_sbuf;
 +SBuf literal("The quick brown fox jumped over the lazy dog");
 +
 +void
 +testSBuf::testSBufConstructDestruct()
 +{
 +    /* NOTE: Do not initialize memory here because we need
 +     * to test correct operation before and after Mem::Init
 +     */
 +
 +    // XXX: partial demo below of how to do constructor unit-test. use scope to ensure each test
 +    // is working on local-scope variables constructed fresh for the test, and destructed when
 +    // scope exists. use nested scopes to test destructor affects on copied data (MemBlob etc)
 +
 +    // TEST: default constructor (implicit destructor non-crash test)
 +    //  test accessors on empty SBuf.
 +    {
 +        SBuf s1;
 +        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
 +        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
 +        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
 +        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
 +    }
 +
 +    // TEST: copy-construct NULL string (implicit destructor non-crash test)
 +    {
 +        SBuf s1(NULL);
 +        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
 +        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
 +        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
 +        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
 +    }
 +
 +    // TEST: copy-construct empty string (implicit destructor non-crash test)
 +    {
 +        SBuf s1("");
 +        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
 +        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
 +        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
 +        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
 +    }
 +
 +    // TEST: copy-construct from a char*
 +    {
 +        SBuf s1(fox);
++        CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(s1.length()),strlen(fox));
 +        CPPUNIT_ASSERT(0==strcmp(fox,s1.c_str()));
 +    }
 +
 +    // TEST: copy-construct from a SBuf
 +    {
 +        SBuf s1(empty_sbuf);
 +        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
 +        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
 +        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
 +        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
 +
 +        SBuf s5(literal);
 +        CPPUNIT_ASSERT_EQUAL(s5,literal);
 +        SBuf s6(fox);
 +        CPPUNIT_ASSERT_EQUAL(s6,literal);
 +        // XXX: other state checks. expected result of calling any state accessor on s4 ?
 +    }
 +
 +    // TEST: check that COW doesn't happen upon copy-construction
 +    {
 +        SBuf s1(empty_sbuf), s2(s1);
 +        CPPUNIT_ASSERT_EQUAL(s1.rawContent(), s2.rawContent());
 +        SBuf s3(literal), s4(literal);
 +        CPPUNIT_ASSERT_EQUAL(s3.rawContent(), s4.rawContent());
 +    }
 +
 +    // TEST: sub-string copy
 +    {
 +        SBuf s1=SBuf(fox,4), s2(fox);
 +        SBuf s3=s2.substr(4,s2.length()); //n is out-of-bounds
 +        CPPUNIT_ASSERT_EQUAL(s1,s3);
 +        SBuf s4=SBuf(fox,0,4);
 +        s3=s2.substr(0,4);
 +        CPPUNIT_ASSERT_EQUAL(s4,s3);
 +    }
 +
 +    // TEST: go via SquidString adapters.
 +    {
 +        String str(fox);
 +        SBuf s1(str);
 +        CPPUNIT_ASSERT_EQUAL(s1,literal);
 +    }
 +
 +    // TEST: go via std::string adapter.
 +    {
 +        std::string str(fox);
 +        SBuf s1(str);
 +        CPPUNIT_ASSERT_EQUAL(s1,literal);
 +    }
 +
 +}
 +
 +void
 +testSBuf::testSBufConstructDestructAfterMemInit()
 +{
 +    Mem::Init();
 +    testSBufConstructDestruct();
 +
 +}
 +
 +void
 +testSBuf::testEqualityTest()
 +{
 +    SBuf s1(fox),s2(fox);
 +    CPPUNIT_ASSERT_EQUAL(s1,s1); //self-equality
 +    CPPUNIT_ASSERT_EQUAL(s1,s2); //same contents
 +    s2.assign("The quick brown fox jumped over the lazy doe");
 +    CPPUNIT_ASSERT(!(s1 == s2)); //same length, different contents
 +    s2.assign("foo");
 +    CPPUNIT_ASSERT(!(s1 == s2)); //different length and contents
 +    CPPUNIT_ASSERT(s1 != s2);    //while we're ready, let's test inequality
 +    s2.clear();
 +    CPPUNIT_ASSERT(!(s1 == s2)); //null and not-null
 +    CPPUNIT_ASSERT(s1 != s2);    //while we're ready, let's test inequality
 +    s1.clear();
 +    CPPUNIT_ASSERT_EQUAL(s1,s2); //null and null
 +}
 +
 +void
 +testSBuf::testAppendSBuf()
 +{
 +    SBuf s1(fox1),s2(fox2);
 +    s1.append(s2);
 +    CPPUNIT_ASSERT_EQUAL(s1,literal);
 +}
 +
 +void
 +testSBuf::testPrintf()
 +{
 +    SBuf s1,s2;
 +    s1.Printf("%s:%d:%03.3f","fox",10,12345.67);
 +    s2.assign("fox:10:12345.670");
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +}
 +
 +void
 +testSBuf::testAppendCString()
 +{
 +    SBuf s1(fox1);
 +    s1.append(fox2);
 +    CPPUNIT_ASSERT_EQUAL(s1,literal);
 +}
 +
 +void
 +testSBuf::testAppendStdString()
 +{
 +    SBuf s1(fox1);
 +    std::string str(fox2);
 +    s1.append(str);
 +    CPPUNIT_ASSERT_EQUAL(s1,literal);
 +}
 +
 +void
 +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);
 +}
 +
 +void
 +testSBuf::testDumpStats()
 +{
 +    SBuf::GetStats().dump(std::cout);
 +    MemBlob::GetStats().dump(std::cout);
 +    std::cout << "sizeof(SBuf): " << sizeof(SBuf) << std::endl;
 +    std::cout << "sizeof(MemBlob): " << sizeof(MemBlob) << std::endl;
 +}
 +
 +void
 +testSBuf::testSubscriptOp()
 +{
 +    SBuf chg(literal);
 +    CPPUNIT_ASSERT_EQUAL(chg[5],'u');
 +    chg.setAt(5,'e');
 +    CPPUNIT_ASSERT_EQUAL(literal[5],'u');
 +    CPPUNIT_ASSERT_EQUAL(chg[5],'e');
 +}
 +
 +// note: can't use cppunit's CPPUNIT_TEST_EXCEPTION because TextException asserts, and
 +// so the test can't be properly completed.
 +void
 +testSBuf::testSubscriptOpFail()
 +{
 +    char c;
 +    c=literal.at(literal.length()); //out of bounds by 1
 +    //notreached
 +    std::cout << c << std::endl;
 +}
 +
 +static int sign(int v)
 +{
 +    if (v < 0)
 +        return -1;
 +    if (v>0)
 +        return 1;
 +    return 0;
 +}
 +
 +void
 +testSBuf::testComparisons()
 +{
 +    //same length
 +    SBuf s1("foo"),s2("foe");
 +    CPPUNIT_ASSERT(s1.compare(s2)>0);
 +    CPPUNIT_ASSERT(s1.compare(s2,caseInsensitive,2)==0);
 +    CPPUNIT_ASSERT(s1 > s2);
 +    CPPUNIT_ASSERT(s2 < s1);
 +    CPPUNIT_ASSERT_EQUAL(sign(s1.compare(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
 +    //different lengths
 +    s1.assign("foo");
 +    s2.assign("foof");
 +    CPPUNIT_ASSERT(s1.compare(s2)<0);
 +    CPPUNIT_ASSERT_EQUAL(sign(s1.compare(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
 +    CPPUNIT_ASSERT(s1 < s2);
 +}
 +
 +void
 +testSBuf::testConsume()
 +{
 +    SBuf s1(literal),s2,s3;
 +    s2=s1.consume(4);
 +    s3.assign("The ");
 +    CPPUNIT_ASSERT_EQUAL(s2,s3);
 +    s3.assign("quick brown fox jumped over the lazy dog");
 +    CPPUNIT_ASSERT_EQUAL(s1,s3);
 +    s1.consume(40);
 +    CPPUNIT_ASSERT_EQUAL(s1,SBuf());
 +}
 +
 +void
 +testSBuf::testRawContent()
 +{
 +    SBuf s1(literal);
 +    SBuf s2(s1);
 +    s2.append("foo");
 +    const char *foo;
 +    foo = s1.rawContent();
 +    CPPUNIT_ASSERT(strncmp(fox,foo,s1.length())==0);
 +    foo = s1.c_str();
 +    CPPUNIT_ASSERT(!strcmp(fox,foo));
 +}
 +
 +void
 +testSBuf::testRawSpace()
 +{
 +    SBuf s1(literal);
 +    SBuf s2(fox1);
 +    SBuf::size_type sz=s2.length();
 +    char *rb=s2.rawSpace(strlen(fox2)+1);
 +    strcpy(rb,fox2);
 +    s2.forceSize(sz+strlen(fox2));
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +}
 +
 +void
 +testSBuf::testChop()
 +{
 +    SBuf s1(literal),s2;
 +    s1.chop(4,5);
 +    s2.assign("quick");
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +    s1=literal;
 +    s2.clear();
 +    s1.chop(5,0);
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +    const char *alphabet="abcdefghijklmnopqrstuvwxyz";
 +    SBuf a(alphabet);
 +    std::string s(alphabet); // TODO
 +    { //regular chopping
 +        SBuf b(a);
 +        b.chop(3,3);
 +        SBuf ref("def");
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +    { // chop at end
 +        SBuf b(a);
 +        b.chop(b.length()-3);
 +        SBuf ref("xyz");
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +    { // chop at beginning
 +        SBuf b(a);
 +        b.chop(0,3);
 +        SBuf ref("abc");
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +    { // chop to zero length
 +        SBuf b(a);
 +        b.chop(5,0);
 +        SBuf ref("");
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +    { // chop beyond end (at npos)
 +        SBuf b(a);
 +        b.chop(SBuf::npos,4);
 +        SBuf ref("");
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +    { // chop beyond end
 +        SBuf b(a);
 +        b.chop(b.length()+2,4);
 +        SBuf ref("");
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +    { // null-chop
 +        SBuf b(a);
 +        b.chop(0,b.length());
 +        SBuf ref(a);
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +    { // overflow chopped area
 +        SBuf b(a);
 +        b.chop(b.length()-3,b.length());
 +        SBuf ref("xyz");
 +        CPPUNIT_ASSERT_EQUAL(ref,b);
 +    }
 +}
 +
 +void
 +testSBuf::testChomp()
 +{
 +    SBuf s1("complete string");
 +    SBuf s2(s1);
 +    s2.trim(SBuf(" ,"));
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +    s2.assign(" complete string ,");
 +    s2.trim(SBuf(" ,"));
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +    s1.assign(", complete string ,");
 +    s2=s1;
 +    s2.trim(SBuf(" "));
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +}
 +
 +// inspired to SBufFindTest; to be expanded.
 +class SBufSubstrAutoTest
 +{
 +    SBuf fullString, sb;
 +    std::string fullReference, str;
 +public:
 +    void performEqualityTest() {
 +        SBuf ref(str);
 +        CPPUNIT_ASSERT_EQUAL(ref,sb);
 +    }
 +    SBufSubstrAutoTest() : fullString(fox), fullReference(fox) {
 +        for (int offset=fullString.length()-1; offset >= 0; --offset ) {
 +            for (int length=fullString.length()-1-offset; length >= 0; --length) {
 +                sb=fullString.substr(offset,length);
 +                str=fullReference.substr(offset,length);
 +                performEqualityTest();
 +            }
 +        }
 +    }
 +};
 +
 +void
 +testSBuf::testSubstr()
 +{
 +    SBuf s1(literal),s2,s3;
 +    s2=s1.substr(4,5);
 +    s3.assign("quick");
 +    CPPUNIT_ASSERT_EQUAL(s2,s3);
 +    s1.chop(4,5);
 +    CPPUNIT_ASSERT_EQUAL(s1,s2);
 +    SBufSubstrAutoTest sat; // work done in the constructor
 +}
 +
 +void
 +testSBuf::testFindChar()
 +{
 +    const char *alphabet="abcdefghijklmnopqrstuvwxyz";
 +    SBuf s1(alphabet);
 +    SBuf::size_type idx;
 +    SBuf::size_type nposResult=SBuf::npos;
 +
 +    // FORWARD SEARCH
 +    // needle in haystack
 +    idx=s1.find('d');
 +    CPPUNIT_ASSERT(idx == 3);
 +    CPPUNIT_ASSERT(s1[idx]=='d');
 +
 +    // needle not present in haystack
 +    idx=s1.find(' '); //fails
 +    CPPUNIT_ASSERT_EQUAL(nposResult,idx);
 +
 +    // search in portion
 +    idx=s1.find('e',3);
 +    CPPUNIT_ASSERT_EQUAL(4,idx);
 +
 +    // char not in searched portion
 +    idx=s1.find('e',5);
 +    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);
 +
 +    // REVERSE SEARCH
 +    // needle in haystack
 +    idx=s1.rfind('d');
 +    CPPUNIT_ASSERT_EQUAL(3, idx);
 +    CPPUNIT_ASSERT_EQUAL('d', s1[idx]);
 +
 +    // needle not present in haystack
 +    idx=s1.rfind(' '); //fails
 +    CPPUNIT_ASSERT_EQUAL(nposResult,idx);
 +
 +    // search in portion
 +    idx=s1.rfind('e',5);
 +    CPPUNIT_ASSERT_EQUAL(4,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);
 +}
 +
 +void
 +testSBuf::testFindSBuf()
 +{
 +    const char *alphabet="abcdefghijklmnopqrstuvwxyz";
 +    SBuf haystack(alphabet);
 +    SBuf::size_type idx;
 +    SBuf::size_type nposResult=SBuf::npos;
 +
 +    // FORWARD search
 +    // needle in haystack
 +    idx = haystack.find(SBuf("def"));
 +    CPPUNIT_ASSERT_EQUAL(3,idx);
 +
 +    idx = haystack.find(SBuf("xyz"));
 +    CPPUNIT_ASSERT_EQUAL(23,idx);
 +
 +    // needle not in haystack, no initial char match
 +    idx = haystack.find(SBuf(" eq"));
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // needle not in haystack, initial sequence match
 +    idx = haystack.find(SBuf("deg"));
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // needle past end of haystack
 +    idx = haystack.find(SBuf("xyz1"));
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // search in portion: needle not in searched part
 +    idx = haystack.find(SBuf("def"),7);
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // search in portion: overhang
 +    idx = haystack.find(SBuf("def"),4);
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // invalid start position
 +    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);
 +
 +    // search in a double-matching haystack
 +    {
 +        SBuf h2=haystack;
 +        h2.append(haystack);
 +
 +        idx = h2.find(SBuf("def"));
 +        CPPUNIT_ASSERT_EQUAL(3,idx);
 +
 +        idx = h2.find(SBuf("xyzab"));
 +        CPPUNIT_ASSERT_EQUAL(23,idx);
 +    }
 +
 +    // REVERSE search
 +    // needle in haystack
 +    idx = haystack.rfind(SBuf("def"));
 +    CPPUNIT_ASSERT_EQUAL(3,idx);
 +
 +    idx = haystack.rfind(SBuf("xyz"));
 +    CPPUNIT_ASSERT_EQUAL(23,idx);
 +
 +    // needle not in haystack, no initial char match
 +    idx = haystack.rfind(SBuf(" eq"));
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // needle not in haystack, initial sequence match
 +    idx = haystack.rfind(SBuf("deg"));
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // needle past end of haystack
 +    idx = haystack.rfind(SBuf("xyz1"));
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // search in portion: needle in searched part
 +    idx = haystack.rfind(SBuf("def"),7);
 +    CPPUNIT_ASSERT_EQUAL(3, idx);
 +
 +    // search in portion: needle not in searched part
 +    idx = haystack.rfind(SBuf("mno"),3);
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // search in portion: overhang
 +    idx = haystack.rfind(SBuf("def"),4);
 +    CPPUNIT_ASSERT_EQUAL(3, 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);
 +
 +    // needle bigger than haystack
 +    idx = SBuf("def").rfind(haystack);
 +    CPPUNIT_ASSERT_EQUAL(nposResult, idx);
 +
 +    // search in a double-matching haystack
 +    {
 +        SBuf h2=haystack;
 +        h2.append(haystack);
 +
 +        idx = h2.rfind(SBuf("def"));
 +        CPPUNIT_ASSERT_EQUAL(29,idx);
 +
 +        idx = h2.find(SBuf("xyzab"));
 +        CPPUNIT_ASSERT_EQUAL(23,idx);
 +    }
 +}
 +
 +void
 +testSBuf::testRFindChar()
 +{
 +    SBuf s1(literal);
 +    SBuf::size_type idx;
 +    idx=s1.rfind(' ');
 +    CPPUNIT_ASSERT_EQUAL(40,idx);
 +    CPPUNIT_ASSERT_EQUAL(' ',s1[idx]);
 +}
 +
 +void
 +testSBuf::testRFindSBuf()
 +{
 +    SBuf haystack(literal),afox("fox");
 +    SBuf goobar("goobar");
 +    SBuf::size_type idx;
 +
 +    // corner case: search for a zero-length SBuf
 +    idx=haystack.rfind(SBuf(""));
 +    CPPUNIT_ASSERT_EQUAL(haystack.length(),idx);
 +
 +    // corner case: search for a needle longer than the haystack
 +    idx=afox.rfind(SBuf("     "));
 +    CPPUNIT_ASSERT(idx==SBuf::npos);
 +
 +    idx=haystack.rfind(SBuf("fox"));
 +    CPPUNIT_ASSERT_EQUAL(16,idx);
 +
 +    // needle not found, no match for first char
 +    idx=goobar.rfind(SBuf("foo"));
 +    CPPUNIT_ASSERT(idx==SBuf::npos);
 +
 +    // needle not found, match for first char but no match for SBuf
 +    idx=haystack.rfind(SBuf("foe"));
 +    CPPUNIT_ASSERT(idx==SBuf::npos);
 +
 +    SBuf g("g"); //match at the last char
 +    idx=haystack.rfind(g);
 +    CPPUNIT_ASSERT_EQUAL(43,idx);
 +    CPPUNIT_ASSERT_EQUAL('g',haystack[idx]);
 +
 +    idx=haystack.rfind(SBuf("The"));
 +    CPPUNIT_ASSERT_EQUAL(0,idx);
 +
 +    haystack.append("The");
 +    idx=haystack.rfind(SBuf("The"));
 +    CPPUNIT_ASSERT_EQUAL(44,idx);
 +
 +    //partial match
 +    haystack="The quick brown fox";
 +    SBuf needle("foxy lady");
 +    idx=haystack.rfind(needle);
 +    CPPUNIT_ASSERT(idx==SBuf::npos);
 +}
 +
 +void
 +testSBuf::testSBufLength()
 +{
 +    SBuf s(fox);
 +    CPPUNIT_ASSERT((size_t)s.length()==strlen(fox));
 +}
 +
 +void
 +testSBuf::testScanf()
 +{
 +    SBuf s1;
 +    char s[128];
 +    int i;
 +    float f;
 +    int rv;
 +    s1.assign("string , 123 , 123.50");
 +    rv=s1.scanf("%s , %d , %f",s,&i,&f);
 +    CPPUNIT_ASSERT(3 == rv);
 +    CPPUNIT_ASSERT(0 == strcmp(s,"string"));
 +    CPPUNIT_ASSERT(i == 123);
 +    CPPUNIT_ASSERT(f == 123.5);
 +}
 +
 +void testSBuf::testCopy()
 +{
 +    char buf[40]; //shorter than literal()
 +    SBuf s(fox1),s2;
 +    CPPUNIT_ASSERT(s.copy(buf,40)==s.length());
 +    CPPUNIT_ASSERT(strncmp(s.rawContent(),buf,s.length())==0);
 +    s=literal;
 +    CPPUNIT_ASSERT(s.copy(buf,40)==40);
 +    s2.assign(buf,0,40);
 +    s.chop(0,40);
 +    CPPUNIT_ASSERT(s==s2);
 +}
 +
 +void testSBuf::testStringOps()
 +{
 +    SBuf sng(literal),
 +    ref("the quick brown fox jumped over the lazy dog");
 +    sng=sng.toLower();
 +    CPPUNIT_ASSERT_EQUAL(ref,sng);
 +    sng=literal;
 +    CPPUNIT_ASSERT(0==sng.compare(ref,caseInsensitive));
 +}
 +
 +void testSBuf::testGrow()
 +{
 +    SBuf t;
 +    t.assign("foo");
 +    const char *ref=t.rawContent();
 +    t.reserveCapacity(10240);
 +    const char *match=t.rawContent();
 +    CPPUNIT_ASSERT(match!=ref);
 +    ref=match;
 +    t.append(literal).append(literal).append(literal).append(literal).append(literal);
 +    t.append(t).append(t).append(t).append(t).append(t);
 +    CPPUNIT_ASSERT(match==ref);
 +}
 +
 +void testSBuf::testStartsWith()
 +{
 +    static SBuf casebuf("THE QUICK");
 +    CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1)));
 +    CPPUNIT_ASSERT(!SBuf("The quick brown").startsWith(SBuf(fox1))); //too short
 +    CPPUNIT_ASSERT(!literal.startsWith(SBuf(fox2))); //wrong contents
 +
 +    CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
 +    casebuf=SBuf(fox1).toUpper();
 +    CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
 +    CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1),caseInsensitive));
 +    casebuf = "tha quick";
 +    CPPUNIT_ASSERT(!literal.startsWith(casebuf,caseInsensitive));
 +}
 +
 +void testSBuf::testSBufStream()
 +{
 +    SBuf b("const.string, int 10 and a float 10.5");
 +    SBufStream ss;
 +    ss << "const.string, int " << 10 << " and a float " << 10.5;
 +    SBuf o=ss.buf();
 +    CPPUNIT_ASSERT_EQUAL(b,o);
 +    ss.clearBuf();
 +    o=ss.buf();
 +    CPPUNIT_ASSERT_EQUAL(SBuf(),o);
 +    SBuf f1(fox1);
 +    SBufStream ss2(f1);
 +    ss2 << fox2;
 +    CPPUNIT_ASSERT_EQUAL(ss2.buf(),literal);
 +    CPPUNIT_ASSERT_EQUAL(f1,SBuf(fox1));
 +}
 +
 +void testSBuf::testFindFirstOf()
 +{
 +    SBuf haystack(literal);
 +    SBuf::size_type idx;
 +
 +    // not found
 +    idx=haystack.find_first_of(SBuf("ADHRWYP"));
 +    CPPUNIT_ASSERT(idx==SBuf::npos);
 +
 +    // found at beginning
 +    idx=haystack.find_first_of(SBuf("THANDF"));
 +    CPPUNIT_ASSERT_EQUAL(0,idx);
 +
 +    //found at end of haystack
 +    idx=haystack.find_first_of(SBuf("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);
 +}
 +
 +void testSBuf::testAutoFind()
 +{
 +    SBufFindTest test;
 +    test.run();
 +}