/*****************************************************************************
    This code will test whether trace levels can be set successfully.
 
    XXX: For the last two testpoints, must verify that the results are
    correct, and put that verification in the test as well.
 *****************************************************************************/
#include <stdio.h>
#include "pslib_strict.h"
#include "psTest.h"
#include <fcntl.h>
#include <unistd.h>


static psS32 testTrace00(void);
static psS32 testTrace01(void);
static psS32 testTrace02(void);
static psS32 testTrace03(void);
static psS32 testTrace04(void);
static psS32 testTrace05(void);
static psS32 testTrace05a(void);
static psS32 testTrace06(void);
static psS32 testTrace08(void);

testDescription tests[] = {
                              {testTrace00, 0, "psTraceSetLevel() and psTraceGetLevel()", 0, false},
                              {testTrace01, 1, "psTraceSetLevel(): set multiple components in one call", 0, false},
                              {testTrace02, 2, "psTraceSetLevel(): test static/dynamic inheritance", 0, false},
                              {testTrace03, 3, "psTraceReset()", 0, false},
                              {testTrace04, 4, "psTrace()", 0, false},
                              {testTrace05, 5, "psTracePrintLevels()", 0, false},
                              {testTrace05a, 5, "optional leading dot and psTracePrintLevels()", 0, false},
                              {testTrace06, 6, "Testing psTraceReset", 0, false},
                              {testTrace08, 8, "Testing ", 0, false},
                              {NULL}
                          };

testDescription tests2[] = {
                               {testTrace08, 8, "Testing ", 0, false},
                           };

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

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

static psS32 testTrace00(void)
{
    psS32 i;
    psS32 lev = 0;

    //    psTraceSetDestination(stderr);
    psTraceSetDestination(2);

    for (i=0;i<10;i++) {
        (void)psTraceSetLevel(".", i);
        lev = psTraceGetLevel(".");
        if (lev != i) {
            fprintf(stderr,"ERROR: (.) expected trace level was %d, actual was %d\n",
                    i, lev);
            return 1;
        }
    }
    (void)psTraceSetLevel(".", 3);

    for (i=5;i<10;i++) {
        (void)psTraceSetLevel(".NODE00", i);
        lev = psTraceGetLevel(".NODE00");
        if (lev != i) {
            fprintf(stderr,
                    "ERROR: (.NODE00) expected trace level was %d, actual was %d\n",
                    i, lev);
            return 2;
        }

        lev = psTraceGetLevel(".");
        if (lev != 3) {
            fprintf(stderr,"ERROR: (.) expected trace level was %d, actual was %d\n",
                    i, 3);
            return 3;
        }
    }


    (void)psTraceSetLevel(".NODE00.NODE01", 4);
    for (i=0;i<10;i++) {
        (void)psTraceSetLevel(".NODE00.NODE01", i);
        lev = psTraceGetLevel(".NODE00.NODE01");
        if (lev != i) {
            fprintf(stderr,
                    "ERROR: (.NODE00.NODE01) expected trace level was %d, actual was %d\n",
                    i, lev);
            return 4;
        }
    }

    return 0;
}

static psS32 testTrace01(void)
{
    //    psTraceSetDestination(stderr);
    psTraceSetDestination(2);
    (void)psTraceSetLevel(".A.B.C.D.E", 5);

    psTrace(".A.C.D.C",1,"You should not see this.\n");
    psTrace(".A.B.C.D.E",2,"You should see this.\n");
    psTrace(".A.B.C.D.E.F",3,"You should see this too.\n");

    psTracePrintLevels();

    return 0;
}

static psS32 testTrace02(void)
{
    psTraceReset();
    //    psTraceSetDestination(stderr);
    psTraceSetDestination(2);
    psTraceSetLevel(".A.B", 2);
    psTraceSetLevel(".A.B.C.D.E", 5);
    psTracePrintLevels();
    psTraceSetLevel(".A.B", 10);
    psTracePrintLevels();

    if (10 != psTraceGetLevel(".A.B.C")) {
        fprintf(stderr,"ERROR: .A.B.C did not dynamically inherit a trace level (%d)\n",
                psTraceGetLevel(".A.B.C"));
        return 2;
    }

    if (10 != psTraceGetLevel(".A.B.C.D")) {
        fprintf(stderr,"ERROR: .A.B.C.D did not dynamically inherit a trace level (%d)\n", psTraceGetLevel(".A.B.C.D"));
        return 2;
    }

    if (5 != psTraceGetLevel(".A.B.C.D.E")) {
        fprintf(stderr,"ERROR: .A.B.C.D.E did dynamically inherit a trace level (%d)\n", psTraceGetLevel(".A.B.C.D.E"));
        return 2;
    }

    return 0;
}

static psS32 testTrace03(void)
{
    psS32 i = 0;
    psS32 lev = 0;

    //    psTraceSetDestination(stderr);
    psTraceSetDestination(2);

    for (i=0;i<10;i++) {
        (void)psTraceSetLevel(".", i);
        psTraceReset();

        lev = psTraceGetLevel(".");
        if (lev != PS_UNKNOWN_TRACE_LEVEL) {
            fprintf(stderr,"ERROR: expected trace level was %d, actual was %d\n",
                    PS_UNKNOWN_TRACE_LEVEL, lev);
            return 1;
        }
    }
    (void)psTraceSetLevel(".", 5);
    (void)psTraceSetLevel(".a", 4);
    (void)psTraceSetLevel(".a.b", 3);
    (void)psTraceSetLevel(".a.b.c", 2);
    if ((5 != psTraceGetLevel(".")) ||
            (4 != psTraceGetLevel(".a")) ||
            (3 != psTraceGetLevel(".a.b")) ||
            (2 != psTraceGetLevel(".a.b.c"))) {
        fprintf(stderr,"ERROR: trace successFlag = false;levels were not settable?\n");
        return 2;
    }

    psTraceReset();
    if ((PS_UNKNOWN_TRACE_LEVEL != psTraceGetLevel(".")) ||
            (PS_UNKNOWN_TRACE_LEVEL != psTraceGetLevel(".a")) ||
            (PS_UNKNOWN_TRACE_LEVEL != psTraceGetLevel(".a.b")) ||
            (PS_UNKNOWN_TRACE_LEVEL != psTraceGetLevel(".a.b.c"))) {
        fprintf(stderr,"ERROR: trace levels were not reset properly\n");
        return 3;
    }

    return 0;
}


static psS32 testTrace04(void)
{
    int FD;
    psS32 nb = 0;
    FD = creat("tst_psTrace02_OUT", 0666);
    //    printf("\nFD = %d\n", FD);
    //    fp = fopen("tst_psTrace02_OUT", "w");
    for (nb = 0 ; nb<4;nb++) {
        if (nb == 0)
            //            psTraceSetDestination(stdout);
            psTraceSetDestination(1);
        if (nb == 1)
            //            psTraceSetDestination(stderr);
            psTraceSetDestination(2);
        if (nb == 2)
            psTraceSetDestination(0); //NULL
        if (nb == 3)
            psTraceSetDestination(FD);

        (void)psTraceSetLevel(".", 4);
        psTrace(".", 5, "(0) This message should not be displayed (%x)\n",
                0xbeefface);
        (void)psTraceSetLevel(".", 7);
        psTrace(".", 5, "(0) This message should be displayed (%x)\n",
                0xbeefface);

        (void)psTraceSetLevel(".a", 4);
        psTrace(".a", 5, "(1) This message should not be displayed (%x)\n",
                0xbeefface);
        (void)psTraceSetLevel(".a", 7);
        psTrace(".a", 5, "(1) This message should be displayed (%x)\n",
                0xbeefface);


        (void)psTraceSetLevel(".a.b", 4);
        psTrace(".a.b", 5, "(2) This message should not be displayed (%x)\n",
                0xbeefface);
        (void)psTraceSetLevel(".a.b", 7);
        psTrace(".a.b", 5, "(2) This message should be displayed (%x)\n",
                0xbeefface);
        (void)psTraceSetLevel(".a.b.c", 12);
        psTrace(".a.b.c", 11, "(3) This message should be displayed (%x)\n",
                0xbeefface);

    }

    close(FD);

    return(0);
}

static psS32 testTrace05(void)
{
    //    psTraceSetDestination(stderr);
    psTraceSetDestination(2);

    (void)psTraceSetLevel(".", 9);

    (void)psTraceSetLevel(".a", 8);
    (void)psTraceSetLevel(".b", 7);
    (void)psTraceSetLevel(".c", 5);

    (void)psTraceSetLevel(".a.a", 4);
    (void)psTraceSetLevel(".a.b", 3);

    (void)psTraceSetLevel(".b.a", 2);
    (void)psTraceSetLevel(".b.b", 1);

    (void)psTraceSetLevel(".c.a", 0);
    (void)psTraceSetLevel(".c.b", 3);
    (void)psTraceSetLevel(".c.c", 5);

    psTracePrintLevels();

    return 0;

}

static psS32 testTrace05a(void)
{
    (void)psTraceSetLevel(".", 9);

    (void)psTraceSetLevel("a", 8);
    (void)psTraceSetLevel("b", 7);
    (void)psTraceSetLevel("c", 5);

    (void)psTraceSetLevel("a.a", 4);
    (void)psTraceSetLevel("a.b", 3);

    (void)psTraceSetLevel("b.a", 2);
    (void)psTraceSetLevel("b.b", 1);

    (void)psTraceSetLevel("c.a", 0);
    (void)psTraceSetLevel("c.b", 3);
    (void)psTraceSetLevel("c.c", 5);

    psTracePrintLevels();

    return 0;

}

static psS32 testTrace06(void)
{
    //    psTraceSetDestination(stderr);
    psTraceSetDestination(2);

    (void)psTraceSetLevel(".", 9);

    (void)psTraceSetLevel(".a", 8);
    (void)psTraceSetLevel(".b", 7);
    (void)psTraceSetLevel(".c", 5);

    (void)psTraceSetLevel(".a.a", 4);
    (void)psTraceSetLevel(".a.b", 3);

    (void)psTraceSetLevel(".b.a", 2);
    (void)psTraceSetLevel(".b.b", 1);

    (void)psTraceSetLevel(".c.a", 0);
    (void)psTraceSetLevel(".c.b", 3);
    (void)psTraceSetLevel(".c.c", 5);

    psTraceReset();

    if ((psTraceGetLevel(".")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".a")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".b")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".c")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".a.a")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".a.b")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".b.a")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".b.b")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".c.a")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".c.b")!=PS_UNKNOWN_TRACE_LEVEL) ||
            (psTraceGetLevel(".c.c")!=PS_UNKNOWN_TRACE_LEVEL)) {
        return 1;
    }

    return 0;
}

// Ensure that the leading dot in the component names are optional.
static psS32 testTrace08(void)
{
    psTraceReset();
    (void)psTraceSetLevel(".", 9);

    (void)psTraceSetLevel(".a", 8);
    (void)psTraceSetLevel(".b", 7);
    (void)psTraceSetLevel(".c", 5);

    (void)psTraceSetLevel(".a.a", 4);
    (void)psTraceSetLevel(".a.b", 3);

    (void)psTraceSetLevel(".b.a", 2);
    (void)psTraceSetLevel(".b.b", 1);

    (void)psTraceSetLevel(".c.a", 0);
    (void)psTraceSetLevel(".c.b", 3);
    (void)psTraceSetLevel(".c.c", 5);

    psTracePrintLevels();

    if ((psTraceGetLevel(".")!=9) ||
            (psTraceGetLevel("a")!=8) ||
            (psTraceGetLevel("b")!=7) ||
            (psTraceGetLevel("c")!=5) ||
            (psTraceGetLevel("a.a")!=4) ||
            (psTraceGetLevel("a.b")!=3) ||
            (psTraceGetLevel("b.a")!=2) ||
            (psTraceGetLevel("b.b")!=1) ||
            (psTraceGetLevel("c.a")!=0) ||
            (psTraceGetLevel("c.b")!=3) ||
            (psTraceGetLevel("c.c")!=5)) {
        printf("psTraceGetLevel(.) is %d\n", psTraceGetLevel("."));
        printf("psTraceGetLevel(a) is %d\n", psTraceGetLevel("a"));
        printf("psTraceGetLevel(b) is %d\n", psTraceGetLevel("b"));
        printf("psTraceGetLevel(c) is %d\n", psTraceGetLevel("c"));
        printf("psTraceGetLevel(a.a) is %d\n", psTraceGetLevel("a.a"));
        printf("psTraceGetLevel(a.b) is %d\n", psTraceGetLevel("a.b"));
        printf("psTraceGetLevel(b.a) is %d\n", psTraceGetLevel("b.a"));
        printf("psTraceGetLevel(b.b) is %d\n", psTraceGetLevel("b.b"));
        printf("psTraceGetLevel(c.a) is %d\n", psTraceGetLevel("c.a"));
        printf("psTraceGetLevel(c.b) is %d\n", psTraceGetLevel("c.b"));
        printf("psTraceGetLevel(c.c) is %d\n", psTraceGetLevel("c.c"));

        return 1;
    }

    return 0;
}
