]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/tests/testSBuf.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / tests / testSBuf.cc
index 23dd6b6396434ed340d9a29951725f41e70cc143..259a05aa18429f3ae4af663414a3b3243bb421da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -8,6 +8,7 @@
 
 #include "squid.h"
 #include "base/CharacterSet.h"
+#include "HttpReply.h"
 #include "sbuf/Algorithms.h"
 #include "sbuf/SBuf.h"
 #include "sbuf/Stream.h"
@@ -25,7 +26,7 @@ CPPUNIT_TEST_SUITE_REGISTRATION( testSBuf );
 #include "event.h"
 #include "MemObject.h"
 void
-eventAdd(const char *name, EVH * func, void *arg, double when, int, bool cbdata)
+eventAdd(const char *, EVH *, void *, double, int, bool)
 {}
 int64_t
 MemObject::endOffset() const
@@ -33,9 +34,9 @@ MemObject::endOffset() const
 /* 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";
+static const char fox[] = "The quick brown fox jumped over the lazy dog";
+static const char fox1[] = "The quick brown fox ";
+static const 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
@@ -66,7 +67,7 @@ testSBuf::testSBufConstructDestruct()
 
     // TEST: copy-construct NULL string (implicit destructor non-crash test)
     {
-        SBuf s1(NULL);
+        SBuf s1(nullptr);
         CPPUNIT_ASSERT_EQUAL(0U,s1.length());
         CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
         CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
@@ -151,20 +152,22 @@ testSBuf::testEqualityTest()
 void
 testSBuf::testAppendSBuf()
 {
-    SBuf empty, s1(fox1), s2(fox2);
-    auto oldId1 = s1.getId();
-    s1.append(s2);
-    CPPUNIT_ASSERT_EQUAL(s1,literal);
+    const SBuf appendix(fox1);
+    const char * const rawAppendix = appendix.rawContent();
 
-    // SBuf docs state that InstanceId does not change
-    CPPUNIT_ASSERT_EQUAL(oldId1, s1.getId());
+    // check whether the optimization that prevents copying when append()ing to
+    // default-constructed SBuf actually works
+    SBuf s0;
+    s0.append(appendix);
+    CPPUNIT_ASSERT_EQUAL(s0.rawContent(), appendix.rawContent());
+    CPPUNIT_ASSERT_EQUAL(s0, appendix);
 
-    // append() has a shortcut for assignment-to-empty
-    // if compiler uses bitwise copy wrongly the ID would copy too
-    auto oldIdEmpty = empty.getId();
-    empty.append(s2);
-    CPPUNIT_ASSERT(empty.getId() != s2.getId());
-    CPPUNIT_ASSERT_EQUAL(oldIdEmpty, empty.getId());
+    // paranoid: check that the above code can actually detect copies
+    SBuf s1(fox1);
+    s1.append(appendix);
+    CPPUNIT_ASSERT(s1.rawContent() != appendix.rawContent());
+    CPPUNIT_ASSERT(s1 != appendix);
+    CPPUNIT_ASSERT_EQUAL(rawAppendix, appendix.rawContent());
 }
 
 void
@@ -416,10 +419,9 @@ testSBuf::testRawSpace()
 {
     SBuf s1(literal);
     SBuf s2(fox1);
-    SBuf::size_type sz=s2.length();
-    char *rb=s2.rawSpace(strlen(fox2)+1);
+    char *rb=s2.rawAppendStart(strlen(fox2)+1);
     strcpy(rb,fox2);
-    s2.forceSize(sz+strlen(fox2));
+    s2.rawAppendFinish(rb, strlen(fox2));
     CPPUNIT_ASSERT_EQUAL(s1,s2);
 }
 
@@ -811,7 +813,7 @@ void
 testSBuf::testReserve()
 {
     SBufReservationRequirements requirements;
-    // use unusual numbers to ensure we dont hit a lucky boundary situation
+    // use unusual numbers to ensure we do not hit a lucky boundary situation
     requirements.minSpace = 10;
     requirements.idealSpace = 82;
     requirements.maxCapacity = 259;
@@ -839,6 +841,106 @@ testSBuf::testReserve()
                 b.append('X');
         }
     }
+
+    // the minimal space requirement should overwrite idealSpace preferences
+    requirements.minSpace = 10;
+    for (const int delta: {-1,0,+1}) {
+        requirements.idealSpace = requirements.minSpace + delta;
+        SBuf buffer;
+        buffer.reserve(requirements);
+        CPPUNIT_ASSERT(buffer.spaceSize() >= requirements.minSpace);
+    }
+
+    // TODO: Decide whether to encapsulate the (nearly identical) code of the
+    // gap-related test cases below into a function, obscuring each case logic a
+    // little, but facilitating new test cases (and removing code duplication).
+
+    {   // reserveSpace() uses the trailing space before the front gap
+        SBuf buffer(fox);
+
+        // assure there is some trailing space
+        buffer.reserveSpace(1);
+        CPPUNIT_ASSERT(buffer.spaceSize() > 0);
+
+        // create a leading gap and (weak-)check that it was created
+        const auto gap = 1U; // the smallest gap may be the most challenging
+        CPPUNIT_ASSERT(gap < buffer.length());
+        const void *gapEnd = buffer.rawContent() + gap;
+        buffer.consume(gap);
+        CPPUNIT_ASSERT_EQUAL(gapEnd, static_cast<const void*>(buffer.rawContent()));
+
+        const auto before = SBuf::GetStats();
+        const auto beforeSpaceSize = buffer.spaceSize();
+        const void * const beforePosition = buffer.rawContent();
+        buffer.reserveSpace(beforeSpaceSize);
+        const auto after = SBuf::GetStats();
+        const void * const afterPosition = buffer.rawContent();
+        CPPUNIT_ASSERT_EQUAL(before.cowAvoided + 1, after.cowAvoided);
+        CPPUNIT_ASSERT_EQUAL(before.cowShift, after.cowShift);
+        CPPUNIT_ASSERT_EQUAL(before.cowJustAlloc, after.cowJustAlloc);
+        CPPUNIT_ASSERT_EQUAL(before.cowAllocCopy, after.cowAllocCopy);
+        CPPUNIT_ASSERT_EQUAL(beforeSpaceSize, buffer.spaceSize());
+        CPPUNIT_ASSERT_EQUAL(beforePosition, afterPosition);
+        CPPUNIT_ASSERT(strcmp(fox + gap, buffer.c_str()) == 0);
+    }
+
+    {   // reserveSpace() uses the front gap when the trailing space is not enough
+        SBuf buffer(fox);
+
+        // assure there is some trailing space to keep the test case challenging
+        buffer.reserveSpace(1);
+        CPPUNIT_ASSERT(buffer.spaceSize() > 0);
+        const void * const initialStorage = buffer.rawContent();
+
+        // create a leading gap and (weak-)check that it was created
+        const auto gap = 1U; // the smallest gap may be the most challenging
+        CPPUNIT_ASSERT(gap < buffer.length());
+        const void *gapEnd = buffer.rawContent() + gap;
+        buffer.consume(gap);
+        CPPUNIT_ASSERT_EQUAL(gapEnd, static_cast<const void*>(buffer.rawContent()));
+
+        const auto before = SBuf::GetStats();
+        const auto beforeSpaceSize = buffer.spaceSize();
+        buffer.reserveSpace(beforeSpaceSize + gap); // force (entire) gap use
+        const auto after = SBuf::GetStats();
+        const void * const afterStorage = buffer.rawContent();
+        CPPUNIT_ASSERT_EQUAL(before.cowAvoided, after.cowAvoided);
+        CPPUNIT_ASSERT_EQUAL(before.cowShift + 1, after.cowShift);
+        CPPUNIT_ASSERT_EQUAL(before.cowJustAlloc, after.cowJustAlloc);
+        CPPUNIT_ASSERT_EQUAL(before.cowAllocCopy, after.cowAllocCopy);
+        CPPUNIT_ASSERT_EQUAL(initialStorage, afterStorage);
+        CPPUNIT_ASSERT(beforeSpaceSize + gap <= buffer.spaceSize());
+        CPPUNIT_ASSERT(strcmp(fox + gap, buffer.c_str()) == 0);
+    }
+
+    {   // reserveSpace() uses the entire front gap when using the front gap
+        SBuf buffer(fox);
+
+        // assure there is some trailing space to keep the test case challenging
+        buffer.reserveSpace(1);
+        CPPUNIT_ASSERT(buffer.spaceSize() > 0);
+        const void * const initialStorage = buffer.rawContent();
+
+        // create a leading gap and (weak-)check that it was created
+        const auto gap = 2U; // the smallest extra gap may be the most challenging
+        CPPUNIT_ASSERT(gap < buffer.length());
+        const void *gapEnd = buffer.rawContent() + gap;
+        buffer.consume(gap);
+        CPPUNIT_ASSERT_EQUAL(gapEnd, static_cast<const void*>(buffer.rawContent()));
+
+        const auto before = SBuf::GetStats();
+        const auto beforeSpaceSize = buffer.spaceSize();
+        buffer.reserveSpace(beforeSpaceSize + 1); // force (minimal) gap use
+        const auto after = SBuf::GetStats();
+        const void * const afterStorage = buffer.rawContent();
+        CPPUNIT_ASSERT_EQUAL(before.cowAvoided, after.cowAvoided);
+        CPPUNIT_ASSERT_EQUAL(before.cowShift + 1, after.cowShift);
+        CPPUNIT_ASSERT_EQUAL(before.cowJustAlloc, after.cowJustAlloc);
+        CPPUNIT_ASSERT_EQUAL(before.cowAllocCopy, after.cowAllocCopy);
+        CPPUNIT_ASSERT_EQUAL(initialStorage, afterStorage);
+        CPPUNIT_ASSERT(beforeSpaceSize + gap <= buffer.spaceSize());
+        CPPUNIT_ASSERT(strcmp(fox + gap, buffer.c_str()) == 0);
+    }
 }
 
 void
@@ -986,7 +1088,7 @@ testSBuf::testSBufHash()
     CPPUNIT_ASSERT_EQUAL(hasher(literal),hasher(SBuf(fox)));
     CPPUNIT_ASSERT_EQUAL(hasher(SBuf(fox)),hasher(SBuf(fox)));
 
-    //differen content should have different hash
+    //different content should have different hash
     CPPUNIT_ASSERT(hasher(SBuf(fox)) != hasher(SBuf(fox1)));
 
     {