/** @file  tst_psHash05.c
*
*  @brief Contains the tests for psHash.[ch]
*
*
*  @author Robert DeSonia, MHPCC
*
*  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
*  @date $Date: 2005-04-07 20:27:41 $
*
*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
*/

#include "psTest.h"
#include "pslib_strict.h"

static psS32 hashToArray( void );

testDescription tests[] = {
                              {hashToArray, 789, "psHashToArray", 0, false},
                              {NULL}
                          };

static void printIntArray(char* name, psArray* arr)
{
    if (arr == NULL) {
        printf("%s = NULL\n",name);
        return;
    }

    printf("%s = {",name);
    for (int i = 0; i < arr->n; i++) {
        if (arr->data[i] == NULL) {
            printf("NULL");
        } else {
            printf("%d",*(int*)arr->data[i]);
        }
        if (i != arr->n-1) {
            printf(",");
        }
    }
    printf("}");
}

psS32 main( psS32 argc, char* argv[] )
{
    psLogSetLevel( PS_LOG_INFO );

    return ( ! runTestSuite( stderr, "psHash", tests, argc, argv ) );
}

psS32 hashToArray( void )
{
    int testNum = 0;
    psArray* array;
    #define BUCKETS 10

    psHash* hash = psHashAlloc(BUCKETS);
    char key[2] = "A";
    bool found[BUCKETS];

    for (int i = 0; i < BUCKETS; i++) {

        array = psHashToArray(hash);

        // return non-null?
        testNum++;
        if (array == NULL) {
            psError(PS_ERR_UNKNOWN, false,
                    "Failed to create an array from a psHash of %d elements.",
                    i);
            return testNum;
        }

        // the size correct
        testNum++;
        if (array->n != i) {
            printIntArray("array",array);
            psError(PS_ERR_UNKNOWN, false,
                    "psHashToArray created a psArray of %d elements from a psHash of %d elements.",
                    array->n, i);
            return testNum;
        }

        // the values correct?

        // zero out the found boolean vector
        for (int j = 0; j < i; j++) {
            found[j] = false;
        }

        // check if all the items in array are valid
        for (int k = 0; k < array->n; k++) {
            int* item = array->data[k];

            testNum++;
            if (item == NULL) {
                printIntArray("array",array);
                psError(PS_ERR_UNKNOWN, true,
                        "The array position %d was NULL.",
                        k);
                return testNum;
            }

            testNum++;
            if (*item < 0 || *item >= BUCKETS) {
                printIntArray("array",array);
                psError(PS_ERR_UNKNOWN, true,
                        "The array position %d was invalid (%d).",
                        k,*item);
                return testNum;
            }

            testNum++;
            if (found[*item]) {
                printIntArray("array",array);
                psError(PS_ERR_UNKNOWN, true,
                        "The array position %d was a duplicate (%d).",
                        k,*item);
                return testNum;
            }

            testNum++;
            if (psMemGetRefCounter(item) != 2) {
                printIntArray("array",array);
                psError(PS_ERR_UNKNOWN, true,
                        "The array position %d was not properly reference counted (%d).",
                        k,psMemGetRefCounter(item));
                return testNum;
            }

            found[*item] = true;
        }

        // check that all the items in psHash was found
        for (int j = 0; j < i; j++) {
            testNum++;
            if (! found[j]) {
                printIntArray("array",array);
                psError(PS_ERR_UNKNOWN, true,
                        "Item %d not found in array.",
                        j);
                return testNum;
            }
        }

        psFree(array);

        // add one element
        int* value = psAlloc(sizeof(int));
        *value = i;
        psHashAdd(hash, key, value);
        *key += 1; // increment the key value

        psFree(value);
    }

    psFree(hash);

    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    array = psHashToArray(NULL);
    testNum++;
    if (array != NULL) {
        printIntArray("array",array);
        psError(PS_ERR_UNKNOWN, false,
                "psHashToArray returned non-null psArray given a null psHash.");
        return testNum;
    }

    return 0;
}

