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

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

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

# Allow child Program objects to have more liberal permissions than the parent.
%no-child-restrictions

%exec-class ListTest

hashdecl T {
    int i = 0;
}

auto sub test_4355(Counter c) {
    on_exit c.dec();
    list<auto> l = map "string-" + sprintf("%05d", $#), xrange(0, 3000);
    return sort(l);
}

auto sub test_4355_stable(Counter c) {
    on_exit c.dec();
    list<auto> l = map "string-" + sprintf("%05d", $#), xrange(0, 10000);
    return sort_stable(l);
}

public class ListTest inherits QUnit::Test {
    constructor() : Test("ListTest", "1.0") {
        addTestCase("list test", \listTest());

        # Return for compatibility with test harness that checks return value.
        set_return_value(main());
    }

    listTest() {
        # issue #4355
        {
            Counter c(1);
            background test_4355(c);
            c.waitForZero();
            assertTrue(True);
        }

        {
            Counter c(1);
            background test_4355_stable(c);
            c.waitForZero();
            assertTrue(True);
        }

        hash<string, list<hash<T>>> h();
        {
            list<string> l0 = h.keys();
            assertEq(True, l0.complexType());
            any l1 = h.keys();
            assertEq(False, l1.complexType());
            l1 += 1;
            assertEq(1, l1[0]);
        }
        {
            # assigning a complex type to a list lvalue strips the type info
            list l = new list<int>();
            assertEq(False, l.complexType());
        }
        {
            list<int> l();
            l = map $1, l, $1;
            assertEq(True, l.complexType());
            assertEq("list<int>", l.fullType());
            assertEq((), l);
            l = map $1, l;
            assertEq(True, l.complexType());
            assertEq("list<int>", l.fullType());
            assertEq((), l);
            l = select l, $1;
            assertEq(True, l.complexType());
            assertEq("list<int>", l.fullType());
            assertEq((), l);
            assertEq(1, test(new list<int>(), new list<string>()));
        }
        {
            Program p(PO_NEW_STYLE);
            p.parse("list sub t() {string line = 'a+b,c'; any x; x = (line =~ x/(.)\\+(.*)/); x[1] = split(',', x[1]); return x[1];}", "");
            assertEq(("b", "c"), p.callFunction("t"));
        }
        {
            list l;
            l += 1;
            assertEq((1,), l);
        }
        {
            list<auto> l;
            l += 1;
            assertEq((1,), l);
        }
        {
            list<int> l;
            l += 1;
            assertEq((1,), l);
        }
        {
            softlist l;
            l += 1;
            assertEq((1,), l);
        }
        {
            softlist<auto> l;
            l += 1;
            assertEq((1,), l);
        }
        {
            softlist<int> l;
            l += 1;
            assertEq((1,), l);
        }
        {
            *list l;
            l += 1;
            assertEq((1,), l);
        }
        {
            *list<auto> l;
            l += 1;
            assertEq((1,), l);
        }
        {
            *list<int> l;
            l += 1;
            assertEq((1,), l);
        }
        {
            *softlist l;
            l += 1;
            assertEq((1,), l);
        }
        {
            *softlist<auto> l;
            l += 1;
            assertEq((1,), l);
        }
        {
            *softlist<int> l;
            l += 1;
            assertEq((1,), l);
        }

        {
            code t = auto sub(int i) { return <StatInfo>{}; };
            auto v = 1;
            list<auto> l = (1, t(v));
            assertEq("hash<StatInfo>", l[1].fullType());
        }
    }

    int test(list<int> l1, list<string> l2) {
        return 1;
    }
}
