/**
 *  C Implementation: tap_psArguments_all
 *
 * Description:  Tests for psArgumentVerbosity, psArgumentGet, psArgumentRemove,
 *               psArgumentParse, psArgumentHelp, psLogArguments, psTraceArguments
 *
 *
 * Author: dRob <David.Robbins@mhpcc.hpc.mil>, (C) 2006
 *
 * Copyright: See COPYING file that comes with this distribution
 *
 */

#include <pslib.h>

#include "tap.h"
#include "pstap.h"

void testArgumentGetParse(void);
void testArgumentVerbosity(void);
//void testLogTraceArguments(void);

int main(void)
{
    psLogSetFormat("HLNM");
    psLogSetLevel(PS_LOG_INFO);
    plan_tests(27);

    note("Tests for psArguments Functions");

    testArgumentGetParse();
    testArgumentVerbosity();
    //    testLogTraceArguments();

    done();
}

void testArgumentGetParse(void)
{
    note("  >>>Test 1:  psArgument Get, Remove, Parse, and Help Fxns");
    psMetadata *arg = NULL;
    char *argv[25];
    argv[0] = "./program";
    argv[1] = "-string";
    argv[2] = "new";
    argv[3] = "-float";
    argv[4] = "6.66";
    argv[5] = "-double";
    argv[6] = "0.666";
    argv[7] = "-int";
    argv[8] = "8";
    argv[9] = "-int";
    argv[10] = "16";
    argv[11] = "-int";
    argv[12] = "32";
    argv[13] = "-int";
    argv[14] = "64";
    argv[15] = "-U8";
    argv[16] = "1";
    argv[17] = "-U16";
    argv[18] = "666";
    argv[19] = "-U32";
    argv[20] = "666";
    argv[21] = "-Bool";
    argv[22] = "true";
    argv[23] = "-int";
    //    argv[24] = "32";
    argv[24] = "-vvv";
    int argc = 25;

    //Try to get an argument's position
    int i = psArgumentGet(argc, argv, "-float");
    {
        ok( i == 3,
            "psArgumentGet:         return correct location of input argument.");
    }
    //Return 0 for attempting to get from a NULL input argument.
    {
        ok( psArgumentGet(argc, NULL, "-float") == 0,
            "psArgumentGet:         return 0 for a NULL input argument.");
    }
    //Return 0 for attempting to find a NULL string
    {
        ok( psArgumentGet(argc, argv, NULL) == 0,
            "psArgumentGet:         return 0 for a NULL input string.");
    }
    //Return 0 for attempting to find an empty string
    {
        ok( psArgumentGet(argc, argv, "") == 0,
            "psArgumentGet:         return 0 for an empty input string.");
    }
    //Return 0 for attempting to get an argument that doesn't match
    {
        ok( psArgumentGet(argc, argv, "-xxx") == 0,
            "psArgumentGet:         return 0 for an empty input string.");
    }
    //Return false for attempting to remove argnum = 0
    {
        ok( !psArgumentRemove(0, &argc, argv),
            "psArgumentRemove:      return false for argnum = 0.");
    }
    //Return false for attempting to remove NULL argc
    {
        ok( !psArgumentRemove(0, NULL, argv),
            "psArgumentRemove:      return false for NULL argc.");
    }

    //Setup the argument list for comparison
    psMetadata *args = psMetadataAlloc();
    psMetadataAdd(args, PS_LIST_TAIL, "-string", PS_DATA_STRING, "Test String", "SomeString");
    psMetadataAdd(args, PS_LIST_TAIL, "-float", PS_DATA_F32, "Test Float", 0.666);
    psMetadataAdd(args, PS_LIST_TAIL, "-double", PS_DATA_F64, "Test Double", 0.666);
    psMetadata *ints = psMetadataAlloc();
    psMetadataAdd(ints, PS_LIST_TAIL, "int1", PS_DATA_S8, "Int1", 8);
    psMetadataAdd(ints, PS_LIST_TAIL, "int2", PS_DATA_S16, "Int2", 16);
    psMetadataAdd(ints, PS_LIST_TAIL, "int3", PS_DATA_S32, "Int3", 32);
    psMetadataAdd(ints, PS_LIST_TAIL, "int4", PS_DATA_S64, "Int4", 64);
    psMetadataAdd(args, PS_LIST_TAIL, "-int", PS_DATA_METADATA, "Integers", ints);
    psFree(ints);                  // Drop reference
    psMetadataAddS32(args, PS_LIST_TAIL, "-multi", 0, "666", 2);
    psMetadataAddS32(args, PS_LIST_TAIL, "-multi", PS_META_DUPLICATE_OK, "hello kitty", 1);

    psMetadataAddU8(args, PS_LIST_TAIL, "-U8", 0, "U8", 1);
    psMetadataAddU16(args, PS_LIST_TAIL, "-U16", 0, "U16", 666);
    psMetadataAddU32(args, PS_LIST_TAIL, "-U32", 0, "U32", 666);
    psMetadataAddU64(args, PS_LIST_TAIL, "-U64", 0, "U64", 666);
    psMetadataAddBool(args, PS_LIST_TAIL, "-Bool", 0, "boolean", true);
    psMetadataAddBool(args, PS_LIST_TAIL, "-Bool2", 0, "boolean", false);
    psSphere *sphere = psSphereAlloc();
    sphere->r = 6.66;
    sphere->d = 666.666;
    psMetadataAddPtr(args, PS_LIST_TAIL, "ptr", PS_DATA_SPHERE, "", sphere);
    psFree(sphere);

    //psArgumentHelp test
    //Do nothing for NULL input (exit gracefully)
    psArgumentHelp(NULL);
    //Print the Argument help for valid metadata
    psArgumentHelp(args);

    //psArgumentParse tests
    //Return false for NULL input arguments
    {
        ok( !psArgumentParse(NULL, &argc, argv),
            "psArgumentParse:       return false for NULL argument metadata input.");
    }
    //Return false for NULL input argc
    {
        ok( !psArgumentParse(args, NULL, argv),
            "psArgumentParse:       return false for NULL argc input.");
    }
    //Return false for NULL input argv
    {
        ok( !psArgumentParse(args, &argc, NULL),
            "psArgumentParse:       return false for NULL argv input.");
    }
    //Return false for argc = 0
    {
        int tempc = 0;
        ok( !psArgumentParse(args, &tempc, argv),
            "psArgumentParse:       return false for argc = 1 input.");
    }
    //Return false for string not found in metadata arguments
    {
        ok( !psArgumentParse(args, &argc, argv),
            "psArgumentParse:      return false for argv containing unspecified input.");
    }
    //Return true for valid case
    {
        psArgumentRemove(25, &argc, argv);
        ok( psArgumentParse(args, &argc, argv),
            "psArgumentParse:      return true for valid inputs.");
    }
    //Return false for inconsistent argc in metadata
    {
        psMetadata *tempArg = psMetadataAlloc();
        psMetadata *mdtemp = psMetadataAlloc();
        psMetadataAdd(mdtemp, PS_LIST_TAIL, "int1", PS_DATA_S8, "Int1", 8);
        psMetadataAdd(mdtemp, PS_LIST_TAIL, "int2", PS_DATA_S16, "Int2", 16);
        psMetadataAdd(mdtemp, PS_LIST_TAIL, "int3", PS_DATA_S32, "Int3", 32);
        psMetadataAdd(tempArg, PS_LIST_TAIL, "-int", PS_DATA_METADATA, "Integers", mdtemp);
        psFree(mdtemp);
        int argcc = 2;
        char *argvv[2];
        argvv[0] = "./program";
        argvv[1] = "-string";
        ok( !psArgumentParse(tempArg, &argcc, argvv),
            "psArgumentParse:      return false for inconsistent argc.");
        psFree(tempArg);
    }
    //Return false for argc = 1
    {
        int argcc = 2;
        char *argvv[2];
        argvv[0] = "./program";
        argvv[1] = "-string";
        ok( !psArgumentParse(args, &argcc, argvv),
            "psArgumentParse:      return false for incomplete string syntax.");
    }
    //Return true for an unfound MULTI match
    {
        int argcc = 3;
        char *argvv[3];
        argvv[0] = "./program";
        argvv[1] = "-multi";
        argvv[2] = "2";
        ok( psArgumentParse(args, &argcc, argvv),
            "psArgumentParse:      return true for MULTI.");
    }

    //Check for Memory leaks
    {
        psFree(args);
        psFree(arg);
        checkMem();
    }
}

void testArgumentVerbosity(void)
{
    note("  >>>Test 2:  psArgumentRemove & psArgumentVerbosity Fxns");

    //Return 2 (default) for NULL input argument
    {
        int argc = 1;
        ok( psArgumentVerbosity(&argc, NULL) == 2,
            "psArgumentVerbosity:  return 2 for NULL argument input.");
    }
    //Return 2 for NULL argc input
    {
        char *argv[1];
        argv[0] = "./program";
        ok( psArgumentVerbosity(NULL, argv) == 2,
            "psArgumentVerbosity:  return 2 for NULL argument input.");
    }
    //Return 3 for "-v" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-v";
        ok( psArgumentVerbosity(&argc, argv) == 3,
            "psArgumentVerbosity:  return 3 for '-v' argument input.");
    }
    //Return 4 for "-vv" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-vv";
        ok( psArgumentVerbosity(&argc, argv) == 4,
            "psArgumentVerbosity:  return 4 for '-vv' argument input.");
    }
    //Return 5 for "-vvv" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-vvv";
        ok( psArgumentVerbosity(&argc, argv) == 5,
            "psArgumentVerbosity:  return 5 for '-vvv' argument input.");
    }
    //Return 2 for "-logfmt" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-logfmt";
        ok( psArgumentVerbosity(&argc, argv) == 2,
            "psArgumentVerbosity:  return 2 for '-logfmt' argument input.");
    }
    //Return 2 for "-logfmt" option with "H"
    {
        int argc = 3;
        char *argv[3];
        argv[0] = "./program";
        argv[1] = "-logfmt";
        argv[2] = "H";
        ok( psArgumentVerbosity(&argc, argv) == 2,
            "psArgumentVerbosity:  return 2 for '-logfmt H' argument inputs.");
    }
    //Return 2 for "-trace" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-trace";
        ok( psArgumentVerbosity(&argc, argv) == 2,
            "psArgumentVerbosity:  return 2 for '-trace' argument input.");
    }
    //Return 2 for "-trace 1 2" option
    {
        int argc = 4;
        char *argv[4];
        argv[0] = "./program";
        argv[1] = "-trace";
        argv[2] = "1";
        argv[3] = "2";
        ok( psArgumentVerbosity(&argc, argv) == 2,
            "psArgumentVerbosity:  return 2 for '-trace 1 2' argument inputs.");
    }
    //Return 2 for "-trace-levels" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-trace-levels";
        ok( psArgumentVerbosity(&argc, argv) == 2,
            "psArgumentVerbosity:  return 2 for '-trace-levels' argument input.");
    }

    //Check for Memory leaks
    {
        checkMem();
    }
}

/*
void testLogTraceArguments(void)
{
    note("  >>>Test 3:  psLogArguments & psTraceArguments Fxns");
 
    //Return 2 (default) for NULL arguments input
    {
        int argc = 4;
        ok( psLogArguments(&argc, NULL) == 2,
            "psLogArguments:       return 2 for NULL argument input.");
    }
    //Return 2 (default) for NULL argc input
    {
        char *argv[1];
        argv[0] = "./program";
        ok( psLogArguments(NULL, argv) == 2,
            "psLogArguments:       return 2 for NULL argc input.");
    }
    //Return 3 for "-v" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-v";
        ok( psLogArguments(&argc, argv) == 3,
            "psLogArguments:       return 3 for '-v' argument input.");
    }
    //Return 4 for "-vv" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-vv";
        ok( psLogArguments(&argc, argv) == 4,
            "psLogArguments:       return 4 for '-vv' argument input.");
    }
    //Return 5 for "-vvv" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-vvv";
        ok( psLogArguments(&argc, argv) == 5,
            "psLogArguments:       return 5 for '-vvv' argument input.");
    }
    //Return 2 for "-logfmt" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-logfmt";
        ok( psLogArguments(&argc, argv) == 2,
            "psLogArguments:       return 2 for '-logfmt' argument input.");
    }
    //Return 2 for "-logfmt" option with "H"
    {
        int argc = 3;
        char *argv[3];
        argv[0] = "./program";
        argv[1] = "-logfmt";
        argv[2] = "H";
        ok( psLogArguments(&argc, argv) == 2,
            "psLogArguments:       return 2 for '-logfmt H' argument inputs.");
    }
 
 
    //psTraceArguments Tests
    //Return 0 (default) for NULL arguments input
    {
        int argc = 4;
        ok( psTraceArguments(&argc, NULL) == 0,
            "psTraceArguments:     return 0 for NULL argument input.");
    }
    //Return 0 (default) for NULL argc input
    {
        char *argv[1];
        argv[0] = "./program";
        ok( psTraceArguments(NULL, argv) == 0,
            "psTraceArguments:     return 0 for NULL argc input.");
    }
    //Return 0 for "-trace" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-trace";
        ok( psTraceArguments(&argc, argv) == 0,
            "psTraceArguments:     return 2 for '-trace' argument input.");
    }
    //Return 2 for "-trace 1 2" option
    {
        int argc = 4;
        char *argv[4];
        argv[0] = "./program";
        argv[1] = "-trace";
        argv[2] = "1";
        argv[3] = "2";
        ok( psTraceArguments(&argc, argv) == 1,
            "psTraceArguments:     return 2 for '-trace 1 2' argument inputs.");
    }
    //Return 2 for "-trace-levels" option
    {
        int argc = 2;
        char *argv[2];
        argv[0] = "./program";
        argv[1] = "-trace-levels";
        ok( psTraceArguments(&argc, argv) == 0,
            "psTraceArguments:     return 2 for '-trace-levels' argument input.");
    }
 
    //Check for Memory leaks
    {
        checkMem();
    }
}
*/
