#1 Add CI tests using the standard test interface
Opened 2 years ago by sturivny. Modified 2 years ago
git://fedorapeople.org/~sturivny/zlib new_tests  into  master

Add CI tests using the standard test interface
Serhii Turivnyi • a year ago  
tests/examples-from-source-package-test/Makefile
file added
+63

@@ -0,0 +1,63 @@

+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ #

+ #   Makefile of /CoreOS/zlib/examples-from-source-package-test

+ #   Description: it compile example app in source package and run it and try to find if no regression

+ #   Author: Jan Scotka <jscotka@redhat.com>

+ #

+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ #

+ #   Copyright (c) 2011 Red Hat, Inc.

+ #

+ #   This copyrighted material is made available to anyone wishing

+ #   to use, modify, copy, or redistribute it subject to the terms

+ #   and conditions of the GNU General Public License version 2.

+ #

+ #   This program is distributed in the hope that it will be

+ #   useful, but WITHOUT ANY WARRANTY; without even the implied

+ #   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR

+ #   PURPOSE. See the GNU General Public License for more details.

+ #

+ #   You should have received a copy of the GNU General Public

+ #   License along with this program; if not, write to the Free

+ #   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,

+ #   Boston, MA 02110-1301, USA.

+ #

+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ 

+ export TEST=/CoreOS/zlib/examples-from-source-package-test

+ export TESTVERSION=1.1

+ 

+ BUILT_FILES=

+ 

+ FILES=$(METADATA) runtest.sh Makefile PURPOSE example.c gun.c

+ 

+ .PHONY: all install download clean

+ 

+ run: $(FILES) build

+ 	./runtest.sh

+ 

+ build: $(BUILT_FILES)

+ 	chmod a+x runtest.sh

+ 

+ clean:

+ 	rm -f *~ $(BUILT_FILES)

+ 

+ 

+ include /usr/share/rhts/lib/rhts-make.include

+ 

+ $(METADATA): Makefile

+ 	@echo "Owner:           Jan Scotka <jscotka@redhat.com>" > $(METADATA)

+ 	@echo "Name:            $(TEST)" >> $(METADATA)

+ 	@echo "TestVersion:     $(TESTVERSION)" >> $(METADATA)

+ 	@echo "Path:            $(TEST_DIR)" >> $(METADATA)

+ 	@echo "Description:     compile example app in source package and run it and try to find regressions" >> $(METADATA)

+ 	@echo "Type:            Sanity" >> $(METADATA)

+ 	@echo "TestTime:        10m" >> $(METADATA)

+ 	@echo "RunFor:          zlib" >> $(METADATA)

+ 	@echo "Requires:        zlib gcc zlib-devel" >> $(METADATA)

+ 	@echo "Priority:        Normal" >> $(METADATA)

+ 	@echo "License:         GPLv2" >> $(METADATA)

+ 	@echo "Confidential:    no" >> $(METADATA)

+ 	@echo "Destructive:     no" >> $(METADATA)

+ 

+ 	rhts-lint $(METADATA)

tests/examples-from-source-package-test/PURPOSE
file added
+3

@@ -0,0 +1,3 @@

+ PURPOSE of /CoreOS/zlib/examples-from-source-package-test

+ Description: compile example app in source package and run it and try to find regressions

+ Author: Jan Scotka <jscotka@redhat.com>

tests/examples-from-source-package-test/example.c
file added
+565

@@ -0,0 +1,565 @@

+ /* example.c -- usage example of the zlib compression library

+  * Copyright (C) 1995-2004 Jean-loup Gailly.

+  * For conditions of distribution and use, see copyright notice in zlib.h

+  */

+ 

+ /* @(#) $Id$ */

+ 

+ #include <stdio.h>

+ #include "zlib.h"

+ 

+ #ifdef STDC

+ #  include <string.h>

+ #  include <stdlib.h>

+ #endif

+ 

+ #if defined(VMS) || defined(RISCOS)

+ #  define TESTFILE "foo-gz"

+ #else

+ #  define TESTFILE "foo.gz"

+ #endif

+ 

+ #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";

+ uLong dictId; /* Adler32 value of the dictionary */

+ 

+ void test_compress      OF((Byte *compr, uLong comprLen,

+                             Byte *uncompr, uLong uncomprLen));

+ void test_gzio          OF((const char *fname,

+                             Byte *uncompr, uLong uncomprLen));

+ void test_deflate       OF((Byte *compr, uLong comprLen));

+ void test_inflate       OF((Byte *compr, uLong comprLen,

+                             Byte *uncompr, uLong uncomprLen));

+ void test_large_deflate OF((Byte *compr, uLong comprLen,

+                             Byte *uncompr, uLong uncomprLen));

+ void test_large_inflate OF((Byte *compr, uLong comprLen,

+                             Byte *uncompr, uLong uncomprLen));

+ void test_flush         OF((Byte *compr, uLong *comprLen));

+ void test_sync          OF((Byte *compr, uLong comprLen,

+                             Byte *uncompr, uLong uncomprLen));

+ void test_dict_deflate  OF((Byte *compr, uLong comprLen));

+ void test_dict_inflate  OF((Byte *compr, uLong comprLen,

+                             Byte *uncompr, uLong uncomprLen));

+ int  main               OF((int argc, char *argv[]));

+ 

+ /* ===========================================================================

+  * Test compress() and uncompress()

+  */

+ void test_compress(compr, comprLen, uncompr, uncomprLen)

+     Byte *compr, *uncompr;

+     uLong comprLen, uncomprLen;

+ {

+     int err;

+     uLong len = (uLong)strlen(hello)+1;

+ 

+     err = compress(compr, &comprLen, (const Bytef*)hello, len);

+     CHECK_ERR(err, "compress");

+ 

+     strcpy((char*)uncompr, "garbage");

+ 

+     err = uncompress(uncompr, &uncomprLen, compr, comprLen);

+     CHECK_ERR(err, "uncompress");

+ 

+     if (strcmp((char*)uncompr, hello)) {

+         fprintf(stderr, "bad uncompress\n");

+         exit(1);

+     } else {

+         printf("uncompress(): %s\n", (char *)uncompr);

+     }

+ }

+ 

+ /* ===========================================================================

+  * Test read/write of .gz files

+  */

+ void test_gzio(fname, uncompr, uncomprLen)

+     const char *fname; /* compressed file name */

+     Byte *uncompr;

+     uLong uncomprLen;

+ {

+ #ifdef NO_GZCOMPRESS

+     fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");

+ #else

+     int err;

+     int len = (int)strlen(hello)+1;

+     gzFile file;

+     z_off_t pos;

+ 

+     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);

+     }

+     strcpy((char*)uncompr, "garbage");

+ 

+     if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {

+         fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));

+         exit(1);

+     }

+     if (strcmp((char*)uncompr, hello)) {

+         fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);

+         exit(1);

+     } else {

+         printf("gzread(): %s\n", (char*)uncompr);

+     }

+ 

+     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, (int)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)) {

+         fprintf(stderr, "bad gzgets after gzseek\n");

+         exit(1);

+     } else {

+         printf("gzgets() after gzseek: %s\n", (char*)uncompr);

+     }

+ 

+     gzclose(file);

+ #endif

+ }

+ 

+ /* ===========================================================================

+  * Test deflate() with small buffers

+  */

+ void test_deflate(compr, comprLen)

+     Byte *compr;

+     uLong comprLen;

+ {

+     z_stream c_stream; /* compression stream */

+     int err;

+     uLong len = (uLong)strlen(hello)+1;

+ 

+     c_stream.zalloc = (alloc_func)0;

+     c_stream.zfree = (free_func)0;

+     c_stream.opaque = (voidpf)0;

+ 

+     err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);

+     CHECK_ERR(err, "deflateInit");

+ 

+     c_stream.next_in  = (Bytef*)hello;

+     c_stream.next_out = compr;

+ 

+     while (c_stream.total_in != len && c_stream.total_out < comprLen) {

+         c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */

+         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");

+ }

+ 

+ /* ===========================================================================

+  * Test inflate() with small buffers

+  */

+ void test_inflate(compr, comprLen, uncompr, uncomprLen)

+     Byte *compr, *uncompr;

+     uLong comprLen, uncomprLen;

+ {

+     int err;

+     z_stream d_stream; /* decompression stream */

+ 

+     strcpy((char*)uncompr, "garbage");

+ 

+     d_stream.zalloc = (alloc_func)0;

+     d_stream.zfree = (free_func)0;

+     d_stream.opaque = (voidpf)0;

+ 

+     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 < uncomprLen && d_stream.total_in < 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)) {

+         fprintf(stderr, "bad inflate\n");

+         exit(1);

+     } else {

+         printf("inflate(): %s\n", (char *)uncompr);

+     }

+ }

+ 

+ /* ===========================================================================

+  * Test deflate() with large buffers and dynamic change of compression level

+  */

+ void test_large_deflate(compr, comprLen, uncompr, uncomprLen)

+     Byte *compr, *uncompr;

+     uLong comprLen, uncomprLen;

+ {

+     z_stream c_stream; /* compression stream */

+     int err;

+ 

+     c_stream.zalloc = (alloc_func)0;

+     c_stream.zfree = (free_func)0;

+     c_stream.opaque = (voidpf)0;

+ 

+     err = deflateInit(&c_stream, Z_BEST_SPEED);

+     CHECK_ERR(err, "deflateInit");

+ 

+     c_stream.next_out = compr;

+     c_stream.avail_out = (uInt)comprLen;

+ 

+     /* At this point, uncompr is still mostly zeroes, so it should compress

+      * very well:

+      */

+     c_stream.next_in = uncompr;

+     c_stream.avail_in = (uInt)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 = (uInt)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 = (uInt)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(compr, comprLen, uncompr, uncomprLen)

+     Byte *compr, *uncompr;

+     uLong comprLen, uncomprLen;

+ {

+     int err;

+     z_stream d_stream; /* decompression stream */

+ 

+     strcpy((char*)uncompr, "garbage");

+ 

+     d_stream.zalloc = (alloc_func)0;

+     d_stream.zfree = (free_func)0;

+     d_stream.opaque = (voidpf)0;

+ 

+     d_stream.next_in  = compr;

+     d_stream.avail_in = (uInt)comprLen;

+ 

+     err = inflateInit(&d_stream);

+     CHECK_ERR(err, "inflateInit");

+ 

+     for (;;) {

+         d_stream.next_out = uncompr;            /* discard the output */

+         d_stream.avail_out = (uInt)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 != 2*uncomprLen + comprLen/2) {

+         fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);

+         exit(1);

+     } else {

+         printf("large_inflate(): OK\n");

+     }

+ }

+ 

+ /* ===========================================================================

+  * Test deflate() with full flush

+  */

+ void test_flush(compr, comprLen)

+     Byte *compr;

+     uLong *comprLen;

+ {

+     z_stream c_stream; /* compression stream */

+     int err;

+     uInt len = (uInt)strlen(hello)+1;

+ 

+     c_stream.zalloc = (alloc_func)0;

+     c_stream.zfree = (free_func)0;

+     c_stream.opaque = (voidpf)0;

+ 

+     err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);

+     CHECK_ERR(err, "deflateInit");

+ 

+     c_stream.next_in  = (Bytef*)hello;

+     c_stream.next_out = compr;

+     c_stream.avail_in = 3;

+     c_stream.avail_out = (uInt)*comprLen;

+     err = deflate(&c_stream, Z_FULL_FLUSH);

+     CHECK_ERR(err, "deflate");

+ 

+     compr[3]++; /* force an error in first compressed block */

+     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");

+ 

+     *comprLen = c_stream.total_out;

+ }

+ 

+ /* ===========================================================================

+  * Test inflateSync()

+  */

+ void test_sync(compr, comprLen, uncompr, uncomprLen)

+     Byte *compr, *uncompr;

+     uLong comprLen, uncomprLen;

+ {

+     int err;

+     z_stream d_stream; /* decompression stream */

+ 

+     strcpy((char*)uncompr, "garbage");

+ 

+     d_stream.zalloc = (alloc_func)0;

+     d_stream.zfree = (free_func)0;

+     d_stream.opaque = (voidpf)0;

+ 

+     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 = (uInt)uncomprLen;

+ 

+     inflate(&d_stream, Z_NO_FLUSH);

+     CHECK_ERR(err, "inflate");

+ 

+     d_stream.avail_in = (uInt)comprLen-2;   /* read all compressed data */

+     err = inflateSync(&d_stream);           /* but skip the damaged part */

+     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");

+ 

+     printf("after inflateSync(): hel%s\n", (char *)uncompr);

+ }

+ 

+ /* ===========================================================================

+  * Test deflate() with preset dictionary

+  */

+ void test_dict_deflate(compr, comprLen)

+     Byte *compr;

+     uLong comprLen;

+ {

+     z_stream c_stream; /* compression stream */

+     int err;

+ 

+     c_stream.zalloc = (alloc_func)0;

+     c_stream.zfree = (free_func)0;

+     c_stream.opaque = (voidpf)0;

+ 

+     err = deflateInit(&c_stream, Z_BEST_COMPRESSION);

+     CHECK_ERR(err, "deflateInit");

+ 

+     err = deflateSetDictionary(&c_stream,

+                                (const Bytef*)dictionary, sizeof(dictionary));

+     CHECK_ERR(err, "deflateSetDictionary");

+ 

+     dictId = c_stream.adler;

+     c_stream.next_out = compr;

+     c_stream.avail_out = (uInt)comprLen;

+ 

+     c_stream.next_in = (Bytef*)hello;

+     c_stream.avail_in = (uInt)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(compr, comprLen, uncompr, uncomprLen)

+     Byte *compr, *uncompr;

+     uLong comprLen, uncomprLen;

+ {

+     int err;

+     z_stream d_stream; /* decompression stream */

+ 

+     strcpy((char*)uncompr, "garbage");

+ 

+     d_stream.zalloc = (alloc_func)0;

+     d_stream.zfree = (free_func)0;

+     d_stream.opaque = (voidpf)0;

+ 

+     d_stream.next_in  = compr;

+     d_stream.avail_in = (uInt)comprLen;

+ 

+     err = inflateInit(&d_stream);

+     CHECK_ERR(err, "inflateInit");

+ 

+     d_stream.next_out = uncompr;

+     d_stream.avail_out = (uInt)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 Bytef*)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);

+     } else {

+         printf("inflate with dictionary: %s\n", (char *)uncompr);

+     }

+ }

+ 

+ /* ===========================================================================

+  * Usage:  example [output.gz  [input.gz]]

+  */

+ 

+ int main(argc, argv)

+     int argc;

+     char *argv[];

+ {

+     Byte *compr, *uncompr;

+     uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */

+     uLong uncomprLen = comprLen;

+     static 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");

+     }

+ 

+     printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",

+             ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());

+ 

+     compr    = (Byte*)calloc((uInt)comprLen, 1);

+     uncompr  = (Byte*)calloc((uInt)uncomprLen, 1);

+     /* compr and uncompr are cleared to avoid reading uninitialized

+      * data and to ensure that uncompr compresses well.

+      */

+     if (compr == Z_NULL || uncompr == Z_NULL) {

+         printf("out of memory\n");

+         exit(1);

+     }

+     test_compress(compr, comprLen, uncompr, uncomprLen);

+ 

+     test_gzio((argc > 1 ? argv[1] : 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;

+ }

tests/examples-from-source-package-test/gun.c
file added
+693

@@ -0,0 +1,693 @@

+ /* gun.c -- simple gunzip to give an example of the use of inflateBack()

+  * Copyright (C) 2003, 2005 Mark Adler

+  * For conditions of distribution and use, see copyright notice in zlib.h

+    Version 1.3  12 June 2005  Mark Adler */

+ 

+ /* Version history:

+    1.0  16 Feb 2003  First version for testing of inflateBack()

+    1.1  21 Feb 2005  Decompress concatenated gzip streams

+                      Remove use of "this" variable (C++ keyword)

+                      Fix return value for in()

+                      Improve allocation failure checking

+                      Add typecasting for void * structures

+                      Add -h option for command version and usage

+                      Add a bunch of comments

+    1.2  20 Mar 2005  Add Unix compress (LZW) decompression

+                      Copy file attributes from input file to output file

+    1.3  12 Jun 2005  Add casts for error messages [Oberhumer]

+  */

+ 

+ /*

+    gun [ -t ] [ name ... ]

+ 

+    decompresses the data in the named gzip files.  If no arguments are given,

+    gun will decompress from stdin to stdout.  The names must end in .gz, -gz,

+    .z, -z, _z, or .Z.  The uncompressed data will be written to a file name

+    with the suffix stripped.  On success, the original file is deleted.  On

+    failure, the output file is deleted.  For most failures, the command will

+    continue to process the remaining names on the command line.  A memory

+    allocation failure will abort the command.  If -t is specified, then the

+    listed files or stdin will be tested as gzip files for integrity (without

+    checking for a proper suffix), no output will be written, and no files

+    will be deleted.

+ 

+    Like gzip, gun allows concatenated gzip streams and will decompress them,

+    writing all of the uncompressed data to the output.  Unlike gzip, gun allows

+    an empty file on input, and will produce no error writing an empty output

+    file.

+ 

+    gun will also decompress files made by Unix compress, which uses LZW

+    compression.  These files are automatically detected by virtue of their

+    magic header bytes.  Since the end of Unix compress stream is marked by the

+    end-of-file, they cannot be concantenated.  If a Unix compress stream is

+    encountered in an input file, it is the last stream in that file.

+ 

+    Like gunzip and uncompress, the file attributes of the orignal compressed

+    file are maintained in the final uncompressed file, to the extent that the

+    user permissions allow it.

+ 

+    On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version

+    1.2.4) is on the same file, when gun is linked with zlib 1.2.2.  Also the

+    LZW decompression provided by gun is about twice as fast as the standard

+    Unix uncompress command.

+  */

+ 

+ /* external functions and related types and constants */

+ #include <stdio.h>          /* fprintf() */

+ #include <stdlib.h>         /* malloc(), free() */

+ #include <string.h>         /* strerror(), strcmp(), strlen(), memcpy() */

+ #include <errno.h>          /* errno */

+ #include <fcntl.h>          /* open() */

+ #include <unistd.h>         /* read(), write(), close(), chown(), unlink() */

+ #include <sys/types.h>

+ #include <sys/stat.h>       /* stat(), chmod() */

+ #include <utime.h>          /* utime() */

+ #include "zlib.h"           /* inflateBackInit(), inflateBack(), */

+                             /* inflateBackEnd(), crc32() */

+ 

+ /* function declaration */

+ #define local static

+ 

+ /* buffer constants */

+ #define SIZE 32768U         /* input and output buffer sizes */

+ #define PIECE 16384         /* limits i/o chunks for 16-bit int case */

+ 

+ /* structure for infback() to pass to input function in() -- it maintains the

+    input file and a buffer of size SIZE */

+ struct ind {

+     int infile;

+     unsigned char *inbuf;

+ };

+ 

+ /* Load input buffer, assumed to be empty, and return bytes loaded and a

+    pointer to them.  read() is called until the buffer is full, or until it

+    returns end-of-file or error.  Return 0 on error. */

+ local unsigned in(void *in_desc, unsigned char **buf)

+ {

+     int ret;

+     unsigned len;

+     unsigned char *next;

+     struct ind *me = (struct ind *)in_desc;

+ 

+     next = me->inbuf;

+     *buf = next;

+     len = 0;

+     do {

+         ret = PIECE;

+         if ((unsigned)ret > SIZE - len)

+             ret = (int)(SIZE - len);

+         ret = (int)read(me->infile, next, ret);

+         if (ret == -1) {

+             len = 0;

+             break;

+         }

+         next += ret;

+         len += ret;

+     } while (ret != 0 && len < SIZE);

+     return len;

+ }

+ 

+ /* structure for infback() to pass to output function out() -- it maintains the

+    output file, a running CRC-32 check on the output and the total number of

+    bytes output, both for checking against the gzip trailer.  (The length in

+    the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and

+    the output is greater than 4 GB.) */

+ struct outd {

+     int outfile;

+     int check;                  /* true if checking crc and total */

+     unsigned long crc;

+     unsigned long total;

+ };

+ 

+ /* Write output buffer and update the CRC-32 and total bytes written.  write()

+    is called until all of the output is written or an error is encountered.

+    On success out() returns 0.  For a write failure, out() returns 1.  If the

+    output file descriptor is -1, then nothing is written.

+  */

+ local int out(void *out_desc, unsigned char *buf, unsigned len)

+ {

+     int ret;

+     struct outd *me = (struct outd *)out_desc;

+ 

+     if (me->check) {

+         me->crc = crc32(me->crc, buf, len);

+         me->total += len;

+     }

+     if (me->outfile != -1)

+         do {

+             ret = PIECE;

+             if ((unsigned)ret > len)

+                 ret = (int)len;

+             ret = (int)write(me->outfile, buf, ret);

+             if (ret == -1)

+                 return 1;

+             buf += ret;

+             len -= ret;

+         } while (len != 0);

+     return 0;

+ }

+ 

+ /* next input byte macro for use inside lunpipe() and gunpipe() */

+ #define NEXT() (have ? 0 : (have = in(indp, &next)), \

+                 last = have ? (have--, (int)(*next++)) : -1)

+ 

+ /* memory for gunpipe() and lunpipe() --

+    the first 256 entries of prefix[] and suffix[] are never used, could

+    have offset the index, but it's faster to waste the memory */

+ unsigned char inbuf[SIZE];              /* input buffer */

+ unsigned char outbuf[SIZE];             /* output buffer */

+ unsigned short prefix[65536];           /* index to LZW prefix string */

+ unsigned char suffix[65536];            /* one-character LZW suffix */

+ unsigned char match[65280 + 2];         /* buffer for reversed match or gzip

+                                            32K sliding window */

+ 

+ /* throw out what's left in the current bits byte buffer (this is a vestigial

+    aspect of the compressed data format derived from an implementation that

+    made use of a special VAX machine instruction!) */

+ #define FLUSHCODE() \

+     do { \

+         left = 0; \

+         rem = 0; \

+         if (chunk > have) { \

+             chunk -= have; \

+             have = 0; \

+             if (NEXT() == -1) \

+                 break; \

+             chunk--; \

+             if (chunk > have) { \

+                 chunk = have = 0; \

+                 break; \

+             } \

+         } \

+         have -= chunk; \

+         next += chunk; \

+         chunk = 0; \

+     } while (0)

+ 

+ /* Decompress a compress (LZW) file from indp to outfile.  The compress magic

+    header (two bytes) has already been read and verified.  There are have bytes

+    of buffered input at next.  strm is used for passing error information back

+    to gunpipe().

+ 

+    lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of

+    file, read error, or write error (a write error indicated by strm->next_in

+    not equal to Z_NULL), or Z_DATA_ERROR for invalid input.

+  */

+ local int lunpipe(unsigned have, unsigned char *next, struct ind *indp,

+                   int outfile, z_stream *strm)

+ {

+     int last;                   /* last byte read by NEXT(), or -1 if EOF */

+     int chunk;                  /* bytes left in current chunk */

+     int left;                   /* bits left in rem */

+     unsigned rem;               /* unused bits from input */

+     int bits;                   /* current bits per code */

+     unsigned code;              /* code, table traversal index */

+     unsigned mask;              /* mask for current bits codes */

+     int max;                    /* maximum bits per code for this stream */

+     int flags;                  /* compress flags, then block compress flag */

+     unsigned end;               /* last valid entry in prefix/suffix tables */

+     unsigned temp;              /* current code */

+     unsigned prev;              /* previous code */

+     unsigned final;             /* last character written for previous code */

+     unsigned stack;             /* next position for reversed string */

+     unsigned outcnt;            /* bytes in output buffer */

+     struct outd outd;           /* output structure */

+ 

+     /* set up output */

+     outd.outfile = outfile;

+     outd.check = 0;

+ 

+     /* process remainder of compress header -- a flags byte */

+     flags = NEXT();

+     if (last == -1)

+         return Z_BUF_ERROR;

+     if (flags & 0x60) {

+         strm->msg = (char *)"unknown lzw flags set";

+         return Z_DATA_ERROR;

+     }

+     max = flags & 0x1f;

+     if (max < 9 || max > 16) {

+         strm->msg = (char *)"lzw bits out of range";

+         return Z_DATA_ERROR;

+     }

+     if (max == 9)                           /* 9 doesn't really mean 9 */

+         max = 10;

+     flags &= 0x80;                          /* true if block compress */

+ 

+     /* clear table */

+     bits = 9;

+     mask = 0x1ff;

+     end = flags ? 256 : 255;

+ 

+     /* set up: get first 9-bit code, which is the first decompressed byte, but

+        don't create a table entry until the next code */

+     if (NEXT() == -1)                       /* no compressed data is ok */

+         return Z_OK;

+     final = prev = (unsigned)last;          /* low 8 bits of code */

+     if (NEXT() == -1)                       /* missing a bit */

+         return Z_BUF_ERROR;

+     if (last & 1) {                         /* code must be < 256 */

+         strm->msg = (char *)"invalid lzw code";

+         return Z_DATA_ERROR;

+     }

+     rem = (unsigned)last >> 1;              /* remaining 7 bits */

+     left = 7;

+     chunk = bits - 2;                       /* 7 bytes left in this chunk */

+     outbuf[0] = (unsigned char)final;       /* write first decompressed byte */

+     outcnt = 1;

+ 

+     /* decode codes */

+     stack = 0;

+     for (;;) {

+         /* if the table will be full after this, increment the code size */

+         if (end >= mask && bits < max) {

+             FLUSHCODE();

+             bits++;

+             mask <<= 1;

+             mask++;

+         }

+ 

+         /* get a code of length bits */

+         if (chunk == 0)                     /* decrement chunk modulo bits */

+             chunk = bits;

+         code = rem;                         /* low bits of code */

+         if (NEXT() == -1) {                 /* EOF is end of compressed data */

+             /* write remaining buffered output */

+             if (outcnt && out(&outd, outbuf, outcnt)) {

+                 strm->next_in = outbuf;     /* signal write error */

+                 return Z_BUF_ERROR;

+             }

+             return Z_OK;

+         }

+         code += (unsigned)last << left;     /* middle (or high) bits of code */

+         left += 8;

+         chunk--;

+         if (bits > left) {                  /* need more bits */

+             if (NEXT() == -1)               /* can't end in middle of code */

+                 return Z_BUF_ERROR;

+             code += (unsigned)last << left; /* high bits of code */

+             left += 8;

+             chunk--;

+         }

+         code &= mask;                       /* mask to current code length */

+         left -= bits;                       /* number of unused bits */

+         rem = (unsigned)last >> (8 - left); /* unused bits from last byte */

+ 

+         /* process clear code (256) */

+         if (code == 256 && flags) {

+             FLUSHCODE();

+             bits = 9;                       /* initialize bits and mask */

+             mask = 0x1ff;

+             end = 255;                      /* empty table */

+             continue;                       /* get next code */

+         }

+ 

+         /* special code to reuse last match */

+         temp = code;                        /* save the current code */

+         if (code > end) {

+             /* Be picky on the allowed code here, and make sure that the code

+                we drop through (prev) will be a valid index so that random

+                input does not cause an exception.  The code != end + 1 check is

+                empirically derived, and not checked in the original uncompress

+                code.  If this ever causes a problem, that check could be safely

+                removed.  Leaving this check in greatly improves gun's ability

+                to detect random or corrupted input after a compress header.

+                In any case, the prev > end check must be retained. */

+             if (code != end + 1 || prev > end) {

+                 strm->msg = (char *)"invalid lzw code";

+                 return Z_DATA_ERROR;

+             }

+             match[stack++] = (unsigned char)final;

+             code = prev;

+         }

+ 

+         /* walk through linked list to generate output in reverse order */

+         while (code >= 256) {

+             match[stack++] = suffix[code];

+             code = prefix[code];

+         }

+         match[stack++] = (unsigned char)code;

+         final = code;

+ 

+         /* link new table entry */

+         if (end < mask) {

+             end++;

+             prefix[end] = (unsigned short)prev;

+             suffix[end] = (unsigned char)final;

+         }

+ 

+         /* set previous code for next iteration */

+         prev = temp;

+ 

+         /* write output in forward order */

+         while (stack > SIZE - outcnt) {

+             while (outcnt < SIZE)

+                 outbuf[outcnt++] = match[--stack];

+             if (out(&outd, outbuf, outcnt)) {

+                 strm->next_in = outbuf; /* signal write error */

+                 return Z_BUF_ERROR;

+             }

+             outcnt = 0;

+         }

+         do {

+             outbuf[outcnt++] = match[--stack];

+         } while (stack);

+ 

+         /* loop for next code with final and prev as the last match, rem and

+            left provide the first 0..7 bits of the next code, end is the last

+            valid table entry */

+     }

+ }

+ 

+ /* Decompress a gzip file from infile to outfile.  strm is assumed to have been

+    successfully initialized with inflateBackInit().  The input file may consist

+    of a series of gzip streams, in which case all of them will be decompressed

+    to the output file.  If outfile is -1, then the gzip stream(s) integrity is

+    checked and nothing is written.

+ 

+    The return value is a zlib error code: Z_MEM_ERROR if out of memory,

+    Z_DATA_ERROR if the header or the compressed data is invalid, or if the

+    trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends

+    prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip

+    stream) follows a valid gzip stream.

+  */

+ local int gunpipe(z_stream *strm, int infile, int outfile)

+ {

+     int ret, first, last;

+     unsigned have, flags, len;

+     unsigned char *next;

+     struct ind ind, *indp;

+     struct outd outd;

+ 

+     /* setup input buffer */

+     ind.infile = infile;

+     ind.inbuf = inbuf;

+     indp = &ind;

+ 

+     /* decompress concatenated gzip streams */

+     have = 0;                               /* no input data read in yet */

+     first = 1;                              /* looking for first gzip header */

+     strm->next_in = Z_NULL;                 /* so Z_BUF_ERROR means EOF */

+     for (;;) {

+         /* look for the two magic header bytes for a gzip stream */

+         if (NEXT() == -1) {

+             ret = Z_OK;

+             break;                          /* empty gzip stream is ok */

+         }

+         if (last != 31 || (NEXT() != 139 && last != 157)) {

+             strm->msg = (char *)"incorrect header check";

+             ret = first ? Z_DATA_ERROR : Z_ERRNO;

+             break;                          /* not a gzip or compress header */

+         }

+         first = 0;                          /* next non-header is junk */

+ 

+         /* process a compress (LZW) file -- can't be concatenated after this */

+         if (last == 157) {

+             ret = lunpipe(have, next, indp, outfile, strm);

+             break;

+         }

+ 

+         /* process remainder of gzip header */

+         ret = Z_BUF_ERROR;

+         if (NEXT() != 8) {                  /* only deflate method allowed */

+             if (last == -1) break;

+             strm->msg = (char *)"unknown compression method";

+             ret = Z_DATA_ERROR;

+             break;

+         }

+         flags = NEXT();                     /* header flags */

+         NEXT();                             /* discard mod time, xflgs, os */

+         NEXT();

+         NEXT();

+         NEXT();

+         NEXT();

+         NEXT();

+         if (last == -1) break;

+         if (flags & 0xe0) {

+             strm->msg = (char *)"unknown header flags set";

+             ret = Z_DATA_ERROR;

+             break;

+         }

+         if (flags & 4) {                    /* extra field */

+             len = NEXT();

+             len += (unsigned)(NEXT()) << 8;

+             if (last == -1) break;

+             while (len > have) {

+                 len -= have;

+                 have = 0;

+                 if (NEXT() == -1) break;

+                 len--;

+             }

+             if (last == -1) break;

+             have -= len;

+             next += len;

+         }

+         if (flags & 8)                      /* file name */

+             while (NEXT() != 0 && last != -1)

+                 ;

+         if (flags & 16)                     /* comment */

+             while (NEXT() != 0 && last != -1)

+                 ;

+         if (flags & 2) {                    /* header crc */

+             NEXT();

+             NEXT();

+         }

+         if (last == -1) break;

+ 

+         /* set up output */

+         outd.outfile = outfile;

+         outd.check = 1;

+         outd.crc = crc32(0L, Z_NULL, 0);

+         outd.total = 0;

+ 

+         /* decompress data to output */

+         strm->next_in = next;

+         strm->avail_in = have;

+         ret = inflateBack(strm, in, indp, out, &outd);

+         if (ret != Z_STREAM_END) break;

+         next = strm->next_in;

+         have = strm->avail_in;

+         strm->next_in = Z_NULL;             /* so Z_BUF_ERROR means EOF */

+ 

+         /* check trailer */

+         ret = Z_BUF_ERROR;

+         if (NEXT() != (outd.crc & 0xff) ||

+             NEXT() != ((outd.crc >> 8) & 0xff) ||

+             NEXT() != ((outd.crc >> 16) & 0xff) ||

+             NEXT() != ((outd.crc >> 24) & 0xff)) {

+             /* crc error */

+             if (last != -1) {

+                 strm->msg = (char *)"incorrect data check";

+                 ret = Z_DATA_ERROR;

+             }

+             break;

+         }

+         if (NEXT() != (outd.total & 0xff) ||

+             NEXT() != ((outd.total >> 8) & 0xff) ||

+             NEXT() != ((outd.total >> 16) & 0xff) ||

+             NEXT() != ((outd.total >> 24) & 0xff)) {

+             /* length error */

+             if (last != -1) {

+                 strm->msg = (char *)"incorrect length check";

+                 ret = Z_DATA_ERROR;

+             }

+             break;

+         }

+ 

+         /* go back and look for another gzip stream */

+     }

+ 

+     /* clean up and return */

+     return ret;

+ }

+ 

+ /* Copy file attributes, from -> to, as best we can.  This is best effort, so

+    no errors are reported.  The mode bits, including suid, sgid, and the sticky

+    bit are copied (if allowed), the owner's user id and group id are copied

+    (again if allowed), and the access and modify times are copied. */

+ local void copymeta(char *from, char *to)

+ {

+     struct stat was;

+     struct utimbuf when;

+ 

+     /* get all of from's Unix meta data, return if not a regular file */

+     if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)

+         return;

+ 

+     /* set to's mode bits, ignore errors */

+     (void)chmod(to, was.st_mode & 07777);

+ 

+     /* copy owner's user and group, ignore errors */

+     (void)chown(to, was.st_uid, was.st_gid);

+ 

+     /* copy access and modify times, ignore errors */

+     when.actime = was.st_atime;

+     when.modtime = was.st_mtime;

+     (void)utime(to, &when);

+ }

+ 

+ /* Decompress the file inname to the file outnname, of if test is true, just

+    decompress without writing and check the gzip trailer for integrity.  If

+    inname is NULL or an empty string, read from stdin.  If outname is NULL or

+    an empty string, write to stdout.  strm is a pre-initialized inflateBack

+    structure.  When appropriate, copy the file attributes from inname to

+    outname.

+ 

+    gunzip() returns 1 if there is an out-of-memory error or an unexpected

+    return code from gunpipe().  Otherwise it returns 0.

+  */

+ local int gunzip(z_stream *strm, char *inname, char *outname, int test)

+ {

+     int ret;

+     int infile, outfile;

+ 

+     /* open files */

+     if (inname == NULL || *inname == 0) {

+         inname = "-";

+         infile = 0;     /* stdin */

+     }

+     else {

+         infile = open(inname, O_RDONLY, 0);

+         if (infile == -1) {

+             fprintf(stderr, "gun cannot open %s\n", inname);

+             return 0;

+         }

+     }

+     if (test)

+         outfile = -1;

+     else if (outname == NULL || *outname == 0) {

+         outname = "-";

+         outfile = 1;    /* stdout */

+     }

+     else {

+         outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);

+         if (outfile == -1) {

+             close(infile);

+             fprintf(stderr, "gun cannot create %s\n", outname);

+             return 0;

+         }

+     }

+     errno = 0;

+ 

+     /* decompress */

+     ret = gunpipe(strm, infile, outfile);

+     if (outfile > 2) close(outfile);

+     if (infile > 2) close(infile);

+ 

+     /* interpret result */

+     switch (ret) {

+     case Z_OK:

+     case Z_ERRNO:

+         if (infile > 2 && outfile > 2) {

+             copymeta(inname, outname);          /* copy attributes */

+             unlink(inname);

+         }

+         if (ret == Z_ERRNO)

+             fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",

+                     inname);

+         break;

+     case Z_DATA_ERROR:

+         if (outfile > 2) unlink(outname);

+         fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);

+         break;

+     case Z_MEM_ERROR:

+         if (outfile > 2) unlink(outname);

+         fprintf(stderr, "gun out of memory error--aborting\n");

+         return 1;

+     case Z_BUF_ERROR:

+         if (outfile > 2) unlink(outname);

+         if (strm->next_in != Z_NULL) {

+             fprintf(stderr, "gun write error on %s: %s\n",

+                     outname, strerror(errno));

+         }

+         else if (errno) {

+             fprintf(stderr, "gun read error on %s: %s\n",

+                     inname, strerror(errno));

+         }

+         else {

+             fprintf(stderr, "gun unexpected end of file on %s\n",

+                     inname);

+         }

+         break;

+     default:

+         if (outfile > 2) unlink(outname);

+         fprintf(stderr, "gun internal error--aborting\n");

+         return 1;

+     }

+     return 0;

+ }

+ 

+ /* Process the gun command line arguments.  See the command syntax near the

+    beginning of this source file. */

+ int main(int argc, char **argv)

+ {

+     int ret, len, test;

+     char *outname;

+     unsigned char *window;

+     z_stream strm;

+ 

+     /* initialize inflateBack state for repeated use */

+     window = match;                         /* reuse LZW match buffer */

+     strm.zalloc = Z_NULL;

+     strm.zfree = Z_NULL;

+     strm.opaque = Z_NULL;

+     ret = inflateBackInit(&strm, 15, window);

+     if (ret != Z_OK) {

+         fprintf(stderr, "gun out of memory error--aborting\n");

+         return 1;

+     }

+ 

+     /* decompress each file to the same name with the suffix removed */

+     argc--;

+     argv++;

+     test = 0;

+     if (argc && strcmp(*argv, "-h") == 0) {

+         fprintf(stderr, "gun 1.3 (12 Jun 2005)\n");

+         fprintf(stderr, "Copyright (c) 2005 Mark Adler\n");

+         fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");

+         return 0;

+     }

+     if (argc && strcmp(*argv, "-t") == 0) {

+         test = 1;

+         argc--;

+         argv++;

+     }

+     if (argc)

+         do {

+             if (test)

+                 outname = NULL;

+             else {

+                 len = (int)strlen(*argv);

+                 if (strcmp(*argv + len - 3, ".gz") == 0 ||

+                     strcmp(*argv + len - 3, "-gz") == 0)

+                     len -= 3;

+                 else if (strcmp(*argv + len - 2, ".z") == 0 ||

+                     strcmp(*argv + len - 2, "-z") == 0 ||

+                     strcmp(*argv + len - 2, "_z") == 0 ||

+                     strcmp(*argv + len - 2, ".Z") == 0)

+                     len -= 2;

+                 else {

+                     fprintf(stderr, "gun error: no gz type on %s--skipping\n",

+                             *argv);

+                     continue;

+                 }

+                 outname = malloc(len + 1);

+                 if (outname == NULL) {

+                     fprintf(stderr, "gun out of memory error--aborting\n");

+                     ret = 1;

+                     break;

+                 }

+                 memcpy(outname, *argv, len);

+                 outname[len] = 0;

+             }

+             ret = gunzip(&strm, *argv, outname, test);

+             if (outname != NULL) free(outname);

+             if (ret) break;

+         } while (argv++, --argc);

+     else

+         ret = gunzip(&strm, NULL, NULL, test);

+ 

+     /* clean up */

+     inflateBackEnd(&strm);

+     return ret;

+ }

tests/examples-from-source-package-test/runtest.sh
file added
+68

@@ -0,0 +1,68 @@

+ #!/bin/bash

+ # vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k

+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ #

+ #   runtest.sh of /CoreOS/zlib/examples-from-source-package-test

+ #   Description: it compile example app in source package and run it and try to find if no regression

+ #   Author: Jan Scotka <jscotka@redhat.com>

+ #

+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ #

+ #   Copyright (c) 2011 Red Hat, Inc.

+ #

+ #   This copyrighted material is made available to anyone wishing

+ #   to use, modify, copy, or redistribute it subject to the terms

+ #   and conditions of the GNU General Public License version 2.

+ #

+ #   This program is distributed in the hope that it will be

+ #   useful, but WITHOUT ANY WARRANTY; without even the implied

+ #   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR

+ #   PURPOSE. See the GNU General Public License for more details.

+ #

+ #   You should have received a copy of the GNU General Public

+ #   License along with this program; if not, write to the Free

+ #   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,

+ #   Boston, MA 02110-1301, USA.

+ #

+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ 

+ # Include rhts environment

+ . /usr/bin/rhts-environment.sh

+ . /usr/lib/beakerlib/beakerlib.sh

+ 

+ PACKAGE="zlib"

+ TMPDIR=`mktemp -d`

+ rlJournalStart

+     rlPhaseStartSetup

+         rlAssertRpm $PACKAGE

+         cp example.c gun.c $TMPDIR/

+         pushd $TMPDIR

+         rlRun "cc -o example example.c -lz"

+         rlAssertExists "example"

+         rlRun "cc -o gun gun.c -lz"

+         rlAssertExists "gun"

+         rlRun "cat gun.c | gzip > gunc.gz"

+     rlPhaseEnd

+ 

+     rlPhaseStartTest

+         rlLog "example tests"

+         rlRun "./example |grep 'uncompress(): hello, hello!'"

+         rlRun "./example |grep 'gzread(): hello, hello!'"

+         rlRun "./example |grep 'gzgets() after gzseek:  hello!'"

+         rlRun "./example |grep 'inflate(): hello, hello!'"

+         rlRun "./example |grep 'large_inflate(): OK'"

+         rlRun "./example |grep 'after inflateSync(): hello, hello!'"

+         rlRun "./example |grep 'inflate with dictionary: hello, hello!'"

+         rlRun "zcat foo.gz|grep 'hello, hello!'"

+ 

+         rlLog "gunzipping abilities of libz"

+         rlRun "cat gunc.gz |./gun >gun.cx"

+         rlRun "diff gun.c gun.cx" 0 "must be same, without any diff, it means decompress PASSed"

+     rlPhaseEnd

+ 

+     rlPhaseStartCleanup

+         popd

+         rlRun "rm -rf $TMPDIR"

+     rlPhaseEnd

+ rlJournalPrintText

+ rlJournalEnd

tests/tests.yml
file added
+23

@@ -0,0 +1,23 @@

+ - hosts: localhost

+   tags:

+   - classic

+   roles:

+   - role: standard-test-beakerlib

+     tests:

+     - examples-from-source-package-test

+     required_packages:

+     - gcc

+     - zlib

+     - zlib-devel

+ - hosts: localhost

+   tags:

+   - container

+   roles:

+   - role: standard-test-beakerlib

+     tests:

+     - examples-from-source-package-test

+     required_packages:

+     - gcc

+     - zlib

+     - zlib-devel

+ 

no initial comment

Justification

Adds tests according to the CI wiki specifically the standard test interface in the spec.

The playbook includes Tier1 level test cases that have been tested in the following contexts and is passing reliably: Classic and Container. Test logs are stored in the artifacts directory.

The following steps are used to execute the tests using the standard test interface:

Test environment

Make sure you have installed packages from the spec

# rpm -q ansible python2-dnf libselinux-python standard-test-roles \
ansible-2.3.2.0-1.fc26.noarch \
python2-dnf-2.6.3-11.fc26.noarch \
libselinux-python-2.6-7.fc26.x86_64 \
standard-test-roles-2.4-1.fc26.noarch

Run tests for Classic

# export TEST_SUBJECTS=
# sudo ansible-playbook --tags classic tests.yml

Snip of the example test run for Classic tests:

TASK [standard-test-beakerlib : Check the results] ************************************************************************************************************************
changed: [localhost]

PLAY RECAP ****************************************************************************************************************************************************************
localhost                  : ok=30   changed=17   unreachable=0    failed=0   

PASS examples-from-source-package-test
PASS examples-from-source-package-test

Notes

Tests will be enabled in CI, yet gating is currently disabled, so nothing will change. Tests will run on each dist-git commit, they are not triggered on koji builds and if you are using FMN, it should notify you of failures normally.

The RH QE maintainer contact in case you have questions: sturivny @redhat.com
The idea is that these tests become yours just as you're maintaining the package, there will of course be people around if you have questions or troubles.

rebased onto 561ef19

a year ago