// $Id: CompositeUnitTest.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 "CompositeUnitTest.h"
#if defined(__NEXT_RUNTIME__)
#import <objc/objc-class.h>
#endif

static void parseName(NSString* name, char** cls, char** mtd, NSString** mtdStr)
{
    const char* nm = [name cString];
    int rc;

    *cls = (char*)[[NSMutableData dataWithLength: [name length]] mutableBytes];
    *mtd = (char*)[[NSMutableData dataWithLength: [name length]] mutableBytes];

    rc = sscanf(nm, " [ %s %[^]] ", *cls, *mtd);

    if (rc == 2)
    {
        *mtdStr = [NSString stringWithCString: *mtd];
    }
    else
    {
        **cls = 0;
        **mtd = 0;
        *mtdStr = name;
        strcpy(*mtd, nm);
    }
}

@implementation CompositeUnitTest

- (id) init
{
    return [self initWithOut: stdout err: stderr];
}

- (id) initWithOut: (FILE*)o err: (FILE*)e
{
    [super initWithOut: o err: e];
    unitTests = [[NSMutableArray alloc] initWithCapacity: 32];
    return self;
}

- (void) dealloc
{
    [unitTests release];
    [super dealloc];
}

- (void) addUnitTest: (UnitTest*)test
{
    [unitTests addObject: test];
    [test setStreamOut: [self outStream] err: [self errStream]];
}

- (int) errorCount
{
    int count = [super errorCount];
    NSEnumerator* itor = [unitTests objectEnumerator];
    id current;

    while (current = [itor nextObject])
    {
        count += [current errorCount];
    }
    return count;
}

- (BOOL) hasTestWithName: (NSString*)test
{
    NSString* mtdStr;
    char* cls;
    char* mtd;

    parseName(test, &cls, &mtd, &mtdStr);

    if (cls[0] != 0)
        return [self lookUpTestWithClass: cls name: mtdStr] != nil;
    else
        return [super hasTestWithName: mtdStr];
}

- (void) listFailedTestsToStream: (FILE*)stream delimiter: (char)delim
{
    int i;
    int count = [unitTests count];
    int last = count - 1;

    [super listFailedTestsToStream: stream delimiter: delim];
    for (i = 0; i < count; i++)
    {
        [[unitTests objectAtIndex: i] listFailedTestsToStream: stream delimiter: delim];
        if (i != last)
            fputc(delim, stream);
    }
}

- (id) lookUpTestWithClass: (const char*)cls name: (NSString*)name
{
    NSEnumerator* itor;
    id current;
    Class myClass = [self class];
    id found;

    if (strcmp(myClass->name, cls) == 0)
        return [super lookUpTestWithName: name];
    itor = [unitTests objectEnumerator];
    while (current = [itor nextObject])
    {
        if ([current isKindOfClass: myClass])
            found = [current lookUpTestWithClass: cls name: name];
        else
            found = [current lookUpTestWithName: name];
        if (found != nil)
            return found;
    }
    return nil;
}

- (void) removeAllUnitTests
{
    [unitTests removeAllObjects];
}

- (void) removeUnitTest: (NSString*)name
{
    int i;

    for (i = 0; i < [unitTests count]; i++)
    {
        if ([name isEqual: [NSString stringWithCString: [[unitTests objectAtIndex: i] class]->name]])
        {
            [unitTests removeObjectAtIndex: i];
            break;
        }
    }
}

- (void) runAllTests
{
    NSEnumerator* itor = [unitTests objectEnumerator];
    id current;

    [super runAllTests];
    while (current = [itor nextObject])
    {
        [current runAllTests];
    }
}

- (BOOL) runTestWithName: (NSString*)name
{
    id current;
    char* cls;
    char* mtd;
    NSString* mtdStr;

    parseName(name, &cls, &mtd, &mtdStr);

    if (cls[0] != 0)
    {
        current = [self lookUpTestWithClass: cls name: mtdStr];
        if (current != nil)
        {
            [self runTest: current];
            return YES;
        }
        else
        {
            return NO;
        }
    }
    else
    {
        return [super runTestWithName: name];
    }
}

- (void) setStreamOut: (FILE*)o err: (FILE*)e
{
    NSEnumerator* itor = [unitTests objectEnumerator];
    id current;

    while (current = [itor nextObject])
    {
        [current setStreamOut: o err: e];
    }
}

- (int) testCount
{
    int count = [super testCount];
    NSEnumerator* itor = [unitTests objectEnumerator];
    id current;

    while (current = [itor nextObject])
    {
        count += [current testCount];
    }
    return count;
}

- (NSArray*) testListQualified: (BOOL)flag
{
    NSMutableArray* allTests = [NSMutableArray arrayWithCapacity: 64];
    NSEnumerator* itor = [unitTests objectEnumerator];
    id current;

    [allTests addObjectsFromArray: [super testListQualified: flag]];
    while (current = [itor nextObject])
    {
        [allTests addObjectsFromArray: [current testListQualified: flag]];
    }
    return allTests;
}

@end
