/**
 *  C Implementation: tap_psBitSet_all
 *
 * Description:  Tests for psBitSetAlloc, psBitSetSet, psMemCheckBitSet, psBitSetClear,
 *               psBitSetTest, psBitSetOp, psBitSetNot, psBitSetToString
 *
 * Author: dRob <David.Robbins@mhpcc.hpc.mil>, (C) 2006
 *
 * Copyright: See COPYING file that comes with this distribution
 *
 */

#include <pslib.h>
#include <string.h>

#include "tap.h"
#include "pstap.h"

void testBitSetBasics(void);
void testBitSetOps(void);

int main(void)
{
    plan_tests(31);

    note("Tests for psBitSet Functions");

    testBitSetBasics();
    testBitSetOps();

    done();
}

void testBitSetBasics(void)
{
    note("  >>>Test 1:  psBitSet Basic Fxns");

    psBitSet *noBits = NULL;
    psBitSet *bs = NULL;

    //Return NULL for attempt to Allocate BitSet of negative size.
    {
        noBits = psBitSetAlloc(-1);
        ok( noBits == NULL,
            "psBitSetAlloc:         return NULL for negative BitSet-size input.");
    }
    //Return properly allocated 0-size psBitSet
    {
        bs = psBitSetAlloc(0);
        ok( bs != NULL && psMemCheckBitSet(bs) && bs->n == 0,
            "psBitSetAlloc:         return properly allocated psBitSet.");
    }
    //Return properly allocated psBitSet
    {
        psFree(bs);
        bs = psBitSetAlloc(8);
        ok( bs != NULL && psMemCheckBitSet(bs) && bs->n == 1,
            "psBitSetAlloc:         return properly allocated psBitSet.");
    }
    //Make sure psMemCheckBitSet works correctly - return false
    {
        int j = 2;
        ok( !psMemCheckBitSet(&j),
            "psMemCheckBitSet:      return false for non-BitSet input.");
    }

    //BitSetSet Tests
    //Return NULL for NULL input psBitSet
    {
        noBits = psBitSetSet(noBits, 0);
        ok( noBits == NULL,
            "psBitSetSet:           return NULL for NULL BitSet input.");
    }
    //Return input BitSet for negative bit input
    {
        noBits = psBitSetSet(bs, -1);
        ok( noBits == bs,
            "psBitSetSet:           return input BitSet for negative bits input.");
        noBits = NULL;
    }
    //Return input BitSet for out-of-range bits
    {
        noBits = psBitSetSet(bs, 8);
        ok( noBits == bs,
            "psBitSetSet:           return input BitSet for out-of-range bits input.");
        noBits = NULL;
    }
    //Return set BitSet for valid inputs
    {
        bs = psBitSetSet(bs, 2);
        ok( bs->bits[0] == 4,
            "psBitSetSet:           return properly set BitSet for valid inputs.");
    }

    //BitSetClear Tests
    //Return NULL for NULL input psBitSet
    {
        noBits = psBitSetClear(noBits, 0);
        ok( noBits == NULL,
            "psBitSetClear:         return NULL for NULL BitSet input.");
    }
    //Return input BitSet for negative bit input
    {
        noBits = psBitSetClear(bs, -1);
        ok( noBits == bs,
            "psBitSetClear:        return input BitSet for negative bits input.");
        noBits = NULL;
    }
    //Return input BitSet for out-of-range bits
    {
        noBits = psBitSetClear(bs, 8);
        ok( noBits == bs,
            "psBitSetClear:        return input BitSet for out-of-range bits input.");
        noBits = NULL;
    }
    //Return cleared BitSet for valid inputs
    {
        bs = psBitSetClear(bs, 2);
        ok( bs->bits[0] == 0,
            "psBitSetClear:        return properly cleared BitSet for valid inputs.");
    }

    //BitSetTest Tests
    //Return false for NULL input psBitSet
    {
        ok( !psBitSetTest(noBits, 0),
            "psBitSetTest:         return false for NULL BitSet input.");
    }
    //Return false for negative bit input
    {
        ok( !psBitSetTest(bs, -1),
            "psBitSetTest:         return false for negative bits input.");
    }
    //Return false for out-of-range bits
    {
        ok( !psBitSetTest(bs, 8),
            "psBitSetTest:         return false for out-of-range bits input.");
    }
    //Return false for non-matching bit in BitSet
    {
        ok( !psBitSetTest(bs, 2),
            "psBitSetTest:         return false for non-matching bit in BitSet.");
    }
    //Return false for non-matching bit in BitSet
    {
        bs = psBitSetSet(bs, 2);
        ok( psBitSetTest(bs, 2),
            "psBitSetTest:         return true for matching bit in BitSet.");
    }


    //Check for Memory leaks
    {
        psFree(bs);
        checkMem();
    }
}

void testBitSetOps(void)
{
    note("  >>>Test 2:  psBitSet Operation Fxns");
    psBitSet *noBits = NULL;
    psBitSet *bs = NULL;
    bs = psBitSetAlloc(8);
    bs = psBitSetSet(bs, 2);  // 0000 0100 == 4
    bs = psBitSetSet(bs, 3);  // 0000 1100 == 12
    bs = psBitSetSet(bs, 4);  // 0001 1100 == 28
    bs = psBitSetSet(bs, 5);  // 0011 1100 == 60
    bs = psBitSetSet(bs, 6);  // 0111 1100 == 124
    bs = psBitSetSet(bs, 7);  // 1111 1100 == 252
    psBitSet *out = NULL;

    //psBitSetNot Tests
    //Return NULL for NULL BitSet input
    {
        out = psBitSetNot(out, noBits);
        ok( out == NULL,
            "psBitSetNot:          return NULL for NULL BitSet input.");
    }
    //Return correct BitSet for valid BitSet input
    {
        out = psBitSetNot(out, bs);  //bs = 1111 1100  so out should = 0000 0011 = 3
        ok( out->bits[0] == 3,
            "psBitSetNot:          return correct BitSet for valid BitSet input.");
    }

    //psBitSetOp Tests   out = psBitSetOp(out, bs1, "op", bs2);
    //Return NULL for NULL BitSet input
    {
        psFree(out);
        out = NULL;
        out = psBitSetOp(out, noBits, "op", noBits);
        ok( out == NULL,
            "psBitSetOp:           return NULL for NULL BitSet input.");
    }
    //Return NULL for NULL operator input
    {
        out = psBitSetOp(out, bs, NULL, noBits);
        ok( out == NULL,
            "psBitSetOp:           return NULL for NULL operator input.");
    }
    //Return NULL for invalid operator input
    {
        out = psBitSetOp(out, bs, "XAND", noBits);
        ok( out == NULL,
            "psBitSetOp:           return NULL for invalid operator input.");
    }
    //Return NULL for AND operator with NULL second BitSet input
    {
        out = psBitSetOp(out, bs, "AND", noBits);
        ok( out == NULL,
            "psBitSetOp:           return NULL for AND operator with NULL second BitSet input.");
    }
    //Return NULL for AND operator with BitSet inputs of differing size.
    psBitSet *bs2 = psBitSetAlloc(16);
    {
        out = psBitSetOp(out, bs, "AND", bs2);
        ok( out == NULL,
            "psBitSetOp:           return NULL for AND operator with BitSet inputs of"
            " differing size.");
    }
    psFree(bs);
    bs = psBitSetAlloc(16);
    bs = psBitSetSet(bs, 1);     // 0000 0010 == 2
    bs2 = psBitSetSet(bs2, 2);   // 0000 0100 == 4
    //Return correct psBitSet output for valid inputs with AND operator
    {
        out = psBitSetOp(out, bs, "AND", bs2);
        ok( out->bits[0] == 0,
            "psBitSetOp:           return correct psBitSet output for valid inputs"
            " with AND operator.");
    }
    //Return correct psBitSet output for valid inputs with OR operator
    {
        out = psBitSetOp(out, bs, "OR", bs2);
        ok( out->bits[0] == 6,
            "psBitSetOp:           return correct psBitSet output for valid inputs"
            " with OR operator.");
    }
    //Return correct psBitSet output for valid inputs with XOR operator
    bs2 = psBitSetSet(bs2, 1);     // 0000 0110 == 6
    {
        out = psBitSetOp(out, bs, "XOR", bs2);
        ok( out->bits[0] == 4,
            "psBitSetOp:           return correct psBitSet output for valid inputs"
            " with XOR operator.");
    }
    //Return correct psBitSet output for valid inputs with NOT operator
    {
        psFree(out);
        out = psBitSetAlloc(0);
        bs = psBitSetSet(bs, 2);  // 0000 0110 == 4
        bs = psBitSetSet(bs, 3);  // 0000 1110 == 12
        bs = psBitSetSet(bs, 4);  // 0001 1110 == 28
        bs = psBitSetSet(bs, 5);  // 0011 1110 == 60
        bs = psBitSetSet(bs, 6);  // 0111 1110 == 124
        bs = psBitSetSet(bs, 7);  // 1111 1110 == 252
        out = psBitSetOp(out, bs, "NOT", bs2);
        ok( out->bits[0] == 1,
            "psBitSetOp:           return correct psBitSet output for valid inputs"
            " with NOT operator.");
    }

    //psBitSetToString Tests
    //Return NULL for NULL BitSet input
    psString bitStr = NULL;
    {
        bitStr = psBitSetToString(noBits);
        ok( bitStr == NULL,
            "psBitSetToString:     return NULL for NULL BitSet input.");
    }
    //Return correct string for valid BitSet input
    {
        psFree(bs);
        bs = psBitSetAlloc(8);
        bs = psBitSetSet(bs, 2);  // 0000 0100 == 4
        bitStr = psBitSetToString(bs);
        ok( !strncmp(bitStr, "00000100", 10),
            "psBitSetToString:     return correct string for valid BitSet input.");
    }


    //Check for Memory leaks
    {
        psFree(bitStr);
        psFree(out);
        psFree(bs);
        psFree(bs2);
        checkMem();
    }
}
