//
// $Id: MultiSetTest.m,v 1.10 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 "MultiSetTest.h"
#import <ObjectiveLib/Set.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <stdlib.h>
#if defined(__NEXT_RUNTIME__)
#import <objc/objc-class.h>
#endif

@implementation MultiSetTest

- (void) testBounds
{
    OLMultiSet* s;
    NSString* strs[] = { @"one", @"one", @"one", @"two", @"two",
                         @"three", @"four", @"four", @"five", @"five" };
    OLPair* p;
    OLAssociativeIterator* itor;

    p = [OLArrayIterator pairWithPointer: strs andPointer: strs + 10];
    s = [[OLMultiSet alloc] initFrom: [p first] to: [p second]];
    itor = [s lowerBound: strs[0]];
    if (![[itor dereference] isEqual: strs[0]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[0] cString], [[itor dereference] cString]];
    }
    itor = [s lowerBound: @"six"];
    if (![[itor dereference] isEqual: strs[5]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[5] cString], [[itor dereference] cString]];
    }
    itor = [s upperBound: strs[0]];
    if (![[itor dereference] isEqual: strs[5]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [strs[5] cString], [[itor dereference] cString]];
    }
    p = [s equalRange: strs[0]];
    for ( ; ![[p first] isEqual: [p second]]; [[p first] advance])
    {
        if (![[[p first] dereference] isEqual: strs[0]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [strs[0] cString], [[[p first] dereference] cString]];
        }
    }
    [s release];
}

- (void) testConvenienceAllocators
{
    OLMultiSet* s;
    OLMultiSet* s2;
    NSNumber* num;

    s = [OLMultiSet multiSet];
    if (![s isMemberOfClass: [OLMultiSet class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLMultiSet class]->name, [s class]->name];
    }
    if (![s empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The set should be empty"];
    }
    num = [[NSNumber alloc] initWithInt: 1];
    [s insert: num];
    [num release];
    num = [[NSNumber alloc] initWithInt: 2];
    [s insert: num];
    [num release];
    num = [[NSNumber alloc] initWithInt: 3];
    [s insert: num];
    [num release];
    s2 = [OLMultiSet multiSetFrom: [s begin] to: [s end]];
    if (![s isEqual: s2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The sets should be equal"];
    }
    num = [[NSNumber alloc] initWithInt: 4];
    [s insert: num];
    [num release];
    num = [[NSNumber alloc] initWithInt: 5];
    [s insert: num];
    [num release];
    s2 = [OLMultiSet multiSetWithOLSet: s];
    if (![s isEqual: s2])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The sets should be equal"];
    }
    s = [OLMultiSet multiSetWithCompare: [OLFunctor functorOfType: OLFunctorType_Greater]];
    if (![s isMemberOfClass: [OLMultiSet class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLMultiSet class]->name, [s class]->name];
    }
    if (![s empty])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "The set should be empty"];
    }
    if (![[s keyComp] isMemberOfClass: [OLGreater class]])
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected \"%s\", but got \"%s\"",
            [OLGreater class]->name, [[s keyComp] class]->name];
    }
}

- (void) testCounting
{
    OLMultiSet* s;
    NSNumber* num;
    int i;
    int j;

    s = [[OLMultiSet alloc] init];
    for (i = 0; i < 100; i++)
    {
        num = [[NSNumber alloc] initWithInt: i];
        if (i == 20)
        {
            for (j = 0; j < 20; j++)
                [s insert: num];
        }
        else
        {
            [s insert: num];
        }
        [num release];
    }
    num = [[NSNumber alloc] initWithInt: 20];
    i = [s count: num];
    [num release];
    if (i != 20)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 20, but got %i", i];
    }
    num = [[NSNumber alloc] initWithInt: 1];
    i = [s count: num];
    [num release];
    if (i != 1)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 1, but got %i", i];
    }
    num = [[NSNumber alloc] initWithInt: 722];
    i = [s count: num];
    [num release];
    if (i != 0)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 0, but got %i", i];
    }
    [s release];
}

- (void) testInsert
{
    OLMultiSet* s;
    NSString* strs[] = { @"one", @"one", @"one", @"two", @"two",
                         @"three", @"four", @"four", @"five", @"five" };
    NSString* orderedStrs[] = { @"five", @"five", @"four", @"four", @"one",
                                @"one", @"one", @"three", @"two", @"two" };
    OLAssociativeIterator* itor;
    OLAssociativeIterator* end;
    NSNumber* num;
    NSNumber* nums[10000];
    OLPair* p;
    int counts[10];
    int i;
    int j;

    s = [[OLMultiSet alloc] init];
    for (i = 0; i < 10; i++)
    {
        itor = [s insert: strs[i]];
        if (![[itor dereference] isEqual: strs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [strs[i] cString], [[itor dereference] cString]];
        }
    }
    if ([s size] != 10)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 10, but got %u", [s size]];
    }
    for (itor = [s begin], end = [s end], i = 0; ![itor isEqual: end]; [itor advance], i++)
    {
        if (![[itor dereference] isEqual: orderedStrs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedStrs[i] cString], [[itor dereference] cString]];
        }
    }
    [s release];
    s = [[OLMultiSet alloc] init];
    for (i = 0; i < 10; i++)
        counts[i] = 0;
    for (i = 0; i < 10000; i++)
    {
        j = lrand48() % 10;
        counts[j]++;
        nums[i] = [[NSNumber alloc] initWithInt: j];
    }
    p = [OLArrayIterator pairWithPointer: nums andPointer: nums + 10000];
    [s insertFrom: [p first] to: [p second]];
    for (i = 0; i < 10000; i++)
        [nums[i] release];
    if ([s size] != 10000)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 10000, but got %u", [s size]];
    }
    end = [s end];
    itor = [s begin];
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < counts[i]; [itor advance], j++)
        {
            if ([itor isEqual: end])
            {
                [self errInFile: __FILE__ line: __LINE__
                    format: "The iterator should not be at the end"];
                break;
            }
            if ([[itor dereference] intValue] != i)
            {
                [self errInFile: __FILE__ line: __LINE__
                    format: "Expected %i, but got %i",
                    i, [[itor dereference] intValue]];
            }
        }
        if ([itor isEqual: end])
            break;
    }
    num = [[NSNumber alloc] initWithInt: 72];
    [s insertAt: [[[s begin] advance] advance] value: num];
    [num release];
    end = [[s end] reverse];
    if ([[end dereference] intValue] != 72)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected %i, but got %i",
            72, [[end dereference] intValue]];
    }
    [s release];
}

- (void) testInitializers
{
    OLMultiSet* s;
    NSString* strs[] = { @"one", @"one", @"one", @"two", @"two",
                         @"three", @"four", @"four", @"five", @"five" };
    NSString* orderedStrs[] = { @"five", @"five", @"four", @"four", @"one",
                                @"one", @"one", @"three", @"two", @"two" };
    OLPair* p;
    OLAssociativeIterator* b;
    OLAssociativeIterator* e;
    int i;

    p = [OLArrayIterator pairWithPointer: strs andPointer: strs + 10];
    s = [[OLMultiSet alloc] initFrom: [p first] to: [p second]];
    if ([s size] != 10)
    {
        [self errInFile: __FILE__ line: __LINE__
            format: "Expected 10, but got %u", [s size]];
    }
    for (b = [s begin], e = [s end], i = 0; ![b isEqual: e]; [b advance], i++)
    {
        if (![[b dereference] isEqual: orderedStrs[i]])
        {
            [self errInFile: __FILE__ line: __LINE__
                format: "Expected \"%s\", but got \"%s\"",
                [orderedStrs[i] cString], [[b dereference] cString]];
        }
    }
    [s release];
}

@end
