#!/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 StackGuardTest

public class StackGuardTest inherits QUnit::Test {
    public {
        const ThreadStackSize = 512 * 1024;
    }

    constructor() : Test("StackGuardTest", "1.0") {
        addTestCase("stack size", \testStackSize());
        addTestCase("Test overflowing the stack limit", \testInfiniteRecurse());
        addTestCase("Test two threads", \testRecurseWithBackground());

        set_return_value(main());
    }

    setUp() {
        if (!Option::HAVE_STACK_GUARD) {
            testSkip("Qore library was not built with stack protection support");
        }
    }

    testStackSize() {
        assertGt(ThreadStackSize, get_stack_size());
        Queue q();
        background sub () {
            try {
                assertGe(ThreadStackSize, get_stack_size());
                q.push();
            } catch (hash<ExceptionInfo> ex) {
                q.push(ex);
            }
        }();
        *hash<ExceptionInfo> ex = q.get();
        if (ex) {
            throw ex.err, ex.desc, ex.arg;
        }
    }

    recurse() {
        recurse();
    }

    testInfiniteRecurse() {
        assertThrows("STACK-LIMIT-EXCEEDED", "this thread's stack has exceeded the stack size limit", \recurse());
    }

    testRecurseWithBackground() {
        background testInfiniteRecurse();
        testInfiniteRecurse();
    }
}
