//
// $Id: GzipStreamTest.m,v 1.4 2005/05/18 06:46:55 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#if defined(HAVE_ZLIB)

#import "GzipStreamTest.h"
#import <ObjectiveLib/GzipOutStream.h>
#import <ObjectiveLib/GzipInStream.h>
#import <ObjectiveLib/DataOutStream.h>
#import <ObjectiveLib/DataInStream.h>
#import <ObjectiveLib/FileOutStream.h>
#import <ObjectiveLib/FileInStream.h>
#import <Foundation/NSString.h>
#import <Foundation/NSData.h>
#import <limits.h>
#import <string.h>
#import <stdlib.h>
#import <unistd.h>
#import <sys/stat.h>
#import <time.h>

@implementation GzipStreamTest

- (void) testBasicGzipStreams
{
    uint8_t srcBuf[256];
    uint8_t destBuf[256];
    int i;
    OLDataOutStream* dout;
    OLGzipOutStream* zout;
    OLGzipInStream* zin;
    OLDataInStream* din;
    unsigned streamed;

    for (i = 0; i < 256; i++)
        srcBuf[i] = i;
    dout = [[OLDataOutStream alloc] init];
    zout = [[OLGzipOutStream alloc] initWithOutStream: dout];
    streamed = [zout writeBytes: srcBuf count: 256];
    if (streamed != 256)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 256, but got %u", streamed];
    }
    [zout release];
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    zin = [[OLGzipInStream alloc] initWithInStream: din];
    [din release];
    streamed = [zin readBytes: destBuf count: 256];
    if (streamed != 256)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 256, but got %u", streamed];
    }
    streamed = [zin readBytes: destBuf count: 700];
    if (streamed != UINT_MAX)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected end-of-stream, but got %u", streamed];
    }
    [zin release];
    if (memcmp(srcBuf, destBuf, 256) != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The inflated data are wrong"];
    }
}

- (void) testComment
{
    OLGzipOutStream* zout;
    OLGzipInStream* zin;
    OLDataOutStream* dout;
    OLDataInStream* din;

    dout = [[OLDataOutStream alloc] init];
    zout = [[OLGzipOutStream alloc] initWithOutStream: dout];
    [zout setComment: @"My dog has fleas"];
    [zout writeByte: 1];
    [zout release];
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    zin = [[OLGzipInStream alloc] initWithInStream: din];
    [din release];
    if ([zin comment] == nil ||
        ![[zin comment] isEqual: @"My dog has fleas"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"My dog has fleas\", but got \"%s\"",
            [[zin originalFileName] cString]];
    }
    [zin release];
}

- (void) testCompatibilityIn
{
    OLFileOutStream* fout;
    OLFileInStream* fin;
    OLGzipInStream* zin;
    int i;
    uint8_t b;

    fout = [[OLFileOutStream alloc] initWithPath: @"gzipin.testfile"];
    for (i = 0; i < 256; i++)
        [fout writeByte: i];
    [fout release];
    if (system("gzip -f gzipin.testfile") != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Couldn't gzip the data"];
        unlink("gzipin.testfile");
    }
    else
    {
        fin = [[OLFileInStream alloc] initWithPath: @"gzipin.testfile.gz"];
        zin = [[OLGzipInStream alloc] initWithInStream: fin];
        [fin release];
        for (i = 0; i < 256; i++)
        {
            b = [zin readByte];
            if (b != i)
            {
                [self errInFile: __FILE__ line: __LINE__
                    format: "Expected %i, but got %u", i, b];
            }
        }
        [zin release];
        unlink("gzipin.testfile.gz");
    }
}

- (void) testCompatibilityOut
{
    OLFileOutStream* fout;
    OLGzipOutStream* zout;
    OLFileInStream* fin;
    int i;
    uint8_t b;

    fout = [[OLFileOutStream alloc] initWithPath: @"gzipout.testfile.gz"];
    zout = [[OLGzipOutStream alloc] initWithOutStream: fout];
    [fout release];
    for (i = 0; i < 256; i++)
        [zout writeByte: i];
    [zout release];
    fout = [[OLFileOutStream alloc] initWithPath: @"gzipout.testfile"];
    for (i = 0; i < 256; i++)
        [fout writeByte: i];
    [fout release];
    if (system("gzip -d -f gzipout.testfile.gz") != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Couldn't gzip the data"];
        unlink("gzipout.testfile.gz");
    }
    else
    {
        fin = [[OLFileInStream alloc] initWithPath: @"gzipout.testfile"];
        for (i = 0; i < 256; i++)
        {
            b = [fin readByte];
            if (b != i)
            {
                [self errInFile: __FILE__ line: __LINE__
                    format: "Expected %i, but got %u", i, b];
            }
        }
        if ([fin readBytes: &b count: 1] != UINT_MAX)
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Should be at end of file"];
        }
        [fin release];
        unlink("gzipout.testfile");
    }
}

- (void) testConvenienceAllocators
{
    OLDataOutStream* dout;
    OLGzipOutStream* zout;
    OLGzipInStream* zin;
    int val;

    dout = [OLDataOutStream stream];
    zout = [OLGzipOutStream streamWithOutStream: dout];
    [zout writeInt: 75];
    [zout close];
    zin = [OLGzipInStream streamWithInStream: [OLDataInStream streamWithDataObject: [dout data]]];
    val = [zin readInt];
    if (val != 75)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 75, but got %i", val];
    }
}

- (void) testExtraFields
{
    OLGzipOutStream* zout;
    OLGzipInStream* zin;
    OLDataOutStream* dout;
    OLDataInStream* din;
    NSData* mdData = [NSData dataWithBytes: "My dog has fleas" length: 16];
    NSData* yvData = [NSData dataWithBytes: "I love Yehudi Villa" length: 19];
    NSData* ef;

    dout = [[OLDataOutStream alloc] init];
    zout = [[OLGzipOutStream alloc] initWithOutStream: dout];
    [zout addExtraField: "MD" withData: mdData];
    [zout addExtraField: "YV" withData: yvData];
    [zout writeByte: 1];
    [zout release];
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    zin = [[OLGzipInStream alloc] initWithInStream: din];
    [din release];
    ef = [zin extraField: "MD"];
    if (ef == nil ||
        ![ef isEqual: mdData])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The extra field was not carried through"];
    }
    ef = [zin extraField: "YV"];
    if (ef == nil ||
        ![ef isEqual: yvData])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The extra field was not carried through"];
    }
    ef = [zin extraField: "GG"];
    if (ef != nil)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "An extra field that shouldn't have been found was found"];
    }
    [zin release];
}

- (void) testMarkModificationTime
{
    OLGzipOutStream* zout;
    OLGzipInStream* zin;
    OLDataOutStream* dout;
    OLDataInStream* din;
    time_t mark;
    time_t found;

    dout = [[OLDataOutStream alloc] init];
    zout = [[OLGzipOutStream alloc] initWithOutStream: dout];
    mark = time(NULL);
    [self logMessage: "Marking time at %s", ctime(&mark)];
    [zout markModificationTime];
    [zout writeByte: 1];
    [zout release];
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    zin = [[OLGzipInStream alloc] initWithInStream: din];
    [din release];
    if ([zin modificationTime] != mark)
    {
        found = [zin modificationTime];
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected %s, but got %s",
            ctime(&mark), ctime(&found)];
    }
    [zin release];
}

- (void) testOriginalFileName
{
    OLGzipOutStream* zout;
    OLGzipInStream* zin;
    OLDataOutStream* dout;
    OLDataInStream* din;
    struct stat statBuf;

    if (system("echo howdy > gziporig.testfile") != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Couldn't create the test file"];
    }
    else
    {
        statBuf.st_mtime = 0;
        stat("gziporig.testfile", &statBuf);
        dout = [[OLDataOutStream alloc] init];
        zout = [[OLGzipOutStream alloc] initWithOutStream: dout];
        [zout setOriginalFileName: @"gziporig.testfile" includeModificationTime: YES];
        [zout writeByte: 1];
        [zout release];
        din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
        [dout release];
        zin = [[OLGzipInStream alloc] initWithInStream: din];
        [din release];
        if ([zin originalFileName] == nil ||
            ![[zin originalFileName] isEqual: @"gziporig.testfile"])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"gziporig.testfile\", but got \"%s\"",
                [[zin originalFileName] cString]];
        }
        if ([zin modificationTime] != statBuf.st_mtime)
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %u, but got %u",
                [zin modificationTime], statBuf.st_mtime];
        }
        [zin release];
        unlink("gziporig.testfile");
    }
}

@end

#endif
