Annotation: unit_tests.begin

CREATE OR REPLACE FUNCTION unit_tests.begin(v integer DEFAULT 9)
RETURNS TABLE(message text, result character)

Information: unit_tests.begin

Schema unit_tests
Function Name begin
Arguments v integer DEFAULT 9
Owner postgres
Result Type TABLE(message text, result character)
Description

Implementation: unit_tests.begin

CREATE OR REPLACE FUNCTION unit_tests.begin(v integer DEFAULT 9)
 RETURNS TABLE(message text, result character)
 LANGUAGE plpgsql
AS $function$
    DECLARE this record;
    DECLARE _function_name text;
    DECLARE _sql text;
    DECLARE _message text;
    DECLARE _result character(1);
    DECLARE _test_id integer;
    DECLARE _status boolean;
    DECLARE _total_tests integer = 0;
    DECLARE _failed_tests integer = 0;
    DECLARE _list_of_failed_tests text;
    DECLARE _started_from TIMESTAMP WITHOUT TIME ZONE;
    DECLARE _completed_on TIMESTAMP WITHOUT TIME ZONE;
    DECLARE _delta integer;
    DECLARE _ret_val text = '';
    DECLARE _verbosity text[] = ARRAY['debug5', 'debug4', 'debug3', 'debug2', 'debug1', 'log', 'notice', 'warning', 'error', 'fatal', 'panic'];
BEGIN
    _started_from := clock_timestamp() AT TIME ZONE 'UTC';

    RAISE INFO 'Test started from : %', _started_from; 

    IF(v > 10) THEN
        v := 9;
    END IF;
    
    EXECUTE 'SET CLIENT_MIN_MESSAGES TO ' || _verbosity[v];

    RAISE WARNING 'CLIENT_MIN_MESSAGES set to : %' , _verbosity[v];
    

    SELECT nextval('unit_tests.tests_test_id_seq') INTO _test_id;

    INSERT INTO unit_tests.tests(test_id)
    SELECT _test_id;

    FOR this IN
        SELECT proname as function_name
        FROM    pg_catalog.pg_namespace n
        JOIN    pg_catalog.pg_proc p
        ON      pronamespace = n.oid
        WHERE   nspname = 'unit_tests'
        AND prorettype='test_result'::regtype::oid
    LOOP
        BEGIN
            _status := false;
            _total_tests := _total_tests + 1;
            
            _function_name = 'unit_tests.' || this.function_name || '()';
            _sql := 'SELECT ' || _function_name || ';';
            
            RAISE NOTICE 'RUNNING TEST : %.', _function_name;

            EXECUTE _sql INTO _message;

            IF _message = '' THEN
                _status := true;
            END IF;

            
            INSERT INTO unit_tests.test_details(test_id, function_name, message, status)
            SELECT _test_id, _function_name, _message, _status;

            IF NOT _status THEN
                _failed_tests := _failed_tests + 1;         
                RAISE WARNING 'TEST % FAILED.', _function_name;
                RAISE WARNING 'REASON: %', _message;
            ELSE
                RAISE NOTICE 'TEST % COMPLETED WITHOUT ERRORS.', _function_name;
            END IF;

        EXCEPTION WHEN OTHERS THEN
            _message := 'ERR' || SQLSTATE || ': ' || SQLERRM;
            INSERT INTO unit_tests.test_details(test_id, function_name, message, status)
            SELECT _test_id, _function_name, _message, false;

            _failed_tests := _failed_tests + 1;         
            RAISE WARNING 'TEST % FAILED.', _function_name;
            RAISE WARNING 'REASON: %', _message;
        END;
    END LOOP;

    _completed_on := clock_timestamp() AT TIME ZONE 'UTC';
    _delta := extract(millisecond from _completed_on - _started_from)::integer;
    
    UPDATE unit_tests.tests
    SET total_tests = _total_tests, failed_tests = _failed_tests, completed_on = _completed_on
    WHERE test_id = _test_id;

    
    WITH failed_tests AS
    (
        SELECT row_number() over (order by id) AS id, 
        unit_tests.test_details.function_name,
        unit_tests.test_details.message
        FROM unit_tests.test_details 
        WHERE test_id = _test_id
        AND status= false
    )

    SELECT array_to_string(array_agg(f.id::text || '. ' || f.function_name || ' --> ' || f.message), E'\n') INTO _list_of_failed_tests 
    FROM failed_tests f;

    _ret_val := _ret_val ||  'Test completed on : ' || _completed_on::text || E' UTC. \nTotal test runtime: ' || _delta::text || E' ms.\n';
    _ret_val := _ret_val || E'\nTotal tests run : ' || COALESCE(_total_tests, '0')::text;
    _ret_val := _ret_val || E'.\nPassed tests    : ' || (COALESCE(_total_tests, '0') - COALESCE(_failed_tests, '0'))::text;
    _ret_val := _ret_val || E'.\nFailed tests    : ' || COALESCE(_failed_tests, '0')::text;
    _ret_val := _ret_val || E'.\n\nList of failed tests:\n' || '----------------------';
    _ret_val := _ret_val || E'\n' || COALESCE(_list_of_failed_tests, '')::text;
    _ret_val := _ret_val || E'\n' || E'End of plpgunit test.\n\n';


    IF _failed_tests > 0 THEN
        _result := 'N';
        RAISE INFO '%', _ret_val;
    ELSE
        _result := 'Y';
        RAISE INFO '%', _ret_val;
    END IF;

    SET CLIENT_MIN_MESSAGES TO notice;

    RETURN QUERY SELECT _ret_val, _result;
END
$function$