]> git.ipfire.org Git - thirdparty/git.git/commitdiff
t/helper: add zlib test-tool
authorJeff King <peff@peff.net>
Fri, 16 May 2025 04:49:59 +0000 (00:49 -0400)
committerJunio C Hamano <gitster@pobox.com>
Fri, 16 May 2025 16:43:11 +0000 (09:43 -0700)
It's occasionally useful when testing or debugging to be able to do raw
zlib inflate/deflate operations (e.g., to check the bytes of a specific
loose or packed object).

Even though zlib's deflate algorithm is used by many other programs,
this is surprisingly hard to do in a portable way. E.g., gzip can do
this if you manually munge some header bytes. But the result is somewhat
arcane, and we don't assume gzip is available anyway. Likewise, pigz
will handle raw zlib, but we can't assume it is available.

So let's introduce a short test helper for just doing zlib operations.
We'll use it in subsequent patches to add some new tests, but it would
also have come in handy a few times in the past:

  - The hard-coded pack data from 3b910d0c5e (add tests for indexing
    packs with delta cycles, 2013-08-23) could probably be generated on
    the fly.

  - Likewise we could avoid the hard-coded data from 0b1493c2d4
    (git_inflate(): skip zlib_post_call() sanity check on Z_NEED_DICT,
    2025-02-25). Though note this would require support for more zlib
    options.

  - It would have helped with the debugging documented in 41dfbb2dbe
    (howto: add article on recovering a corrupted object, 2013-10-25).

I'll leave refactoring existing tests for another day, but I hope the
examples above show the general utility.

I aimed for simplicity in the code. In particular, it will read all
input into a memory buffer, rather than streaming. That makes the zlib
loops harder to get wrong (which has been a source of subtle bugs in the
past).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Makefile
t/helper/meson.build
t/helper/test-tool.c
t/helper/test-tool.h
t/helper/test-zlib.c [new file with mode: 0644]

index de73c6ddcd1e308f8818fd839904b69b7246c419..14616ff6255e58388f94bd138739ece55c652ecb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -859,6 +859,7 @@ TEST_BUILTINS_OBJS += test-wildmatch.o
 TEST_BUILTINS_OBJS += test-windows-named-pipe.o
 TEST_BUILTINS_OBJS += test-write-cache.o
 TEST_BUILTINS_OBJS += test-xml-encode.o
+TEST_BUILTINS_OBJS += test-zlib.o
 
 # Do not add more tests here unless they have extra dependencies. Add
 # them in TEST_BUILTINS_OBJS above.
index d4e8b26df8d6de7d8a485405feb563aad513f10d..675e64c0101b61c5ff880cc4c53be4897fbb94c8 100644 (file)
@@ -77,6 +77,7 @@ test_tool_sources = [
   'test-windows-named-pipe.c',
   'test-write-cache.c',
   'test-xml-encode.c',
+  'test-zlib.c',
 ]
 
 test_tool = executable('test-tool',
index 74812ed86d385af013c53b88de0b3585120ef082..a7abc618b3887eecdcc45edccd1551d7e4b1fb41 100644 (file)
@@ -91,6 +91,7 @@ static struct test_cmd cmds[] = {
        { "windows-named-pipe", cmd__windows_named_pipe },
 #endif
        { "write-cache", cmd__write_cache },
+       { "zlib", cmd__zlib },
 };
 
 static NORETURN void die_usage(void)
index 2571a3ccfe8991932de4df568bda1046af8793bf..7f150fa1eb9ad2d0103196c2c2f337701a429a9e 100644 (file)
@@ -84,6 +84,7 @@ int cmd__wildmatch(int argc, const char **argv);
 int cmd__windows_named_pipe(int argc, const char **argv);
 #endif
 int cmd__write_cache(int argc, const char **argv);
+int cmd__zlib(int argc, const char **argv);
 
 int cmd_hash_impl(int ac, const char **av, int algo, int unsafe);
 
diff --git a/t/helper/test-zlib.c b/t/helper/test-zlib.c
new file mode 100644 (file)
index 0000000..de7e9ed
--- /dev/null
@@ -0,0 +1,62 @@
+#include "test-tool.h"
+#include "git-zlib.h"
+#include "strbuf.h"
+
+static const char *zlib_usage = "test-tool zlib [inflate|deflate]";
+
+static void do_zlib(struct git_zstream *stream,
+                   int (*zlib_func)(git_zstream *, int),
+                   int fd_in, int fd_out)
+{
+       struct strbuf buf_in = STRBUF_INIT;
+       int status = Z_OK;
+
+       if (strbuf_read(&buf_in, fd_in, 0) < 0)
+               die_errno("read error");
+
+       stream->next_in = (unsigned char *)buf_in.buf;
+       stream->avail_in = buf_in.len;
+
+       while (status == Z_OK ||
+              (status == Z_BUF_ERROR && !stream->avail_out)) {
+               unsigned char buf_out[4096];
+
+               stream->next_out = buf_out;
+               stream->avail_out = sizeof(buf_out);
+
+               status = zlib_func(stream, Z_FINISH);
+               if (write_in_full(fd_out, buf_out,
+                                 sizeof(buf_out) - stream->avail_out) < 0)
+                       die_errno("write error");
+       }
+
+       if (status != Z_STREAM_END)
+               die("zlib error %d", status);
+
+       strbuf_release(&buf_in);
+}
+
+int cmd__zlib(int argc, const char **argv)
+{
+       git_zstream stream;
+
+       if (argc != 2)
+               usage(zlib_usage);
+
+       memset(&stream, 0, sizeof(stream));
+
+       if (!strcmp(argv[1], "inflate")) {
+               git_inflate_init(&stream);
+               do_zlib(&stream, git_inflate, 0, 1);
+               git_inflate_end(&stream);
+       } else if (!strcmp(argv[1], "deflate")) {
+               git_deflate_init(&stream, Z_DEFAULT_COMPRESSION);
+               do_zlib(&stream, git_deflate, 0, 1);
+               git_deflate_end(&stream);
+       } else {
+               error("unknown mode: %s", argv[1]);
+               usage(zlib_usage);
+       }
+
+       return 0;
+}