/** @file  tst_psMetadata_04.c
 *
 *  @brief Test driver for psMetadata functions
 *
 *  This test driver contains the following tests for psMetadata:
 *     Test A - Allocate metadata and items
 *     Test B - Lookup metadata item by name
 *     Test C - Attempt to use null metadata
 *     Test D - Attempt to use null key
 *     Test E - Attempt to lookup non-existant metadata item
 *     Test F - Lookup metadata item by index
 *     Test G - Lookup metadata item and return psS32 value
 *     Test H - Lookup metadata item and return psF64 value
 *     Test I - Lookup metadata item and return psVector pointer
 *     Test J - Lookup metadata item and return psMetadata pointer
 *     Test K - Lookup metadata item and return psString value
 *     Test L - Attempt to use null metadata
 *     Test M - Attempt to get non-existant metadata item
 *     Test N - Attempt to look up with an invalid metadata object
 *     Test O - Attempt get item  with an invalid metadata object
 *     Test P - Attempt get value of non-existant metadata item
 *     Test Q - Free psMetadata
 *
 *  @author  Ross Harman, MHPCC
 *
 *  @version $Revision: 1.11 $  $Name: not supported by cvs2svn $
 *  @date  $Date: 2006-02-03 00:12:02 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 *
 */

#include <string.h>
#include "pslib_strict.h"
#include "psTest.h"

static void printMetadataItem(psMetadataItem *metadataItem)
{
    printf("Key Name: %8s  ", metadataItem->name);
    printf("Key mdType: 0x%08x  ", metadataItem->type);

    switch (metadataItem->type) {
    case PS_DATA_METADATA_MULTI:
        printf("Key Value: %17c", ' ');
        break;
    case PS_DATA_BOOL:
        printf("Key Value: %15d  ", metadataItem->data.B);
        break;
    case PS_DATA_S32:
        printf("Key Value: %15d  ", metadataItem->data.S32);
        break;
    case PS_DATA_F32:
        printf("Key Value: %15.3f  ", metadataItem->data.F32);
        break;
    case PS_DATA_F64:
        printf("Key Value: %15.3f  ", metadataItem->data.F64);
        break;
    case PS_DATA_STRING:
        printf("Key Value: %15s  ", (char*)metadataItem->data.V);
        break;
    default:
        printf("Bad type: %d ", metadataItem->type);
    }
    printf("Key Comment: %s\n", metadataItem->comment);
}


psS32 main( psS32 argc, char* argv[] )
{
    psBool status = 0;
    psMetadataItem *item1 = NULL;
    psMetadataItem *item2 = NULL;
    psMetadataItem *item3 = NULL;
    psMetadataItem *item4 = NULL;
    psMetadataItem *item5 = NULL;
    psMetadataItem *item6 = NULL;
    psMetadataItem *item7 = NULL;
    psMetadataItem *item8 = NULL;
    psMetadataItem *item = NULL;
    psMetadata *metadata = NULL;
    psMetadata *newMD = NULL;
    char string[50];
    psHash* tmpTable = NULL;
    psList* tmpList = NULL;


    // Test A - Allocate metadata and items
    printPositiveTestHeader(stdout, "psMetadata", "Test A - Allocate metadata items");
    psVector *vec = psVectorAlloc(5, PS_TYPE_S32);
    metadata = psMetadataAlloc();
    newMD = psMetadataAlloc();
    strncpy(string, "String was here", 50);
    psMetadataAddF64(newMD, PS_LIST_HEAD, "yourItem1", 0, "I am a psF64", 4.14);
    item1 = psMetadataItemAlloc("myItem1", PS_DATA_BOOL, "I am a boolean", true);
    item2 = psMetadataItemAlloc("myItem2", PS_DATA_S32, "I am a integer", 55);
    item3 = psMetadataItemAlloc("myItem3", PS_DATA_BOOL, "I am a boolean", false);
    item4 = psMetadataItemAlloc("myItem4", PS_DATA_S32, "I am a integer", 66);
    item5 = psMetadataItemAlloc("myItem5", PS_DATA_F64, "I am a double", 3.14);
    item6 = psMetadataItemAlloc("myItem6", PS_DATA_VECTOR, "I am a vector", vec);
    item7 = psMetadataItemAlloc("myItem7", PS_DATA_METADATA, "I am a metadata", newMD);
    item8 = psMetadataItemAlloc("myItem8", PS_DATA_STRING, "I am a string", string);
    printMetadataItem(item1);
    printMetadataItem(item2);
    printMetadataItem(item3);
    printMetadataItem(item4);
    printMetadataItem(item5);
    psMetadataAddItem(metadata, item1, PS_LIST_HEAD, PS_META_DEFAULT);
    psMetadataAddItem(metadata, item2, PS_LIST_HEAD, PS_META_DEFAULT);
    psMetadataAddItem(metadata, item3, PS_LIST_HEAD, PS_META_DEFAULT);
    psMetadataAddItem(metadata, item4, PS_LIST_HEAD, PS_META_DEFAULT);
    psMetadataAddItem(metadata, item5, PS_LIST_HEAD, PS_META_DEFAULT);
    psMetadataAddItem(metadata, item6, PS_LIST_HEAD, PS_META_DEFAULT);
    psMetadataAddItem(metadata, item7, PS_LIST_HEAD, PS_META_DEFAULT);
    psMetadataAddItem(metadata, item8, PS_LIST_HEAD, PS_META_DEFAULT);
    psMemDecrRefCounter(vec); // vs. psFree, which now would set vec to NULL (want to keep it to comparison later)
    printFooter(stdout, "psMetadata", "Test A - Allocate metadata items", true);


    // Test B - Lookup metadata item by name
    printPositiveTestHeader(stdout, "psMetadata", "Test B - Lookup metadata item by name");
    item = psMetadataLookup(metadata, "myItem2");
    printf("Found item named %s\n", item->name);
    if(item == NULL) {
        printf("ERROR: Item should not be null\n");
        return 10;
    }
    printFooter(stdout, "psMetadata", "Test B - Lookup metadata item by name", true);


    // Test C - Attempt to use null metadata
    printNegativeTestHeader(stdout,"psMetadata", "Test C - Attempt to use null metadata",
                            "Null metadata collection not allowed", 0);
    if ( psMetadataLookup(NULL, "myItem2") != NULL ) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataLookup did not return NULL with null metadata.");
        return 11;
    }
    printFooter(stdout, "psMetadata", "Test C - Attempt to use null metadata", true);


    // Test D - Attempt to use null key
    printNegativeTestHeader(stdout,"psMetadata", "Test D - Attempt to use null key",
                            "Null key name not allowed", 0);
    if ( psMetadataLookup(metadata, NULL) != NULL ) {
        psError(PS_ERR_UNKNOWN, true,"psMetadata did not return NULL with null key.");
        return 12;
    }
    printFooter(stdout, "psMetadata", "Test D - Attempt to use null key", true);


    // Test E - Attempt to lookup non-existant metadata item
    printNegativeTestHeader(stdout,"psMetadata", "Test E - Attempt to lookup non-existant metadata item",
                            "Couldn't find metadata item. Name: AARGH", 0);
    if ( psMetadataLookup(metadata, "AARGH") != NULL ) {
        psError(PS_ERR_UNKNOWN, true,"psMetadata did not return NULL with a non-existant item.");
        return 13;
    }
    printFooter(stdout, "psMetadata", "Test E - Attempt to lookup non-existant metadata item", true);


    // Test F - Lookup metadata item by index
    printPositiveTestHeader(stdout, "psMetadata", "Test F - Lookup metadata item by index");
    item = psMetadataGet(metadata, 0);
    printf("Found item named %s\n", item->name);
    if(item == NULL) {
        printf("ERROR: Item should not be null\n");
        return 14;
    }
    printFooter(stdout, "psMetadata", "Test F - Lookup metadata item by index", true);

    // Test G - Lookup metadata item and return psS32 value
    printPositiveTestHeader(stdout, "psMetadata", "Test G - Lookup metadata item and return psS32 value");
    psS32 valueS32 = 0;
    valueS32 = psMetadataLookupS32(&status, metadata, "myItem2");
    if(valueS32 != 55) {
        printf("ERROR: Bad value, %d, Expected 55\n", valueS32);
        return 15;
    } else if(! status) {
        printf("ERROR: Bad status, %d\n", status);
        return 15;
    }
    printFooter(stdout, "psMetadata", "Test G - Lookup metadata item and return psS32 value", true);

    // Test H - Lookup metadata item and return psF64 value
    printPositiveTestHeader(stdout, "psMetadata", "Test H - Lookup metadata item and return psF64 value");
    psF64 valueF64 = 0.0;
    valueF64 = psMetadataLookupF64(&status, metadata, "myItem5");
    if(fabs(valueF64-3.14) > FLT_EPSILON) {
        printf("ERROR: Bad value, %g, Expected 3.14\n", valueF64);
        return 16;
    } else if(! status) {
        printf("ERROR: Bad status, %d\n", status);
        return 16;
    }
    printFooter(stdout, "psMetadata", "Test H - Lookup metadata item and return psF64 value", true);

    // Test I - Lookup metadata item and return psVector pointer
    printPositiveTestHeader(stdout, "psMetadata", "Test I - Lookup metadata item and return psVector pointer");
    psVector *valueVec = psMetadataLookupPtr(&status, metadata, "myItem6");
    if(valueVec != vec) {
        printf("ERROR: Bad vector pointer\n");
        return 17;
    } else if(! status) {
        printf("ERROR: Bad status, %d\n", status);
        return 17;
    }
    printFooter(stdout, "psMetadata", "Test I - Lookup metadata item and return psVector pointer", true);

    // Test J - Lookup metadata item and return psMetadata pointer
    printPositiveTestHeader(stdout, "psMetadata", "Test J - Lookup metadata item and return psMetadata pointer");
    psMetadata *metaData = NULL;
    metaData = psMetadataLookupMD(&status, metadata, "myItem7");
    if(metaData != newMD) {
        printf("ERROR: Bad metadata pointer\n");
        return 25;
    } else if(! status) {
        printf("ERROR: Bad status, %d\n", status);
        return 25;
    }
    printFooter(stdout, "psMetadata", "Test J - Lookup metadata item and return psMetadata pointer", true);

    // Test K - Lookup metadata item and return psString value
    printPositiveTestHeader(stdout, "psMetadata", "Test K - Lookup metadata item and return psString value");
    psString newSTR;
    newSTR = psMetadataLookupStr(&status, metadata, "myItem8");
    if( strncmp(newSTR, string, 50) ) {
        printf("ERROR: Bad string value \n");
        return 26;
    } else if(! status) {
        printf("ERROR: Bad status, %d\n", status);
        return 26;
    }
    printFooter(stdout, "psMetadata", "Test K - Lookup metadata item and return psString value", true);

    // Test L - Attempt to use null metadata
    printNegativeTestHeader(stdout,"psMetadata", "Test L - Attempt to use null metadata",
                            "Null metadata collection not allowed", 0);
    item = psMetadataGet(NULL, 0);
    if ( item != NULL ) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataGet did not return NULL with null metadata structure");
        return 18;
    }
    printFooter(stdout, "psMetadata", "Test L - Attempt to use null metadata", true);


    // Test M - Attempt to get non-existant metadata item
    printNegativeTestHeader(stdout,"psMetadata", "Test M - Attempt to get non-existant metadata item",
                            "Couldn't find metadata item with given index. Index: 22", 0);
    if ( psMetadataGet(metadata, 22) != NULL ) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataGet did not return NULL with non-existant metadata item");
        return 19;
    }
    printFooter(stdout, "psMetadata", "Test M - Attempt to get non-existant metadata item", true);

    // Test N - Attempt to look up with an invalid metadata object
    printNegativeTestHeader(stdout,"psMetadata","Test N - Attemp to look up with an invalid metadata",
                            "Lookup item with invalid metadata object.", 0 );
    tmpTable = metadata->hash;
    metadata->hash = NULL;
    if ( psMetadataLookup(metadata,"myItem2") != NULL ) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataLookup did not return null for invalid metadata object");
        return 20;
    }
    metadata->hash = tmpTable;
    printFooter(stdout, "psMetadata","Test N - Attempt to lookup an invalid metadata object.",true);

    // Test O - Attempt get item with an invalid metadata object
    printNegativeTestHeader(stdout,"psMetadata","Test O - Attempt to get item with an invalid metadata",
                            "Get item with invalid metadata object.", 0 );
    tmpList = metadata->list;
    metadata->list = NULL;
    if ( psMetadataGet(metadata,0) != NULL ) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataLookup did not return null for invalid metadata object");
        return 21;
    }
    metadata->list = tmpList;
    printFooter(stdout, "psMetadata","Test O - Attempt to get item with  invalid metadata object",true);

    // Test P - Attempt get psS32 value of non-existant metadata item
    printPositiveTestHeader(stdout, "psMetadata", "Test P - Attempt get psS32 value of non-existant metadata item");
    valueS32 = psMetadataLookupS32(&status, metadata, "myItem22");
    if(status) {
        printf("ERROR: Bad status, %d, \n", status);
        return 22;
    }
    printFooter(stdout, "psMetadata","Test P - Attempt get psS32 value of non-existant metadata item",true);

    // Test P - Attempt get psF64 value of non-existant metadata item
    printPositiveTestHeader(stdout, "psMetadata", "Test P - Attempt get psF64 value of non-existant metadata item");
    valueF64 = psMetadataLookupF64(&status, metadata, "myItem22");
    if(status) {
        printf("ERROR: Bad status, %d, \n", status);
        return 23;
    }
    printFooter(stdout, "psMetadata","Test P - Attempt get psF64 value of non-existant metadata item",true);

    // Test P - Attempt get psVector value of non-existant metadata item
    printPositiveTestHeader(stdout, "psMetadata", "Test P - Attempt get psVector value of non-existant metadata item");
    valueVec = psMetadataLookupPtr(&status, metadata, "myItem22");
    if(status) {
        printf("ERROR: Bad status, %d, \n", status);
        return 24;
    }
    printFooter(stdout, "psMetadata","Test P - Attempt get psVector value of non-existant metadata item",true);

    // Test Q - Free psMetadata
    printPositiveTestHeader(stdout, "psMetadata", "Test Q - Free psMetadata");
    //    psFree(string);
    psFree(newMD);
    psFree(item1);
    psFree(item2);
    psFree(item3);
    psFree(item4);
    psFree(item5);
    psFree(item6);
    psFree(item7);
    psFree(item8);
    psFree(metadata);
    if ( psMemCheckLeaks(0, NULL, stdout,false) != 0 ) {
        psError(PS_ERR_UNKNOWN, true,"memory leaks detected.");
        return 23;
    }
    psMemCheckCorruption(0);
    psS32 nBad = psMemCheckCorruption(0);
    if(nBad) {
        printf("ERROR: Found %d bad memory blocks\n", nBad);
        return 24;
    }
    printFooter(stdout, "psMetadata", "Test Q - Free psMetadata", true);


    return 0;
}
