//
// $Id: MapTest.m,v 1.14 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.
 */

#import "MapTest.h"
#import <ObjectiveLib/Map.h>
#import <ObjectiveLib/Vector.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSData.h>
#import <Foundation/NSArchiver.h>
#if defined(HAVE_KEYED_ARCHIVES)
#import <Foundation/NSKeyedArchiver.h>
#endif
#import <stdlib.h>
#if defined(__NEXT_RUNTIME__)
#import <objc/objc-class.h>
#endif

@implementation MapTest

- (void) testBounds
{
    OLMap* m;
    NSString* keys[] = { @"five", @"one", @"three", @"two" };
    NSString* vals[] = { @"5", @"1", @"3", @"2" };
    OLAssociativeIterator* itor;
    OLPair* p;
    int i;

    m = [[OLMap alloc] init];
    for (i = 0; i < 4; i++)
        [m insertKey: keys[i] value: vals[i]];
    itor = [m lowerBound: @"four"];
    if (![[[itor dereference] first] isEqual: keys[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[1] cString], [[[itor dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[1] cString], [[[itor dereference] second] cString]];
    }
    itor = [m upperBound: @"four"];
    if (![[[itor dereference] first] isEqual: keys[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[1] cString], [[[itor dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[1] cString], [[[itor dereference] second] cString]];
    }
    itor = [m lowerBound: @"one"];
    if (![[[itor dereference] first] isEqual: keys[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[1] cString], [[[itor dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[1] cString], [[[itor dereference] second] cString]];
    }
    itor = [m upperBound: @"one"];
    if (![[[itor dereference] first] isEqual: keys[2]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[2] cString], [[[itor dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[2]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[2] cString], [[[itor dereference] second] cString]];
    }
    p = [m equalRange: @"three"];
    if (![[[[p first] dereference] first] isEqual: keys[2]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[2] cString], [[[[p first] dereference] first] cString]];
    }
    if (![[[[p first] dereference] second] isEqual: vals[2]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[2] cString], [[[[p first] dereference] second] cString]];
    }
    if (![[[[p second] dereference] first] isEqual: keys[3]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[3] cString], [[[[p second] dereference] first] cString]];
    }
    if (![[[[p second] dereference] second] isEqual: vals[3]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[3] cString], [[[[p second] dereference] second] cString]];
    }
    [m release];
}

- (void) testCoding
{
    NSMutableData* data;
    NSArchiver* archiver;
    NSData* archData;
    OLMap* m1;
    OLMap* m2;
    NSNumber* k;
    NSNumber* v;
    int i;


    m1 = [[OLMap alloc] init];
    for (i = 0; i< 5000; i++)
    {
        k = [[NSNumber alloc] initWithInt: i];
        v = [[NSNumber alloc] initWithInt: lrand48() % 1000];
        [m1 assignKey: k value: v];
        [k release];
        [v release];
    }
    data = [[NSMutableData alloc] initWithCapacity: 5000];
    archiver = [[NSArchiver alloc] initForWritingWithMutableData: data];
    [archiver encodeRootObject: m1];
    [archiver release];
    m2 = [NSUnarchiver unarchiveObjectWithData: data];
    [data release];
    if (![m1 isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps should be equal"];
    }
#if defined(HAVE_KEYED_ARCHIVES)
    archData = [NSKeyedArchiver archivedDataWithRootObject: m1];
    m2 = [NSKeyedUnarchiver unarchiveObjectWithData: archData];
    if (![m1 isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps should be equal"];
    }
#endif
    [m1 release];
}

- (void) testConvenienceAllocators
{
    OLMap* m;
    OLMap* m2;
    NSNumber* num;

    m = [OLMap map];
    if (![m isMemberOfClass: [OLMap class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLMap class]->name, [m class]->name];
    }
    if (![m empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The map should be empty"];
    }
    num = [[NSNumber alloc] initWithInt: 1];
    [m assignKey: num value: [num description]];
    [num release];
    num = [[NSNumber alloc] initWithInt: 2];
    [m assignKey: num value: [num description]];
    [num release];
    num = [[NSNumber alloc] initWithInt: 3];
    [m assignKey: num value: [num description]];
    [num release];
    m2 = [OLMap mapFrom: [m begin] to: [m end]];
    if (![m isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps should be equal"];
    }
    num = [[NSNumber alloc] initWithInt: 4];
    [m assignKey: num value: [num description]];
    [num release];
    num = [[NSNumber alloc] initWithInt: 5];
    [m assignKey: num value: [num description]];
    [num release];
    m2 = [OLMap mapWithMap: m];
    if (![m isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps should be equal"];
    }
    m = [OLMap mapWithCompare: [OLFunctor functorOfType: OLFunctorType_Greater]];
    if (![m isMemberOfClass: [OLMap class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLMap class]->name, [m class]->name];
    }
    if (![m empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The map should be empty"];
    }
    if (![[m keyComp] isMemberOfClass: [OLGreater class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLGreater class]->name, [[m keyComp] class]->name];
    }
}

- (void) testErase
{
    OLMap* m;
    NSString* keys[] = { @"five", @"four", @"one", @"three", @"two" };
    NSString* vals[] = { @"5", @"4", @"1", @"3", @"2" };
    OLAssociativeIterator* itor;
    OLAssociativeIterator* end;
    int i;

    m = [[OLMap alloc] init];
    for (i = 0; i < 5; i++)
        [m insertKey: keys[i] value: vals[i]];
    [m insertKey: @"six" value: @"6"];
    itor = [m begin];
    [OLIterator advanceIterator: itor distance: 3];
    [m erase: itor];
    if ([m size] != 5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 5, but got %u", [m size]];
    }
    for (itor = [m begin], end = [m end], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        if (![[[itor dereference] first] isEqual: keys[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [keys[i] cString], [[[itor dereference] first] cString]];
        }
        if (![[[itor dereference] second] isEqual: vals[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [vals[i] cString], [[[itor dereference] second] cString]];
        }
    }
    itor = [m begin];
    [OLIterator advanceIterator: itor distance: 2];
    [m eraseFrom: itor to: end];
    if ([m size] != 2)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 2, but got %u", [m size]];
    }
    for (itor = [m begin], end = [m end], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        if (![[[itor dereference] first] isEqual: keys[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [keys[i] cString], [[[itor dereference] first] cString]];
        }
        if (![[[itor dereference] second] isEqual: vals[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [vals[i] cString], [[[itor dereference] second] cString]];
        }
    }
    i = [m eraseKey: keys[0]];
    if (i != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %i", i];
    }
    if ([m size] != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %u", [m size]];
    }
    itor = [m begin];
    if (![[[itor dereference] first] isEqual: keys[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[1] cString], [[[itor dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[1] cString], [[[itor dereference] second] cString]];
    }
    [m clear];
    if ([m size] != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 0, but got %u", [m size]];
    }
    if (![m empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The map is empty"];
    }
    [m release];
}

- (void) testFind
{
    OLMap* m;
    NSString* keys[] = { @"five", @"four", @"one", @"three", @"two" };
    NSString* vals[] = { @"5", @"4", @"1", @"3", @"2" };
    OLAssociativeIterator* itor;
    OLAssociativeIterator* end;
    id val;
    int i;

    m = [[OLMap alloc] init];
    for (i = 0; i < 5; i++)
        [m insertKey: keys[i] value: vals[i]];
    end = [m end];
    i = [m count: @"one"];
    if (i != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %u", i];
    }
    i = [m count: @"six"];
    if (i != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 0, but got %u", i];
    }
    itor = [m find: @"three"];
    if ([itor isEqual: end])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "\"three\"should have been found"];
    }
    if (![[[itor dereference] first] isEqual: keys[3]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [keys[3] cString], [[[itor dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[3]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[3] cString], [[[itor dereference] second] cString]];
    }
    itor = [m find: @"doggy"];
    if (![itor isEqual: end])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "\"doggy\"should not have been found"];
    }
    val = [m valueForKey: @"two"];
    if (![val isEqual: vals[4]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[3] cString], [val cString]];
    }
    val = [m valueForKey: @"dogbite"];
    if (val != nil)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected nil"];
    }
    [m release];
}

- (void) testInsert
{
    OLMap* m;
    NSString* strs[] = { @"one", @"two", @"three", @"four", @"five" };
    NSString* vals[] = { @"1", @"2", @"3", @"4", @"5" };
    NSString* orderedStrs[] = { @"five", @"four", @"one", @"three", @"two" };
    NSString* orderedVals[] = { @"5", @"4", @"1", @"3", @"2" };
    int i;
    OLPair* p;
    OLPair* r;
    OLVector* v;
    OLAssociativeIterator* itor;
    OLAssociativeIterator* end;

    m = [[OLMap alloc] init];
    p = [[OLPair alloc] initWithFirst: strs[0] second: vals[0]];
    r = [m insert: p];
    [p release];
    if ([m size] != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %u", [m size]];
    }
    if (![[r second] boolValue])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected YES, but got NO"];
    }
    if (![[[[r first] dereference] first] isEqual: strs[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[0] cString], [[[[r first] dereference] first] cString]];
    }
    if (![[[[r first] dereference] second] isEqual: vals[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[0] cString], [[[[r first] dereference] second] cString]];
    }
    p = [[OLPair alloc] initWithFirst: strs[0] second: vals[1]];
    r = [m insert: p];
    [p release];
    if ([m size] != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %u", [m size]];
    }
    if ([[r second] boolValue])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected YES, but got NO"];
    }
    if (![[[[r first] dereference] first] isEqual: strs[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[0] cString], [[[[r first] dereference] first] cString]];
    }
    if (![[[[r first] dereference] second] isEqual: vals[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[0] cString], [[[[r first] dereference] second] cString]];
    }
    [m assignKey: strs[0] value: vals[1]];
    if ([m size] != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %u", [m size]];
    }
    itor = [m begin];
    if (![[[itor dereference] first] isEqual: strs[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[0] cString], [[[[r first] dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[1]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[1] cString], [[[[r first] dereference] second] cString]];
    }
    [m assignKey: strs[0] value: vals[0]];
    if (![[[itor dereference] first] isEqual: strs[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[0] cString], [[[[r first] dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[0] cString], [[[[r first] dereference] second] cString]];
    }
    v = [[OLVector alloc] init];
    for (i = 1; i < 4; i++)
    {
        p = [[OLPair alloc] initWithFirst: strs[i] second: vals[i]];
        [v pushBack: p];
        [p release];
    }
    [m insertFrom: [v begin] to: [v end]];
    [v release];
    if ([m size] != 4)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 4, but got %u", [m size]];
    }
    end = [m end];
    for (itor = [m begin], i = 1; ![itor isEqual: end]; [itor advance], i++)
    {
        if (![[[itor dereference] first] isEqual: orderedStrs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedStrs[i] cString], [[[itor dereference] first] cString]];
        }
        if (![[[itor dereference] second] isEqual: orderedVals[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedVals[i] cString], [[[itor dereference] second] cString]];
        }
    }
    p = [[OLPair alloc] initWithFirst: strs[4] second: vals[4]];
    itor = [m insertAt: [[m begin] advance] value: p];
    [p release];
    if ([m size] != 5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 5, but got %u", [m size]];
    }
    if (![[[itor dereference] first] isEqual: strs[4]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[0] cString], [[[itor dereference] first] cString]];
    }
    if (![[[itor dereference] second] isEqual: vals[4]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [vals[0] cString], [[[itor dereference] second] cString]];
    }
    end = [m end];
    for (itor = [m begin], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        if (![[[itor dereference] first] isEqual: orderedStrs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedStrs[i] cString], [[[itor dereference] first] cString]];
        }
        if (![[[itor dereference] second] isEqual: orderedVals[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedVals[i] cString], [[[itor dereference] second] cString]];
        }
    }
    r = [m insertKey: @"doggy" value: @"boy"];
    if ([m size] != 6)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 6, but got %u", [m size]];
    }
    if (![[r second] boolValue])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected YES, but got NO"];
    }
    if (![[[[r first] dereference] first] isEqual: @"doggy"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"doggy\", but got \"%s\"",
            [[[[r first] dereference] first] cString]];
    }
    if (![[[[r first] dereference] second] isEqual: @"boy"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"boy\", but got \"%s\"",
            [[[[r first] dereference] second] cString]];
    }
    r = [m insertKey: @"doggy" value: @"chuck"];
    if ([m size] != 6)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 6, but got %u", [m size]];
    }
    if ([[r second] boolValue])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected NO, but got YES"];
    }
    if (![[[[r first] dereference] first] isEqual: @"doggy"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"doggy\", but got \"%s\"",
            [[[[r first] dereference] first] cString]];
    }
    if (![[[[r first] dereference] second] isEqual: @"boy"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"boy\", but got \"%s\"",
            [[[[r first] dereference] second] cString]];
    }
    [m release];
}

- (void) testInitializers
{
    OLMap* m;
    OLGreater* greater;
    OLVector* v;
    NSString* strs[] = { @"one", @"two", @"three", @"four", @"five" };
    NSString* orderedStrs[] = { @"five", @"four", @"one", @"three", @"two" };
    NSNumber* num;
    OLPair* p;
    int i;
    OLAssociativeIterator* b;
    OLAssociativeIterator* e;
    OLMap* m2;

    m = [[OLMap alloc] init];
    if (![m empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The map should be empty"];
    }
    [m release];
    greater = [[OLGreater alloc] init];
    m = [[OLMap alloc] initWithCompare: greater];
    if (![m empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The map should be empty"];
    }
    if ([m keyComp] != greater)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The key comparison object is wrong"];
    }
    if ([m valueComp] != greater)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The value comparison object is wrong"];
    }
    [m release];
    v = [[OLVector alloc] init];
    for (i = 0; i < 5; i++)
    {
        num = [[NSNumber alloc] initWithInt: i + 1];
        p = [[OLPair alloc] initWithFirst: strs[i] second: num];
        [num release];
        [v pushBack: p];
        [p release];
    }
    m = [[OLMap alloc] initFrom: [v begin] to: [v end]];
    if ([m size] != 5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 5, but got %u", [m size]];
    }
    for (b = [m begin], e = [m end], i = 0; ![b isEqual: e]; [b advance], i++)
    {
        if (![[[b dereference] first] isEqual: orderedStrs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedStrs[i] cString], [[[b dereference] first] cString]];
        }
        [self logMessage: "[%s] = %i",
            [orderedStrs[i] cString], [[[b dereference] second] intValue]];
    }
    [m release];
    m = [[OLMap alloc] initFrom: [v begin] to: [v end] compare: greater];
    [v release];
    [greater release];
    if ([m size] != 5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 5, but got %u", [m size]];
    }
    [self logMessage: ""];
    for (b = [m begin], e = [m end], i = 4; ![b isEqual: e]; [b advance], i--)
    {
        if (![[[b dereference] first] isEqual: orderedStrs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedStrs[i] cString], [[[b dereference] first] cString]];
        }
        [self logMessage: "[%s] = %i",
            [orderedStrs[i] cString], [[[b dereference] second] intValue]];
    }
    m2 = [[OLMap alloc] initWithMap: m];
    if ([m2 size] != 5)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 5, but got %u", [m2 size]];
    }
    [self logMessage: ""];
    for (b = [m2 begin], e = [m2 end], i = 4; ![b isEqual: e]; [b advance], i--)
    {
        if (![[[b dereference] first] isEqual: orderedStrs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedStrs[i] cString], [[[b dereference] first] cString]];
        }
        [self logMessage: "[%s] = %i",
            [orderedStrs[i] cString], [[[b dereference] second] intValue]];
    }
    if (![m isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps must be equal"];
    }
    [m release];
    [m2 release];
}

- (void) testIterators
{
    OLMap* m;
    int nums[] = { 4, 3, 5, 1, 2 };
    int orderedNums[] = { 1, 2, 3, 4, 5 };
    int i;
    OLAssociativeIterator* itor;
    OLAssociativeIterator* end;
    OLReverseBidiIterator* rtor;
    OLReverseBidiIterator* rend;
    NSNumber* key;
    NSNumber* value;

    m = [[OLMap alloc] init];
    for (i = 0; i < 5; i++)
    {
        key = [[NSNumber alloc] initWithInt: nums[i]];
        value = [[NSNumber alloc] initWithInt: nums[i] + 1000];
        [m insertKey: key value: value];
        [key release];
        [value release];
    }
    end = [m end];
    for (itor = [m begin], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        if ([[[itor dereference] first] intValue] != orderedNums[i])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i], [[[itor dereference] first] intValue]];
        }
        if ([[[itor dereference] second] intValue] != orderedNums[i] + 1000)
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i] + 1000, [[[itor dereference] second] intValue]];
        }
    }
    [itor reverse];
    for (i = 4; i >= 0; i--, [itor reverse])
    {
        if ([[[itor dereference] first] intValue] != orderedNums[i])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i], [[[itor dereference] first] intValue]];
        }
        if ([[[itor dereference] second] intValue] != orderedNums[i] + 1000)
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i] + 1000, [[[itor dereference] second] intValue]];
        }
    }
    rend = [m rend];
    for (rtor = [m rbegin], i = 4; ![rtor isEqual: rend]; [rtor advance], i--)
    {
        if ([[[rtor dereference] first] intValue] != orderedNums[i])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i], [[[rtor dereference] first] intValue]];
        }
        if ([[[rtor dereference] second] intValue] != orderedNums[i] + 1000)
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i] + 1000, [[[rtor dereference] second] intValue]];
        }
    }
    [rtor reverse];
    for (i = 0; i < 5; i++, [rtor reverse])
    {
        if ([[[rtor dereference] first] intValue] != orderedNums[i])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i], [[[rtor dereference] first] intValue]];
        }
        if ([[[rtor dereference] second] intValue] != orderedNums[i] + 1000)
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                orderedNums[i] + 1000, [[[rtor dereference] second] intValue]];
        }
    }
    [m release];
}

- (void) testProperties
{
    NSString* keys[] = { @"one", @"two", @"three" };
    NSString* vals[] = { @"1", @"2", @"3" };
    OLMap* m;
    OLMap* m2;
    int i;

    m = [[OLMap alloc] init];
    if (![m empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The map is empty"];
    }
    for (i = 0; i < 3; i++)
        [m insertKey: keys[i] value: vals[i]];
    if ([m empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The map is not empty"];
    }
    if (![[m allocator] isEqual: [OLAllocator defaultAllocator]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The allocator is incorrect"];
    }
    if ([m allocator] != [OLAllocator defaultAllocator])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The allocator is incorrect"];
    }
    m2 = [[OLMap alloc] init];
    if ([m isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps are not equal"];
    }
    if (![m2 size] == 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 0, but got %i", [m2 size]];
    }
    [m2 insertFrom: [m begin] to: [m end]];
    if (![m isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps are equal"];
    }
    if ([m maxSize] != [m2 maxSize])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "All maps must have the same max size"];
    }
    [self logMessage: "The max size of a map is %u", [m maxSize]];
    if (![m size] == 3)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 3, but got %i", [m size]];
    }
    if ([m valueComp] != [m keyComp])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Value comp and key comp should point to the same object"];
    }
    [m release];
    [m2 release];
}

- (void) testSwap
{
    OLMap* m;
    OLMap* m2;
    NSString* keys[] = { @"one", @"two", @"three" };
    NSString* vals[] = { @"1", @"2", @"3" };
    NSString* okeys[] = { @"one", @"three", @"two" };
    NSString* keys2[] = { @"four", @"five", @"six" };
    NSString* vals2[] = { @"4", @"5", @"6" };
    NSString* okeys2[] = { @"five", @"four", @"six" };
    int i;
    OLAssociativeIterator* itor;
    OLAssociativeIterator* end;

    m = [[OLMap alloc] init];
    for (i = 0; i < 3; i++)
        [m insertKey: keys[i] value: vals[i]];
    m2 = [[OLMap alloc] init];
    for (i = 0; i < 3; i++)
        [m2 insertKey: keys2[i] value: vals2[i]];
    [m swap: m2];
    if ([m size] != 3)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 3, but got %i", [m size]];
    }
    if ([m2 size] != 3)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 3, but got %i", [m2 size]];
    }
    end = [m end];
    for (itor = [m begin], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        if (![[[itor dereference] first] isEqual: okeys2[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [okeys2[i] cString], [[[itor dereference] first] cString]];
        }
    }
    end = [m2 end];
    for (itor = [m2 begin], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        if (![[[itor dereference] first] isEqual: okeys[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [okeys[i] cString], [[[itor dereference] first] cString]];
        }
    }
    [m release];
    [m2 release];
}

@end
