/**
 *  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"

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

    // testArgumentGetParse()
    {
        psMemId id = psMemGetId();
        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();
        }
        ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
    }


    // testArgumentVerbosity()
    {
        psMemId id = psMemGetId();
        //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.");
        }

        //These routines should return 5 since that was the last level set above with -vvv
        //Return 5 for "-logfmt" option
        {
            int argc = 2;
            char *argv[2];
            argv[0] = "./program";
            argv[1] = "-logfmt";
            int rc = psArgumentVerbosity(&argc, argv);
            ok(rc == 5, "psArgumentVerbosity:  return 5 for '-logfmt' argument input (was %d)", rc);
        }

        //Return 5 for "-logfmt" option with "H"
        {
            int argc = 3;
            char *argv[3];
            argv[0] = "./program";
            argv[1] = "-logfmt";
            argv[2] = "H";
            int rc = psArgumentVerbosity(&argc, argv);
            ok(rc == 5, "psArgumentVerbosity:  return 5 for '-logfmt H' argument inputs (was %d)", rc);
        }

        //Return 5 for "-trace" option
        {
            int argc = 2;
            char *argv[2];
            argv[0] = "./program";
            argv[1] = "-trace";
            int rc = psArgumentVerbosity(&argc, argv);
            ok(rc == 5, "psArgumentVerbosity:  return 5 for '-trace' argument input (was %d)", rc);
        }

        //Return 5 for "-trace 1 2" option
        {
            int argc = 4;
            char *argv[4];
            argv[0] = "./program";
            argv[1] = "-trace";
            argv[2] = "1";
            argv[3] = "2";
            int rc = psArgumentVerbosity(&argc, argv);
            ok(rc == 5, "psArgumentVerbosity:  return 5 for '-trace 1 2' argument inputs (was %d", rc);
        }

        //Return 5 for "-trace-levels" option
        {
            int argc = 2;
            char *argv[2];
            argv[0] = "./program";
            argv[1] = "-trace-levels";
            int rc = psArgumentVerbosity(&argc, argv);
            ok(rc == 5, "psArgumentVerbosity:  return 5 for '-trace-levels' argument input (was %d)", rc);
        }
        ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
    }
}


/* XXX: Why is this commented out?
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();
    }
}
*/
