Author: brane
Date: Sun Jan 18 09:08:13 2026
New Revision: 1931402

Log:
Add another test for the Adler-32 implementation. All code branches
should now be covered with tests, even if this new test is a bit
contrived.

* subversion/libsvn_subr/adler32.c
  (SVN__ADLER32_SIZE_MAX): Do not define this constant if SVN__ADLER32_STATIC
   is defined. This allows adler32-test.c to locally override the maximum
   block size.

* subversion/tests/libsvn_subr/adler32-test.c: Add a comment about sorting
   the constant arrays that contain test inputs.
  (do_random_test): Move common code from the dependent test functions
   that call to here.
  (test_magic_length, test_prime_length, test_power2_length): Rename from
   test_random_magic, test_random_prime and test_random_power2,
   respectively; and just call do_random_test.
  (local_adler32): New, defined implicitly by including adler32.c
   with a modified maximum block size.
  (test_large_size): New test case; exercises the unlikely code branch in
   our Adler-32 implementation.
  (test_funcs): Update the whole array.

Modified:
   subversion/trunk/build/generator/gen_base.py
   subversion/trunk/subversion/libsvn_subr/adler32.c
   subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c

Modified: subversion/trunk/build/generator/gen_base.py
==============================================================================
--- subversion/trunk/build/generator/gen_base.py        Sun Jan 18 08:30:14 
2026        (r1931401)
+++ subversion/trunk/build/generator/gen_base.py        Sun Jan 18 09:08:13 
2026        (r1931402)
@@ -1288,6 +1288,9 @@ class IncludeDependencyInfo:
       if os.sep.join(['libsvn_subr', 'cmdline.c']) in fname \
            and 'config_keys.inc' == include_param:
         continue # generated by GeneratorBase.write_config_keys
+      if os.sep.join(['tests', 'libsvn_subr', 'adler32-test.c']) in fname \
+           and '../../libsvn_subr/adler32.c' == include_param:
+        continue # adler32-test.c inludes the source file on purpose
       elif direct_possibility_fname in domain_fnames:
         self._upd_dep_hash(hdrs, direct_possibility_fname, type_code)
       elif (len(domain_fnames) == 1

Modified: subversion/trunk/subversion/libsvn_subr/adler32.c
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/adler32.c   Sun Jan 18 08:30:14 
2026        (r1931401)
+++ subversion/trunk/subversion/libsvn_subr/adler32.c   Sun Jan 18 09:08:13 
2026        (r1931402)
@@ -47,10 +47,17 @@ typedef z_size_t svn__adler32_size_t;
 #else
 typedef uInt svn__adler32_size_t;
 #define svn__adler32_impl adler32
-#endif
-#define SVN__ADLER32_SIZE_MAX (~(svn__adler32_size_t)0)
+#endif  /* SVN_ZLIB_HAS_ADLER32_Z */
+
 #define svn__adler32_fn(c,d,s) svn__adler32_impl((c), (const Bytef *)(d), (s))
 
+/* See adler32-test.c which invokes dark magic in order to test the
+   (len > SVN__ADLER32_SIZE_MAX) branch of the implementation. */
+#ifndef SVN__ADLER32_STATIC
+#define SVN__ADLER32_STATIC
+#define SVN__ADLER32_SIZE_MAX (~(svn__adler32_size_t)0)
+#endif
+
 /*
  * 65521 is the largest prime less than 65536.
  * "That 65521 is prime is important to avoid a possible large class of
@@ -62,7 +69,7 @@ typedef uInt svn__adler32_size_t;
  * Start with CHECKSUM and update the checksum by processing a chunk
  * of DATA sized LEN.
  */
-apr_uint32_t
+SVN__ADLER32_STATIC apr_uint32_t
 svn__adler32(apr_uint32_t checksum, const char *data, apr_off_t len)
 {
   /* Process large amounts of data in max-sized chunks.

Modified: subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c        Sun Jan 
18 08:30:14 2026        (r1931401)
+++ subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c        Sun Jan 
18 09:08:13 2026        (r1931402)
@@ -51,6 +51,8 @@ static const char *make_random_data(apr_
 }
 
 
+/* NOTE: The following constant arrays of data sizes must
+         be sorted in ascending order. */
 static const apr_off_t magic[8] = {
   0, 1, 79, 80, 81, 5551, 5552, 5553
 };
@@ -110,59 +112,86 @@ static const apr_off_t power2[66] = {
 
 
 static svn_error_t *
-do_random_test(apr_uint32_t *seed,
-               const apr_off_t lengths[],
+do_random_test(const apr_off_t lengths[],
                const apr_size_t array_size,
                apr_pool_t *pool)
 {
-  const char *data = make_random_data(seed, lengths[array_size - 1], pool);
+  apr_uint32_t seed;
+  const apr_off_t length = lengths[array_size - 1];
+  const char *data = make_random_data(&seed, length, pool);
+
+  apr_uint32_t value_from_svn;
+  uLong value_from_zlib;
   int i;
 
   for (i = 0; i < array_size; ++i)
     {
-      apr_uint32_t value_from_svn = svn__adler32(0, data, lengths[i]);
-      uLong value_from_zlib = adler32(0, (const Bytef*)data, (uInt)lengths[i]);
-      SVN_TEST_ASSERT(value_from_svn == value_from_zlib);
+      /* This will blow up if the lengths array isn't sorted. */
+      SVN_TEST_ASSERT(lengths[i] <= length);
+
+      value_from_svn = svn__adler32(0, data, lengths[i]);
+      value_from_zlib = adler32(0, (const Bytef*)data, (uInt)lengths[i]);
+      if (value_from_svn != value_from_zlib)
+        {
+          fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
+          SVN_TEST_ASSERT(value_from_svn == value_from_zlib);
+        }
     }
 
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_magic_length(apr_pool_t *pool)
+{
+  return do_random_test(magic, sizeof(magic) / sizeof(magic[0]), pool);
+}
 
 static svn_error_t *
-test_random_magic(apr_pool_t *pool)
+test_prime_length(apr_pool_t *pool)
 {
-  apr_uint32_t seed;
-  svn_error_t *err = do_random_test(&seed, magic,
-                                    sizeof(magic) / sizeof(magic[0]),
-                                    pool);
-  if (err)
-    fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
-  return err;
+  return do_random_test(prime, sizeof(prime) / sizeof(prime[0]), pool);
 }
 
 static svn_error_t *
-test_random_prime(apr_pool_t *pool)
+test_power2_length(apr_pool_t *pool)
 {
-  apr_uint32_t seed;
-  svn_error_t *err = do_random_test(&seed, prime,
-                                    sizeof(prime) / sizeof(prime[0]),
-                                    pool);
-  if (err)
-    fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
-  return err;
+  return do_random_test(power2, sizeof(power2) / sizeof(power2[0]), pool);
 }
 
+
+/* Insert a static implementation of svn__adler32() with the maximum data
+   size set low enough that we can test the rarely used large-block branch
+   of the code without allocating too many terabytes of memory. */
+#define SVN__ADLER32_STATIC static
+#define svn__adler32 local_adler32
+#define SVN__ADLER32_SIZE_MAX (256U * 256U - 1U) /* 2^16 - 1 = 0xFFFF */
+#include "../../libsvn_subr/adler32.c"
+#undef svn__adler32
+#undef SVN__ADLER32_STATIC
+
 static svn_error_t *
-test_random_power2(apr_pool_t *pool)
+test_large_size(apr_pool_t *pool)
 {
   apr_uint32_t seed;
-  svn_error_t *err = do_random_test(&seed, power2,
-                                    sizeof(power2) / sizeof(power2[0]),
-                                    pool);
-  if (err)
-    fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
-  return err;
+  const svn__adler32_size_t length = 256 * 256 * 256; /* 2^24 = 16 MiB */
+  const char *data = make_random_data(&seed, length, pool);
+
+  apr_uint32_t value_from_svn;
+  uLong value_from_zlib;
+
+  SVN_TEST_ASSERT(length > 256 * SVN__ADLER32_SIZE_MAX);
+
+  value_from_svn = local_adler32(0, data, length);
+  value_from_zlib = svn__adler32_fn(0, data, length);
+
+  if (value_from_svn != value_from_zlib)
+    {
+      fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
+      SVN_TEST_ASSERT(value_from_svn == value_from_zlib);
+    }
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -173,12 +202,14 @@ static int max_threads = 4;
 static struct svn_test_descriptor_t test_funcs[] =
   {
     SVN_TEST_NULL,
-    SVN_TEST_PASS2(test_random_magic,
-                   "adler32 random with magic length"),
-    SVN_TEST_PASS2(test_random_prime,
-                   "adler32 random with prime length"),
-    SVN_TEST_PASS2(test_random_power2,
-                   "adler32 random with 2^n length"),
+    SVN_TEST_PASS2(test_magic_length,
+                   "adler32 with magic length"),
+    SVN_TEST_PASS2(test_prime_length,
+                   "adler32 with prime length"),
+    SVN_TEST_PASS2(test_power2_length,
+                   "adler32 with 2^n length"),
+    SVN_TEST_PASS2(test_large_size,
+                   "adler32 with data size > block size"),
     SVN_TEST_NULL
   };
 

Reply via email to