/** @file  tst_psLookupTable_01.c
*
*  @brief Test driver for psLookupTable functions
*
*  This test driver contains the following tests for psLookupTable functions:
*     testLookupAlloc - test allocation and freeing of psLookupTable
*     testLookupRead - test different files and types within files
*                      being read correctly and some failure cases
*     testLookupTableInterpolate - test the interpolation function
*     testLookupTableInterpolateAll - test interpolation of all row values
*
*  @author  Ross Harman, MHPCC
*
*  @version $Revision: 1.4 $  $Name: not supported by cvs2svn $
*  @date  $Date: 2006-02-24 23:43:16 $
*
*  Copyright 2004-5 Maui High Performance Computing Center, University of Hawaii
*
*/

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

static psS32 testLookupTableAlloc(void);
static psS32 testVectorsReadFromFile(void);
static psS32 testLookupTableImport(void);
static psS32 testLookupTableRead(void);
static psS32 testLookupTableInterpolate(void);
static psS32 testLookupTableInterpolateAll(void);

const psF64 errorTol_psF64 = 1.0e-4;
const psF64 tableU8_validFrom = 0;
const psF64 tableU8_validTo = 3;
const psS32 tableU8_size = 4;
const char tableU8_format[] = "\%d \%d \%d \%ld \%d \%d \%d \%ld \%f \%lf";
const char tableU8_filename[] = VERIFIED_DIR "/tableU8.dat";
const psS32 tableU8_indexCol = 0;
const psS32 tableU8_index[] =
    {
        0,   1,    2,   3
    };
const psU16 tableU8_val1[]  =
    {
        2,   4,    6,   8
    };
const psU32 tableU8_val2[]  =
    {
        4,   8,   12,  16
    };
const psU64 tableU8_val3[]  =
    {
        8,  16,   24,  32
    };
const psS8  tableU8_val4[]  =
    {
        0,  -1,   -2,  -3
    };
const psS16 tableU8_val5[]  =
    {
        -2,  -4,   -6,  -8
    };
const psS32 tableU8_val6[]  =
    {
        -4,  -8,  -12, -16
    };
const psS64 tableU8_val7[]  =
    {
        -8, -16,  -24, -32
    };
const psF32 tableU8_val8[]  =
    {
        -0.5, 0.0,  0.5,0.75
    };
const psF64 tableU8_val9[]  =
    {
        -1.5,-1.0,-0.25,1.75
    };

const psF64 tableF32_validFrom = -10.05;
const psF64 tableF32_validTo = 3500.67;
const psS32 tableF32_size = 4;
const psS32 tableF32_cols = 9;
const char tableF32_filename[] = VERIFIED_DIR "/tableF32.dat";
const char tableF32_format[] = "\%f \%d \%d \%ld \%d \%d \%d \%ld \%d \%lf";
const char tableF32_indexCol = 0;
const psElemType tableF32_colType[] =
    {
        PS_TYPE_F32, PS_TYPE_S32, PS_TYPE_S32, PS_TYPE_S64,
        PS_TYPE_S32, PS_TYPE_S32, PS_TYPE_S32, PS_TYPE_S64,
        PS_TYPE_F64
    };
const psF32 tableF32_index[] =
    {
        -10.05,1.009,23.45,3500.67
    };
const psS32 tableF32_col1[] =
    {
        2, 4, 6, 8
    };
const psS32 tableF32_col2[] =
    {
        4, 8, 12, 16
    };
const psS64 tableF32_col3[] =
    {
        8, 16, 24, 32
    };
const psS32 tableF32_col4[] =
    {
        0, -1, -2, -3
    };
const psS32 tableF32_col5[] =
    {
        -2, -4, -6, -8
    };
const psS32 tableF32_col6[] =
    {
        -4, -8, -12, -16
    };
const psS64 tableF32_col7[] =
    {
        -8, -16, -24, -32
    };
const psF64 tableF32_col8[] =
    {
        -1.5, -1.0, -0.25, 1.75
    };


const psF64 table10_validFrom = 1;
const psF64 table10_validTo   = 10;
const psS32 table10_size      = 10;
const char table10_format[] = "\%d \%d \%d \%ld \%d \%d \%d \%ld \%f \%lf";
const char table10_filename[] = VERIFIED_DIR "/table10.dat";
const psS32 table10_indexCol = 0;
const psS32  table10_index[]   =
    {
        1,   2,    3,   4,    5,    6,    7,    8,   9,    10
    };
const psS32 table10_val1[]    =
    {
        4,   6,    8,  10,   12,   14,   16,   18,   20,   22
    };
const psS32 table10_val2[]    =
    {
        8,  12,   16,  20,   24,   28,   32,   36,   40,   44
    };
const psS64 table10_val3[]    =
    {
        16,  24,   32,  64,  128,  256,  512, 1024, 2048, 4096
    };
const psS32  table10_val4[]    =
    {
        -1,  -2,   -3,  -4,   -5,   -6,   -7,   -8,   -9,  -10
    };
const psS32 table10_val5[]    =
    {
        -4,  -6,   -8, -10,  -12,  -14,  -16,  -18,  -20,  -22
    };
const psS32 table10_val6[]    =
    {
        -8, -12,  -16, -20,  -24,  -28,  -32,  -36,  -40,  -44
    };
const psS64 table10_val7[]    =
    {
        -16, -24,  -32, -64, -128, -256, -512,-1024,-2048,-4096
    };
const psF32 table10_val8[]    =
    {
        -2.25,-1.5,-0.75, 0.0, 0.75, 1.50, 2.25, 3.00, 3.75, 4.50
    };
const psF64 table10_val9[]    =
    {
        -2.67,0.66, 3.99,7.32,10.65,13.98,17.31,20.64,23.97,27.30
    };
const psF64 interpolVal1[]    =
    {
        5.25, 12.5, 25, 160, -5.25, -12.5, -25, -160, 0.9375, 11.4825
    };
const psF64 interpolVal2[]    =
    {
        5, 12, 24, 128, -5, -12, -24, -128, 0.75, 10.65
    };
const psF64 interpolVal3[]    =
    {
        4, 8, 16, -1, -4, -8, -16, -2.25, -2.67
    };

testDescription tests[] = {
                              {testLookupTableAlloc,817,"psLookupTableAlloc",0,false},
                              {testVectorsReadFromFile,999,"psVectorsReadFromFile",0,false},
                              {testLookupTableImport,666,"psLookupTableImport",0,false},
                              {testLookupTableRead,998,"psLookupTableRead",0,false},
                              {testLookupTableInterpolate,997,"psLookupTableInterpolate",0,false},
                              {testLookupTableInterpolateAll,996,"psLookupTableInterpolateAll",0,false},
                              {NULL}
                          };

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

    if ( ! runTestSuite(stderr,"psLookupTable",tests,argc,argv)) {
        return 1;
    }
    return 0;
}

psS32 testLookupTableAlloc(void)
{
    psLookupTable*  table1 = NULL;

    // Allocate lookup table with valid parameters
    table1 = psLookupTableAlloc("tableF32.dat","\%f \%lf \%d \%ld",10);
    if(table1 == NULL) {
        psError(PS_ERR_UNKNOWN,true,"Null lookup table generated from valid parameters");
        return 1;
    }
    if(strcmp(table1->filename,"tableF32.dat") != 0) {
        psError(PS_ERR_UNKNOWN,true,"File name not properly stored in psLookupTable structure.");
        return 2;
    }
    if(strcmp(table1->format,"\%f \%lf \%d \%ld") != 0) {
        psError(PS_ERR_UNKNOWN,true,"Format string not properly storeed in psLookupTable structure.");
        return 3;
    }
    if(table1->indexCol != 10) {
        psError(PS_ERR_UNKNOWN,true,"Member indexCol not set properly");
        return 3;
    }
    psFree(table1);

    // Allocate lookup table with invalid filename
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid file name");
    table1 = psLookupTableAlloc(NULL,"\%d",3);
    if(table1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Null file name accepted by psLookupTableAlloc");
        return 4;
    }

    // Allocate lookup table with invalid format
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid format string");
    table1 = psLookupTableAlloc("tableF32.dat",NULL,3);
    if(table1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Null format string accepted by psLookupTableAlloc");
        return 5;
    }

    return 0;
}

psS32 testVectorsReadFromFile(void)
{
    psArray*   out        = NULL;
    psVector*  tempVector = NULL;

    // Read file and place into an array of vectors
    out = psVectorsReadFromFile(VERIFIED_DIR "/tableF32.dat","\%f \%d \%d \%ld \%d \%d \%d \%ld \%*d \%lf");
    if(out == NULL) {
        psError(PS_ERR_UNKNOWN,true,"Unable to read file into array of vectors");
        return 1;
    }
    // Verify the number of vectors in array is as expected
    if(out->n != tableF32_cols) {
        psError(PS_ERR_UNKNOWN,true,"Expected number of columns = %d not equal to actual = %d",
                tableF32_cols, out->n);
        return 2;
    }
    // Verify the number of entries in vectors is as expected
    for(int i = 0; i < out->n; i++ ) {
        tempVector = out->data[i];
        if(tempVector->n != tableF32_size) {
            psError(PS_ERR_UNKNOWN,true,"Col #%d Expected number of entries = %d  not equal to actual = %d",
                    i,tableF32_size,tempVector->n);
            return 3;
        }
    }
    // Verify the vector types are as expected
    for(int i = 0; i < out->n; i++) {
        tempVector = out->data[i];
        if(tempVector->type.type != tableF32_colType[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #%d Expected type = %d not equal to actual = %d",
                    i,tableF32_colType[i],tempVector->type.type);
            return 4;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[0];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.F32[i] != tableF32_index[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #0 Vector element[%d] expected = %f not equal to actual = %f",
                    i, tableF32_index[i],tempVector->data.F32[i]);
            return 5 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[1];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col1[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #1 Vector element[%d] expected = %d not equal to actual = %d",
                    i, tableF32_col1[i],tempVector->data.S32[i]);
            return 10 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[2];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col2[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #2 Vector element[%d] expected = %d not equal to actual = %d",
                    i, tableF32_col2[i],tempVector->data.S32[i]);
            return 15 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[3];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S64[i] != tableF32_col3[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #3 Vector element[%d] expected = %ld not equal to actual = %ld",
                    i, tableF32_col3[i],tempVector->data.S64[i]);
            return 20 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[4];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col4[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #4 Vector element[%d] expected = %d not equal to actual = %d",
                    i, tableF32_col4[i],tempVector->data.S32[i]);
            return 25 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[5];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col5[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #5 Vector element[%d] expected = %d not equal to actual = %d",
                    i, tableF32_col5[i],tempVector->data.S32[i]);
            return 30 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[6];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col6[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #6 Vector element[%d] expected = %d not equal to actual = %d",
                    i, tableF32_col6[i],tempVector->data.S32[i]);
            return 35 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[7];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S64[i] != tableF32_col7[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #7 Vector element[%d] expected = %ld not equal to actual = %ld",
                    i, tableF32_col7[i],tempVector->data.S64[i]);
            return 40 + i;
        }
    }
    // Verify the values in the vectors are as expected
    tempVector = out->data[8];
    for(int i = 0; i < tempVector->n; i++) {
        if(tempVector->data.F64[i] != tableF32_col8[i]) {
            psError(PS_ERR_UNKNOWN,true,"Col #8 Vector element[%d] expected = %lf not equal to actual = %lf",
                    i, tableF32_col8[i],tempVector->data.F64[i]);
            return 45 + i;
        }
    }
    psFree(out);

    // Attempt to read vectors from valid file with invalid format
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL format");
    out = psVectorsReadFromFile(VERIFIED_DIR "/tableF32.dat",NULL);
    if(out != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with NULL format string");
        return 50;
    }

    // Attempt to read vectors from invalid file with valid format
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL filename");
    out = psVectorsReadFromFile(NULL,"%f %f");
    if(out != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with NULL file name");
        return 51;
    }

    // Attempt to read vectors from valid file with invalid format specifiers
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid format specifier");
    out = psVectorsReadFromFile(VERIFIED_DIR "/tableF32.data","\%f \%c \%d");
    if(out != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with invalid format specifier");
        return 52;
    }

    // Attempt to read vectors from non-existant file
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for non-existant file");
    out = psVectorsReadFromFile("nonexistant.dat","\%f \%d \%d");
    if(out != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with non-existant file");
        return 53;
    }

    // Attempt to read vectors from file with errors in the numbers
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for error is file");
    out = psVectorsReadFromFile(VERIFIED_DIR "/tableF32_err.dat","\%f \%d \%d \%ld \%d \%d \%d \%ld \%d \%lf");
    if(out != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with file with errors");
        return 54;
    }

    return 0;
}

psS32 testLookupTableImport(void)
{
    psLookupTable*  outTable = NULL;
    psLookupTable*  inTable  = NULL;
    psArray*        vectors  = NULL;

    // Attempt to import table with NULL table
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL table argument");
    outTable = psLookupTableImport(NULL,vectors,1);
    if(outTable != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with NULL input table");
        return 1;
    }

    // Allocate valid table, format string and index column
    inTable = psLookupTableAlloc(table10_filename,table10_format,table10_indexCol);

    // Attempt to import table with NULL vector argument
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL vectors");
    outTable = psLookupTableImport(inTable,vectors,table10_indexCol);
    if(outTable != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with NULL input vectors");
        return 2;
    }

    // Allocate valid array
    vectors = psArrayAlloc(10);

    // Attempt to import table with invalid index column
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid index column");
    outTable = psLookupTableImport(inTable,vectors,-1);
    if(outTable != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with invalid index column specified");
        return 3;
    }
    psFree(vectors);

    // Attempt to import file with file with unsorted index vector
    // Read vectors from file
    vectors = psVectorsReadFromFile(table10_filename,table10_format);
    outTable = psLookupTableImport(inTable,vectors,table10_indexCol);
    if(outTable != inTable) {
        psError(PS_ERR_UNKNOWN,true,"Did not set proper return value");
        return 4;
    }
    // Verify the index column vector
    psVector* indexVector = outTable->index;
    for(int i = 0; i < indexVector->n; i++) {
        if(indexVector->data.S32[i] != table10_index[i]) {
            psError(PS_ERR_UNKNOWN,true,"Index value[%d] = %d is not as expected %d",
                    i,indexVector->data.S32[i],table10_index[i]);
            return i*4;
        }
    }
    // Verify the value array vectors
    psVector* valueVector = outTable->values->data[1];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.S32[i] != table10_val1[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %d is not as expected %d",
                    i,valueVector->data.S32[i],table10_val1[i]);
            return i*5;
        }
    }
    valueVector = outTable->values->data[2];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.S32[i] != table10_val2[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %d is not as expected %d",
                    i,valueVector->data.S32[i],table10_val2[i]);
            return i*6;
        }
    }
    valueVector = outTable->values->data[3];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.S64[i] != table10_val3[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %ld is not as expected %ld",
                    i,valueVector->data.S64[i],table10_val3[i]);
            return i*7;
        }
    }
    valueVector = outTable->values->data[4];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.S32[i] != table10_val4[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %d is not as expected %d",
                    i,valueVector->data.S32[i],table10_val4[i]);
            return i*8;
        }
    }
    valueVector = outTable->values->data[5];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.S32[i] != table10_val5[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %d is not as expected %d",
                    i,valueVector->data.S32[i],table10_val5[i]);
            return i*9;
        }
    }
    valueVector = outTable->values->data[6];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.S32[i] != table10_val6[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %d is not as expected %d",
                    i,valueVector->data.S32[i],table10_val6[i]);
            return i*10;
        }
    }
    valueVector = outTable->values->data[7];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.S64[i] != table10_val7[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %ld is not as expected %ld",
                    i,valueVector->data.S64[i],table10_val7[i]);
            return i*11;
        }
    }
    valueVector = outTable->values->data[8];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.F32[i] != table10_val8[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %f is not as expected %f",
                    i,valueVector->data.F32[i],table10_val8[i]);
            return i*12;
        }
    }
    valueVector = outTable->values->data[9];
    for(int i = 0; i < valueVector->n; i++) {
        if(valueVector->data.F64[i] != table10_val9[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value [%d] = %lf is not as expected %lf",
                    i,valueVector->data.F64[i],table10_val9[i]);
            return i*13;
        }
    }
    // Verify the table members are set properly
    if(outTable->indexCol != table10_indexCol) {
        psError(PS_ERR_UNKNOWN,true,"Member indexCol = %d not as expected %d",
                outTable->indexCol,table10_indexCol);
        return 100;
    }
    if(outTable->validFrom != table10_validFrom) {
        psError(PS_ERR_UNKNOWN,true,"Member validFrom = %d not as expected %d",
                outTable->validFrom, table10_validFrom);
        return 101;
    }
    if(outTable->validTo != table10_validTo) {
        psError(PS_ERR_UNKNOWN,true,"Member validTo = %d not as expected %d",
                outTable->validTo, table10_validTo);
        return 102;
    }
    if(strcmp(outTable->filename,table10_filename) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Member filename = %d not as expected %s",
                outTable->filename,table10_filename);
        return 103;
    }
    if(strcmp(outTable->format,table10_format) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Member format = %d not as expected %s",
                outTable->format,table10_format);
        return 104;
    }
    psFree(vectors);
    psFree(inTable);

    // Attempt to import file with file with sorted index vector
    // Read vectors from file
    // Allocate valid table, format string and index column
    inTable = psLookupTableAlloc(tableU8_filename,tableU8_format,tableU8_indexCol);
    vectors = psVectorsReadFromFile(tableU8_filename,tableU8_format);
    outTable = psLookupTableImport(inTable,vectors,tableU8_indexCol);
    if(outTable != inTable) {
        psError(PS_ERR_UNKNOWN,true,"Did not set proper return value");
        return 4;
    }
    // Verify the index column vector
    indexVector = outTable->index;
    for(int i = 0; i < indexVector->n; i++) {
        if(indexVector->data.S32[i] != tableU8_index[i]) {
            psError(PS_ERR_UNKNOWN,true,"Index value[%d] = %d is not as expected %d",
                    i,indexVector->data.S32[i],tableU8_index[i]);
        }
    }
    // Verify the table members are set properly
    if(outTable->indexCol != tableU8_indexCol) {
        psError(PS_ERR_UNKNOWN,true,"Member indexCol = %d not as expected %d",
                outTable->indexCol,tableU8_indexCol);
        return 100;
    }
    if(outTable->validFrom != tableU8_validFrom) {
        psError(PS_ERR_UNKNOWN,true,"Member validFrom = %d not as expected %d",
                outTable->validFrom, tableU8_validFrom);
        return 101;
    }
    if(outTable->validTo != tableU8_validTo) {
        psError(PS_ERR_UNKNOWN,true,"Member validTo = %d not as expected %d",
                outTable->validTo, tableU8_validTo);
        return 102;
    }
    if(strcmp(outTable->filename,tableU8_filename) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Member filename = %d not as expected %s",
                outTable->filename,tableU8_filename);
        return 103;
    }
    if(strcmp(outTable->format,tableU8_format) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Member format = %d not as expected %s",
                outTable->format,tableU8_format);
        return 104;
    }
    psFree(inTable);
    psFree(vectors);

    return 0;
}

psS32 testLookupTableRead(void)
{
    psLookupTable*  table1  = NULL;
    long           numRows = 0;

    // Attempt to read table with NULL input table specified
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL table");
    numRows = psLookupTableRead(table1);
    if(numRows != 0) {
        psError(PS_ERR_UNKNOWN,true,"Did not return zero for NULL input table");
        return 1;
    }

    // Set up valid table to read
    table1 = psLookupTableAlloc(tableF32_filename,tableF32_format,tableF32_indexCol);
    // Read table
    numRows = psLookupTableRead(table1);
    // Verify return value equals number of lines read
    if(numRows != tableF32_size) {
        psError(PS_ERR_UNKNOWN,true,"Return value %d not as expected %d",
                numRows,tableF32_size);
        return 1;
    }
    // Verify the members and values in table
    if(fabs(table1->validFrom - tableF32_validFrom) > errorTol_psF64) {
        psError(PS_ERR_UNKNOWN,true,"Member validFrom = %f not as expected %f",
                table1->validFrom,tableF32_validFrom);
        return 2;
    }
    if(fabs(table1->validTo - tableF32_validTo) > errorTol_psF64) {
        psError(PS_ERR_UNKNOWN,true,"Member validTo = %f not as expected %f",
                table1->validTo,tableF32_validTo);
        return 3;
    }
    if(strcmp(table1->filename,tableF32_filename) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Member filename %s not as expected %s",
                table1->filename,tableF32_filename);
        return 4;
    }
    if(strcmp(table1->format,tableF32_format) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Member format %s not as expected %s",
                table1->format,tableF32_format);
        return 5;
    }
    if(table1->indexCol != tableF32_indexCol) {
        psError(PS_ERR_UNKNOWN,true,"Member indexCol %d not as expected %d",
                table1->indexCol,tableF32_indexCol);
        return 6;
    }
    for(psS32 i = 0; i < table1->index->n; i++) {
        if(fabs(table1->index->data.F32[i]-tableF32_index[i]) > errorTol_psF64) {
            psError(PS_ERR_UNKNOWN,true,"Index column[%d] = %f not as expected %f",
                    i,table1->index->data.F32[i],tableF32_index[i]);
            return i*7;
        }
    }
    psVector* tempVector = table1->values->data[1];
    for(psS32 i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col1[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value column[%d] = %d not as expected %d",
                    i,tempVector->data.S32[i],tableF32_col1[i]);
            return i*8;
        }
    }
    tempVector = table1->values->data[2];
    for(psS32 i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col2[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value column[%d] = %d not as expected %d",
                    i,tempVector->data.S32[i],tableF32_col2[i]);
            return i*9;
        }
    }
    tempVector = table1->values->data[3];
    for(psS32 i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S64[i] != tableF32_col3[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value column[%d] = %ld not as expected %ld",
                    i,tempVector->data.S64[i],tableF32_col3[i]);
            return i*10;
        }
    }
    tempVector = table1->values->data[4];
    for(psS32 i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col4[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value column[%d] = %d not as expected %d",
                    i,tempVector->data.S32[i],tableF32_col4[i]);
            return i*11;
        }
    }
    tempVector = table1->values->data[5];
    for(psS32 i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col5[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value column[%d] = %d not as expected %d",
                    i,tempVector->data.S32[i],tableF32_col5[i]);
            return i*12;
        }
    }
    tempVector = table1->values->data[6];
    for(psS32 i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S32[i] != tableF32_col6[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value column[%d] = %d not as expected %d",
                    i,tempVector->data.S32[i],tableF32_col6[i]);
            return i*13;
        }
    }
    tempVector = table1->values->data[7];
    for(psS32 i = 0; i < tempVector->n; i++) {
        if(tempVector->data.S64[i] != tableF32_col7[i]) {
            psError(PS_ERR_UNKNOWN,true,"Value column[%d] = %ld not as expected %ld",
                    i,tempVector->data.S64[i],tableF32_col7[i]);
            return i*14;
        }
    }
    psFree(table1);

    // Set up invalid table to read
    table1 = psLookupTableAlloc(tableF32_filename,tableF32_format,tableF32_indexCol);
    table1->indexCol = -1;
    // Read invalid table
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message invalid table indexCol");
    numRows = psLookupTableRead(table1);
    // Verify the num of rows read is zero
    if(numRows != 0) {
        psError(PS_ERR_UNKNOWN,true,"Did not return 0 for line read for invalid table");
        return 15;
    }
    psFree(table1);

    return 0;
}

psS32 testLookupTableInterpolate(void)
{
    psLookupTable*  table1 = NULL;
    psF64            out1 = 0.0;

    // Attempt to perform interpolation with NULL table
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid table");
    out1 = psLookupTableInterpolate(table1,0,0);
    if( !isnan(out1) ) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NaN as expected");
        return 1;
    }

    // Interpolate values within the list and verify return values
    table1 = psLookupTableAlloc(table10_filename,table10_format,table10_indexCol);
    psS32 numLines = psLookupTableRead(table1);
    if(numLines != table10_size) {
        psError(PS_ERR_UNKNOWN,true,"Line read %d not as expected %d",numLines,table10_size);
        return 2;
    }
    for(psS32 i = 0; i < table1->values->n; i++ ) {
        out1 = psLookupTableInterpolate(table1, 5.25, i);
        if( fabs(out1-interpolVal1[i]) > errorTol_psF64) {
            psError(PS_ERR_UNKNOWN,true,"Did not return expected value. %lg expected %lg",out1,interpolVal1[i]);
            return 3*i;
        }
    }
    for(psS32 i = 0; i < table1->values->n; i++ ) {
        out1 = psLookupTableInterpolate(table1, 5.0, i);
        if( fabs(out1-interpolVal2[i]) > errorTol_psF64) {
            psError(PS_ERR_UNKNOWN,true,"Did not return expected value. %lg expected %lg",out1,interpolVal2[i]);
            return 4*i;
        }
    }

    // Interpolate value just below the lowest index value
    out1 = psLookupTableInterpolate(table1,0,0);
    if ( fabs(out1- NAN) > FLT_EPSILON ) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NAN returned %lf",out1);
        return 5;
    }

    // Interpolate value just above the highest index value
    out1 = psLookupTableInterpolate(table1,11,0);
    if ( fabs(out1-NAN) > FLT_EPSILON ) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NAN returned %lf",out1);
        return 7;
    }

    // Interpolate value with a column number greater than the table has
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error out of range.");
    out1 = psLookupTableInterpolate(table1, 5, 100);
    if ( fabs(out1-NAN) > FLT_EPSILON ) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NAN returned %lf",out1);
        return 9;
    }
    psFree(table1);

    return 0;
}

psS32 testLookupTableInterpolateAll(void)
{
    psLookupTable*  table1 = NULL;
    psVector*        interpValues;

    // Interpolate values with NULL table
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL table");
    interpValues = psLookupTableInterpolateAll(table1,5, NULL);
    if(interpValues != NULL ) {
        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for NULL table");
        return 5;
    }

    // Interpolate values within the list and verify return values
    table1 = psLookupTableAlloc(table10_filename,table10_format,table10_indexCol);
    psS32 numLines = psLookupTableRead(table1);
    if(numLines != table10_size) {
        psError(PS_ERR_UNKNOWN,true,"Num lines read %d not as expected %d",numLines,table10_size);
        return 6;
    }
    interpValues = psLookupTableInterpolateAll(table1,5.25, NULL);
    if(interpValues == NULL) {
        psError(PS_ERR_UNKNOWN,true,"Returned vector is NULL.");
        return 1;
    }
    for(psS32 i = 0; i < table1->values->n; i++ ) {
        if( fabs(interpValues->data.F64[i]-interpolVal1[i]) > errorTol_psF64) {
            psError(PS_ERR_UNKNOWN,true,"Did not return expected value. %lg expected %lg",
                    interpValues->data.F64[i],interpolVal1[i]);
            return 2*i;
        }
    }
    psFree(interpValues);

    // Interpolate values with index outside table
    interpValues = psLookupTableInterpolateAll(table1,0, NULL);
    if(interpValues != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did return NULL");
        return 4;
    }
    psFree(table1);

    return 0;
}

