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

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

%disable-warning unreferenced-variable

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

%exec-class HashTimeTest

class HashTimeTest inherits QUnit::Test {
    private {
        hash h;
        list l;

        int hash_keycount = 1000; # hash keys count
        int min_length    =   20; # minimum hash key length
        int num_loops     =    2; # times to search the hash
        int limit_time    =  200; # tests fails if it takes more secs
    }

    constructor() : QUnit::Test("Hash timing test", "1.0") {
        addTestCase("Test", \test());

        set_return_value(main());
    }

    globalSetUp() {
        l = ();
        srand(now());
    }

    test() {
        # test create
        date list_start = now_us();
        foreach int i in (range(hash_keycount)) {
            l += getKey(i);
        }
        assertEq(elements(l), hash_keycount, "created list of " + hash_keycount + " elements");
        date start = now_us();
        date interval_create = start - list_start;
        assertTrue(interval_create < limit_time, "Create interval: " + interval_create + "s");

        # test insert
        foreach int i in (range(hash_keycount)) {
            h{l[i]} = True;
        }
        date search = now_us();
        date interval_insert = search - start;
        assertTrue(interval_insert < limit_time, "Inserts interval: " + interval_insert + "s");

        # test search
        search = now_us();
        for (int loop = 0; loop < num_loops; loop++) {
            foreach int i in (range(hash_keycount)) {
                bool v = h.(l[i]);
            }
        }
        date et = now_us();
        date interval_search = et - search;
        assertTrue(interval_search < limit_time, hash_keycount * num_loops + " searches interval: " + interval_search + " s");
    }

    string rstr(int len) {
        string str = "";

        for (int i = 0; i < len; i++) {
            str += doChar(rand() % 52);
        }

        return str;
    }

    string doChar(int v) {
        return v < 26 ? chr(v + ord("A")) : chr(v - 26 + ord("a"));
    }

    string getKey(int n) {
        string str = "";

        int v = n % 52;
        str += doChar(v) + rstr(2);
        n -= v;
        while (n > 51) {
            n /= 52;
            str += doChar((n - 1) % 52) + rstr(2);
        }
        str += rstr(min_length - str.size());
        return str;
    }
}

