#!/usr/bin/env qore
# -*- mode: qore; indent-tabs-mode: nil -*-

%new-style
%enable-all-warnings
%require-types
%strict-args

%requires ../../../../../qlib/QUnit.qm

%exec-class Test

class Test inherits QUnit::Test {
    constructor() : QUnit::Test("Queue", "1.0") {
        addTestCase("simple tests", \simpleTests());
        addTestCase("timeout", \timeoutTests());
        addTestCase("leak test", \leakTest());
        set_return_value(main());
    }

    leakTest() {
        Queue q();
        File f();
        f.setEventQueue(q);
        # this creates a memory leak visible in valgrind for example
        assertEq(Type::Object, q.copy().type());
    }

    simpleTests() {
        Queue q();

        q.push(1);
        assertEq(1, q.get());
        assertEq(0, q.size());
        q.push(1);
        q.setError("ERR", "desc");
        assertThrows("ERR", "desc", \q.push(), 1);
        q.clearError();
        assertEq(0, q.size());
        q.push(1);
        assertEq(1, q.get());
        assertEq(0, q.size());

        Counter c(1);
        background wait(q, c);
        # wait for background thread to start waiting
        while (!q.getReadWaiting())
            usleep(1ms);

        # set queue to error
        q.setError("ERR", "desc");
        c.waitForZero();
    }

    timeoutTests() {
        Queue q(1);
        assertThrows("QUEUE-TIMEOUT", \q.get(), -1);
        assertThrows("QUEUE-TIMEOUT", \q.pop(), -1);
        assertThrows("QUEUE-TIMEOUT", \q.get(), -10000);
        assertThrows("QUEUE-TIMEOUT", \q.pop(), -10000);
        q.push(True);
        assertThrows("QUEUE-TIMEOUT", \q.insert(), (True, -1));
        assertThrows("QUEUE-TIMEOUT", \q.push(), (True, -1));
        assertThrows("QUEUE-TIMEOUT", \q.insert(), (True, -10000));
        assertThrows("QUEUE-TIMEOUT", \q.push(), (True, -10000));

        assertThrows("QUEUE-TIMEOUT-ERROR", \q.get(), -9999999999);
        assertThrows("QUEUE-TIMEOUT-ERROR", \q.get(), 9999999999);
        assertThrows("QUEUE-TIMEOUT-ERROR", \q.pop(), -9999999999);
        assertThrows("QUEUE-TIMEOUT-ERROR", \q.pop(), 9999999999);
        assertThrows("QUEUE-TIMEOUT-ERROR", \q.insert(), (True, -9999999999));
        assertThrows("QUEUE-TIMEOUT-ERROR", \q.insert(), (True, 9999999999));
        assertThrows("QUEUE-TIMEOUT-ERROR", \q.push(), (True, -9999999999));
        assertThrows("QUEUE-TIMEOUT-ERROR", \q.push(), (True, 9999999999));
    }

    wait(Queue q, Counter c) {
        on_exit c.dec();
        assertThrows("ERR", \q.get());
    }
}
