/** @file  tst_psString.c
 *
 * -*- mode: C; c-basic-indent: 4; tab-width: 8; indent-tabs-mode: nil -*-
 * vim: set cindent ts=8 sw=4 expandtab:
 *
 *  @brief Test driver for psString functions
 *
 *  This test driver contains the following test points for psStringCopy
 *  and psStringNCopy, and related string functions.
 *    1) Verify string copy - psStringCopy
 *    2) Verify empty string copy - psStringCopy
 *    3) Verify string copy with length - psStringNCopy
 *    4) Verify empty string copy with length - psStringNCopy
 *    5) Copy string to larger string - psStringNCopy
 *    6) Copy string with negative size - psStringNCopy
 *    7) Verifiy creation of string literal - PS_STRING
 *
 *  Return:   Number of test points which failed
 *
 *  @author  Eric Van Alst, MHPCC
 *
 *  @version $Revision: 1.4 $  $Name: not supported by cvs2svn $
 *  @date  $Date: 2006-02-01 20:40:56 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 *
 */

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

#define STR_0 "binky had a leeeetle lamb"

static psS32 testStringCopy00(void);
static psS32 testStringCopy01(void);
static psS32 testStringCopy02(void);
static psS32 testStringCopy03(void);
static psS32 testStringCopy04(void);
//static psS32 testStringCopy05(void);
static psS32 testStringCopy06(void);

static psS32 testStrAppend00(void);
static psS32 testStrAppend01(void);
static psS32 testStrAppend02(void);
static psS32 testStrAppend03(void);

static psS32 testStrPrepend00(void);
static psS32 testStrPrepend01(void);
static psS32 testStrPrepend02(void);
static psS32 testStrPrepend03(void);

static psS32 testStrSplit00(void);
static psS32 testNULLStrings(void);

testDescription tests[] = {
                              {testStringCopy00, 0, "Verify string copy", 0, false},
                              {testStringCopy01, 1, "Verify empty string copy", 0, false},
                              {testStringCopy02, 2, "Verify string copy with length", 0, false},
                              {testStringCopy03, 3, "Verify empty string copy with length", 0, false},
                              {testStringCopy04, 4, "Copy string to larger string", 0, false},
                              //                              {testStringCopy05, 5, "Copy string with negative size", 0, false},
                              {testStringCopy06, 6, "Verify creation of string literal", 0, false},

                              {testStrAppend00,  7, "Verify generic string append", 0, false},
                              {testStrAppend01,  8, "Test append NULL handling", 0, false},
                              {testStrAppend02,  9, "Verify append string creation", 0, false},
                              {testStrAppend03, 10, "Test append null-op", 0, false},

                              {testStrPrepend00,11, "Verify generic string prepend", 0, false},
                              {testStrPrepend01,12, "Test prepend NULL handling", 0, false},
                              {testStrPrepend02,13, "Verify prepend string creation", 0, false},
                              {testStrPrepend03,14, "Test prepend null-op", 0, false},
                              {testStrSplit00,15, "Test String Splitting", 0, false},
                              {testNULLStrings,666, "Test NULL String Error Handling", 0, false},
                              {NULL}
                          };

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

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

/*
psS32 main( psS32 argc,
          char * argv[] )
{
    psBool  tpResult = false;
    char  stringval[20] = "E R R O R";
    char  stringval1[20] = "e r r o r";
    char  *stringvalnocopy = "F A I L";
    char  *substringval = "e r r";
    psS32   substringlen = 6;
    char  *emptyval = "";
    psS32   tpFails = 0;
    char  *strResult;
    psS32   increaseSize = 5;
    psS32   negativeSize = -5;
    psS32   result = 0;
    psS32   result1 = 0;
    psS32   memBlockAllocated = 0;
    psMemBlock ***memBlockPtr = NULL;
 
*/

static psS32 testStringCopy00(void)
{
    char  stringval[20] = "E R R O R";
    psS32   result = 0;
    psS32   result1 = 0;
    char  *strResult;

    // Test point #1 Verify string copy - psStringCopy
    strResult = psStringCopy(stringval);
    // Perform string compare
    result = strcmp(strResult, stringval);
    // Modify original string
    stringval[0]='G';
    result1 = strcmp(strResult, stringval);
    stringval[0]='E';
    if ( ( result != 0 ) || ( result1 == 0) ) {
        fprintf(stderr, "Failed test point #1 strcmp result = %d expected 0\n",result);
        fprintf(stderr, "                               src = %s expected %s\n",
                strResult, stringval);
        fprintf(stderr, "             changed strcmp result = %d expected 1\n",result1);
        fprintf(stderr, "             changed           src = %s expected %s\n",strResult,
                stringval);
        return 1;
    }

    // Free memory allocated
    psFree(strResult);

    return 0;
}

static psS32 testStringCopy01(void)
{
    char  *emptyval = "";
    psS32   result = 0;
    char  *strResult;

    // Test point #2 Verify empty string copy - psStringCopy
    strResult = psStringCopy(emptyval);
    // Perform string compare
    result = strcmp(strResult, emptyval);
    if ( result != 0 ) {
        fprintf(stderr,"Failed test point #2 strcmp result = %d expected 0\n",result);
        fprintf(stderr,"                               src = %s expected %s\n",
                strResult, emptyval);
        return 1;
    }

    // Free memory allocated
    psFree(strResult);

    return 0;
}

static psS32 testStringCopy02(void)
{
    psS32   result = 0;
    psS32   result1 = 0;
    char  *strResult;
    char  stringval1[20] = "e r r o r";
    psS32   substringlen = 5;
    char  *substringval = "e r r";

    // Test point #3 Verify string copy with length - psStringNCopy
    strResult = psStringNCopy(stringval1, substringlen);
    // Perform string compare and get string length
    result = strncmp(strResult, substringval, substringlen);
    // Change original string
    stringval1[0] = 'g';
    result1 = strncmp(strResult, substringval, substringlen);
    if ( ( result != 0 ) || ( result1 != 0 ) ) {
        fprintf(stderr,"Failed test point #3 strcmp result = %d expected 0\n",result);
        fprintf(stderr,"                               src = %s expected %s\n",
                strResult, substringval);
        fprintf(stderr,"             changed strcmp result = %d expected 0\n",result1);
        fprintf(stderr,"                               src = %s expected %s\n",
                strResult, substringval);
        return 1;
    }
    // Free memory allocated
    psFree(strResult);

    return 0;
}

static psS32 testStringCopy03(void)
{
    psS32   result = 0;
    psS32   result1 = 0;
    char  *strResult;
    char  *stringvalnocopy = "F A I L";

    // Test point #4 Verify empty string copy with length - psStringNCopy
    strResult = psStringNCopy(stringvalnocopy, 0);
    // Perform string compare and get sting length
    result = strcmp(strResult, stringvalnocopy);
    result1 = strlen(strResult);
    if ( result == 0 ) {
        fprintf(stderr,"Failed test point #4 strcmp result = %d didn't expected %d\n",result,0);
        fprintf(stderr,"                               src = %s didn't expected %s\n",
                strResult, stringvalnocopy);
        return 1;
    }
    // Free memory
    psFree(strResult);

    return 0;
}

static psS32 testStringCopy04(void)
{
    psS32   result = 0;
    psS32   result1 = 0;
    char  *strResult;
    char  stringval[20] = "E R R O R";
    psS32   increaseSize = 5;

    // Test point #5 Copy string to larger string - psStringNCopy
    strResult = psStringNCopy(stringval, (strlen(stringval) + increaseSize));
    // Perform string compare and get string length
    result = strcmp(strResult, stringval);
    result1 = strlen(strResult);
    // The strings should still compare
    if ( ( result != 0 ) ||
            ( result1 != strlen(stringval) ) ) {
        fprintf(stderr,"Failed test point #5 strcmp result = %d expected %d\n",result,0);
        fprintf(stderr,"                               src = %s expected %s\n",
                strResult, stringval);
        fprintf(stderr,"                     strlne result = %d expected %d\n",result1,
                (psS32)strlen(stringval));
        return 1;
    }
    // Free memory
    psFree(strResult);

    return 0;
}

// XXX This test needs to be modified to check for maximum size
//     This will require a mod to psStringNCopy source to check for maximum size
//
//static psS32 testStringCopy05(void)
//{
//    char  *strResult;
//    char  stringval[20] = "E R R O R";
//    psS32   negativeSize = -5;
//
//    // Test point #6 Copy string with negative size - psStringNCopy
//    strResult = psStringNCopy(stringval, negativeSize);
//    if ( strResult != NULL ) {
//        fprintf(stderr,"Failed test point #6 return value = %p expected NULL\n",
//                strResult);
//        return 1;
//    }
//    // Memory should not have been allocated
//
//    return 0;
//}

static psS32 testStringCopy06(void)
{
    char  *strResult;
    char  stringval[20] = "E R R O R";
    psS32   result = 0;

    // Test point #7 Verify creation of string literal - PS_STRING
    strResult = PS_STRING(E R R O R);
    result = strcmp(strResult, stringval);
    if ( result != 0 ) {
        fprintf(stderr,"Failed test point #7 strcmp result = %d expected %d",result,0);
        return 1;
    }
    // Memory should not have been allocated

    return 0;
}

static psS32 testStrAppend00(void)
{
    char *str=NULL;
    int result = 0;

    str = psStringCopy("3.14159");

    psStringAppend(&str, "%d%s", 2653589, "79323846");

    // Test point: Verify string append
    result = strcmp(str, "3.14159265358979323846");
    if ( result != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }

    psFree(str);

    return 0;
}

static psS32 testStrAppend01(void)
{
    ssize_t sz;
    char *str=NULL;

    // test nonsensical invocations ...
    sz = psStringAppend(NULL, NULL);
    if ( sz != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }
    sz = psStringAppend(&str, NULL);
    if ( sz != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }

    return 0;
}

static psS32 testStrAppend02(void)
{
    char *str=NULL;
    int result;

    // test string creation
    psStringAppend(&str, "%s", "fubar");
    result = strcmp(str, "fubar");
    if ( result != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }

    psFree(str);

    return 0;
}

static psS32 testStrAppend03(void)
{
    char *str=NULL;
    int result;

    str = psStringCopy(STR_0);

    // test null-op
    psStringAppend(&str, "");
    result = strcmp(str, STR_0);
    if ( result != 0 ) {
        fprintf(stderr,"Failed test point str=[%s]\n", str);
        return 1;
    }

    psFree(str);

    return 0;
}

static psS32 testStrPrepend00(void)
{
    char *str=NULL;
    int result = 0;

    str = psStringCopy("79323846");

    psStringPrepend(&str, "%s%d","3.14159", 2653589 );

    // Test point: Verify string append
    result = strcmp(str, "3.14159265358979323846");
    if ( result != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }

    psFree(str);

    return 0;
}

static psS32 testStrPrepend01(void)
{
    ssize_t sz;
    char *str=NULL;

    // test nonsensical invocations ...
    sz = psStringPrepend(NULL, NULL);
    if ( sz != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }
    sz = psStringPrepend(&str, NULL);
    if ( sz != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }

    return 0;
}

static psS32 testStrPrepend02(void)
{
    char *str=NULL;
    int result;

    // test string creation
    psStringPrepend(&str, "%s", "fubar");
    result = strcmp(str, "fubar");
    if ( result != 0 ) {
        fprintf(stderr,"%s","Failed test point\n");
        return 1;
    }

    psFree(str);

    return 0;
}

static psS32 testStrPrepend03(void)
{
    char *str=NULL;
    int result;

    str = psStringCopy(STR_0);

    // test null-op
    psStringPrepend(&str, "");
    result = strcmp(str, STR_0);
    if ( result != 0 ) {
        fprintf(stderr,"Failed test point str=[%s]\n", str);
        return 1;
    }

    psFree(str);

    return 0;
}

static psS32 testStrSplit00(void)
{
    psList *strList = NULL;
    char str[35];
    char split[5];
    strncpy(str, "This is, a, test case, to check.", 35);
    strncpy(split, ",", 2);
    psString psStr;
    psString psSplit;
    psStr = psStringCopy(str);
    psSplit = psStringCopy(split);

    //Return NULL for NULL inputs
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    strList = psStringSplit(NULL, NULL);
    if (strList != NULL) {
        psFree(strList);
        return 1;
    }
    //Return NULL for NULL string input
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    strList = psStringSplit(NULL, split);
    if (strList != NULL) {
        psFree(strList);
        return 2;
    }
    //Return NULL for NULL splitter input
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    strList = psStringSplit(str, NULL);
    if (strList != NULL) {
        psFree(strList);
        return 3;
    }
    //Return a psList* of psStrings
    strList = psStringSplit(str, split);
    if (strList->n != 4) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return the correct number of strings.\n");
        return 4;
    }
    if ( strncmp((psString)(strList->head->data), "This is", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 5;
    }
    if ( strncmp((psString)(strList->head->next->data), " a", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 6;
    }
    if ( strncmp((psString)(strList->head->next->next->data), " test case", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 7;
    }
    if ( strncmp((psString)(strList->head->next->next->next->data), " to check.", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 8;
    }
    psFree(strList);
    //Return correct psList when using (psString, char*)
    strList = psStringSplit(psStr, split);
    if (strList->n != 4) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return the correct number of strings.\n");
        return 9;
    }
    if ( strncmp((psString)(strList->head->data), "This is", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 10;
    }
    if ( strncmp((psString)(strList->head->next->data), " a", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 11;
    }
    if ( strncmp((psString)(strList->head->next->next->data), " test case", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 12;
    }
    if ( strncmp((psString)(strList->head->next->next->next->data), " to check.", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 13;
    }
    psFree(strList);
    //Return correct psList when using (char*, psString)
    strList = psStringSplit(str, psSplit);
    if (strList->n != 4) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return the correct number of strings.\n");
        return 14;
    }
    if ( strncmp((psString)(strList->head->data), "This is", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 15;
    }
    if ( strncmp((psString)(strList->head->next->data), " a", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 16;
    }
    if ( strncmp((psString)(strList->head->next->next->data), " test case", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 17;
    }
    if ( strncmp((psString)(strList->head->next->next->next->data), " to check.", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 18;
    }
    psFree(strList);
    //Return correct psList when using (psString, psString)
    strList = psStringSplit(psStr, psSplit);
    if (strList->n != 4) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return the correct number of strings.\n");
        return 19;
    }
    if ( strncmp((psString)(strList->head->data), "This is", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 20;
    }
    if ( strncmp((psString)(strList->head->next->data), " a", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 21;
    }
    if ( strncmp((psString)(strList->head->next->next->data), " test case", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 22;
    }
    if ( strncmp((psString)(strList->head->next->next->next->data), " to check.", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 23;
    }
    psFree(strList);
    //Return correct psList output for string of zero length case
    strncpy(str, "This is,, a,, test case,, to check.", 35);
    strList = psStringSplit(str, split);
    if (strList->n != 4) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return the correct number of strings.\n");
        return 24;
    }
    if ( strncmp((psString)(strList->head->data), "This is", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 25;
    }
    if ( strncmp((psString)(strList->head->next->data), " a", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 26;
    }
    if ( strncmp((psString)(strList->head->next->next->data), " test case", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 27;
    }
    if ( strncmp((psString)(strList->head->next->next->next->data), " to check.", 10) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psStringSplit failed to return expected strings.");
        return 28;
    }

    psFree(strList);
    psFree(psStr);
    psFree(psSplit);
    return 0;
}

static psS32 testNULLStrings(void)
{
    psString nullTest = NULL;
    psString output = NULL;
    ssize_t outSize = 0;
    char** nullDest = NULL;
    char** test;
    //psStringCopy should return NULL for NULL input string
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    output = psStringCopy(nullTest);
    if (output != NULL) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringCopy failed to return NULL for NULL input string.\n");
        return 1;
    }
    //psStringNCopy should return NULL for NULL input string
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    output = psStringNCopy(nullTest, 100);
    if (output != NULL) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringNCopy failed to return NULL for NULL input string.\n");
        return 2;
    }

    //psStringAppend should return 0 for NULL input destination
    outSize = psStringAppend(nullDest, "");
    if (outSize != 0) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringAppend failed to return 0 for NULL input destination.\n");
        return 3;
    }
    //psStringAppend should return 0 for NULL input format
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    outSize = psStringAppend(test, nullTest);
    if (outSize != 0) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringAppend failed to return 0 for NULL input format.\n");
        return 4;
    }
    //psStringPrepend should return 0 for NULL input destination
    outSize = psStringPrepend(nullDest, " ");
    if (outSize != 0) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringPrepend failed to return 0 for NULL input destination.\n");
        return 3;
    }
    //psStringPrepend should return 0 for NULL input format
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    outSize = psStringPrepend(test, nullTest);
    if (outSize != 0) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringPrepend failed to return 0 for NULL input format.\n");
        return 4;
    }
    //psStringSplit should return NULL for NULL input string
    psList *nullList = NULL;
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    nullList = psStringSplit(nullTest, ",");
    if (nullList != NULL) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringSplit failed to return NULL for NULL input string.\n");
        return 5;
    }
    //psStringSplit should return NULL for NULL input splitter
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    nullList = psStringSplit("Hello World", nullTest);
    if (nullList != NULL) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psStringSplit failed to return NULL for NULL input splitter.\n");
        return 6;
    }

    return 0;
}

