/** @file  tst_psMemory.c
*
*  @brief Contains the tests for psMemory.[ch]
*
*
*  @author Robert DeSonia, MHPCC
*
*  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
*  @date $Date: 2005-09-22 22:51:46 $
*
*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
*/

#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdlib.h>


#include "psTest.h"
#include "pslib.h" // need to allow malloc for callback use

static psS32 TPFreeReferencedMemory( void );
static psS32 TPOutOfMemory( void );
static psS32 TPReallocOutOfMemory( void );
static psPtr TPOutOfMemoryExhaustedCallback( size_t size );
static psS32 TPCheckBufferPositive( void );
static psS32 TPrealloc( void );
static psS32 TPallocCallback( void );
static psMemId memAllocCallback( const psMemBlock *ptr );
static psMemId memFreeCallback( const psMemBlock *ptr );
static psS32 TPcheckLeaks( void );
static psS32 TPmemCorruption( void );
static psS32 TPmultipleFree( void );
static psS32 memCheckTypes( void );
void memProblemCallback( psMemBlock *ptr, const char *filename, unsigned int lineno );

static psS32 problemCallbackCalled = 0;
static psS32 allocCallbackCalled = 0;
static psS32 freeCallbackCalled = 0;
static psS32 exhaustedCallbackCalled = 0;

testDescription tests[] = {
                              {TPCheckBufferPositive, 449, "checkBufferPositive", 0, false},
                              {TPOutOfMemory, 450, "outOfMemory", -6, false},
                              {TPReallocOutOfMemory, 562, "reallocOutOfMemory", -6, false},
                              {TPrealloc, 451, "psRealloc", 0, false},
                              {TPallocCallback, 452, "allocCallback", 0, false},
                              {TPallocCallback, 453, "allocCallback2", 0, true},
                              {TPcheckLeaks, 454, "checkLeaks", 0, false},
                              {TPmemCorruption, 455, "psMemCorruption", 0, false},
                              {TPFreeReferencedMemory, 456, "freeReferencedMemory", 0, false},
                              {TPmultipleFree, 699, "multipleFree", -6, false},
                              {memCheckTypes, 700, "psMemCheckType", 0, false},
                              {NULL}
                          };

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

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

// Testpoint #449, psAlloc shall allocate memory blocks writeable by caller.
psS32 TPCheckBufferPositive( void )
{
    psS32 * mem;
    const psS32 size = 100;
    psS32 failed = 0;

    psLogMsg( __func__, PS_LOG_INFO, "psAlloc shall allocate memory blocks writeable by caller.\n" );

    mem = ( psS32* ) psAlloc( size * sizeof( psS32 ) );
    if ( mem == NULL ) {
        psError(PS_ERR_UNKNOWN, true, "psAlloc returned a NULL value in %s!", __func__ );
        return 1;
    }

    for ( psS32 index = 0;index < size;index++ ) {
        mem[ index ] = index;
    }

    for ( psS32 index = 0;index < size;index++ ) {
        if ( mem[ index ] != index ) {
            failed++;
        }
    }

    psFree( mem );

    return failed;
}

psS32 TPFreeReferencedMemory( void )
{
    // create memory
    psS32 * mem;
    psS32 ref = 0;

    psLogMsg( __func__, PS_LOG_INFO, "memory reference count shall be incrementable/decrementable" );

    mem = ( psS32* ) psAlloc( 100 * sizeof( psS32 ) );

    ref = psMemGetRefCounter( mem );
    if ( ref != 1 ) {
        psError(PS_ERR_UNKNOWN, true, "Expected to buffer reference count to be initially 1, but it was %d.", ref );
        return 1;
    }

    psMemIncrRefCounter( mem );
    psMemIncrRefCounter( mem );
    psMemIncrRefCounter( mem );

    ref = psMemGetRefCounter( mem );
    if ( ref != 4 ) {
        psError(PS_ERR_UNKNOWN, true, "Expected to find buffer reference count to be 4, but it was %d.", ref );
        return 1;
    }

    psMemDecrRefCounter( mem );
    psMemDecrRefCounter( mem );

    ref = psMemGetRefCounter( mem );
    if ( ref != 2 ) {
        psError(PS_ERR_UNKNOWN, true, "Expected to find buffer reference count to be 2, but it was %d.", ref );
        return 1;
    }

    psLogMsg( __func__, PS_LOG_INFO, "psFree shall be just decrement a multiple refererenced pointer." );

    psMemDecrRefCounter( mem );

    ref = psMemGetRefCounter( mem );
    if ( ref != 1 ) {
        psError(PS_ERR_UNKNOWN, true, "Expected to find buffer reference count to be 1, but it was %d.", ref );
        return 1;
    }

    psFree( mem );

    return 0;
}

// Bug/Task #562 regression test.  Upon requesting more memory than is available, psRealloc shall call
// the psMemExhaustedCallback.
psS32 TPReallocOutOfMemory( void )
{
    psS32 * mem[ 100 ];
    psMemExhaustedCallback cb;

    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
        mem[ lcv ] = NULL;
    }

    psLogMsg( __func__, PS_LOG_INFO, "Upon requesting more memory than is available, psRealloc shall call "
              "the psMemExhaustedCallback.\n" );

    exhaustedCallbackCalled = 0;

    cb = psMemExhaustedCallbackSet( TPOutOfMemoryExhaustedCallback );

    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
        mem[ lcv ] = ( psS32* ) psAlloc( 10 );
    }

    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
        mem[ lcv ] = ( psS32* ) psRealloc( mem[ lcv ], SIZE_MAX/2 - 1000 );
    }

    psMemExhaustedCallbackSet( cb );

    if ( exhaustedCallbackCalled == 0 ) {
        psError(PS_ERR_UNKNOWN,true, "Called psRealloc with HUGE memory requirement and survived in %s!", __func__ );
        return 1;
    }

    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
        psFree( mem[ lcv ] );
    }

    return 0;
}
// Testpoint #450,  Upon requesting more memory than is available, psalloc shall call
// the psMemExhaustedCallback.
psS32 TPOutOfMemory( void )
{
    psS32 * mem[ 100 ];
    psMemExhaustedCallback cb;

    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
        mem[ lcv ] = NULL;
    }

    psLogMsg( __func__, PS_LOG_INFO, "Upon requesting more memory than is available, psalloc shall call "
              "the psMemExhaustedCallback.\n" );

    exhaustedCallbackCalled = 0;

    cb = psMemExhaustedCallbackSet( TPOutOfMemoryExhaustedCallback );

    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
        mem[ lcv ] = ( psS32* ) psAlloc( SIZE_MAX/2 - 1000 );
    }

    psMemExhaustedCallbackSet( cb );

    if ( exhaustedCallbackCalled == 0 ) {
        psError(PS_ERR_UNKNOWN,true, "Called psAlloc with HUGE memory requirement and survived in %s!", __func__ );
        return 1;
    }

    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
        psFree( mem[ lcv ] );
    }

    return 0;
}

// Testpoint #451,  psRealloc shall increase/decrease memory buffer while preserving contents
psS32 TPrealloc( void )
{
    psS32 * mem1;
    psS32* mem2;
    psS32* mem3;
    const psS32 initialSize = 100;

    psLogMsg( __func__, PS_LOG_INFO, "psRealloc shall increase/decrease memory buffer while "
              "preserving contents" );

    // allocate buffer with known values.
    mem1 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
    mem2 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
    mem3 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
    for ( psS32 lcv = 0;lcv < initialSize;lcv++ ) {
        mem1[ lcv ] = mem2[ lcv ] = mem3[ lcv ] = lcv;
    }

    psMemCheckCorruption( 1 );
    psLogMsg( __func__, PS_LOG_INFO, "Expanding memory buffer." );

    // realloc to 2x
    mem1 = ( psS32* ) psRealloc( mem1, 2 * initialSize * sizeof( psS32 ) );
    mem2 = ( psS32* ) psRealloc( mem2, 2 * initialSize * sizeof( psS32 ) );
    mem3 = ( psS32* ) psRealloc( mem3, 2 * initialSize * sizeof( psS32 ) );

    // check values of initial block
    for ( psS32 i = 0;i < initialSize;i++ ) {
        if ( mem1[ i ] != i || mem2[ i ] != i || mem3[ i ] != i ) {
            psError(PS_ERR_UNKNOWN,true, "Realloc didn't preserve the contents with expanding buffer in %s.",
                    __func__ );
            break;
        }
    }

    psMemCheckCorruption( 1 );
    psLogMsg( __func__, PS_LOG_INFO, "Shrinking memory buffer." );

    // realloc to 1/2 initial value.
    mem1 = ( psS32* ) psRealloc( mem1, ( initialSize / 2 ) * sizeof( psS32 ) );
    mem2 = ( psS32* ) psRealloc( mem2, ( initialSize / 2 ) * sizeof( psS32 ) );
    mem3 = ( psS32* ) psRealloc( mem3, ( initialSize / 2 ) * sizeof( psS32 ) );

    // check values of initial block
    for ( psS32 i = 0;i < initialSize / 2;i++ ) {
        if ( mem1[ i ] != i || mem2[ i ] != i || mem3[ i ] != i ) {
            psError(PS_ERR_UNKNOWN,true, "Realloc didn't preserve the contents with shrinking buffer in %s.",
                    __func__ );
            break;
        }
    }

    psFree( mem1 );
    psFree( mem2 );
    psFree( mem3 );

    return 0;
}

psS32 TPallocCallback( void )
{
    psS32 * mem1;
    psS32* mem2;
    psS32* mem3;
    psS32 currentId = psMemGetId();
    const psS32 initialSize = 100;
    psS32 mark;

    allocCallbackCalled = 0;
    freeCallbackCalled = 0;
    psMemAllocCallbackSet( memAllocCallback );
    psMemFreeCallbackSet( memFreeCallback );

    psMemAllocCallbackSetID( currentId + 1 );
    psMemFreeCallbackSetID( currentId + 1 );

    psLogMsg( __func__, PS_LOG_INFO, "call to psAlloc/psRealloc shall generate a callback if specified "
              "memory ID is allocated." );

    // allocate buffer with known values.
    mem1 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
    mem2 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
    mem3 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );

    psFree( mem1 );
    psFree( mem2 );
    psFree( mem3 );

    if ( allocCallbackCalled != 2 || freeCallbackCalled != 2 ) {
        psError(PS_ERR_UNKNOWN,true, "alloc/free callbacks were not called the proper number of times in %s",
                __func__ );
        return 1;
    }

    allocCallbackCalled = 0;
    freeCallbackCalled = 0;

    mark = psMemGetId();

    mem1 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );

    psMemAllocCallbackSetID( mark );

    mem1 = ( psS32* ) psRealloc( mem1, initialSize * 2 * sizeof( psS32 ) );

    psFree( mem1 );

    if ( allocCallbackCalled != 2 ) {
        psError(PS_ERR_UNKNOWN,true, "realloc callbacks were not called the proper number of times in %s",
                __func__ );
        return 1;
    }

    return 0;

}

psS32 TPcheckLeaks( void )
{
    const psS32 numBuffers = 5;
    psS32* buffers[ 5 ];
    psS32 lcv;
    psS32 currentId = psMemGetId();
    psMemBlock** blks;
    psS32 nLeaks = 0;
    psS32 lineMark = 0;

    psLogMsg( __func__, PS_LOG_INFO, "psMemCheckLeaks shall return the number of blocks above an ID "
              "that are still allocated" );

    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
        lineMark = __LINE__ + 1;
        buffers[ lcv ] = psAlloc( sizeof( psS32 ) );
    }

    for ( lcv = 1;lcv < numBuffers;lcv++ ) {
        psFree( buffers[ lcv ] );
    }

    psLogMsg( __func__, PS_LOG_INFO, "following psMemCheckLeaks call should produce one instance." );

    nLeaks = psMemCheckLeaks( currentId, &blks, stderr, false );

    if ( nLeaks != 1 ) {
        psError(PS_ERR_UNKNOWN,true, "psMemCheckLeaks should have found 1 leak, but found %d in %s.", nLeaks, __func__ );
        return 1;
    }

    if ( blks[ 0 ] ->lineno != lineMark ) {
        psError(PS_ERR_UNKNOWN,true, "psMemCheckLeaks found a leak other than the expected one (line %d vs %d) in %s.",
                lineMark, blks[ 0 ] ->lineno, __func__ );
        return 1;
    }

    psFree( buffers[ 0 ] );
    psFree( blks );

    psLogMsg( __func__, PS_LOG_INFO, "Testing psMemCheckLeaks again with a different leak location" );
    psMemCheckLeaks(currentId,NULL,stderr, false);

    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
        lineMark = __LINE__ + 1;
        buffers[ lcv ] = psAlloc( sizeof( psS32 ) );
    }

    for ( lcv = 0;lcv < numBuffers - 1;lcv++ ) {
        psFree( buffers[ lcv ] );
    }

    psLogMsg( __func__, PS_LOG_INFO, "following psMemCheckLeaks call should produce one error." );

    nLeaks = psMemCheckLeaks( currentId, &blks, stderr, false );

    if ( nLeaks != 1 ) {
        psError(PS_ERR_UNKNOWN,true, "psMemCheckLeaks should have found 1 leak, but found %d in %s.", nLeaks, __func__ );
        return 1;
    }

    if ( blks[ 0 ] ->lineno != lineMark ) {
        psError(PS_ERR_UNKNOWN,true, "psMemCheckLeaks found a leak other than the expected one in %s.", __func__ );
        return 1;
    }

    psFree( buffers[ 4 ] );
    psFree( blks );

    psLogMsg( __func__, PS_LOG_INFO, "Testing psMemCheckLeaks again with multiple leak locations." );

    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
        lineMark = __LINE__ + 1;
        buffers[ lcv ] = psAlloc( sizeof( psS32 ) );
    }

    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
        if ( lcv % 2 == 0 ) {
            psFree( buffers[ lcv ] );
        }
    }

    psLogMsg( __func__, PS_LOG_INFO, "following psMemCheckLeaks call should produce two errors." );

    nLeaks = psMemCheckLeaks( currentId, &blks, stderr, false );

    if ( nLeaks != 2 ) {
        psError(PS_ERR_UNKNOWN,true, "psMemCheckLeaks should have found 1 leak, but found %d in %s.", nLeaks, __func__ );
        return 1;
    }

    if ( blks[ 0 ] ->lineno != lineMark ) {
        psError(PS_ERR_UNKNOWN,true, "psMemCheckLeaks found a leak other than the expected one in %s.", __func__ );
        return 1;
    }

    psFree( blks );
    psFree( buffers[ 1 ] );
    psFree( buffers[ 3 ] );

    return 0;
}

psS32 TPmemCorruption( void )
{
    psS32 * buffer = NULL;
    psS32 oldValue = 0;
    psS32 corruptions = 0;
    psMemProblemCallback cb;

    psLogMsg( __func__, PS_LOG_INFO, "psMemCheckCorruption shall detect memory corruptions" );

    buffer = psAlloc( sizeof( psS32 ) );

    // cause memory corruption via buffer underflow
    *buffer = 1;
    buffer--;
    oldValue = *buffer;
    *buffer = 2;

    problemCallbackCalled = 0;
    cb = psMemProblemCallbackSet( memProblemCallback );

    psLogMsg( __func__, PS_LOG_INFO, "psMemCheckCorruption should output an error message and "
              "memProblemCallback callback should be called." );

    corruptions = psMemCheckCorruption( 0 );

    // restore the memory problem callback
    psMemProblemCallbackSet( cb );

    // restore the value, 'uncorrupting' the buffer
    *buffer = oldValue;
    buffer++;

    psFree( buffer );

    if ( corruptions != 1 ) {
        psError(PS_ERR_UNKNOWN,true, "Expected one memory corruption but found %d in %s.",
                corruptions, __func__ );
        return 1;
    }

    if ( problemCallbackCalled != 1 ) {
        psError(PS_ERR_UNKNOWN,true, "The memProblemCallback was not invoked but should have been in %s",
                __func__ );
        return 1;
    }

    return 0;

}

void memProblemCallback( psMemBlock *ptr, const char *file, unsigned int lineno )
{
    psLogMsg( __func__, PS_LOG_INFO, "memory callback called for id %lu (%s:%d).",
              ptr->id, file, lineno );
    problemCallbackCalled++;
    return ;
}

psMemId memAllocCallback( const psMemBlock *ptr )
{
    psLogMsg( __func__, PS_LOG_INFO, "block %lu was (re)allocated", ptr->id );
    allocCallbackCalled++;
    return 1;
}

psMemId memFreeCallback( const psMemBlock *ptr )
{
    psLogMsg( __func__, PS_LOG_INFO, "block %lu was freed", ptr->id );
    freeCallbackCalled++;
    return 1;
}

psPtr TPOutOfMemoryExhaustedCallback( size_t size )
{
    psLogMsg( __func__, PS_LOG_INFO, "Custom MemExhaustedCallback was invoked." );
    exhaustedCallbackCalled++;
    return NULL;
}

psS32 TPmultipleFree( void )
{

    psPtr buffer = psAlloc( 1024 );
    psPtr buffer2 = buffer;

    psFree( buffer );

    psLogMsg( __func__, PS_LOG_INFO, "Next should abort due to multiple freeing." );
    psFree( buffer2 );

    psError(PS_ERR_UNKNOWN,true,
            "Multiple psFree call survived");

    return 0;
}

static psS32 memCheckTypes( void )
{
    psArray *negative;
    negative = psArrayAlloc(2);
    psMetadata *neg;
    neg = psMetadataAlloc();

    psArray *array;
    array = psArrayAlloc(100);
    if ( !psMemCheckType(PS_DATA_ARRAY, array) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckArray failed in memCheckType. \n");
        psFree(array);
        return 1;
    }
    psLogMsg( __func__, PS_LOG_INFO, "Next should error from invalid datatype." );
    if ( !psMemCheckType(PS_DATA_ARRAY, neg) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckArray failed in memCheckType. \n");
    }
    psFree(array);

    psBitSet *bits;
    bits = psBitSetAlloc(100);
    if ( !psMemCheckType(PS_DATA_BITSET, bits) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckBitSet failed in memCheckType. \n");
        psFree(bits);
        return 1;
    }
    psLogMsg( __func__, PS_LOG_INFO, "Next should error from invalid datatype." );
    if ( !psMemCheckType(PS_DATA_BITSET, negative) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckBitSet failed in memCheckType. \n");
    }
    psFree(bits);

    psCube *cube;
    cube = psCubeAlloc();
    if ( !psMemCheckType(PS_DATA_CUBE, cube) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckCube failed in memCheckType. \n");
        psFree(cube);
        return 1;
    }
    psFree(cube);

    psFits *fits;
    char *filename = "table.fits";
    fits = psFitsAlloc(filename);
    if ( !psMemCheckType(PS_DATA_FITS, fits) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckFits failed in memCheckType. \n");
        psFree(fits);
        return 1;
    }
    psFree(fits);

    psHash *hash;
    hash = psHashAlloc(100);
    if ( !psMemCheckType(PS_DATA_HASH, hash) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckHash failed in memCheckType. \n");
        psFree(hash);
        return 1;
    }
    psFree(hash);

    psHistogram *histogram;
    histogram = psHistogramAlloc(1.1, 2.2, 2);
    if ( !psMemCheckType(PS_DATA_HISTOGRAM, histogram) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckHistogram failed in memCheckType. \n");
        psFree(histogram);
        return 1;
    }
    psFree(histogram);

    psImage *image;
    image = psImageAlloc(5, 5, PS_TYPE_F32);
    if ( !psMemCheckType(PS_DATA_IMAGE, image) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckImage failed in memCheckType. \n");
        psFree(image);
        return 1;
    }
    psFree(image);

    psKernel *kernel;
    kernel = psKernelAlloc(0, 1, 0, 1);
    if ( !psMemCheckType(PS_DATA_KERNEL, kernel) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckKernel failed in memCheckType. \n");
        psFree(kernel);
        return 1;
    }
    psFree(kernel);

    psList *list;
    list = psListAlloc(NULL);
    if ( !psMemCheckType(PS_DATA_LIST, list) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckList failed in memCheckType. \n");
        psFree(list);
        return 1;
    }
    psFree(list);

    psLookupTable *lookup;
    char *file = "tableF32.dat";
    char *format = "\%f \%lf \%d \%ld";
    lookup = psLookupTableAlloc(file, format, 10);
    if ( !psMemCheckType(PS_DATA_LOOKUPTABLE, lookup) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckLookupTable failed in memCheckType. \n");
        psFree(lookup);
        return 1;
    }
    psFree(lookup);

    psMetadata *metadata;
    metadata = psMetadataAlloc();
    if ( !psMemCheckType(PS_DATA_METADATA, metadata) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckMetadata failed in memCheckType. \n");
        psFree(metadata);
        return 1;
    }
    psFree(metadata);

    psMetadataItem *metaItem;
    metaItem = psMetadataItemAlloc("name", PS_DATA_S32, "COMMENT", 1);
    if ( !psMemCheckType(PS_DATA_METADATAITEM, metaItem) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckMetadataItem failed in memCheckType. \n");
        psFree(metaItem);
        return 1;
    }
    psFree(metaItem);

    psMinimization *min;
    min = psMinimizationAlloc(3, 0.1);
    if ( !psMemCheckType(PS_DATA_MINIMIZATION, min) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckMinimization failed in memCheckType. \n");
        psFree(min);
        return 1;
    }
    psFree(min);

    psPixels *pixels;
    pixels = psPixelsAlloc(100);
    if ( !psMemCheckType(PS_DATA_PIXELS, pixels) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPixels failed in memCheckType. \n");
        psFree(pixels);
        return 1;
    }
    psFree(pixels);

    psPlane *plane;
    plane = psPlaneAlloc();
    if ( !psMemCheckType(PS_DATA_PLANE, plane) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPlane failed in memCheckType. \n");
        psFree(plane);
        return 1;
    }
    psFree(plane);

    psPlaneDistort *planeDistort;
    planeDistort = psPlaneDistortAlloc(1, 1, 1, 1);
    if ( !psMemCheckType(PS_DATA_PLANEDISTORT, planeDistort) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPlaneDistort failed in memCheckType. \n");
        psFree(planeDistort);
        return 1;
    }
    psFree(planeDistort);

    psPlaneTransform *planeTransform;
    planeTransform = psPlaneTransformAlloc(1, 1);
    if ( !psMemCheckType(PS_DATA_PLANETRANSFORM, planeTransform) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPlaneTransform failed in memCheckType. \n");
        psFree(planeTransform);
        return 1;
    }
    psFree(planeTransform);

    psPolynomial1D *poly1;
    poly1 = psPolynomial1DAlloc(2, PS_POLYNOMIAL_ORD);
    if ( !psMemCheckType(PS_DATA_POLYNOMIAL1D, poly1) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPolynomial1D failed in memCheckType. \n");
        psFree(poly1);
        return 1;
    }
    psFree(poly1);

    psPolynomial2D *poly2;
    poly2 = psPolynomial2DAlloc(2, 1, PS_POLYNOMIAL_ORD);
    if ( !psMemCheckType(PS_DATA_POLYNOMIAL2D, poly2) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPolynomial2D failed in memCheckType. \n");
        psFree(poly2);
        return 1;
    }
    psFree(poly2);

    psPolynomial3D *poly3;
    poly3 = psPolynomial3DAlloc(2, 1, 2, PS_POLYNOMIAL_ORD);
    if ( !psMemCheckType(PS_DATA_POLYNOMIAL3D, poly3) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPolynomial3D failed in memCheckType. \n");
        psFree(poly3);
        return 1;
    }
    psFree(poly3);

    psPolynomial4D *poly4;
    poly4 = psPolynomial4DAlloc(2, 1, 2, 1, PS_POLYNOMIAL_ORD);
    if ( !psMemCheckType(PS_DATA_POLYNOMIAL4D, poly4) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckPolynomial4D failed in memCheckType. \n");
        psFree(poly4);
        return 1;
    }
    psFree(poly4);

    psProjection *proj;
    proj = psProjectionAlloc(1, 1, 2.1, 2.1, PS_PROJ_TAN);
    if ( !psMemCheckType(PS_DATA_PROJECTION, proj) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckProjection failed in memCheckType. \n");
        psFree(proj);
        return 1;
    }
    psFree(proj);

    psScalar *scalar;
    psC64 c64 = 1.1 + 7I;
    scalar = psScalarAlloc(c64, PS_TYPE_F64);
    if ( !psMemCheckType(PS_DATA_SCALAR, scalar) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckScalar failed in memCheckType. \n");
        psFree(scalar);
        return 1;
    }
    psFree(scalar);

    psSphere *sphere;
    sphere = psSphereAlloc();
    if ( !psMemCheckType(PS_DATA_SPHERE, sphere) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckSphere failed in memCheckType. \n");
        psFree(sphere);
        return 1;
    }
    psFree(sphere);

    psSphereRot *sphereRot;
    sphereRot = psSphereRotAlloc(0, 0, 20);
    if ( !psMemCheckType(PS_DATA_SPHEREROT, sphereRot) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckSphereRot failed in memCheckType. \n");
        psFree(sphereRot);
        return 1;
    }
    psFree(sphereRot);

    psSpline1D *spline;
    spline = psSpline1DAlloc(2, 1, 0, 2);
    if ( !psMemCheckType(PS_DATA_SPLINE1D, spline) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckSpline1D failed in memCheckType. \n");
        psFree(spline);
        return 1;
    }
    psFree(spline);

    psStats *stats;
    stats = psStatsAlloc(PS_STAT_MAX);
    if ( !psMemCheckType(PS_DATA_STATS, stats) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckStats failed in memCheckType. \n");
        psFree(stats);
        return 1;
    }
    psFree(stats);

    psTime *time;
    time = psTimeAlloc(PS_TIME_UT1);
    if ( !psMemCheckType(PS_DATA_TIME, time) )  {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckTime failed in memCheckType. \n");
        psFree(time);
        return 1;
    }
    psFree(time);

    psVector *vector;
    vector = psVectorAlloc(100, PS_TYPE_F32);
    if ( !psMemCheckType(PS_DATA_VECTOR, vector) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "psMemCheckVector failed in memCheckType. \n");
        psFree(vector);
        return 1;
    }
    psFree(vector);


    psFree(negative);
    psFree(neg);

    return 0;
}
