/** @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.1 $  $Name: not supported by cvs2svn $
 *  @date  $Date: 2006-12-18 19:18:46 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 *
 */

#include <string.h>
#include "pslib.h"
#include "tap.h"
#include "pstap.h"


#define STR_0 "binky had a leeeetle lamb"

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

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

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

psS32 testStrSplit00(void);
psS32 testNULLStrings(void);
psS32 testStrCheck(void);

static const char* const NullString = "";


psS32 main( psS32 argc, char* argv[] )
{
    plan_tests(55);

    testStringCopy00();
    testStringCopy01();
    testStringCopy02();
    testStringCopy03();
    testStringCopy04();
    testStringCopy06();

    testStrAppend00();
    testStrAppend01();
    testStrAppend02();
    testStrAppend03();

    testStrPrepend00();
    testStrPrepend01();
    testStrPrepend02();
    testStrPrepend03();

    testStrSplit00();
    testNULLStrings();
    testStrCheck();
}


psS32 testStringCopy00(void)
{
    diag("testStringCopy00");

    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';
    ok ( ( result == 0 ) && ( result1 != 0),
         "Failed test point #1 strcmp result = %d expected 0\n",result);

    // Free memory allocated
    psFree(strResult);

    return 0;
}


psS32 testStringCopy01(void)
{
    diag("testStringCopy01");

    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);
    ok ( result == 0,
         "test point #2 strcmp result = %d expected 0\n",result);

    // Free memory allocated
    psFree(strResult);

    return 0;
}


psS32 testStringCopy02(void)
{
    diag("testStringCopy02");

    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);
    ok ( ( result == 0 ) && ( result1 == 0 ),
         "Failed test point #3 strcmp result = %d expected 0\n",result);

    // Free memory allocated
    psFree(strResult);

    return 0;
}

psS32 testStringCopy03(void)
{
    diag("testStringCopy03");

    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);
    ok ( result != 0,
         "test point #4 strcmp result = %d didn't expected %d\n",result,0);

    // Free memory
    psFree(strResult);

    return 0;
}

psS32 testStringCopy04(void)
{
    diag("testStringCopy04");

    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
    ok ( result == 0 && result1 == strlen(stringval),
         "test point #5 strcmp result = %d expected %d\n",result,0);

    // 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
//
//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;
//}


psS32 testStringCopy06(void)
{
    diag("testStringCopy06");

    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);
    ok ( result == 0,
         "test point #7 strcmp result = %d expected %d",result,0);

    // Memory should not have been allocated
    return 0;
}


psS32 testStrAppend00(void)
{
    diag("testStrAppend00");

    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");
    ok ( result == 0, "Failed test point\n");

    psFree(str);

    return 0;
}

psS32 testStrAppend01(void)
{
    diag("testStrAppend01");

    ssize_t sz;
    char *str=NULL;

    // test nonsensical invocations ...
    sz = psStringAppend(NULL, NULL);
    ok ( sz == 0, "Failed test point\n");

    sz = psStringAppend(&str, NULL);
    ok ( sz == 0, "Failed test point\n");

    return 0;
}


psS32 testStrAppend02(void)
{
    diag("testStrAppend02");

    char *str=NULL;
    int result;

    // test string creation
    psStringAppend(&str, "%s", "fubar");
    result = strcmp(str, "fubar");
    ok ( result == 0, "Failed test point\n");

    psFree(str);

    return 0;
}

psS32 testStrAppend03(void)
{
    diag("testStrAppend03");

    char *str=NULL;
    int result;

    str = psStringCopy(STR_0);

    // test null-op
    psStringAppend(&str, NullString);
    result = strcmp(str, STR_0);
    ok ( result == 0, "Failed test point str=[%s]\n", str);

    psFree(str);

    return 0;
}


psS32 testStrPrepend00(void)
{
    diag("testStrPrepend00");

    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");
    ok ( result == 0, "Failed test point\n");

    psFree(str);

    return 0;
}


psS32 testStrPrepend01(void)
{
    diag("testStrPrepend01");

    ssize_t sz;
    char *str=NULL;

    // test nonsensical invocations ...
    sz = psStringPrepend(NULL, NULL);
    ok ( sz == 0, "Failed test point\n");

    sz = psStringPrepend(&str, NULL);
    ok ( sz == 0, "Failed test point\n");

    return 0;
}

psS32 testStrPrepend02(void)
{
    diag("testStrPrepend02");

    char *str=NULL;
    int result;

    // test string creation
    psStringPrepend(&str, "%s", "fubar");
    result = strcmp(str, "fubar");
    ok ( result == 0, "Failed test point\n");

    psFree(str);

    return 0;
}

psS32 testStrPrepend03(void)
{
    diag("testStrPrepend03");

    char *str=NULL;
    int result;

    str = psStringCopy(STR_0);

    // test null-op
    psStringPrepend(&str, NullString);
    result = strcmp(str, STR_0);
    ok ( result == 0, "test point str=[%s]\n", str);

    psFree(str);

    return 0;
}


psS32 testStrSplit00(void)
{
    diag("testStrSplit00");

    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
    strList = psStringSplit(NULL, NULL, true);
    ok (!strList, "psStringSplit" );
    psFree(strList);

    strList = NULL;
    //Return empty list for NULL string input
    strList = psStringSplit(NULL, split, true);
    ok ( !psListLength(strList), "psListLength()" );
    psFree(strList);

    strList = NULL;
    //Return NULL for NULL splitter input
    strList = psStringSplit(str, NULL, true);
    ok ( !strList, "psStringSplit" );
    psFree(strList);

    strList = NULL;
    //Return a psList* of psStrings
    strList = psStringSplit(str, split, true);
    ok (strList->n == 4,
        "psStringSplit to return the correct number of strings.\n");

    ok ( !strncmp((psString)(strList->head->data), "This is", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->data), " a", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->data), " test case",10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->next->data), " to check.", 10),
         "psStringSplit failed to return expected strings.");

    psFree(strList);
    //Return correct psList when using (psString, char*)
    strList = psStringSplit(psStr, split, true);
    ok (strList->n == 4,
        "psStringSplit to return the correct number of strings.\n");

    ok ( !strncmp((psString)(strList->head->data), "This is", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->data), " a", 10),
         "psStringSplit failed to return expected strings.");

    ok ( strncmp((psString)(strList->head->next->next->data), " test case",10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->next->data), " to check.", 10),
         "psStringSplit to return expected strings.");

    psFree(strList);
    //Return correct psList when using (char*, psString)
    strList = psStringSplit(str, psSplit, true);
    ok (strList->n == 4,
        "psStringSplit to return the correct number of strings.\n");

    ok ( !strncmp((psString)(strList->head->data), "This is", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->data), " a", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->data), " test case",10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->next->data), " to check.", 10),
         "psStringSplit to return expected strings.");

    psFree(strList);
    //Return correct psList when using (psString, psString)
    strList = psStringSplit(psStr, psSplit, true);
    ok (strList->n == 4,
        "psStringSplit to return the correct number of strings.\n");

    ok ( !strncmp((psString)(strList->head->data), "This is", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->data), " a", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->data), " test case",10),
         "psStringSplit  to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->next->data), " to check.", 10),
         "psStringSplit to return expected strings.");

    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, false);
    ok (strList->n == 4,
        "psStringSplit to return the correct number of strings.\n");

    ok ( !strncmp((psString)(strList->head->data), "This is", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->data), " a", 10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->data), " test case",10),
         "psStringSplit to return expected strings.");

    ok ( !strncmp((psString)(strList->head->next->next->next->data), " to check.", 10),
         "psStringSplit to return expected strings.");

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

psS32 testNULLStrings(void)
{
    diag("testNULLStrings");

    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);
    ok (output == NULL,
        "psStringCopy to return NULL for NULL input string.\n");

    //psStringNCopy should return NULL for NULL input string
    output = psStringNCopy(nullTest, 100);
    ok (output == NULL,
        "psStringNCopy to return NULL for NULL input string.\n");

    //psStringAppend should return 0 for NULL input destination
    outSize = psStringAppend(nullDest, NullString);
    ok (outSize == 0,
        "psStringAppend to return 0 for NULL input destination.\n");

    //psStringAppend should return 0 for NULL input format
    outSize = psStringAppend(test, nullTest);
    ok (outSize == 0,
        "psStringAppend to return 0 for NULL input format.\n");

    //psStringPrepend should return 0 for NULL input destination
    outSize = psStringPrepend(nullDest, " ");
    ok (outSize == 0,
        "psStringPrepend to return 0 for NULL input destination.\n");

    //psStringPrepend should return 0 for NULL input format
    outSize = psStringPrepend(test, nullTest);
    ok (outSize == 0,
        "psStringPrepend to return 0 for NULL input format.\n");

    //psStringSplit should return empty list for NULL input string
    psList *nullList = NULL;
    nullList = psStringSplit(nullTest, ",", true);
    ok ( !psListLength(nullList),
         "psStringSplit to return NULL for NULL input string.\n");
    psFree(nullList);

    nullList = NULL;
    //psStringSplit should return NULL for NULL input splitter
    nullList = psStringSplit("Hello World", nullTest, true);
    ok ( !nullList,
         "psStringSplit to return NULL for NULL input splitter.\n");
    psFree(nullList);

    return 0;
}

psS32 testStrCheck(void)
{
    diag("testStrCheck");

    psString str = NULL;
    str = psStringAlloc(10);
    strcpy(str, "Hello");
    ok (psMemCheckString(str), "psString allocated!\n");

    ok (psMemCheckType(PS_DATA_STRING, str), "psString allocated!\n");
    psFree(str);

    char charStr[10];
    ok (!psMemCheckType(PS_DATA_STRING, charStr),
        "Input string is a psDataType");

    return 0;
}
