// ========================================================= //
//                                                           //
//   File      : test_arb_error.cxx                          //
//   Purpose   : test header class ARB_ERROR                 //
//                                                           //
//   Coded by Ralf Westram (coder@reallysoft.de) in Jan 22   //
//   http://www.arb-home.de/                                 //
//                                                           //
// ========================================================= //

// --------------------------------------------------------------------------------

#ifdef UNIT_TESTS
#ifndef TEST_UNIT_H
#include <test_unit.h>
#endif

#include <arb_error.h>
#include <arb_msg.h>
#include <ErrorOrType.h>

static const char *SOME_ERROR = "whatever";

#if defined(ASSERTION_USED)

static void drop_unused_ARB_ERROR() {
    ARB_ERROR e0;
}
static void drop_ARB_ERROR() {
    ARB_ERROR e1 = SOME_ERROR;
}
static void overwrite_ARB_ERROR() {
    ARB_ERROR e1 = SOME_ERROR;
    ARB_ERROR e2 = SOME_ERROR;

    e1 = e2;           // expect this command to trigger assertion
    ARB_SIGSEGV(true); // -> this is never reached
}

#endif

static ARB_ERROR forwardError(ARB_ERROR err) {
    return err;
}
static ARB_ERROR annotateError(ARB_ERROR err) {
    if (err) {
        ARB_ERROR ann_err = GBS_global_string("annotated '%s'", err.deliver());
        err               = ann_err;
    }
    return err;
}

void TEST_misuse_ARB_ERROR_crashtest() {
    TEST_EXPECT_CODE_ASSERTION_FAILS(drop_unused_ARB_ERROR);
    TEST_EXPECT_CODE_ASSERTION_FAILS(drop_ARB_ERROR);
    TEST_EXPECT_CODE_ASSERTION_FAILS(overwrite_ARB_ERROR);
}
void TEST_class_ARB_ERROR() {
    // unused error:
    {
        ARB_ERROR e0;
        TEST_EXPECT_NULL(e0.deliver());
    }

    // simple error delivery:
    {
        ARB_ERROR e1 = SOME_ERROR;
        TEST_EXPECT_EQUAL(e1.deliver(), SOME_ERROR);
    }

    // deliver reassigned error (copy ctor):
    {
        ARB_ERROR e1 = SOME_ERROR;
        ARB_ERROR e2(e1);
        TEST_EXPECT_EQUAL(e2.deliver(), SOME_ERROR);
    }
    // deliver reassigned error (also copy ctor):
    {
        ARB_ERROR e1 = SOME_ERROR;
        ARB_ERROR e2 = e1; // assign in definition == copy-ctor
        TEST_EXPECT_EQUAL(e2.deliver(), SOME_ERROR);
    }
    // deliver reassigned error (op=):
    {
        ARB_ERROR e1 = SOME_ERROR;
        ARB_ERROR e2;
        e2 = e1; // real assignment
        TEST_EXPECT_EQUAL(e2.deliver(), SOME_ERROR);
    }

    // deliver error forwarded through function:
    {
        ARB_ERROR e0;
        ARB_ERROR e1 = SOME_ERROR;
        ARB_ERROR f0 = forwardError(e0);
        ARB_ERROR f1 = forwardError(e1);
        TEST_EXPECT_NULL(f0.deliver());
        TEST_EXPECT_EQUAL(f1.deliver(), SOME_ERROR);
    }
    // forward and annotate error:
    {
        ARB_ERROR e0;
        ARB_ERROR e1 = SOME_ERROR;
        ARB_ERROR a0 = annotateError(e0);
        ARB_ERROR a1 = annotateError(e1);
        TEST_EXPECT_NULL(a0.deliver());
        TEST_EXPECT_EQUAL(a1.deliver(), "annotated 'whatever'");
    }
}

typedef ErrorOr<int> ErrorOrInt;

#if defined(ASSERTION_USED)

static void drop_ErrorOr0() {
    ErrorOrInt e(NULp, 42);
}
static void drop_ErrorOr1() {
    ErrorOrInt e(SOME_ERROR, 0);
}
static void retrieve_unchecked_ErrorOr0() {
    ErrorOrInt e(NULp, 21);
    int v = e.getValue(); // getValue w/o previous mandatory hasError
    TEST_EXPECT_EQUAL(v, 21);
}
static void retrieve_unchecked_ErrorOr1() {
    ErrorOrInt e(SOME_ERROR, 0);
    ARB_ERROR  ae = e.getError(); // getError w/o previous mandatory hasError
    TEST_REJECT_NULL(ae.deliver());
}

#endif

static ErrorOrInt generateErrorOr(int i) {
    return ErrorOrInt(NULp, i);
}
static ErrorOrInt generateErrorOr(const char *msg) {
    return ErrorOrInt(msg, -1);
}

void TEST_misuse_ErrorOr_crashtest() {
    TEST_EXPECT_CODE_ASSERTION_FAILS(drop_ErrorOr0);
    TEST_EXPECT_CODE_ASSERTION_FAILS(drop_ErrorOr1);
    TEST_EXPECT_CODE_ASSERTION_FAILS(retrieve_unchecked_ErrorOr0);
    TEST_EXPECT_CODE_ASSERTION_FAILS(retrieve_unchecked_ErrorOr1);
}
void TEST_ErrorOr() {
    // simple uses (create, check, use + destroy):
    {
        ErrorOrInt e(SOME_ERROR, 0);
        TEST_EXPECT(e.hasError());
        TEST_EXPECT_EQUAL(e.getError().deliver(), SOME_ERROR);
    }
    {
        ErrorOrInt v(NULp, 7);
        TEST_EXPECT(v.hasValue());
        TEST_EXPECT_EQUAL(v.getValue(), 7);
    }

    // test copy-construction:
    {
        ErrorOrInt e(SOME_ERROR, 0);
        ErrorOrInt c = e;
        TEST_EXPECT(c.hasError());
        TEST_EXPECT_EQUAL(c.getError().deliver(), SOME_ERROR);
    }
    {
        ErrorOrInt v(NULp, 17);
        ErrorOrInt c = v;
        TEST_EXPECT(c.hasValue());
        TEST_EXPECT_EQUAL(c.getValue(), 17);
    }
    {
        ErrorOrInt v = generateErrorOr(17);
        TEST_EXPECT(v.hasValue());
        TEST_EXPECT_EQUAL(v.getValue(), 17);
    }
    {
        ErrorOrInt e = generateErrorOr(SOME_ERROR);
        TEST_EXPECT(e.hasError());
        TEST_EXPECT_EQUAL(e.getError().deliver(), SOME_ERROR);
    }
}


#endif // UNIT_TESTS

// --------------------------------------------------------------------------------



