Hi, 

I was bored a bit and noticed the latest zlib version contains tests in
example.c. I've cleaned up the file and added it to regress framework.
The testsuite shouldn't output anything if all is well.
I've changed the types quite a bit so someone with better understanding of C and
Zlib should review them so that they don't contain any suprises.

Timo

Index: regress/lib/Makefile
===================================================================
RCS file: /cvs/src/regress/lib/Makefile,v
retrieving revision 1.18
diff -u -u -p -r1.18 Makefile
--- regress/lib/Makefile        31 Oct 2014 14:10:55 -0000      1.18
+++ regress/lib/Makefile        26 Dec 2015 08:58:54 -0000
@@ -1,7 +1,7 @@
 #      $OpenBSD: Makefile,v 1.18 2014/10/31 14:10:55 jsing Exp $
 
 SUBDIR+= csu libc libcrypto libevent libm libpthread libskey libssl libtls \
-        libutil
+        libutil libz
 
 install:
 
Index: regress/lib/libz/Makefile
===================================================================
RCS file: regress/lib/libz/Makefile
diff -N regress/lib/libz/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/lib/libz/Makefile   26 Dec 2015 08:58:54 -0000
@@ -0,0 +1,6 @@
+PROG=zlib_testsuite
+LDADD=-lz
+
+CLEANFILES=foo.gz zlib_testsuite.o zlib_testsuite
+
+.include <bsd.regress.mk>
Index: regress/lib/libz/zlib_testsuite.c
===================================================================
RCS file: regress/lib/libz/zlib_testsuite.c
diff -N regress/lib/libz/zlib_testsuite.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/lib/libz/zlib_testsuite.c   26 Dec 2015 08:58:54 -0000
@@ -0,0 +1,542 @@
+/*
+ * zlib_testsuite.c -- regression tests for zlib compression library
+ *
+ * Copyright (C) 1995-2006, 2011 Jean-loup Gailly.
+ * Copyright (C) 2015 Timo Myyrä.
+ *
+ * based on the example.c from upstream zlib distribution but modified for
+ * better fit for regression tests.
+ *
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* $OpenBSD$ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+
+#define CHECK_ERR(err, msg) { \
+    if (err != Z_OK) { \
+        fprintf(stderr, "%s error: %d\n", msg, err); \
+        exit(1); \
+    } \
+}
+
+const char     hello[] = "hello, hello!";
+/*
+ * "hello world" would be more standard, but the repeated "hello" stresses
+ * the compression code better, sorry...
+ */
+
+const char     dictionary[] = "hello";
+unsigned long  dictId;         /* Adler32 value of the dictionary */
+
+void   test_compress(void *, size_t, void *, size_t);
+void   test_deflate(void *, size_t);
+void   test_deflate_levels(void);
+void   test_dict_deflate(void *, size_t);
+void   test_dict_inflate(void *, size_t, void *, size_t);
+void   test_flush(void *, size_t);
+void   test_gzio(const char *, void *, size_t);
+void   test_inflate(void *, size_t, void *, size_t);
+void   test_large_deflate(void *, size_t, void *, size_t);
+void   test_large_inflate(void *, size_t, void *, size_t);
+void   test_sync(void *, size_t, void *, size_t);
+
+/*
+ * Test compress() and uncompress()
+ */
+void
+test_compress(void *compr, size_t comprLen, void *uncompr, size_t uncomprLen)
+{
+       int     err;
+       size_t  len = strlen(hello) + 1;
+
+       err = compress(compr, &comprLen, (const unsigned char *)hello, len);
+       CHECK_ERR(err, "compress");
+
+       strlcpy((char *)uncompr, "garbage", sizeof(uncompr));
+
+       err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+       CHECK_ERR(err, "uncompress");
+
+       if (strcmp((char *)uncompr, hello) != 0) {
+               fprintf(stderr, "bad uncompress\n");
+               exit(1);
+       }
+}
+
+/*
+ * Test deflate() with small buffers
+ */
+void
+test_deflate(void *compr, size_t comprLen)
+{
+       z_stream        c_stream;
+       int             err;
+       size_t          len = strlen(hello) + 1;
+
+       c_stream.zalloc = NULL;
+       c_stream.zfree = NULL;
+       c_stream.opaque = NULL;
+
+       err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+       CHECK_ERR(err, "deflateInit");
+
+       c_stream.next_in = (unsigned char *)hello;
+       c_stream.next_out = compr;
+
+       while (c_stream.total_in != (off_t)len && c_stream.total_out < 
(off_t)comprLen) {
+               /* force small buffers */
+                c_stream.avail_in = c_stream.avail_out = 1;
+               err = deflate(&c_stream, Z_NO_FLUSH);
+               CHECK_ERR(err, "deflate");
+       }
+       /* Finish the stream, still forcing small buffers: */
+       for (;;) {
+               c_stream.avail_out = 1;
+               err = deflate(&c_stream, Z_FINISH);
+               if (err == Z_STREAM_END)
+                       break;
+               CHECK_ERR(err, "deflate");
+       }
+
+       err = deflateEnd(&c_stream);
+       CHECK_ERR(err, "deflateEnd");
+}
+
+void
+test_deflate_levels(void)
+{
+       z_stream        strm;
+       int             err, i;
+
+       strm.zalloc = NULL;
+       strm.zfree = NULL;
+       strm.opaque = NULL;
+
+       for (i = 0; i < 10; i++) {
+               err = deflateInit(&strm, i);
+               CHECK_ERR(err, "deflate_level");
+       }
+}
+
+/*
+ * Test read/write of .gz files
+ */
+void
+test_gzio(const char *fname, void *uncompr, size_t uncomprLen)
+{
+       int             err;
+       gzFile          file;
+       z_off_t         pos;
+       size_t          len = strlen(hello) + 1;
+
+       file = gzopen(fname, "wb");
+       if (file == NULL) {
+               fprintf(stderr, "gzopen error\n");
+               exit(1);
+       }
+       gzputc(file, 'h');
+       if (gzputs(file, "ello") != 4) {
+               fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+               exit(1);
+       }
+       if (gzprintf(file, ", %s!", "hello") != 8) {
+               fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+               exit(1);
+       }
+       gzseek(file, 1L, SEEK_CUR);     /* add one zero byte */
+       gzclose(file);
+
+       file = gzopen(fname, "rb");
+       if (file == NULL) {
+               fprintf(stderr, "gzopen error\n");
+               exit(1);
+       }
+       strlcpy((char *) uncompr, "garbage", sizeof(uncompr));
+
+       if ((size_t)gzread(file, uncompr, uncomprLen) != len) {
+               fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+               exit(1);
+       }
+       if (strcmp((char *) uncompr, hello) != 0) {
+               fprintf(stderr, "bad gzread: %s\n", (char *) uncompr);
+               exit(1);
+       }
+
+       pos = gzseek(file, -8L, SEEK_CUR);
+       if (pos != 6 || gztell(file) != pos) {
+               fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+                       (long) pos, (long) gztell(file));
+               exit(1);
+       }
+       if (gzgetc(file) != ' ') {
+               fprintf(stderr, "gzgetc error\n");
+               exit(1);
+       }
+       if (gzungetc(' ', file) != ' ') {
+               fprintf(stderr, "gzungetc error\n");
+               exit(1);
+       }
+       gzgets(file, (char *) uncompr, uncomprLen);
+       if (strlen((char *) uncompr) != 7) {    /* " hello!" */
+               fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, 
&err));
+               exit(1);
+       }
+       if (strcmp((char *) uncompr, hello + 6) != 0) {
+               fprintf(stderr, "bad gzgets after gzseek\n");
+               exit(1);
+       }
+
+       gzclose(file);
+}
+
+/*
+ * Test inflate() with small buffers
+ */
+void
+test_inflate(void *compr, size_t comprLen, void *uncompr, size_t uncomprLen)
+{
+       int             err;
+       z_stream        d_stream;
+
+       strlcpy((char *)uncompr, "garbage", sizeof(uncompr));
+
+       d_stream.zalloc = NULL;
+       d_stream.zfree = NULL;
+       d_stream.opaque = NULL;
+
+       d_stream.next_in = compr;
+       d_stream.avail_in = 0;
+       d_stream.next_out = uncompr;
+
+       err = inflateInit(&d_stream);
+       CHECK_ERR(err, "inflateInit");
+
+       while (d_stream.total_out < (off_t)uncomprLen && d_stream.total_in < 
(off_t)comprLen) {
+               d_stream.avail_in = d_stream.avail_out = 1;     /* force small 
buffers */
+               err = inflate(&d_stream, Z_NO_FLUSH);
+               if (err == Z_STREAM_END)
+                       break;
+               CHECK_ERR(err, "inflate");
+       }
+
+       err = inflateEnd(&d_stream);
+       CHECK_ERR(err, "inflateEnd");
+
+       if (strcmp((char *) uncompr, hello) != 0) {
+               fprintf(stderr, "bad inflate\n");
+               exit(1);
+       }
+}
+
+/*
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void
+test_large_deflate(void *compr, size_t comprLen, void *uncompr, size_t 
uncomprLen)
+{
+       z_stream        c_stream;
+       int             err;
+
+       c_stream.zalloc = NULL;
+       c_stream.zfree = NULL;
+       c_stream.opaque = NULL;
+
+       err = deflateInit(&c_stream, Z_BEST_SPEED);
+       CHECK_ERR(err, "deflateInit");
+
+       c_stream.next_out = compr;
+       c_stream.avail_out = comprLen;
+
+       /*
+        * At this point, uncompr is still mostly zeroes, so it should
+        * compress very well:
+        */
+       c_stream.next_in = uncompr;
+       c_stream.avail_in = uncomprLen;
+       err = deflate(&c_stream, Z_NO_FLUSH);
+       CHECK_ERR(err, "deflate");
+       if (c_stream.avail_in != 0) {
+               fprintf(stderr, "deflate not greedy\n");
+               exit(1);
+       }
+       /* Feed in already compressed data and switch to no compression: */
+       deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+       c_stream.next_in = compr;
+       c_stream.avail_in = (unsigned int)comprLen / 2;
+       err = deflate(&c_stream, Z_NO_FLUSH);
+       CHECK_ERR(err, "deflate");
+
+       /* Switch back to compressing mode: */
+       deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+       c_stream.next_in = uncompr;
+       c_stream.avail_in = (unsigned int)uncomprLen;
+       err = deflate(&c_stream, Z_NO_FLUSH);
+       CHECK_ERR(err, "deflate");
+
+       err = deflate(&c_stream, Z_FINISH);
+       if (err != Z_STREAM_END) {
+               fprintf(stderr, "deflate should report Z_STREAM_END\n");
+               exit(1);
+       }
+       err = deflateEnd(&c_stream);
+       CHECK_ERR(err, "deflateEnd");
+}
+
+/*
+ * Test inflate() with large buffers
+ */
+void
+test_large_inflate(void *compr, size_t comprLen, void *uncompr, size_t 
uncomprLen)
+{
+       int             err;
+       z_stream        d_stream;
+
+       strlcpy((char *) uncompr, "garbage", sizeof(uncompr));
+
+       d_stream.zalloc = NULL;
+       d_stream.zfree = NULL;
+       d_stream.opaque = NULL;
+
+       d_stream.next_in = compr;
+       d_stream.avail_in = comprLen;
+
+       err = inflateInit(&d_stream);
+       CHECK_ERR(err, "inflateInit");
+
+       for (;;) {
+               d_stream.next_out = uncompr;    /* discard the output */
+               d_stream.avail_out = uncomprLen;
+               err = inflate(&d_stream, Z_NO_FLUSH);
+               if (err == Z_STREAM_END)
+                       break;
+               CHECK_ERR(err, "large inflate");
+       }
+
+       err = inflateEnd(&d_stream);
+       CHECK_ERR(err, "inflateEnd");
+
+       if (d_stream.total_out != (off_t)(2 * uncomprLen + comprLen / 2)) {
+               fprintf(stderr, "bad large inflate: %lld\n", 
d_stream.total_out);
+               exit(1);
+       }
+}
+
+/*
+ * Test deflate() with full flush
+ */
+void
+test_flush(void *compr, size_t comprLen)
+{
+       z_stream        c_stream;
+       int             err;
+       size_t          len = strlen(hello) + 1;
+
+       c_stream.zalloc = NULL;
+       c_stream.zfree = NULL;
+       c_stream.opaque = NULL;
+
+       err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+       CHECK_ERR(err, "deflateInit");
+
+       c_stream.next_in = (unsigned char *)hello;
+       c_stream.next_out = compr;
+       c_stream.avail_in = 3;
+       c_stream.avail_out = comprLen;
+       err = deflate(&c_stream, Z_FULL_FLUSH);
+       CHECK_ERR(err, "deflate");
+
+       /* force an error in first compressed block */
+       ((unsigned char *) compr)[3]++;
+       c_stream.avail_in = len - 3;
+
+       err = deflate(&c_stream, Z_FINISH);
+       if (err != Z_STREAM_END) {
+               CHECK_ERR(err, "deflate");
+       }
+       err = deflateEnd(&c_stream);
+       CHECK_ERR(err, "deflateEnd");
+}
+
+/*
+ * Test inflateSync()
+ */
+void
+test_sync(void *compr, size_t comprLen, void *uncompr, size_t uncomprLen)
+{
+       int             err;
+       z_stream        d_stream;
+
+       strlcpy((char *)uncompr, "garbage", sizeof(uncompr));
+
+       d_stream.zalloc = NULL;
+       d_stream.zfree = NULL;
+       d_stream.opaque = NULL;
+
+       d_stream.next_in = compr;
+       d_stream.avail_in = 2;  /* just read the zlib header */
+
+       err = inflateInit(&d_stream);
+       CHECK_ERR(err, "inflateInit");
+
+       d_stream.next_out = uncompr;
+       d_stream.avail_out = (unsigned int)uncomprLen;
+
+       inflate(&d_stream, Z_NO_FLUSH);
+       CHECK_ERR(err, "inflate");
+
+       /* read all compressed data */
+       d_stream.avail_in = (unsigned int)comprLen - 2;
+
+       /* but skip the damaged part */
+       err = inflateSync(&d_stream);
+       CHECK_ERR(err, "inflateSync");
+
+       err = inflate(&d_stream, Z_FINISH);
+       if (err != Z_DATA_ERROR) {
+               fprintf(stderr, "inflate should report DATA_ERROR\n");
+               /* Because of incorrect adler32 */
+               exit(1);
+       }
+       err = inflateEnd(&d_stream);
+       CHECK_ERR(err, "inflateEnd");
+}
+
+/*
+ * Test deflate() with preset dictionary
+ */
+void
+test_dict_deflate(void *compr, size_t comprLen)
+{
+       z_stream        c_stream;
+       int             err;
+
+       c_stream.zalloc = NULL;
+       c_stream.zfree = NULL;
+       c_stream.opaque = NULL;
+
+       err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+       CHECK_ERR(err, "deflateInit");
+
+       err = deflateSetDictionary(&c_stream,
+             (const unsigned char *)dictionary, sizeof(dictionary));
+       CHECK_ERR(err, "deflateSetDictionary");
+
+       dictId = c_stream.adler;
+       c_stream.next_out = compr;
+       c_stream.avail_out = comprLen;
+
+       c_stream.next_in = (unsigned char *)hello;
+       c_stream.avail_in = strlen(hello) + 1;
+
+       err = deflate(&c_stream, Z_FINISH);
+       if (err != Z_STREAM_END) {
+               fprintf(stderr, "deflate should report Z_STREAM_END\n");
+               exit(1);
+       }
+       err = deflateEnd(&c_stream);
+       CHECK_ERR(err, "deflateEnd");
+}
+
+/*
+ * Test inflate() with a preset dictionary
+ */
+void
+test_dict_inflate(void *compr, size_t comprLen, void *uncompr, size_t 
uncomprLen)
+{
+       int             err;
+       z_stream        d_stream;
+
+       strlcpy((char *)uncompr, "garbage", sizeof(uncompr));
+
+       d_stream.zalloc = NULL;
+       d_stream.zfree = NULL;
+       d_stream.opaque = NULL;
+
+       d_stream.next_in = compr;
+       d_stream.avail_in = comprLen;
+
+       err = inflateInit(&d_stream);
+       CHECK_ERR(err, "inflateInit");
+
+       d_stream.next_out = uncompr;
+       d_stream.avail_out = uncomprLen;
+
+       for (;;) {
+               err = inflate(&d_stream, Z_NO_FLUSH);
+               if (err == Z_STREAM_END)
+                       break;
+               if (err == Z_NEED_DICT) {
+                       if (d_stream.adler != dictId) {
+                               fprintf(stderr, "unexpected dictionary");
+                               exit(1);
+                       }
+                       err = inflateSetDictionary(&d_stream, (const unsigned 
char *)dictionary,
+                                                  sizeof(dictionary));
+               }
+               CHECK_ERR(err, "inflate with dict");
+       }
+
+       err = inflateEnd(&d_stream);
+       CHECK_ERR(err, "inflateEnd");
+
+       if (strcmp((char *) uncompr, hello)) {
+               fprintf(stderr, "bad inflate with dict\n");
+               exit(1);
+       }
+}
+
+int
+main(int argc, char *argv[])
+{
+       void    *compr, *uncompr;
+       size_t   comprLen = 10000 * sizeof(int);
+       size_t   uncomprLen = comprLen;
+       const char*     testfile = "foo.gz";
+
+       const char *myVersion = ZLIB_VERSION;
+
+       if (zlibVersion()[0] != myVersion[0]) {
+               fprintf(stderr, "incompatible zlib version\n");
+               exit(1);
+
+       } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+               fprintf(stderr, "warning: different zlib version\n");
+       }
+
+       compr = calloc(comprLen, 1);
+       uncompr = calloc(uncomprLen, 1);
+
+       if (compr == NULL || uncompr == NULL) {
+               fprintf(stderr, "out of memory\n");
+               exit(1);
+       }
+
+       test_deflate_levels();
+
+        test_compress(compr, comprLen, uncompr, uncomprLen);
+
+       test_gzio(testfile, uncompr, uncomprLen);
+
+       test_deflate(compr, comprLen);
+       test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+       test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+       test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+       test_flush(compr, comprLen);
+       test_sync(compr, comprLen, uncompr, uncomprLen);
+       comprLen = uncomprLen;
+
+       test_dict_deflate(compr, comprLen);
+       test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+       free(compr);
+       free(uncompr);
+
+       return(0);
+}

Reply via email to