//
// $Id: MultiMapTest.m,v 1.8 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 "MultiMapTest.h"
#import <ObjectiveLib/Map.h>
#import <ObjectiveLib/Algorithm.h>
#import <ObjectiveLib/Vector.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#if defined(__NEXT_RUNTIME__)
#import <objc/objc-class.h>
#endif

@implementation MultiMapTest

- (void) testBounds
{
    OLMultiMap* m;
    NSNumber* num;
    NSMutableString* str;
    OLAssociativeIterator* itor;
    OLPair* p;
    int i;
    unsigned count;

    m = [[OLMultiMap alloc] init];
    for (i = 0; i < 10; i++)
    {
        if (i != 4)
        {
            num = [[NSNumber alloc] initWithInt: i];
            [m assignKey: num value: [num description]];
            if (i == 2)
            {
                str = [[NSMutableString alloc] initWithString: [num description]];
                [str appendString: @".1"];
                [m assignKey: num value: str];
                [str release];
                str = [[NSMutableString alloc] initWithString: [num description]];
                [str appendString: @".2"];
                [m assignKey: num value: [num description]];
                [str release];
            }
            [num release];
        }
    }
    num = [[NSNumber alloc] initWithInt: 8];
    itor = [m lowerBound: num];
    if (![[[itor dereference] first] isEqual: num])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 8, but got %i", [[[itor dereference] first] intValue]];
    }
    if (![[[itor dereference] second] isEqual: [num description]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [[num description] cString], [[[itor dereference] second] cString]];
    }
    [num release];
    num = [[NSNumber alloc] initWithInt: 4];
    itor = [m lowerBound: num];
    [num release];
    num = [[NSNumber alloc] initWithInt: 5];
    if (![[[itor dereference] first] isEqual: num])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 8, but got %i", [[[itor dereference] first] intValue]];
    }
    if (![[[itor dereference] second] isEqual: [num description]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [[num description] cString], [[[itor dereference] second] cString]];
    }
    [num release];
    num = [[NSNumber alloc] initWithInt: 8];
    itor = [m upperBound: num];
    [num release];
    num = [[NSNumber alloc] initWithInt: 9];
    if (![[[itor dereference] first] isEqual: num])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 9, but got %i", [[[itor dereference] first] intValue]];
    }
    if (![[[itor dereference] second] isEqual: [num description]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [[num description] cString], [[[itor dereference] second] cString]];
    }
    [num release];
    num = [[NSNumber alloc] initWithInt: 2];
    p = [m equalRange: num];
    [num release];
    count = [OLIterator distanceFrom: [p first] to: [p second]];
    if (count != 3)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 3, but got %i", count];
    }
    for ( ; ![[p first] isEqual: [p second]]; [[p first] advance])
    {
        if ([[[[p first] dereference] first] intValue] != 2)
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected 2, but got %i",
                [[[[p first] dereference] first] intValue]];
        }
    }
    [m release];
}

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

    m = [OLMultiMap multiMap];
    if (![m isMemberOfClass: [OLMultiMap class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLMultiMap 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 = [OLMultiMap multiMapFrom: [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 = [OLMultiMap multiMapWithMap: m];
    if (![m isEqual: m2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The maps should be equal"];
    }
    m = [OLMultiMap multiMapWithCompare: [OLFunctor functorOfType: OLFunctorType_Greater]];
    if (![m isMemberOfClass: [OLMultiMap class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLMultiMap 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) testCounting
{
    OLMultiMap* m;
    NSNumber* num;
    int i;
    int j;

    m = [[OLMultiMap alloc] init];
    for (i = 0; i < 100; i++)
    {
        num = [[NSNumber alloc] initWithInt: i];
        if (i == 20)
        {
            for (j = 0; j < 20; j++)
                [m assignKey: num value: [num description]];
        }
        else
        {
            [m assignKey: num value: [num description]];
        }
        [num release];
    }
    num = [[NSNumber alloc] initWithInt: 20];
    i = [m count: num];
    [num release];
    if (i != 20)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 20, but got %i", i];
    }
    num = [[NSNumber alloc] initWithInt: 20000];
    i = [m count: num];
    [num release];
    if (i != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 0, but got %i", i];
    }
    [m release];
}

- (void) testInsert
{
    OLMultiMap* m;
    OLAssociativeIterator* r;
    OLPair* p;
    OLVector* v;
    NSNumber* num;
    OLAssociativeIterator* itor;
    OLAssociativeIterator* end;
    int keys[] = { 1, 3, 4, 4, 5, 5, 6, 6, 9, 9 };
    int i;

    m = [[OLMultiMap alloc] init];
    p = [[OLPair alloc] initWithFirst: @"my" second: @"dog"];
    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 dereference] first] isEqual: @"my"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"my\", but got \"%s\"",
            [[[r dereference] first] cString]];
    }
    if (![[[r dereference] second] isEqual: @"dog"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"dog\", but got \"%s\"",
            [[[r dereference] second] cString]];
    }
    p = [[OLPair alloc] initWithFirst: @"my" second: @"cat"];
    r = [m insert: p];
    [p release];
    if ([m size] != 2)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %u", [m size]];
    }
    if (![[[r dereference] first] isEqual: @"my"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"my\", but got \"%s\"",
            [[[r dereference] first] cString]];
    }
    if (![[[r dereference] second] isEqual: @"cat"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"cat\", but got \"%s\"",
            [[[r dereference] second] cString]];
    }
    p = [[OLPair alloc] initWithFirst: @"your" second: @"cat"];
    r = [m insertAt: r value: p];
    [p release];
    if ([m size] != 3)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 3, but got %u", [m size]];
    }
    if (![[[r dereference] first] isEqual: @"your"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"your\", but got \"%s\"",
            [[[r dereference] first] cString]];
    }
    if (![[[r dereference] second] isEqual: @"cat"])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"cat\", but got \"%s\"",
            [[[r dereference] second] cString]];
    }
    [m release];
    m = [[OLMultiMap alloc] init];
    v = [[OLVector alloc] init];
    for (i = 0; i < 10; i++)
    {
        num = [[NSNumber alloc] initWithInt: keys[i]];
        p = [[OLPair alloc] initWithFirst: num second: [num description]];
        [num release];
        [v pushBack: p];
        [p release];
    }
    [OLAlgorithm randomShuffleFrom: [v begin] to: [v end]];
    [m insertFrom: [v begin] to: [v end]];
    [v release];
    if ([m size] != 10)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 10, but got %u", [m size]];
    }
    for (itor = [m begin], end = [m end], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        num = [[NSNumber alloc] initWithInt: keys[i]];
        if (![[[itor dereference] first] isEqual: num])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                [num intValue], [[[itor dereference] first] intValue]];
        }
        if (![[[itor dereference] second] isEqual: [num description]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [[num description] cString], [[[itor dereference] second] cString]];
        }
        [num release];
    }
    num = [[NSNumber alloc] initWithInt: 700];
    [m assignKey: num value: [num description]];
    itor = [m find: num];
    if (![[[itor dereference] first] isEqual: num])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected %i, but got %i",
            [num intValue], [[[itor dereference] first] intValue]];
    }
    if (![[[itor dereference] second] isEqual: [num description]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [[num description] cString], [[[itor dereference] second] cString]];
    }
    [num release];
    [m release];
}

- (void) testInitializers
{
    OLMultiMap* m;
    NSString* keys[] = { @"five", @"five", @"four", @"four", @"one",
                         @"one", @"one", @"three", @"two", @"two" };
    int vals[] = { 5, 5, 4, 4, 1, 1, 1, 3, 2, 2 };
    NSNumber* num;
    OLPair* pairs[10];
    OLPair* p;
    OLAssociativeIterator* b;
    OLAssociativeIterator* e;
    int i;

    for (i = 0; i < 10; i++)
    {
        num = [[NSNumber alloc] initWithInt: vals[i]];
        pairs[i] = [[OLPair alloc] initWithFirst: keys[i] second: num];
        [num release];
    }
    p = [OLArrayIterator pairWithPointer: pairs distance: 10];
    [OLAlgorithm randomShuffleFrom: [p first] to: [p second]];
    m = [[OLMultiMap alloc] initFrom: [p first] to: [p second]];
    for (i = 0; i < 10; i++)
        [pairs[i] release];
    if ([m size] != 10)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 10, 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: keys[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [keys[i] cString], [[[b dereference] first] cString]];
        }
        if ([[[b dereference] second] intValue] != vals[i])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected %i, but got %i",
                vals[i], [[[b dereference] second] intValue]];
        }
    }
    [m release];
}

@end
