Skip to content

Commit f2ed511

Browse files
peffgitster
authored andcommitted
t/helper: add zlib test-tool
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 3b910d0 (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 0b1493c (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 41dfbb2 (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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d295638 commit f2ed511

File tree

5 files changed

+66
-0
lines changed

5 files changed

+66
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ TEST_BUILTINS_OBJS += test-wildmatch.o
859859
TEST_BUILTINS_OBJS += test-windows-named-pipe.o
860860
TEST_BUILTINS_OBJS += test-write-cache.o
861861
TEST_BUILTINS_OBJS += test-xml-encode.o
862+
TEST_BUILTINS_OBJS += test-zlib.o
862863

863864
# Do not add more tests here unless they have extra dependencies. Add
864865
# them in TEST_BUILTINS_OBJS above.

t/helper/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ test_tool_sources = [
7777
'test-windows-named-pipe.c',
7878
'test-write-cache.c',
7979
'test-xml-encode.c',
80+
'test-zlib.c',
8081
]
8182

8283
test_tool = executable('test-tool',

t/helper/test-tool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ static struct test_cmd cmds[] = {
9191
{ "windows-named-pipe", cmd__windows_named_pipe },
9292
#endif
9393
{ "write-cache", cmd__write_cache },
94+
{ "zlib", cmd__zlib },
9495
};
9596

9697
static NORETURN void die_usage(void)

t/helper/test-tool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ int cmd__wildmatch(int argc, const char **argv);
8484
int cmd__windows_named_pipe(int argc, const char **argv);
8585
#endif
8686
int cmd__write_cache(int argc, const char **argv);
87+
int cmd__zlib(int argc, const char **argv);
8788

8889
int cmd_hash_impl(int ac, const char **av, int algo, int unsafe);
8990

t/helper/test-zlib.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include "test-tool.h"
2+
#include "git-zlib.h"
3+
#include "strbuf.h"
4+
5+
static const char *zlib_usage = "test-tool zlib [inflate|deflate]";
6+
7+
static void do_zlib(struct git_zstream *stream,
8+
int (*zlib_func)(git_zstream *, int),
9+
int fd_in, int fd_out)
10+
{
11+
struct strbuf buf_in = STRBUF_INIT;
12+
int status = Z_OK;
13+
14+
if (strbuf_read(&buf_in, fd_in, 0) < 0)
15+
die_errno("read error");
16+
17+
stream->next_in = (unsigned char *)buf_in.buf;
18+
stream->avail_in = buf_in.len;
19+
20+
while (status == Z_OK ||
21+
(status == Z_BUF_ERROR && !stream->avail_out)) {
22+
unsigned char buf_out[4096];
23+
24+
stream->next_out = buf_out;
25+
stream->avail_out = sizeof(buf_out);
26+
27+
status = zlib_func(stream, Z_FINISH);
28+
if (write_in_full(fd_out, buf_out,
29+
sizeof(buf_out) - stream->avail_out) < 0)
30+
die_errno("write error");
31+
}
32+
33+
if (status != Z_STREAM_END)
34+
die("zlib error %d", status);
35+
36+
strbuf_release(&buf_in);
37+
}
38+
39+
int cmd__zlib(int argc, const char **argv)
40+
{
41+
git_zstream stream;
42+
43+
if (argc != 2)
44+
usage(zlib_usage);
45+
46+
memset(&stream, 0, sizeof(stream));
47+
48+
if (!strcmp(argv[1], "inflate")) {
49+
git_inflate_init(&stream);
50+
do_zlib(&stream, git_inflate, 0, 1);
51+
git_inflate_end(&stream);
52+
} else if (!strcmp(argv[1], "deflate")) {
53+
git_deflate_init(&stream, Z_DEFAULT_COMPRESSION);
54+
do_zlib(&stream, git_deflate, 0, 1);
55+
git_deflate_end(&stream);
56+
} else {
57+
error("unknown mode: %s", argv[1]);
58+
usage(zlib_usage);
59+
}
60+
61+
return 0;
62+
}

0 commit comments

Comments
 (0)