//
// $Id: BzlibStreamTest.m,v 1.3 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_BZLIB)

#import "BzlibStreamTest.h"
#import <ObjectiveLib/BzlibOutStream.h>
#import <ObjectiveLib/DataOutStream.h>
#import <ObjectiveLib/BzlibInStream.h>
#import <ObjectiveLib/DataInStream.h>
#import <ObjectiveLib/FileOutStream.h>
#import <ObjectiveLib/FileInStream.h>
#import <Foundation/NSData.h>
#import <Foundation/NSString.h>
#import <Foundation/NSException.h>
#import <stdlib.h>
#import <string.h>
#import <limits.h>
#import <unistd.h>

@implementation BzlibStreamTest

- (void) testBasicBzlibStreams
{
    uint8_t srcBuf[256];
    uint8_t destBuf[256];
    int i;
    OLDataOutStream* dout;
    OLBzlibOutStream* zout;
    OLBzlibInStream* zin;
    OLDataInStream* din;
    unsigned streamed;
    uint8_t* srcBuf2;
    uint8_t* destBuf2;
    unsigned bigBufSize = 1024 * 1024;

    dout = [[OLDataOutStream alloc] init];
    zout = [[OLBzlibOutStream alloc] initWithOutStream: dout blockSize: 9 bufferSize: 32];
    for (i = 0; i < 256; i++)
        srcBuf[i] = i;
    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 = [[OLBzlibInStream alloc] initWithInStream: din bufferSize: 32];
    [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"];
    }
    srcBuf2 = malloc(bigBufSize);
    for (i = 0; i < bigBufSize; i++)
        srcBuf2[i] = lrand48() % 256;
    dout = [[OLDataOutStream alloc] init];
    zout = [[OLBzlibOutStream alloc] initWithOutStream: dout];
    streamed = [zout writeBytes: srcBuf2 count: bigBufSize];
    if (streamed != bigBufSize)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected %u, but got %u", bigBufSize, streamed];
    }
    [self logMessage: "Compressed %u bytes to %u bytes",
        bigBufSize, [[dout data] length]];
    [zout release];
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    zin = [[OLBzlibInStream alloc] initWithInStream: din];
    [din release];
    destBuf2 = malloc(bigBufSize);
    streamed = [zin readBytes: destBuf2 count: bigBufSize];
    if (streamed != bigBufSize)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected %u, but got %u", bigBufSize, streamed];
    }
    streamed = [zin readBytes: destBuf2 count: 700];
    if (streamed != UINT_MAX)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected end-of-stream, but got %u", streamed];
    }
    [zin release];
    if (memcmp(srcBuf2, destBuf2, bigBufSize) != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The inflated data are wrong"];
    }
}

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

    fout = [[OLFileOutStream alloc] initWithPath: @"bzlibin.testfile"];
    for (i = 0; i < 256; i++)
        [fout writeByte: i];
    [fout release];
    if (system("bzip2 -f bzlibin.testfile") != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Couldn't bzip2 the data"];
        unlink("bzlibin.testfile");
    }
    else
    {
        fin = [[OLFileInStream alloc] initWithPath: @"bzlibin.testfile.bz2"];
        zin = [[OLBzlibInStream 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("bzlibin.testfile.bz2");
    }
}

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

    fout = [[OLFileOutStream alloc] initWithPath: @"bzlibout.testfile.bz2"];
    zout = [[OLBzlibOutStream alloc] initWithOutStream: fout];
    [fout release];
    for (i = 0; i < 256; i++)
        [zout writeByte: i];
    [zout release];
    if (system("bzip2 -d -f bzlibout.testfile.bz2") != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Couldn't bzip2 the data"];
        unlink("bzlibout.testfile.bz2");
    }
    else
    {
        fin = [[OLFileInStream alloc] initWithPath: @"bzlibout.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("bzlibout.testfile");
    }
}

- (void) testConvenienceAllocators
{
    OLDataOutStream* dout;
    OLBzlibOutStream* zout;
    OLBzlibInStream* zin;
    int val;

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

- (void) testInitializers
{
    OLBzlibOutStream* zout = nil;
    OLDataOutStream* dout;
    int i = 0;

    dout = [OLDataOutStream stream];

    NS_DURING

        for (i = 1; i < 10; i++)
        {
            zout = [[OLBzlibOutStream alloc] initWithOutStream: dout blockSize: i];
            [zout release];
        }

    NS_HANDLER

        [self errInFile: __FILE__ line: __LINE__
            format: "(block size %i) %s: %s",
            i, [[localException name] cString], [[localException reason] cString]];

    NS_ENDHANDLER

    NS_DURING
    
        zout = [[OLBzlibOutStream alloc] initWithOutStream: dout blockSize: 10];

    NS_HANDLER

        [self logMessage: "Got expected exception:\n  %s: %s",
            [[localException name] cString], [[localException reason] cString]];

    NS_ENDHANDLER

    [zout release];
}

@end

#endif
