//
// $Id: ObjectStreamTest.m,v 1.7 2005/05/18 06:46:56 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.
 */

#import "ObjectStreamTest.h"
#import <ObjectiveLib/DataOutStream.h>
#import <ObjectiveLib/DataInStream.h>
#import <ObjectiveLib/ObjectOutStream.h>
#import <ObjectiveLib/ObjectInStream.h>
#import <ObjectiveLib/Vector.h>
#import <Foundation/NSString.h>
#import <Foundation/NSException.h>
#import <Foundation/NSData.h>
#import <Foundation/NSValue.h>
#if defined(__NEXT_RUNTIME__)
#import <objc/objc-class.h>
#endif
#import <string.h>
#import <stdlib.h>

extern NSString* makeBigString();

@implementation ObjectStreamTest

- (void) testConvenienceAllocators
{
    OLDataOutStream* dout;
    OLObjectOutStream* oout;
    OLObjectInStream* oin;
    NSNumber* num;

    dout = [OLDataOutStream stream];
    oout = [OLObjectOutStream streamWithOutStream: dout];
    [oout writeObject: [NSNumber numberWithInt: 75]];
    [oout close];
    oin = [OLObjectInStream streamWithInStream: [OLDataInStream streamWithDataObject: [dout data]]];
    num = [oin readObject];
    if ([num intValue] != 75)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 75, but got %i", [num intValue]];
    }
}

- (void) testEncodeBytes
{
    OLDataOutStream* dout;
    OLDataInStream* din;
    OLObjectOutStream* oout;
    OLObjectInStream* oin;
    uint8_t buf[10000];
    unsigned retLength;
    int i;
    uint8_t* retBuf = NULL;


    for (i = 0; i < 10000; i++)
        buf[i] = i % 256;
    dout = [[OLDataOutStream alloc] init];
    oout = [[OLObjectOutStream alloc] initWithOutStream: dout];
    NS_DURING
        [oout encodeBytes: buf length: 10000];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    [oout release];
    oin = [[OLObjectInStream alloc] initWithInStream: din];
    NS_DURING
        retBuf = [oin decodeBytesWithReturnedLength: &retLength];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (retLength != 10000)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 10000, but got %u", retLength];
    }
    if (memcmp(buf, retBuf, 10000) != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The arrays should be equal"];
    }
    [din release];
    [oin release];
}

- (void) testEncodeDataObject
{
    OLDataOutStream* dout;
    OLDataInStream* din;
    OLObjectOutStream* oout;
    OLObjectInStream* oin;
    NSMutableData* data;
    NSData* retData = nil;
    int i;
    uint8_t byte;

    data = [[NSMutableData alloc] init];
    for (i = 0; i < 100000; i++)
    {
        byte = lrand48() % 256;
        [data appendBytes: &byte length: 1];
    }
    dout = [[OLDataOutStream alloc] init];
    oout = [[OLObjectOutStream alloc] initWithOutStream: dout];
    NS_DURING
        [oout encodeDataObject: data];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    [oout release];
    oin = [[OLObjectInStream alloc] initWithInStream: din];
    NS_DURING
        retData = [oin decodeDataObject];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (![data isEqual: retData])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The objects should be equal"];
    }
    [data release];
    [din release];
    [oin release];
}

- (void) testEncodeObjCTypes
{
    OLDataOutStream* dout;
    OLDataInStream* din;
    OLObjectOutStream* oout;
    OLObjectInStream* oin;
    char ch;
    short sh;
    int i;
    long l;
    long long ll;
    float f;
    double d;
    SEL s;
    char* str;
    NSString* bigStr;
    uint8_t arr[] = { 0, 1, 2, 3 };
    int* pi;
    typedef struct __StructOne
    {
        int one;
        long two;
    } StructOne;
    typedef struct __StructTwo
    {
        struct __StructOne sone;
        float flt;
        double dbl;
    } StructTwo;
    struct __StructTwo s2;
    uint8_t readArr[4];

    dout = [[OLDataOutStream alloc] init];
    oout = [[OLObjectOutStream alloc] initWithOutStream: dout];
    ch = 42;
    [self logMessage: "Encoding: %s", @encode(char)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(char) at: &ch];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    sh = 30000;
    [self logMessage: "Encoding: %s", @encode(short)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(short) at: &sh];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    i = 1000000000;
    [self logMessage: "Encoding: %s", @encode(int)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(int) at: &i];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    l = 1000000001L;
    [self logMessage: "Encoding: %s", @encode(long)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(long) at: &l];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    ll = 5000000000LL;
    [self logMessage: "Encoding: %s", @encode(long long)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(long long) at: &ll];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    f = 2.5;
    [self logMessage: "Encoding: %s", @encode(float)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(float) at: &f];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    d = 4.2;
    [self logMessage: "Encoding: %s", @encode(double)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(double) at: &d];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    s = @selector(testEncodeObjCTypes);
    [self logMessage: "Encoding: %s", @encode(SEL)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(SEL) at: &s];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    str = "My dog has fleas";
    [self logMessage: "Encoding: %s", @encode(char*)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(char*) at: &str];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    bigStr = makeBigString();
    str = (char*)[bigStr UTF8String];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(char*) at: &str];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    [self logMessage: "Encoding: %s", @encode(uint8_t[4])];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(uint8_t[4]) at: &arr];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    pi = &i;
    [self logMessage: "Encoding: %s", @encode(int*)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(int*) at: &pi];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    s2.sone.one = 1;
    s2.sone.two = 2;
    s2.flt = 1.5;
    s2.dbl = 2.5;
    [self logMessage: "Encoding: %s", @encode(StructTwo)];
    NS_DURING
        [oout encodeValueOfObjCType: @encode(StructTwo) at: &s2];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    [oout release];
    oin = [[OLObjectInStream alloc] initWithInStream: din];
    ch = 0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(char) at: &ch];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (ch != 42)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 42, but got %i", ch];
    }
    sh = 0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(short) at: &sh];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (sh != 30000)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 30000, but got %i", sh];
    }
    i = 0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(int) at: &i];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (i != 1000000000)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1000000000, but got %i", i];
    }
    l = 0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(long) at: &l];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (l != 1000000001)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1000000001, but got %li", l];
    }
    ll = 0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(long long) at: &ll];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (ll != 5000000000LL)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 5000000000, but got %lli", ll];
    }
    f = 0.0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(float) at: &f];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (f != 2.5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 2.5, but got %g", f];
    }
    d = 0.0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(double) at: &d];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (d != 4.2)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 4.2, but got %g", d];
    }
    s = NULL;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(SEL) at: &s];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
#if defined(__NEXT_RUNTIME__)
    if (s != @selector(testEncodeObjCTypes))
#else
    if (!sel_eq(s, @selector(testEncodeObjCTypes)))
#endif
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The selector is not the same"];
    }
    NS_DURING
        [oin decodeValueOfObjCType: @encode(char*) at: &str];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (strcmp(str, "My dog has fleas") != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"My dog has fleas\", but got \"%s\"", str];
    }
#if defined(__NEXT_RUNTIME__)
    free(str);
#endif
    NS_DURING
        [oin decodeValueOfObjCType: @encode(char*) at: &str];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (strcmp(str, [bigStr UTF8String]) != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The strings should be equal"];
    }
    [bigStr release];
#if defined(__NEXT_RUNTIME__)
    free(str);
#endif
    NS_DURING
        [oin decodeValueOfObjCType: @encode(uint8_t[4]) at: &readArr];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (memcmp(arr, readArr, 4) != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The arrays should be equal"];
    }
    NS_DURING
        [oin decodeValueOfObjCType: @encode(int*) at: &pi];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (*pi != 1000000000)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1000000000, but got %i", *pi];
    }
#if defined(__NEXT_RUNTIME__)
    free(pi);
#endif
    s2.sone.one = 0;
    s2.sone.two = 0;
    s2.flt = 0.0;
    s2.dbl = 0.0;
    NS_DURING
        [oin decodeValueOfObjCType: @encode(StructTwo) at: &s2];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    if (s2.sone.one != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %i", s2.sone.one];
    }
    if (s2.sone.two != 2)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 2, but got %li", s2.sone.two];
    }
    if (s2.flt != 1.5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1.2, but got %g", s2.flt];
    }
    if (s2.dbl != 2.5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 2.1, but got %g", s2.dbl];
    }
    [din release];
    [oin release];
}

- (void) testObjectReadWrite
{
    OLDataOutStream* dout;
    OLObjectOutStream* oout;
    OLDataInStream* din;
    OLObjectInStream* oin;
    NSString* readStr;
    NSNumber* num;
    int i = 0;
    int j;
    OLVector* nums;
    OLVector* written;
    id read;

    dout = [[OLDataOutStream alloc] init];
    oout = [[OLObjectOutStream alloc] initWithOutStream: dout];
    NS_DURING
        [oout writeObject: @"My dog has fleas"];
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught %s: %s",
            [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    [oout release];
    oin = [[OLObjectInStream alloc] initWithInStream: din];
    readStr = [oin readObject];
    if (![readStr isEqual: @"My dog has fleas"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"My dog has fleas\", but got \"%s\"",
            [[readStr description] cString]];
    }
    [din release];
    [oin release];
    dout = [[OLDataOutStream alloc] init];
    oout = [[OLObjectOutStream alloc] initWithOutStream: dout];
    nums = [[OLVector alloc] init];
    written = [[OLVector alloc] init];
    NS_DURING
        for (i = 0; i < 10000; i++)
        {
                if ((i - 3) > 0)
                {
                    for (j = 0; j < 3; j++)
                    {
                        [written pushBack: [nums at: j]];
                        [oout writeObject: [written back]];
                    }
                    for (j = 2; j >= 1; j--)
                    {
                        [written pushBack: [nums at: [nums size] - j]];
                        [oout writeObject: [written back]];
                    }
                }
                num = [[NSNumber alloc] initWithInt: i];
                [nums pushBack: num];
                [written pushBack: num];
                [oout writeObject: num];
                [num release];
        }
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught (at index %i) %s: %s",
            i, [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    [nums release];
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    [oout release];
    oin = [[OLObjectInStream alloc] initWithInStream: din];
    NS_DURING
        for (i = 0; i < 10000; i++)
        {
            read = [oin readObject];
            if (![read isEqual: [written at: i]])
            {
                [self errInFile: __FILE__ line: __LINE__
                    format: "Expected \"%s\", but got \"%s\"",
                    [[[written at: i] description] cString],
                    [[read description] cString]];
            }
        }
    NS_HANDLER
        [self errInFile: __FILE__ line: __LINE__
            format: "Caught (at index %i) %s: %s",
            i, [[localException name] cString], [[localException reason] cString]];
    NS_ENDHANDLER
    [written release];
    [din release];
    [oin release];
}

- (void) testPrimitiveReadWrite
{
    OLDataOutStream* dout;
    OLObjectOutStream* oout;
    OLDataInStream* din;
    OLObjectInStream* oin;
    uint8_t bytes[] = { 0, 1, 2, 3 };
    uint8_t bytes2[4];
    NSString* theStr;
    NSString* readStr;
    uint8_t i8;
    uint16_t i16;
    uint32_t i32;
    uint64_t i64;
    int i;
    double d;
    float f;

    dout = [[OLDataOutStream alloc] init];
    oout = [[OLObjectOutStream alloc] initWithOutStream: dout];
    [oout writeBool: YES];
    [oout writeBool: NO];
    [oout writeByte: 42];
    [oout writeBytes: bytes count: 4];
    [oout writeDouble: 2.7];
    [oout writeFloat: 3.5];
    [oout writeInt: 74550];
    [oout writeInt16: 200];
    [oout writeInt32: 100000];
    [oout writeInt64: 5000000000LL];
    [oout writeStringAsUTF8: @"My dog has fleas"];
    theStr = makeBigString();
    [oout writeStringAsUTF8: theStr];
    din = [[OLDataInStream alloc] initWithDataObject: [dout data]];
    [dout release];
    [oout release];
    oin = [[OLObjectInStream alloc] initWithInStream: din];
    if (![oin readBool])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected YES, but got NO"];
    }
    if ([oin readBool])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected NO, but got YES"];
    }
    i8 = [oin readByte];
    if (i8 != 42)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 42, but got %i", i8];
    }
    i = [oin readBytes: bytes2 count: 4];
    if (i != 4)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 4, but got %i", i];
    }
    for (i = 0; i < 4; i++)
    {
        if (bytes[i] != bytes2[i])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i", bytes[i], bytes2[i]];
        }
    }
    d = [oin readDouble];
    if (d != 2.7)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 2.7, but got %g", d];
    }
    f = [oin readFloat];
    if (f != 3.5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 3.5, but got %g", f];
    }
    i = [oin readInt];
    if (i != 74550)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 74550, but got %i", i];
    }
    i16 = [oin readInt16];
    if (i16 != 200)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 200, but got %i", i16];
    }
    i32 = [oin readInt32];
    if (i32 != 100000)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 100000, but got %i", i32];
    }
    i64 = [oin readInt64];
    if (i64 != 5000000000LL)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 5000000000, but got %lli", i64];
    }
    readStr = [oin readStringAsUTF8];
    if (![readStr isEqual: @"My dog has fleas"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"My dog has fleas\", but got \"%s\"", [readStr UTF8String]];
    }
    readStr = [oin readStringAsUTF8];
    if (![readStr isEqual: theStr])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected the strings to be equal"];
    }
    [theStr release];
    [din release];
    [oin release];
}

@end
