]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
Add unit tests for HIST_count_wksp 4411/head
authorArpad Panyik <Arpad.Panyik@arm.com>
Wed, 11 Jun 2025 12:19:42 +0000 (12:19 +0000)
committerArpad Panyik <Arpad.Panyik@arm.com>
Fri, 13 Jun 2025 22:55:53 +0000 (22:55 +0000)
The following tests are included:
- Empty input scenario test.
- Workspace size and alignment tests.
- Symbol out-of-range tests.
- Cover multiple input sizes, vary permitted maximum symbol
  values, and include diverse symbol distributions.

These tests verifies count table correctness, maxSymbolValuePtr
updates, and error-handling paths. It enables automated regression
of core histogram logic as well.

.github/workflows/dev-short-tests.yml
tests/cli-tests/run.py
tests/fuzzer.c

index 8e8753658f4e12b82b19097e0c0b78969a852747..31d44542f1f2c1701b790f8ec88627c3d3c16bb0 100644 (file)
@@ -435,6 +435,8 @@ jobs:
         make clean
         LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check
         LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests
+        CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check
+        CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests
 # This test is only compatible with standard libraries that support BTI (Branch Target Identification).
 # Unfortunately, the standard library provided on Ubuntu 24.04 does not have this feature enabled.
 #        make clean
index 011c8478ea5e8da3f822877cc1d44b550aa2fb8b..0addd6b1aa7285be9c18c05269c408f74f594a29 100755 (executable)
@@ -640,7 +640,7 @@ if __name__ == "__main__":
         help="Preserve the scratch directory TEST_DIR/scratch/ for debugging purposes."
     )
     parser.add_argument("--verbose", action="store_true", help="Verbose test output.")
-    parser.add_argument("--timeout", default=200, type=int, help="Test case timeout in seconds. Set to 0 to disable timeouts.")
+    parser.add_argument("--timeout", default=800, type=int, help="Test case timeout in seconds. Set to 0 to disable timeouts.")
     parser.add_argument(
         "--exec-prefix",
         default=None,
index b74460bb573f441da271ac8beaee9a72317baac5..da380aced925db77ed6bb30ade701fb645c5a9f1 100644 (file)
 /* must be included after util.h, due to ERROR macro redefinition issue on Visual Studio */
 #include "zstd_internal.h" /* ZSTD_WORKSPACETOOLARGE_MAXDURATION, ZSTD_WORKSPACETOOLARGE_FACTOR, KB, MB */
 #include "threading.h"    /* ZSTD_pthread_create, ZSTD_pthread_join */
+#include "compress/hist.h" /* HIST_count_wksp */
+
+
+/*-************************************
+*  Macros
+**************************************/
+#define COUNTOF(array)    (sizeof(array) / sizeof(*(array)))
 
 
 /*-************************************
@@ -567,6 +574,123 @@ static void test_decompressBound(unsigned tnb)
     DISPLAYLEVEL(3, "OK \n");
 }
 
+static unsigned test_histCountWksp(unsigned seed, unsigned testNb)
+{
+    static const unsigned symLowLimits[] =  {   0,  27,   0,   0,  27,  42,   0,   0, 27, 42, 27, 42 };
+    static const unsigned symHighLimits[] = { 255, 255, 210, 110,  42,  42, 210, 110, 42, 42, 42, 42 };
+    static const unsigned symMaxLimits[] =  { 255, 255, 255, 255, 255, 255, 230, 130, 99, 99, 42, 42 };
+    static const size_t inputSizes[] = { 3367, 1761, 893, 117 };
+    unsigned workspace[HIST_WKSP_SIZE_U32];
+    size_t res, i, is, il;
+
+    DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with empty source : ", testNb++);
+    {
+        /* With NULL source UBSan of older Clang could fail: applying zero offset to null pointer. */
+        static const unsigned char source[4] = { 0 };
+        unsigned count[1] = { 0 };
+        unsigned maxSym = 0;
+        res = HIST_count_wksp(count, &maxSym, source, 0, workspace, sizeof(workspace));
+        CHECK_EQ(res, 0);
+        CHECK_EQ(maxSym, 0);
+        CHECK_EQ(count[0], 0);
+    }
+    DISPLAYLEVEL(3, "OK \n");
+
+#if HIST_WKSP_SIZE_U32
+    DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with small workspace : ", testNb++);
+    {
+        unsigned count[1] = { 0 };
+        unsigned maxSym = 0;
+        res = HIST_count_wksp(count, &maxSym, NULL, 0, workspace, sizeof(workspace) - 1);
+        CHECK_EQ(res, ERROR(workSpace_tooSmall));
+        CHECK_EQ(maxSym, 0);
+        CHECK_EQ(count[0], 0);
+    }
+    DISPLAYLEVEL(3, "OK \n");
+
+    DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with wrong workspace alignment : ", testNb++);
+    {
+        unsigned count[1] = { 0 };
+        unsigned maxSym = 0;
+        res = HIST_count_wksp(count, &maxSym, NULL, 0, (unsigned*)(void*)((char*)workspace + 1), sizeof(workspace));
+        CHECK_EQ(res, ERROR(GENERIC));
+        CHECK_EQ(maxSym, 0);
+        CHECK_EQ(count[0], 0);
+    }
+    DISPLAYLEVEL(3, "OK \n");
+#endif
+
+    DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with symbol out of range, small size : ", testNb++);
+    {
+        /* For less elements HIST_count_parallel_wksp would fail. */
+        static const unsigned char source[4] = { 1, 4, 0, 2 };
+        static const unsigned expected[6] = { 0 };
+        unsigned count[6] = { 0 };
+        unsigned maxSym = 2;
+        res = HIST_count_wksp(count, &maxSym, source, sizeof(source), workspace, sizeof(workspace));
+        CHECK_EQ(res, ERROR(maxSymbolValue_tooSmall));
+        CHECK_EQ(maxSym, 2);
+        for (i = 0; i < COUNTOF(expected); ++i) CHECK_EQ(count[i], expected[i]);
+    }
+    DISPLAYLEVEL(3, "OK \n");
+
+    DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with symbol out of range, medium size : ", testNb++);
+    {
+        unsigned char source[3407];
+        unsigned count[6] = { 0 };
+        unsigned maxSym = 2;
+        for (i = 0; i < COUNTOF(source); ++i) {
+            source[i] = (48271 * (i + 1)) & 3;
+        }
+        res = HIST_count_wksp(count, &maxSym, source, sizeof(source), workspace, sizeof(workspace));
+        CHECK_EQ(res, ERROR(maxSymbolValue_tooSmall));
+        CHECK_EQ(maxSym, 2);
+        for (i = 0; i < COUNTOF(count); ++i) CHECK_EQ(count[i], 0);
+    }
+    DISPLAYLEVEL(3, "OK \n");
+
+    for (il = 0; il < COUNTOF(symMaxLimits); ++il) {
+        unsigned symMax = symMaxLimits[il];
+        unsigned symLow = symLowLimits[il];
+        unsigned symHigh = symHighLimits[il];
+        unsigned symRange = symHigh - symLow + 1;
+
+        for (is = 0; is < COUNTOF(inputSizes); ++is) {
+            unsigned char source[4000];
+            size_t inputSize = inputSizes[is];
+            assert(inputSize <= sizeof(source));
+            DISPLAYLEVEL(3, "test%3u : HIST_count_wksp test in [%u..%u], symMax: %u, inputSize: %u : ",
+                         testNb++, symLow, symHigh, symMax, (unsigned)inputSize);
+            {
+                unsigned count[260] = { 0 };
+                unsigned expected[COUNTOF(count)] = { 0 };
+                unsigned maxSym = symMax;
+                unsigned realMaxSym = symMax;
+                unsigned maxCount = 0;
+                for (i = 0; i < inputSize; ++i) {
+                    unsigned prng = (48271 * (i + seed)) % symRange + symLow;
+                    source[i] = (unsigned char)prng;
+                    ++expected[prng];
+                }
+                /* for basic buffer overwrite checks */
+                for (i = maxSym + 1; i < COUNTOF(count); ++i) expected[i] = count[i] = ~0u;
+                for (i = 0; i <= maxSym; ++i) maxCount = MAX(maxCount, expected[i]);
+                for (i = realMaxSym; i > 0; --i) {
+                    if (expected[i]) break;
+                    --realMaxSym;
+                }
+                res = HIST_count_wksp(count, &maxSym, source, inputSize, workspace, sizeof(workspace));
+                CHECK_EQ(res, maxCount);
+                CHECK_EQ(maxSym, realMaxSym);
+                for (i = 0; i < COUNTOF(expected); ++i) CHECK_EQ(count[i], expected[i]);
+            }
+            DISPLAYLEVEL(3, "OK \n");
+        }
+    }
+
+    return testNb;
+}
+
 static void test_setCParams(unsigned tnb)
 {
     ZSTD_CCtx* const cctx = ZSTD_createCCtx();
@@ -712,6 +836,8 @@ static int basicUnitTests(U32 const seed, double compressibility)
     }
     DISPLAYLEVEL(3, "OK \n");
 
+    testNb = test_histCountWksp(seed, testNb);
+
     DISPLAYLEVEL(3, "test%3u : compress %u bytes : ", testNb++, (unsigned)CNBuffSize);
     {   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
         if (cctx==NULL) goto _output_error;