
/** @file  tst_psMetadata_06.c
*
*  @brief Test driver for psMetadata functions
*
*  This test driver contains the following tests for psMetadata:
*     Test A - Allocate metadata and items
*     Test B - Add leaf node on top of existing leaf node
*     Test C - Add leaf node to existing folder node
*     Test D - Add folder node on top of existing leaf node
*     Test E - Free psMetadata
*
*  @author  Ross Harman, MHPCC
*
*  @version $Revision: 1.1 $  $Name: not supported by cvs2svn $
*  @date  $Date: 2005-07-13 02:47:01 $
*
*  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_META_MULTI:
        printf("Key Value: %17c", ' ');
        break;
    case PS_META_LIST:
        printf("Key Value: %15s  ", "psList");
        break;
    case PS_META_BOOL:
        printf("Key Value: %15d  ", metadataItem->data.B);
        break;
    case PS_META_S32:
        printf("Key Value: %15d  ", metadataItem->data.S32);
        break;
    case PS_META_F32:
        printf("Key Value: %15.3f  ", metadataItem->data.F32);
        break;
    case PS_META_F64:
        printf("Key Value: %15.3f  ", metadataItem->data.F64);
        break;
    case PS_META_STR:
        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[] )
{
    psMetadataItem *item1a = NULL;
    psMetadataItem *item1b = NULL;
    psMetadataItem *item1c = NULL;
    psMetadataItem *item2a = NULL;
    psMetadataItem *item2b = NULL;
    psMetadata *metadata = NULL;


    // Test A - Allocate metadata and items
    printPositiveTestHeader(stdout, "psMetadata", "Test A - Allocate metadata and items");
    item1a = psMetadataItemAlloc("myItem1", PS_META_BOOL, "I am a boolean", true);
    item1b = psMetadataItemAlloc("myItem1", PS_META_S32, "I am a signed integer", 111);
    item1c = psMetadataItemAlloc("myItem1", PS_META_S32, "I am a signed integer", 222);
    item2a = psMetadataItemAlloc("myItem2", PS_META_S32, "I am a signed integer", 333);
    item2b = psMetadataItemAlloc("myItem2", PS_META_LIST, "I am a list", NULL);
    metadata = psMetadataAlloc();
    printMetadataItem(item1a);
    printMetadataItem(item1b);
    printMetadataItem(item1c);
    printMetadataItem(item2a);
    printMetadataItem(item2b);
    printFooter(stdout, "psMetadata", "Test A - Allocate metadata and items", true);


    // Test B - Add leaf node on top of existing leaf node
    printPositiveTestHeader(stdout, "psMetadata", "Test B - replace an item in the metadata");
    if(!psMetadataAddItem(metadata, item1a, PS_LIST_HEAD, PS_META_DEFAULT)) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem returned false for adding a node top.");
        return 20;
    }
    psMetadataItem* tempItem = psMetadataLookup(metadata, item1a->name);
    if (tempItem != item1a) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem didn't add the metadata entry.");
        return 20;
    }

    if (!psMetadataAddItem(metadata, item1b, PS_LIST_HEAD, PS_META_REPLACE)) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem returned false for adding a node top.");
        return 21;
    }

    tempItem = psMetadataLookup(metadata, item1a->name);
    if (tempItem != item1b) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem didn't replace the metadata entry.");
        return 21;
    }

    printFooter(stdout, "psMetadata", "Test B - replace an item in the metadata", true);


    // Test C - Add leaf node to existing folder node
    printPositiveTestHeader(stdout, "psMetadata", "Test C - add duplicate-key metadata item");
    if (!psMetadataAddItem(metadata, item1c, PS_LIST_HEAD, PS_META_DUPLICATE_OK)) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem return false for adding a not to existing node.");
        return 22;
    }

    tempItem = psMetadataLookup(metadata, item1a->name);
    if (tempItem == NULL || tempItem->type != PS_META_MULTI) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem didn't add additional metadata entry of same key.");
        return 22;
    }
    printFooter(stdout, "psMetadata", "Test C - add duplicate-key metadata item", true);


    // Test D - Add folder node on top of existing leaf node
    printPositiveTestHeader(stdout, "psMetadata", "Test D - Add folder node on top of existing leaf node");
    if (!psMetadataAddItem(metadata, item2a, PS_LIST_HEAD, PS_META_DEFAULT)) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem returned false for adding a node to existing leaf node.");
        return 23;
    }
    if (!psMetadataAddItem(metadata, item2b, PS_LIST_HEAD, PS_META_DUPLICATE_OK)) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem returned false for adding a nod to existing leaf node.");
        return 24;
    }
    printFooter(stdout, "psMetadata", "Test D - Add folder node on top of existing leaf node", true);
    tempItem = psMetadataLookup(metadata, item1a->name);
    if (tempItem == NULL || tempItem->type != PS_META_MULTI) {
        psError(PS_ERR_UNKNOWN, true,"psMetadataAddItem didn't add additional metadata entry of same key.");
        return 24;
    }


    // Test E - Free psMetadata
    printPositiveTestHeader(stdout, "psMetadata", "Test E - Free psMetadata");
    psFree(item1a);
    psFree(item1b);
    psFree(item1c);
    psFree(item2a);
    psFree(item2b);
    psFree(metadata);
    if ( psMemCheckLeaks(0, NULL, stdout, false) != 0 ) {
        psError(PS_ERR_UNKNOWN, true,"Memory leaks detected.");
        return 25;
    }
    psMemCheckCorruption(0);
    psS32 nBad = psMemCheckCorruption(0);
    if(nBad) {
        printf("ERROR: Found %d bad memory blocks\n", nBad);
    }
    printFooter(stdout, "psMetadata", "Test E - Free psMetadata", true);


    return 0;
}
