git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 08/13] t/helper: add zlib test-tool

From
Jeff King <peff@peff.net>
Date
May 16, 2025, 04:49 UTC
Message-ID
<20250516044959.GH22242@coredump.intra.peff.net>
In-Reply-To
<20250516044916.GA21985@coredump.intra.peff.net>

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>
---
 Makefile             |  1 +
 t/helper/meson.build |  1 +
 t/helper/test-tool.c |  1 +
 t/helper/test-tool.h |  1 +
 t/helper/test-zlib.c | 62 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+)
 create mode 100644 t/helper/test-zlib.c
diff --git a/Makefile b/Makefile
index de73c6ddcd..14616ff625 100644
--- 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.
diff --git a/t/helper/meson.build b/t/helper/meson.build
index d4e8b26df8..675e64c010 100644
--- a/t/helper/meson.build
+++ b/t/helper/meson.build
@@ -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',
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 74812ed86d..a7abc618b3 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -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)
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 2571a3ccfe..7f150fa1eb 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -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
index 0000000000..de7e9edee1
--- /dev/null
+++ b/t/helper/test-zlib.c
@@ -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;
+}
-- 
2.49.0.896.g93578ceaaf
Previous: Junio C HamanoNext: Junio C Hamano
Message 18 of 35 in “dropping support for non-standard object types”
  1. 0/13 dropping support for non-standard object typesJeff King, May 16, 2025
  2. 01/13 object-file.h: fix typo in variable declarationJeff King, May 16, 2025
  3. 02/13 cat-file: make --allow-unknown-type a noopJeff King, May 16, 2025
  4. Patrick SteinhardtMay 16, 2025
  5. Jeff KingMay 19, 2025
  6. Patrick SteinhardtMay 19, 2025
  7. Junio C HamanoMay 16, 2025
  8. 03/13 object-file: drop OBJECT_INFO_ALLOW_UNKNOWN_TYPE flagJeff King, May 16, 2025
  9. 04/13 cat-file: use type enum instead of buffer for -t optionJeff King, May 16, 2025
  10. Junio C HamanoMay 16, 2025
  11. 05/13 oid_object_info_convert(): stop using string for object typeJeff King, May 16, 2025
  12. 06/13 fsck: stop using object_info->type_name strbufJeff King, May 16, 2025
  13. Patrick SteinhardtMay 16, 2025
  14. Junio C HamanoMay 19, 2025
  15. Jeff KingMay 19, 2025
  16. 07/13 oid_object_info(): drop type_name strbufJeff King, May 16, 2025
  17. Junio C HamanoMay 19, 2025
  18. 08/13 t/helper: add zlib test-toolJeff King, May 16, 2025
  19. Junio C HamanoMay 19, 2025
  20. Jeff KingMay 19, 2025
  21. Junio C HamanoMay 21, 2025
  22. 09/13 t: add lib-loose.shJeff King, May 16, 2025
  23. Patrick SteinhardtMay 16, 2025
  24. Jeff KingMay 19, 2025
  25. Junio C HamanoMay 19, 2025
  26. 10/13 hash-object: stop allowing unknown typesJeff King, May 16, 2025
  27. Junio C HamanoMay 19, 2025
  28. 11/13 hash-object: merge HASH_* and INDEX_* flagsJeff King, May 16, 2025
  29. Patrick SteinhardtMay 16, 2025
  30. 12/13 hash-object: handle --literally with OPT_NEGBITJeff King, May 16, 2025
  31. Junio C HamanoMay 19, 2025
  32. 13/13 object-file: drop support for writing objects with unknown typesJeff King, May 16, 2025
  33. Patrick SteinhardtMay 16, 2025
  34. Junio C HamanoMay 19, 2025
  35. Junio C HamanoMay 16, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.