/**
 *  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"


int main(void)
{
    psLogSetFormat("HLNM");
    psLogSetLevel(PS_LOG_INFO);
    plan_tests(32);


    // testBitSetBasics()
    {
        psMemId id = psMemGetId();
        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 FALSE for NULL input psBitSet
        {
            bool rc = psBitSetSet(NULL, 0);
            ok(rc == false,
                "psBitSetSet:           return FALSE for NULL BitSet input.");
        }
        //Return FALSE for negative bit input
        {
            bool rc = psBitSetSet(bs, -1);
            ok( rc == false,
                "psBitSetSet:           return TRUE for negative bits input.");
            noBits = NULL;
        }
        //Return FALSE for out-of-range bits
        {
            psFree(bs);
            bs = psBitSetAlloc(8);
            bool rc = psBitSetSet(bs, 8);
            ok( rc == false,
                "psBitSetSet:           return TRUE for out-of-range bits input.");
            noBits = NULL;
        }

        //Return set BitSet for valid inputs
        {
            psBitSetSet(bs, 2);
            ok( bs->bits[0] == 4,
                "psBitSetSet:           return properly set BitSet for valid inputs.");
        }

        //BitSetClear Tests
        //Return FALSE for NULL input psBitSet
        {
            bool rc = psBitSetClear(noBits, 0);
            ok( rc == false,
                "psBitSetClear:         return FALSE for NULL BitSet input.");
        }
        //Return FALSE for negative bit input
        {
            bool rc = psBitSetClear(bs, -1);
            ok( rc == false,
                "psBitSetClear:        return TRUE for negative bits input.");
            noBits = NULL;
        }
        //Return FALSE for out-of-range bits
        {
            bool rc = psBitSetClear(bs, 8);
            ok( rc == false,
                "psBitSetClear:        return FALSE for out-of-range bits input.");
            noBits = NULL;
        }

        //Return cleared BitSet for valid inputs
        {
            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
        {
            psBitSetSet(bs, 2);
            ok( psBitSetTest(bs, 2),
                "psBitSetTest:         return true for matching bit in BitSet.");
        }

        psFree(bs);
        ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
    }


    // testBitSetOps()
    {
        psMemId id = psMemGetId();
        psBitSet *noBits = NULL;
        psBitSet *bs = NULL;
        bs = psBitSetAlloc(8);
        psBitSetSet(bs, 2);  // 0000 0100 == 4
        psBitSetSet(bs, 3);  // 0000 1100 == 12
        psBitSetSet(bs, 4);  // 0001 1100 == 28
        psBitSetSet(bs, 5);  // 0011 1100 == 60
        psBitSetSet(bs, 6);  // 0111 1100 == 124
        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);
        psBitSetSet(bs, 1);     // 0000 0010 == 2
        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
        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);
            psBitSetSet(bs, 2);  // 0000 0110 == 4
            psBitSetSet(bs, 3);  // 0000 1110 == 12
            psBitSetSet(bs, 4);  // 0001 1110 == 28
            psBitSetSet(bs, 5);  // 0011 1110 == 60
            psBitSetSet(bs, 6);  // 0111 1110 == 124
            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);
            psBitSetSet(bs, 2);  // 0000 0100 == 4
            bitStr = psBitSetToString(bs);
            ok( !strncmp(bitStr, "00000100", 10),
                "psBitSetToString:     return correct string for valid BitSet input.");
        }

        psFree(bitStr);
        psFree(out);
        psFree(bs);
        psFree(bs2);
        ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
    }
}
