//-*-c++-*--------------------------------------------------------------
//  barefTst.cpp
//   Test program for testing the NSR ByteArrayRef object.
//
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett-Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//
//  CLASSES:
//  
//----------------------------------------------------------------------
//
// $Source: /projects/HMS/nsr/udfAncil/ssTest/barefTst.cpp,v $
// $Revision: 1.15 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/04/30 23:32:03 $


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>               
#include <errno.h>
#include "nsrLib.h"
#include "nsrRSSdv.h"

// Defines

#define BYTEARRAY_MAX           49152   // Max size of a ByteArray, in bytes
#define TESTMEM_ITERATIONS      100     // # iterations for testMemory()

// Function prototypes

static INT32 CheckSum(BYTE_PTR,UINT32);
static void initData(void);
static INT32 testByteArrayRef(void);
static INT32 testConstruction(INT32 testno);
static INT32 testoffsetlength(INT32 testno);
static INT32 testToMem(INT32 testno);
static INT32 testFromMem(INT32 testno);
static INT32 testMemory(INT32 testno);


// Some global data

BYTE_PTR data_buffer = new BYTE[BYTEARRAY_MAX];
BYTE_PTR zero_buffer = new BYTE[BYTEARRAY_MAX];


//-----------------------------------------------------------------------------
// main():
//
// We expect no arguments.
//-----------------------------------------------------------------------------


INT32 main (void)
{
    INT32       rc;

    initData();
    rc = testByteArrayRef();
    if(rc == 0) {
        printf("\nPassed all tests\n");
    }
    else {
        printf("\nFAILED %ld test(s)!\n",rc);
    }
    return rc;
}

//-----------------------------------------------------------------------------
// testByteArrayRef():  The actual test code.
//
// ASSUMPTIONS:  we assume that ByteArray works.
//
// TESTS:
//
// 1.  Construction and Validity:  verify that both constructors work
//     properly for both stack-based and dynamic objects.  Verify that the
//     isValid() method is correct.
//
// 2.  offset, length, theArray:  verify that the offset(), length(), and
//     theArray() methods work properly for getting and setting the fields of 
//     the ByteArrayRef, and that the isValid() method properly reflects 
//     changes.
//
// 3.  toMem():  Verify that the toMem() function works properly (with both
//     valid and invalid ByteArrayRefs).
//
// 4.  fromMem():  Verify the fromMem() function.
//
// 5.  Memory verification.  Perform many reads and writes to and from 
//     memory referred to by ByteArrayRefs to verify that offsetting and
//     bounds checking are handled properly.
//-----------------------------------------------------------------------------

static INT32
testByteArrayRef(void)
{
    INT32 rval = 0;

    rval += testConstruction(1);
    rval += testoffsetlength(2);
    rval += testToMem(3);
    rval += testFromMem(4);
    rval += testMemory(5);

    return -rval;
}

//-----------------------------------------------------------------------------
// testConstruction():  Tests construction and validity checking.
//
// Returns 0 on success, -1 on failure.
//-----------------------------------------------------------------------------

static INT32
testConstruction(INT32  testno)
{
    ByteArray           good_barr(BYTEARRAY_MAX);
    ByteArray           null_barr(0);
    ByteArrayRef *      brefptr;
    INT32               rval = 0;

    printf("\n***** Test %ld:  Construction and Validity *****\n\n",testno);

    ByteArrayRef        bref(good_barr);
    printf("Creating good ByteArrayRef. . .");
    if(bref.isValid() == True) {
        printf("succeeded\n");
    } 
    else {
        printf("FAILED\n");
        rval = -1;
    }

    printf("Creating good ByteArrayRef pointer. . .");
    brefptr = new ByteArrayRef(good_barr);
    if(brefptr == NULL) {
        printf("FAILED, no free store left\n");
        rval = -1;
    }
    else {
        if(brefptr->isValid() == True) {
            printf("succeeded\n");
        }
        else {
            printf("FAILED\n");
            rval = -1;
        }
        delete brefptr;
    }

    printf("Creating invalid ByteArrayRef. . .");
    ByteArrayRef        bad_bref(null_barr);
    if(bad_bref.isValid() == False) {
        printf("succeeded\n");
    }
    else {
        printf("FAILED\n");
        rval = -1;
    }

    printf("Creating invalid ByteArrayRef pointer. . .");
    brefptr = new ByteArrayRef(null_barr);
    if(brefptr == NULL) {
        printf("FAILED, no free store left\n");
        rval = -1;
    }
    else {
        if(brefptr->isValid() == False) {
            printf("succeeded\n");
        }
        else {
            printf("FAILED\n");
            rval = -1;
        }
        delete brefptr;
    }

    return rval;
}

//-----------------------------------------------------------------------------
// testoffsetlength():  Tests the offset(), length(), and theArray() methods
//                      to verify that values can be changed and that validity
//                      checks are properly made.
//-----------------------------------------------------------------------------

struct offlen_test 
{
    UINT32      offset;
    UINT32      length;
    Boolean     valid;          // Makes a valid ByteArrayRef?
}; 

// These values assume the ByteArray we're referring to is BYTEARRAY_MAX
// bytes long.  To add test cases, just add some more entries to the 
// test_values array.

struct offlen_test test_values[] = { 
                                     {100,24000,True},
                                     {32000L,BYTEARRAY_MAX-32000L,True},
                                     {100,BYTEARRAY_MAX - 50,False},
                                     {32000L,0,False},
                                     {32000L,1,True},
                                     {BYTEARRAY_MAX+1,1,False},
                                     {0,BYTEARRAY_MAX,True},
                                     {0,BYTEARRAY_MAX+1,False}
                                   };

static INT32
testoffsetlength(INT32  testno)
{
    ByteArray           good_barr(BYTEARRAY_MAX);
    INT32               rval = 0;
    INT32               i;

    printf("\n***** Test %ld:  offset and length Testing *****\n\n",testno);

    ByteArrayRef        good_bref(good_barr);

    printf("ByteArray size is %ld\n\n",BYTEARRAY_MAX);
    printf("OFFSET LENGTH EXPECTED RESULT\n");
    printf("------ ------ -------- ------\n");
    for(i = 0; i < (sizeof(test_values) / sizeof(struct offlen_test)); i++)
    {
        good_bref.offset(test_values[i].offset);
        good_bref.length(test_values[i].length);
        printf("%6ld %6ld %8s %6s\n",
               good_bref.offset(),
               good_bref.length(),
               (test_values[i].valid == True ? "True" : "False"),
               (good_bref.isValid() == True ? "True" : "False"));
        if(good_bref.isValid() != test_values[i].valid) {
            rval = -1;
        }
    }

#ifdef OLD_BYTE_ARRAY_REF
    const ByteArray&    baref = good_bref.theArray();
    printf("theArray() test:  %s\n",(baref == good_barr) ? "succeeded" :
           "FAILED");
#endif
    return rval;
}

//-----------------------------------------------------------------------------
// testToMem():  Test the toMem() method.  Verify that the data is being
//               successfully copied from the ByteArrayRef to the data buffer.
//-----------------------------------------------------------------------------

struct tomem_values 
{
    UINT32      offset;
    UINT32      length;
    UINT32      align;          // offset into the data buffer
};

struct tomem_values ToMem[] = { 
                                {0,BYTEARRAY_MAX,0},    // Whole ByteArray
                                {0,12000,100},          // Beginning segment
                                {17233,883,9172},       // Middle segment
                                {34001L,BYTEARRAY_MAX-34001L,2301} // End segment
                              };
                

static INT32
testToMem(INT32 testno)
{
    ByteArray           goodbarr(BYTEARRAY_MAX);

    BYTE_PTR            buffer = new BYTE[BYTEARRAY_MAX];
    BYTE_PTR            bptr;
    INT32               crc1,crc2;
    INT32               rval = 0;
    INT32               i;

    printf("\n***** Test %ld:  toMem() Testing *****\n\n",testno);

    goodbarr.fromMem(data_buffer);

    // Try a couple of invalid ones first. . .

    ByteArrayRef        baref(goodbarr,0,0);    // an invalid ByteArrayRef!

    printf("Trying toMem() on an invalid ByteArrayRef. . .test ");
    if(baref.toMem(buffer) == False) {
        printf("Succeeded\n");
    }
    else {
        printf("Failed\n");
        rval = -1;
    }

    baref.offset(0);
    baref.length(BYTEARRAY_MAX);
    printf("Trying toMem() with an invalid BYTE_PTR buffer. . .test ");
    if(baref.toMem(NULL) == False) {
        printf("Succeeded\n");
    }
    else {
        printf("Failed\n");
        rval = -1;
    }

    // Now start doing some tests.  Whole thing, a segment from the beginning,
    // a segment in the middle, and a segment at the end.

    printf("offset length Data CRC Written CRC Success?\n");
    printf("------ ------ -------- ----------- --------\n");
    for(i = 0; i < (sizeof(ToMem) / sizeof(struct tomem_values)); i++)
    {
        NSR::MemSet(buffer,0,BYTEARRAY_MAX);
        bptr = data_buffer + ToMem[i].align;
        NSR::MemMove((BYTE_PTR) goodbarr,bptr,ToMem[i].length);
        crc1 = CheckSum(((BYTE_PTR) goodbarr) + ToMem[i].offset,ToMem[i].length);
        baref.offset(ToMem[i].offset);
        baref.length(ToMem[i].length);
        baref.toMem(buffer);
        crc2 = CheckSum(buffer,ToMem[i].length);
        printf("%6ld %6ld %8lx %11lx %8s\n",
               baref.offset(),
               baref.length(),
               crc1,
               crc2,
               (crc1 == crc2) ? "Yes" : "NO");
        if(crc1 != crc2) {
            rval = -1;
        }
    }
    return rval;
}

//-----------------------------------------------------------------------------
// testFromMem():  Test the fromMem() method.  Verify that the data is being
//                 successfully copied from the databuffer to the ByteArrayRef.
//-----------------------------------------------------------------------------

struct frommem_values 
{
    UINT32      offset;
    UINT32      length;
    UINT32      align;          // offset into the data buffer
};

struct frommem_values FromMem[] = { 
                                {0,BYTEARRAY_MAX,0},    // Whole ByteArray
                                {0,17593,3032},         // Beginning segment
                                {15332,1792,4321},      // Middle segment
                                {53000L,BYTEARRAY_MAX-53000L,24733} // End segment
                              };
                

static INT32
testFromMem(INT32  testno)
{
    ByteArray           goodbarr(BYTEARRAY_MAX);
    BYTE_PTR            buffer = new BYTE[BYTEARRAY_MAX];
    BYTE_PTR            bptr;
    INT32               crc1,crc2;
    INT32               rval = 0;
    INT32               i;

    printf("\n***** Test %ld:  fromMem() Testing *****\n\n",testno);

    memmove(buffer,data_buffer,BYTEARRAY_MAX);

    // Try a couple of invalid ones first. . .

    ByteArrayRef        baref(goodbarr,0,0);    // an invalid ByteArrayRef!

    printf("Trying fromMem() on an invalid ByteArrayRef. . .test ");
    if(baref.fromMem(buffer) == False) {
        printf("Succeeded\n");
    }
    else {
        printf("Failed\n");
        rval = -1;
    }

    baref.offset(0);
    baref.length(BYTEARRAY_MAX);
    printf("Trying fromMem() with an invalid BYTE_PTR buffer. . .test ");
    if(baref.fromMem(NULL) == False) {
        printf("Succeeded\n");
    }
    else {
        printf("Failed\n");
        rval = -1;
    }

    // Now start doing some tests.  Whole thing, a segment from the beginning,
    // a segment in the middle, and a segment at the end.

    printf("offset length Data CRC    Read CRC Success?\n");
    printf("------ ------ -------- ----------- --------\n");
    for(i = 0; i < (sizeof(FromMem) / sizeof(struct frommem_values)); i++)
    {
        bptr = data_buffer + ToMem[i].align;
        crc1 = CheckSum(bptr,ToMem[i].length);
        baref.offset(ToMem[i].offset);
        baref.length(ToMem[i].length);
        baref.fromMem(bptr);
        crc2 = CheckSum(((BYTE_PTR) goodbarr) + baref.offset(),ToMem[i].length);
        printf("%6ld %6ld %8lx %11lx %8s\n",
               baref.offset(),
               baref.length(),
               crc1,
               crc2,
               (crc1 == crc2) ? "Yes" : "NO");
        if(crc1 != crc2) {
            rval = -1;
        }
    }
    return rval;
}

//-----------------------------------------------------------------------------
// testMemory():  Perform lots of random reads/writes using the ByteArrayRef.
//                This function tests the casting operator (BYTE_PTR).
//-----------------------------------------------------------------------------

static INT32
testMemory(INT32  testno)
{
    INT32               i,off,len;
    INT32               crc1,crc2;
    INT32               rval = 0;
    ByteArray           goodbarr(BYTEARRAY_MAX);
    BYTE_PTR            buffer = new BYTE[BYTEARRAY_MAX];
    ByteArrayRef        baref(goodbarr);
    BYTE_PTR            bptr;

    printf("\n***** Test %ld:  Memory() Testing *****\n\n",testno);
    srand48((long) rand());

    // Perform iterations of reads and writes to memory referred to by the
    // ByteArrayRef.  In each iteration, we first set the ByteArrayRef to
    // a random offset and length into the real ByteArray.  Then we write
    // some data into the ByteArrayRef, read it into a separate buffer, and
    // compare crc's.

    goodbarr.fromMem(zero_buffer);      // Zero out the ByteArray 
    for(i = 0; i < TESTMEM_ITERATIONS; i++) {
        off = lrand48() % (BYTEARRAY_MAX - 1);
        len = (lrand48() % (off - BYTEARRAY_MAX)) + 1;
        printf("Iteration %3ld, offset = %5ld, length = %5ld:  ",i,off,len);
        baref.offset(off);
        baref.length(len);
        crc1 = CheckSum(data_buffer,len);
        bptr = (BYTE_PTR) baref;
        NSR::MemMove(bptr,data_buffer,len);  // Write data into ByteArrayRef
        bptr = (BYTE_PTR) goodbarr;
        crc2 = CheckSum(bptr + off,len);
        if(crc1 == crc2) {
            printf("Succeeded\n");
        }
        else {
            printf("FAILED!  written crc %8lx != read crc %8lx\n",crc1,crc2);
            rval = -1;
        }
    }
    return rval;
}        

//-----------------------------------------------------------------------------
// CheckSum():  The usual checksum/CRC code, stolen once again from 
//              distress.c...
//-----------------------------------------------------------------------------

static INT32
CheckSum(BYTE_PTR data,UINT32 size)
{
    INT32 i;
    INT32 csum = 0;

    for(i = 0; i < size; i++) {
        csum = ((unsigned)csum<<1 | (unsigned)csum>>31) ^ (unsigned)data[i];
    }
    return csum;
}

//-----------------------------------------------------------------------------
// initData():  Fill up the data array with random data.
//-----------------------------------------------------------------------------

static void
initData(void)
{
    INT32       i;

    srand(time((time_t *) NULL));
    for(i = 0; i < BYTEARRAY_MAX; i++)
    {
        data_buffer[i] = lrand48() % 256;
        zero_buffer[i] = 0;
    }
}


