BEGIN;
    -- Load the TAP functions.
    CREATE EXTENSION pgtap;

    -- Plan the tests.

    SELECT plan(159);

    -- Add data

    \i sql/modules/test/Base.sql

    -- Validate required tables

    SELECT has_table('lsmb_group');
    SELECT has_table('lsmb_group_grants');
    SELECT has_table('lsmb_module');

    -- Validate required functions

    SELECT has_function('lsmb__create_role',ARRAY['text']);
    SELECT has_function('lsmb__grant_exec',ARRAY['text','text']);
    SELECT has_function('lsmb__grant_menu',ARRAY['text','integer','text']);
    SELECT has_function('lsmb__grant_perms',ARRAY['text','text','text','text[]']);
    SELECT has_function('lsmb__grant_perms',ARRAY['text','text','text']);
    SELECT has_function('lsmb__grant_role',ARRAY['text','text']);
    SELECT has_function('lsmb__is_allowed_role',ARRAY['text[]']);
    SELECT has_function('quote_ident_array',ARRAY['text[]']);
    SELECT has_function('tg_enforce_perms_eclass','{}'::text[]);

    -- This function is vulnerable to SQL injection but it is transient for the
    -- purposes of these test cases. In particular it is intended only to ensure
    -- that basic permissions are tested.
    --
    -- IT IS THE RESPONSIBILITY OF TEST CASE AUTHORS TO ENSURE THAT THE USAGE OF
    -- THIS FUNCTION IS SAFE.
    CREATE OR REPLACE FUNCTION test__has_select_permission
                                (rolname name, relspec text)
    returns bool language plpgsql as
    $$
    BEGIN
       EXECUTE 'SET SESSION AUTHORIZATION ' || lsmb__role(rolname);
       EXECUTE 'SELECT * FROM '  || relspec || ' LIMIT 1';
       RESET SESSION AUTHORIZATION;
       RETURN TRUE;
    EXCEPTION
       WHEN insufficient_privilege THEN
           RESET SESSION AUTHORIZATION;
           RETURN FALSE;
    END;
    $$;

    -- READ PERMISSIONS
    PREPARE test AS SELECT
                 test__has_select_permission('budget_view', 'budget_info');
    SELECT results_eq('test',ARRAY[true],'budget_view can read budget_info');
    DEALLOCATE test;

    PREPARE test AS SELECT
                 test__has_select_permission('budget_view', 'budget_line');
    SELECT results_eq('test',ARRAY[true],'budget_view can read budget_info');
    DEALLOCATE test;

    PREPARE test AS SELECT
            test__has_select_permission('file_read', 'file_base');
    SELECT results_eq('test',ARRAY[true],'file_read can read file_base');
    DEALLOCATE test;

    PREPARE test AS SELECT
            test__has_select_permission('file_read', 'file_links');
    SELECT results_eq('test',ARRAY[true],'file_read can read file_links');
    DEALLOCATE test;

    PREPARE test AS SELECT
            test__has_select_permission('file_read', 'file_secondary_attachment');
    SELECT results_eq('test',ARRAY[true],'file_read can read file_secondary_transaction');
    DEALLOCATE test;

    PREPARE test AS SELECT
            test__has_select_permission('file_read', 'file_order');
    SELECT results_eq('test',ARRAY[true],'file_read can read file_order');
    DEALLOCATE test;

    PREPARE test AS SELECT
            test__has_select_permission('file_read', 'file_part');
    SELECT results_eq('test',ARRAY[true],'file_read can read file_part');
    DEALLOCATE test;

    SELECT results_eq(
        'SELECT test__has_select_permission(''contact_read'', ''' || t || ''')',
        ARRAY[true],'contact_read can read ' || t
    ) FROM unnest(ARRAY['partsvendor'::text, 'partscustomer', 'taxcategory',
              'entity', 'company', 'location', 'entity_to_location',
              'entity_to_contact', 'person', 'entity_credit_account',
              'contact_class', 'eca_tax', 'entity_class', 'entity_note',
              'entity_bank_account', 'entity_other_name', 'location_class',
              'person_to_company', 'eca_to_contact', 'eca_to_location', 'eca_note',
              'pricegroup'
           ]) t;

    SELECT results_eq(
        'SELECT test__has_select_permission(''ar_transaction_list'', ''' || t || ''')',
        ARRAY[true],'ar_transaction_list can read ' || t
    ) FROM unnest(ARRAY['partsvendor'::text, 'partscustomer', 'taxcategory',
              'entity', 'company', 'location', 'entity_to_location',
              'entity_to_contact', 'person', 'entity_credit_account',
              'contact_class', 'eca_tax', 'entity_class', 'entity_note',
              'entity_bank_account', 'entity_other_name', 'location_class',
              'person_to_company', 'eca_to_contact', 'eca_to_location', 'eca_note',
              'ar', 'acc_trans', 'invoice', 'ac_tax_form', 'invoice_tax_form'
           ]) t;

    SELECT results_eq(
        'SELECT test__has_select_permission(''ap_transaction_list'', ''' || t || ''')',
        ARRAY[true],'ap_transaction_list can read ' || t
    ) FROM unnest(ARRAY['partsvendor'::text, 'partscustomer', 'taxcategory',
              'entity', 'company', 'location', 'entity_to_location',
              'entity_to_contact', 'person', 'entity_credit_account',
              'contact_class', 'eca_tax', 'entity_class', 'entity_note',
              'entity_bank_account', 'entity_other_name', 'location_class',
              'person_to_company', 'eca_to_contact', 'eca_to_location', 'eca_note',
              'ap', 'acc_trans', 'invoice', 'ac_tax_form', 'invoice_tax_form'
           ]) t;

    SELECT results_eq(
        'SELECT test__has_select_permission(''sales_order_list'', ''' || t || ''')',
        ARRAY[true],'sales_order_list can read ' || t
    ) FROM unnest(ARRAY['partsvendor'::text, 'partscustomer', 'taxcategory',
              'entity', 'company', 'location', 'entity_to_location',
              'entity_to_contact', 'person', 'entity_credit_account',
              'contact_class', 'eca_tax', 'entity_class', 'entity_note',
              'entity_bank_account', 'entity_other_name', 'location_class',
              'person_to_company', 'eca_to_contact', 'eca_to_location', 'eca_note',
              'oe', 'orderitems'
           ]) t;

    SELECT results_eq(
        'SELECT test__has_select_permission(''purchase_order_list'', ''' || t || ''')',
        ARRAY[true],'purchase_order_list can read ' || t
    ) FROM unnest(ARRAY['partsvendor'::text, 'partscustomer', 'taxcategory',
              'entity', 'company', 'location', 'entity_to_location',
              'entity_to_contact', 'person', 'entity_credit_account',
              'contact_class', 'eca_tax', 'entity_class', 'entity_note',
              'entity_bank_account', 'entity_other_name', 'location_class',
              'person_to_company', 'eca_to_contact', 'eca_to_location', 'eca_note',
              'oe', 'orderitems'
           ]) t;

    SELECT results_eq(
        'SELECT test__has_select_permission(''inventory_reports'', ''' || t || ''')',
        ARRAY[true],'inventory_reports can read ' || t
    ) FROM unnest(array['ar'::text, 'ap', 'warehouse_inventory', 'invoice', 'acc_trans']) t;

    SELECT results_eq(
        'SELECT test__has_select_permission(''gl_reports'', ''' || t || ''')',
        ARRAY[true],'gl_reports can read ' || t
    ) FROM unnest(array['gl'::text, 'acc_trans', 'account_checkpoint', 'ar', 'ap',
                      'entity', 'entity_credit_account'])t;

    SELECT results_eq(
        'SELECT test__has_select_permission(''financial_reports'', ''' || t || ''')',
        ARRAY[true],'financial_reports can read ' || t
    ) FROM unnest(array['gl'::text, 'acc_trans', 'account_checkpoint', 'ar', 'ap',
                      'entity', 'entity_credit_account', 'cash_impact'])t;

    -- Finish the tests and clean up.
    SELECT * FROM finish();

ROLLBACK;
