CREATE OR REPLACE PACKAGE BODY qu_engine
/*
| This program is a part of Qute:
| Qute - Quick Unit Test Engine
| Design, Generate, Run Test Code
| www.unit-test.com
|
| Copyright, PL/Solutions, 2003-2005
| All rights reserved
*/
IS
c_assigned_list CONSTANT VARCHAR2 ( 100 ) := 'assigned variables';
c_declared_list CONSTANT VARCHAR2 ( 100 ) := 'declared variables';
--
c_select_from_dual CONSTANT VARCHAR2 ( 100 )
:= 'SELECT ''Not a selectable'' FROM dual';
--
c_simple_tc_start CONSTANT VARCHAR2 ( 100 ) := '/*START_SIMPLE_TC*/';
c_simple_tc_end CONSTANT VARCHAR2 ( 100 ) := '/*END_SIMPLE_TC*/';
--
g_current_harness_guid VARCHAR2 ( 32767 ) DEFAULT NULL;
g_dbms_output_only BOOLEAN DEFAULT FALSE;
TYPE coll_placeholders_aat IS TABLE OF BOOLEAN
INDEX BY qu_placeholder_tp.name_t;
g_coll_placeholders coll_placeholders_aat;
FUNCTION hash_value ( string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN DBMS_UTILITY.get_hash_value ( string_in, 1, 2 ** 31 - 1 );
END hash_value;
FUNCTION in_quotes ( string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN '''' || string_in || '''';
END in_quotes;
FUNCTION at_least_null ( string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
IF RTRIM ( string_in ) IS NULL
THEN
RETURN qu_test_case_xp.null_value_indicator;
ELSE
RETURN RTRIM ( string_in );
END IF;
END at_least_null;
FUNCTION at_least_null ( string_in IN CLOB )
RETURN CLOB
IS
BEGIN
IF is_really_null ( string_in )
THEN
RETURN qu_test_case_xp.null_value_indicator;
ELSE
RETURN RTRIM ( string_in );
END IF;
END at_least_null;
FUNCTION qute#error_info
RETURN VARCHAR2
IS
l_stack VARCHAR2 ( 32767 );
BEGIN
BEGIN
EXECUTE IMMEDIATE 'BEGIN :val := ''PL/SQL Error Backtrace: ''
|| CHR(10) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE; END;'
USING OUT l_stack;
EXCEPTION
WHEN OTHERS
THEN
l_stack := DBMS_UTILITY.format_call_stack;
END;
RETURN DBMS_UTILITY.format_error_stack || CHR ( 10 ) || l_stack;
END qute#error_info;
FUNCTION current_harness_guid
RETURN VARCHAR2
IS
BEGIN
RETURN g_current_harness_guid;
END current_harness_guid;
PROCEDURE set_current_harness_info (
run_harness_id_in IN VARCHAR2
, dbms_output_only_in IN BOOLEAN
)
IS
BEGIN
g_current_harness_guid := run_harness_id_in;
g_dbms_output_only := dbms_output_only_in;
END set_current_harness_info;
FUNCTION dbms_output_only
RETURN BOOLEAN
IS
BEGIN
RETURN NVL ( g_dbms_output_only, FALSE );
END dbms_output_only;
FUNCTION VERSION
RETURN VARCHAR2
IS
BEGIN
RETURN c_version;
END VERSION;
FUNCTION fe_min_version
RETURN VARCHAR2
IS
BEGIN
RETURN c_fe_min_vers;
END fe_min_version;
FUNCTION success
RETURN PLS_INTEGER
IS
BEGIN
RETURN c_success;
END;
FUNCTION generation_failure
RETURN PLS_INTEGER
IS
BEGIN
RETURN c_gen_failure;
END;
FUNCTION compile_failure
RETURN PLS_INTEGER
IS
BEGIN
RETURN c_compile_failure;
END;
FUNCTION is_guid ( string_in IN VARCHAR2 )
RETURN BOOLEAN
IS
BEGIN
RETURN string_in LIKE c_mask;
END is_guid;
FUNCTION standardize_guid ( string_in IN VARCHAR2 )
RETURN guid_t
IS
FUNCTION add_squiggly_brackets ( string_in IN VARCHAR2 )
RETURN guid_t
IS
BEGIN
RETURN '{' || UPPER ( string_in ) || '}';
END add_squiggly_brackets;
FUNCTION is_guid ( string_in IN VARCHAR2 )
RETURN BOOLEAN
IS
BEGIN
RETURN string_in LIKE c_mask;
END is_guid;
BEGIN
-- If not already in the 8-4-4-4-rest format, then make it so.
IF is_guid ( string_in )
THEN
RETURN string_in;
ELSE
IF string_in LIKE c_mask_nb
THEN
RETURN add_squiggly_brackets ( string_in );
ELSE
RETURN '{'
|| SUBSTR ( string_in, 1, 8 )
|| '-'
|| SUBSTR ( string_in, 9, 4 )
|| '-'
|| SUBSTR ( string_in, 13, 4 )
|| '-'
|| SUBSTR ( string_in, 17, 4 )
|| '-'
|| SUBSTR ( string_in, 21 )
|| '}';
END IF;
END IF;
END standardize_guid;
FUNCTION standard_guid
RETURN guid_t
IS
BEGIN
RETURN standardize_guid ( SYS_GUID );
END standard_guid;
/* 1.1.3 Just use CASE
FUNCTION ifelse ( bool_in IN BOOLEAN, tval_in IN BOOLEAN, fval_in IN BOOLEAN
)
RETURN BOOLEAN
IS
BEGIN
IF bool_in
THEN
RETURN tval_in;
ELSE
RETURN fval_in;
END IF;
END;
FUNCTION ifelse ( bool_in IN BOOLEAN, tval_in IN DATE, fval_in IN DATE )
RETURN DATE
IS
BEGIN
IF bool_in
THEN
RETURN tval_in;
ELSE
RETURN fval_in;
END IF;
END;
FUNCTION ifelse ( bool_in IN BOOLEAN, tval_in IN NUMBER, fval_in IN NUMBER )
RETURN NUMBER
IS
BEGIN
IF bool_in
THEN
RETURN tval_in;
ELSE
RETURN fval_in;
END IF;
END;
FUNCTION ifelse ( bool_in IN BOOLEAN, tval_in IN VARCHAR2, fval_in IN
VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
IF bool_in
THEN
RETURN tval_in;
ELSE
RETURN fval_in;
END IF;
END;*/
FUNCTION yn2truefalse ( yn IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
IF yn = c_yes
THEN
RETURN 'TRUE';
ELSIF yn = c_no
THEN
RETURN 'FALSE';
ELSE
RETURN 'NULL';
END IF;
END;
FUNCTION vc2bool ( vc IN VARCHAR2 )
RETURN BOOLEAN
IS
BEGIN
IF vc = c_yes
THEN
RETURN TRUE;
ELSIF vc = c_no
THEN
RETURN FALSE;
ELSE
RETURN NULL;
END IF;
END;
FUNCTION bool2vc ( bool IN BOOLEAN )
RETURN VARCHAR2
IS
BEGIN
IF bool
THEN
RETURN c_yes;
ELSIF NOT bool
THEN
RETURN c_no;
ELSE
RETURN 'NULL';
END IF;
END;
FUNCTION is_really_null ( value_in IN VARCHAR2 )
RETURN BOOLEAN
IS
BEGIN
RETURN value_in IS NULL OR value_in = '''''' OR value_in = 'NULL';
END is_really_null;
-- LK 05/09/06
-- Version for CLOBs
FUNCTION is_really_null ( value_in IN CLOB )
RETURN BOOLEAN
IS
BEGIN
RETURN value_in IS NULL
OR DBMS_LOB.getlength ( value_in ) = 0
OR value_in = ''''''
OR value_in = 'NULL';
END is_really_null;
-- LK 05/09/06
FUNCTION clob_is_null ( value_in IN CLOB )
RETURN BOOLEAN
IS
BEGIN
IF value_in IS NULL
THEN
RETURN TRUE;
ELSE
RETURN DBMS_LOB.getlength ( value_in ) = 0;
END IF;
END clob_is_null;
FUNCTION clob_is_not_null ( value_in IN CLOB )
RETURN BOOLEAN
IS
BEGIN
RETURN NOT clob_is_null ( value_in );
END clob_is_not_null;
PROCEDURE recomp_one (
owner_in IN VARCHAR2
, NAME_IN IN VARCHAR2
, type_in IN VARCHAR2
, status_out OUT PLS_INTEGER
)
IS
BEGIN
BEGIN
EXECUTE IMMEDIATE 'ALTER '
|| type_in
|| ' '
|| owner_in
|| '.'
|| NAME_IN
|| ' COMPILE REUSE SETTINGS';
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
IF qu_all_objects.object_status ( owner_in, NAME_IN, type_in ) = 'INVALID'
THEN
status_out := c_compile_failure;
ELSE
status_out := c_success;
END IF;
END recomp_one;
PROCEDURE recompile (
harness_id_in IN qu_harness_tp.universal_id_t
, recompile_program_in IN BOOLEAN
, recompile_harness_in IN BOOLEAN
, prog_status_out OUT PLS_INTEGER
, spec_status_out OUT PLS_INTEGER
, body_status_out OUT PLS_INTEGER
)
IS
l_harness qu_harness_tp.qu_harness_rt;
l_status PLS_INTEGER;
BEGIN
prog_status_out := c_notset;
spec_status_out := c_notset;
body_status_out := c_notset;
l_harness := qu_harness_qp.onerow ( harness_id_in );
-- Swallow errors, since we will check status afterwards.
IF recompile_program_in
THEN
recomp_one ( l_harness.program_owner
, l_harness.program_name
, l_harness.program_type
, l_status
);
IF l_harness.program_type = 'PACKAGE' AND l_status = c_success
THEN
recomp_one ( l_harness.program_owner
, l_harness.program_name
, 'PACKAGE BODY'
, l_status
);
END IF;
prog_status_out := l_status;
END IF;
IF recompile_harness_in
THEN
recomp_one ( l_harness.harness_owner
, l_harness.name
, 'PACKAGE'
, spec_status_out
);
recomp_one ( l_harness.harness_owner
, l_harness.name
, 'PACKAGE BODY'
, body_status_out
);
END IF;
END recompile;
FUNCTION is_in_arg (
argmode_in IN VARCHAR2
, include_inout_in IN BOOLEAN DEFAULT TRUE
)
RETURN BOOLEAN
IS
BEGIN
IF include_inout_in
THEN
RETURN argmode_in IN ( qu_describe.c_in, qu_describe.c_in_out );
ELSE
RETURN argmode_in IN ( qu_describe.c_in );
END IF;
END is_in_arg;
FUNCTION is_out_arg ( argmode_in IN VARCHAR2 )
RETURN BOOLEAN
IS
BEGIN
RETURN argmode_in IN ( qu_describe.c_out, qu_describe.c_in_out );
END is_out_arg;
FUNCTION minimized_whitespace ( string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN REPLACE ( TRANSLATE ( string_in
, CHR ( 10 ) || CHR ( 13 )
, CHR ( 10 )
)
, CHR ( 9 )
, ' '
);
END minimized_whitespace;
FUNCTION exc_section_for_tc (
test_case_id_in IN qu_test_case_tp.universal_id_t
, outcomes_in IN qu_outcome_xp.qu_outcome_tt
, start_indent_in IN PLS_INTEGER
)
RETURN VARCHAR2
IS
c_last_when_others CONSTANT qu_engine.maxvarchar2
:= 'qute#report_result(result_guid_in => '''
|| test_case_id_in
|| ''', status_in => '''
|| qu_result_xp.c_runtime_error
|| ''', description_in => qute#error_info);';
l_oc_index qu_outcome_tp.universal_id_t;
TYPE when_info_rt IS RECORD (
outcome_universal_id qu_outcome_tp.universal_id_t
, exception_name qu_outcome_tp.name_t
, assertion_name qu_assertion_tp.name_t
);
TYPE when_info_tt IS TABLE OF when_info_rt
INDEX BY PLS_INTEGER;
l_when_info when_info_rt;
l_whens when_info_tt;
l_when_others when_info_tt;
l_raise_any_guid qu_outcome_tp.universal_id_t;
l_not_raise_any_guid qu_outcome_tp.universal_id_t;
--
l_exc_section qu_engine.maxvarchar2;
PROCEDURE build_when_lists (
raise_any_guid_out IN OUT qu_outcome_tp.universal_id_t
, not_raise_any_guid_out IN OUT qu_outcome_tp.universal_id_t
, whens_out IN OUT when_info_tt
, when_others_out IN OUT when_info_tt
)
IS
PROCEDURE add_to_others (
row_in IN qu_outcome_tp.universal_id_t
, remove_quotes_in IN BOOLEAN
)
IS
l_next_when PLS_INTEGER;
BEGIN
l_next_when := when_others_out.COUNT + 1;
IF remove_quotes_in
THEN
when_others_out ( l_next_when ).exception_name :=
qu_all_objects.no_quotes
( outcomes_in ( row_in
).control.attribute.value1
);
ELSE
when_others_out ( l_next_when ).exception_name :=
outcomes_in ( row_in ).control.attribute.value1;
END IF;
when_others_out ( l_next_when ).outcome_universal_id :=
outcomes_in ( row_in
).outcome.universal_id;
when_others_out ( l_next_when ).assertion_name :=
outcomes_in ( row_in
).assertion.name;
END add_to_others;
BEGIN
raise_any_guid_out := NULL;
not_raise_any_guid_out := NULL;
l_oc_index := outcomes_in.FIRST;
-- First pass, check for raise any
WHILE ( l_oc_index IS NOT NULL AND raise_any_guid_out IS NULL )
LOOP
IF outcomes_in ( l_oc_index ).assertion.universal_id =
qu_assertion_xp.guid_for_name
( qu_assertion_xp.c_raises_any_name
)
THEN
raise_any_guid_out :=
outcomes_in ( l_oc_index ).outcome.universal_id;
END IF;
l_oc_index := outcomes_in.NEXT ( l_oc_index );
END LOOP;
IF raise_any_guid_out IS NOT NULL
THEN
GOTO analysis_complete;
END IF;
-- Second pass, check for not raise any
l_oc_index := outcomes_in.FIRST;
WHILE ( l_oc_index IS NOT NULL AND not_raise_any_guid_out IS NULL )
LOOP
IF outcomes_in ( l_oc_index ).assertion.universal_id =
qu_assertion_xp.guid_for_name
( qu_assertion_xp.c_not_raises_any_name
)
THEN
not_raise_any_guid_out :=
outcomes_in ( l_oc_index ).outcome.universal_id;
END IF;
l_oc_index := outcomes_in.NEXT ( l_oc_index );
END LOOP;
IF not_raise_any_guid_out IS NOT NULL
THEN
GOTO analysis_complete;
END IF;
l_oc_index := outcomes_in.FIRST;
WHILE ( l_oc_index IS NOT NULL )
LOOP
-- If expected value is a literal then if it is a number
-- add to the whens list. If it is a string or an expression
-- then add to when others list.
IF qu_assertion_xp.is_exception_assertion
( outcomes_in ( l_oc_index
).assertion.universal_id
)
THEN
IF outcomes_in ( l_oc_index ).control.attribute.is_expression
=
c_no
AND outcomes_in ( l_oc_index
).control.attribute.assign_in_setup =
c_no
THEN
DECLARE
l_number NUMBER;
l_next_when PLS_INTEGER;
BEGIN
-- If an expression, then must be used in others only.
IF outcomes_in ( l_oc_index
).control.attribute.value1_is_expr =
c_no
THEN
l_number :=
TO_NUMBER
( qu_all_objects.no_quotes
( outcomes_in ( l_oc_index
).control.attribute.value1
)
);
END IF;
add_to_others ( l_oc_index, TRUE );
EXCEPTION
-- Not a valid number....
WHEN OTHERS
THEN
l_next_when := whens_out.COUNT + 1;
whens_out ( l_next_when ).exception_name :=
qu_all_objects.no_quotes
( outcomes_in ( l_oc_index
).control.attribute.value1
);
whens_out ( l_next_when ).outcome_universal_id :=
outcomes_in ( l_oc_index
).outcome.universal_id;
whens_out ( l_next_when ).assertion_name :=
outcomes_in ( l_oc_index
).assertion.name;
END;
ELSE
add_to_others ( l_oc_index, FALSE );
END IF;
END IF;
l_oc_index := outcomes_in.NEXT ( l_oc_index );
END LOOP;
<<analysis_complete>>
NULL;
END build_when_lists;
PROCEDURE pl ( string_in IN VARCHAR2, start_indent_in IN PLS_INTEGER )
IS
BEGIN
l_exc_section :=
l_exc_section
|| CASE
WHEN l_exc_section IS NULL
THEN NULL
ELSE CHR ( 10 ) || LPAD ( ' ', start_indent_in, ' ' )
END
|| string_in;
END pl;
PROCEDURE pl_report (
rec_in IN when_info_rt
, raises_is_success_in IN BOOLEAN
, indent_in IN PLS_INTEGER
, override_message_in IN VARCHAR2 DEFAULT NULL
)
IS
BEGIN
pl ( 'qute#report_result(result_guid_in => '''
|| rec_in.outcome_universal_id
|| ''''
, start_indent_in + indent_in
);
pl
( ', status_in => '''
|| CASE
WHEN rec_in.assertion_name IN
( qu_assertion_xp.c_raises_name
, qu_assertion_xp.c_raises_any_name
)
THEN CASE
WHEN raises_is_success_in
THEN c_result_success
ELSE c_result_failure
END
WHEN rec_in.assertion_name IN
( qu_assertion_xp.c_not_raises_name
, qu_assertion_xp.c_not_raises_any_name
)
THEN CASE
WHEN raises_is_success_in
THEN c_result_failure
ELSE c_result_success
END
ELSE rec_in.assertion_name
END
|| ''', description_in => '''
|| NVL ( override_message_in
, 'Exception '
|| rec_in.exception_name
|| ' was '
|| CASE
WHEN raises_is_success_in
THEN NULL
ELSE 'not'
END
|| ' raised.'''
)
|| ');'
, start_indent_in + indent_in + 3
);
END pl_report;
BEGIN
/* 1.1.2 Precedence for exception assertions:
1. Raise any
2. Does not raise any
3. All other exception assertions */
build_when_lists ( l_raise_any_guid
, l_not_raise_any_guid
, l_whens
, l_when_others
);
IF l_raise_any_guid IS NOT NULL
THEN
l_when_info.outcome_universal_id := l_raise_any_guid;
l_when_info.assertion_name := qu_assertion_xp.c_raises_any_name;
l_when_info.exception_name := NULL;
pl_report
( rec_in => l_when_info
, raises_is_success_in => FALSE
, indent_in => start_indent_in + 3
, override_message_in => 'No exception was raised by this
program.'
);
pl ( 'EXCEPTION WHEN OTHERS THEN ', start_indent_in );
pl_report
( rec_in => l_when_info
, raises_is_success_in => TRUE
, indent_in => start_indent_in + 3
, override_message_in => 'An exception was raised by this
program.'
);
ELSIF l_not_raise_any_guid IS NOT NULL
THEN
l_when_info.outcome_universal_id := l_not_raise_any_guid;
l_when_info.assertion_name := qu_assertion_xp.c_not_raises_any_name;
l_when_info.exception_name := NULL;
pl_report
( rec_in => l_when_info
, raises_is_success_in => TRUE
, indent_in => start_indent_in + 3
, override_message_in => 'No exception was raised by this
program.'
);
pl ( 'EXCEPTION WHEN OTHERS THEN ', start_indent_in );
pl_report
( rec_in => l_when_info
, raises_is_success_in => FALSE
, indent_in => start_indent_in + 3
, override_message_in => 'An exception was raised by this
program.'
);
ELSE
IF l_whens.COUNT > 0 OR l_when_others.COUNT > 0
THEN
-- If there is no exception, set outcome according to the
-- the type of assertion (raises or not raises).
pl ( '-- No error raised, so report that result...'
, start_indent_in + 3
);
FOR indx IN 1 .. l_whens.COUNT
LOOP
pl_report ( rec_in => l_whens ( indx )
, raises_is_success_in => FALSE
, indent_in => 3
);
END LOOP;
FOR indx IN 1 .. l_when_others.COUNT
LOOP
pl_report ( rec_in => l_when_others ( indx )
, raises_is_success_in => FALSE
, indent_in => 3
);
END LOOP;
pl ( '-- Check for expected and unexpected exceptions.'
, start_indent_in
);
pl ( 'EXCEPTION', start_indent_in );
FOR indx IN 1 .. l_whens.COUNT
LOOP
pl ( 'WHEN ' || l_whens ( indx ).exception_name || ' THEN'
, start_indent_in + 3
);
pl_report ( rec_in => l_whens ( indx )
, raises_is_success_in => TRUE
, indent_in => 3
);
END LOOP;
pl ( 'WHEN OTHERS THEN ', start_indent_in + 3 );
IF l_when_others.COUNT = 0
THEN
pl ( c_last_when_others, start_indent_in + 6 );
ELSE
pl
( 'DECLARE c_sqlcode PLS_INTEGER := SQLCODE; BEGIN CASE
c_sqlcode '
, start_indent_in + 3
);
FOR indx IN 1 .. l_when_others.COUNT
LOOP
pl
( 'WHEN '
|| CASE
WHEN l_when_others ( indx ).exception_name IN
( '100', '-1403' )
THEN '100'
ELSE l_when_others ( indx ).exception_name
END
|| ' THEN '
, start_indent_in + 6
);
pl_report ( rec_in => l_when_others ( indx
)
, raises_is_success_in => TRUE
, indent_in => start_indent_in + 6
);
END LOOP;
pl ( 'ELSE ' || c_last_when_others || ' END CASE; END;'
, start_indent_in + 6
);
END IF;
END IF;
END IF;
RETURN l_exc_section;
END exc_section_for_tc;
FUNCTION select_statement (
outcome_in IN qu_outcome_xp.qu_outcome_rt
, type_in IN VARCHAR2
, immediate_in IN BOOLEAN DEFAULT FALSE
, with_select_list_in IN BOOLEAN DEFAULT TRUE
)
RETURN VARCHAR2
IS
l_table maxvarchar2
:= CASE type_in
WHEN qu_outcome_xp.c_control
THEN outcome_in.control.attribute.value1
WHEN qu_outcome_xp.c_result
THEN outcome_in.RESULT.attribute.value1
END;
l_where maxvarchar2
:= CASE type_in
WHEN qu_outcome_xp.c_control
THEN outcome_in.control.attribute.value2
WHEN qu_outcome_xp.c_result
THEN outcome_in.RESULT.attribute.value2
END;
l_have_expr BOOLEAN
:= CASE type_in
WHEN qu_outcome_xp.c_control
THEN outcome_in.control.attribute.value1_is_expr = c_yes
OR outcome_in.control.attribute.value2_is_expr = c_yes
WHEN qu_outcome_xp.c_result
THEN outcome_in.RESULT.attribute.value1_is_expr = c_yes
OR outcome_in.RESULT.attribute.value2_is_expr = c_yes
END;
BEGIN
IF l_table IS NULL
THEN
-- Cheap, easy and always ready.
RETURN 'SYS.DUAL';
ELSIF l_have_expr
THEN
-- Cannot evaluate it. Instead, build a string that can be
used/evaluated in
-- the generated test code.
RETURN CASE
WHEN qu_all_objects.string_is_query ( l_table )
THEN l_table
WHEN with_select_list_in
THEN '''SELECT * FROM '' || ' || l_table
ELSE l_table
END
|| CASE
WHEN is_really_null ( l_where )
THEN NULL
ELSE ' || '' WHERE '' || ' || l_where
END;
ELSE
RETURN qu_all_objects.select_statement ( l_table
, l_where
, immediate_in
, with_select_list_in
);
END IF;
END select_statement;
PROCEDURE set_qute_global_placeholders (
context_in IN VARCHAR2
, outcome_in IN qu_outcome_xp.qu_outcome_rt
, override_key_indicator_in IN VARCHAR2 DEFAULT NULL
)
IS
l_placeholders qu_placeholder_tp.qu_placeholder_tc;
l_value maxvarchar2;
BEGIN
l_placeholders := qu_template_xp.global_placeholders;
FOR indx IN l_placeholders.FIRST .. l_placeholders.LAST
LOOP
l_value := NULL;
CASE
WHEN l_placeholders ( indx ).name = 'qute.test_package_name'
THEN
l_value :=
CASE
WHEN outcome_in.harness.harness_owner IS NULL
THEN outcome_in.harness.name
--BM375 WHEN outcome_in.harness.harness_owner = USER
-- THEN outcome_in.harness.name
ELSE outcome_in.harness.harness_owner
|| '.'
|| outcome_in.harness.name
END;
WHEN l_placeholders ( indx ).name = 'qute.outcome_guid'
THEN
l_value := in_quotes ( outcome_in.outcome.universal_id );
WHEN l_placeholders ( indx ).name = 'qute.assertion_guid'
THEN
l_value := in_quotes ( outcome_in.assertion.universal_id );
WHEN l_placeholders ( indx ).name = 'qute.outcome_guid_hash'
THEN
l_value := hash_value ( outcome_in.outcome.universal_id );
WHEN l_placeholders ( indx ).name = 'qute.key_for_indicator'
THEN
/*qd_runtime.TRACE ( 'key for ind override'
, override_key_indicator_in
, TRUE
);
qd_runtime.TRACE
( 'qu_outcome.key for ind'
, qu_outcome_xp.key_for_indicator
( outcome_in => outcome_in
, template_in =>
outcome_in.TEMPLATE.template_row
)
, TRUE
);*/
l_value :=
NVL
( override_key_indicator_in
, hash_value
( qu_outcome_xp.key_for_indicator
( outcome_in => outcome_in
, template_in =>
outcome_in.TEMPLATE.template_row
)
)
);
WHEN l_placeholders ( indx ).name = 'qute.operator'
THEN
l_value := in_quotes ( outcome_in.OPERATOR.name );
WHEN l_placeholders ( indx ).name = 'qute.operator_symbol'
THEN
l_value := outcome_in.OPERATOR.operator_symbol;
WHEN l_placeholders ( indx ).name = 'qute.operator_description'
THEN
l_value := outcome_in.OPERATOR.description;
WHEN l_placeholders ( indx ).name =
'qute.opposite_operator_description'
THEN
l_value :=
qu_operator_xp.opposite_description
( outcome_in.OPERATOR.universal_id
);
WHEN l_placeholders ( indx ).name = 'qute.nulls_eq_is_true'
THEN
l_value := yn2truefalse ( outcome_in.outcome.null_ok );
WHEN l_placeholders ( indx ).name = 'qute.runtime_error'
THEN
l_value := in_quotes ( qu_result_xp.c_runtime_error );
WHEN l_placeholders ( indx ).name = 'qute.raise_exception_on_error'
THEN
l_value := yn2truefalse ( outcome_in.outcome.raise_exception );
WHEN l_placeholders ( indx ).name = 'qute.slash'
THEN
l_value := '/';
WHEN l_placeholders ( indx ).name = 'qute.variable_prefix'
THEN
l_value := c_qute_var_prefix;
WHEN l_placeholders ( indx ).name = 'qute.start_time_variable'
THEN
l_value := c_start_time_varname;
WHEN l_placeholders ( indx ).name = 'qute.end_time_variable'
THEN
l_value := c_end_time_varname;
ELSE
-- If a placeholder is not handled here,
-- then we have bad code a coming!
qd_runtime.raise_error
( 'UNANTICIPATED-ERROR'
, 'No placeholder assignment logic for '
|| l_placeholders ( indx ).name
);
END CASE;
qu_replace.add_set ( context_in, l_placeholders ( indx ).name, l_value
);
END LOOP;
END set_qute_global_placeholders;
PROCEDURE load_coll_placeholders
IS
BEGIN
g_coll_placeholders ( 'return_equality_check' ) := TRUE;
g_coll_placeholders ( 'match_index_values' ) := TRUE;
g_coll_placeholders ( 'fp.start_index' ) := TRUE;
g_coll_placeholders ( 'fp.end_index' ) := TRUE;
g_coll_placeholders ( 'fp.index_type' ) := TRUE;
g_coll_placeholders ( 'exp.start_index' ) := TRUE;
g_coll_placeholders ( 'exp.end_index' ) := TRUE;
g_coll_placeholders ( 'exp.index_type' ) := TRUE;
g_coll_placeholders ( 'fp.collection_initialization' ) := TRUE;
g_coll_placeholders ( 'exp.collection_initialization' ) := TRUE;
g_coll_placeholders ( 'local_collection_declarations' ) := TRUE;
g_coll_placeholders ( 'local_collection_initialization' ) := TRUE;
g_coll_placeholders ( 'collections_against_instructions_comment' ) :=
TRUE;
END load_coll_placeholders;
FUNCTION is_coll_placeholder ( NAME_IN IN VARCHAR2 )
RETURN BOOLEAN
IS
BEGIN
RETURN g_coll_placeholders.EXISTS ( NAME_IN );
END is_coll_placeholder;
/*
FUNCTION substitute (substitutions_in
qu_substitution_tp.qu_substitution_tc, string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN qu_substitution_xp.substituted_string ( substitutions_in,
string_in );
END substitute;
*/
FUNCTION expected_value_string (
outcome_in IN qu_outcome_xp.qu_outcome_rt
, substitutions_in IN qu_substitution_tp.qu_substitution_tc
, use_result_if_control_null_in IN BOOLEAN DEFAULT FALSE
)
RETURN CLOB
IS
BEGIN
IF outcome_in.control.attribute.assign_in_setup = c_yes
THEN
RETURN qu_substitution_xp.substituted_string
( substitutions_in
, outcome_in.control.attribute.argument_alias
);
ELSE
RETURN CASE
WHEN is_really_null ( outcome_in.control.attribute.external_value )
THEN at_least_null ( outcome_in.control.attribute.value1 )
ELSE outcome_in.control.attribute.external_value
END;
END IF;
END expected_value_string;
PROCEDURE set_standard_exp_placeholders (
context_in IN VARCHAR2
, outcome_in IN qu_outcome_xp.qu_outcome_rt
)
IS
l_placeholders qu_placeholder_tp.qu_placeholder_tc;
l_value maxvarchar2;
BEGIN
l_placeholders := qu_template_xp.exp_placeholders;
FOR indx IN l_placeholders.FIRST .. l_placeholders.LAST
LOOP
l_value := NULL;
CASE
WHEN l_placeholders ( indx ).name = 'exp.variable_name'
THEN
l_value := outcome_in.control.attribute.argument_alias;
WHEN l_placeholders ( indx ).name = 'exp.datatype'
THEN
l_value := outcome_in.control.attribute.datatype_declare;
WHEN l_placeholders ( indx ).name = 'exp.is_selectable'
THEN
l_value :=
CASE
WHEN qu_datatype_xp.is_selectable
( outcome_in.control.data_type.universal_id
)
THEN 'TRUE'
ELSE 'FALSE'
END;
WHEN l_placeholders ( indx ).name = 'exp.is_cursor_variable'
THEN
l_value :=
CASE
WHEN qu_datatype_xp.is_ref_cursor
( outcome_in.control.data_type.universal_id
)
THEN 'TRUE'
ELSE 'FALSE'
END;
WHEN l_placeholders ( indx ).name = 'exp.value'
THEN
l_value :=
at_least_null
( expected_value_string ( outcome_in
, outcome_in.substitutions
)
);
WHEN l_placeholders ( indx ).name = 'exp.description'
THEN
l_value := 'SET BY DATATYPE';
WHEN l_placeholders ( indx ).name = 'exp.datatype_guid'
THEN
l_value :=
'''' || outcome_in.control.data_type.universal_id || '''';
ELSE
-- If a placeholder is not handled here,
-- then we have bad code a coming!
qd_runtime.raise_error
( 'UNANTICIPATED-ERROR'
, 'No placeholder assignment logic for '
|| l_placeholders ( indx ).name
);
END CASE;
qu_replace.add_set ( context_in, l_placeholders ( indx ).name, l_value
);
END LOOP;
END set_standard_exp_placeholders;
PROCEDURE set_standard_fp_placeholders (
context_in IN VARCHAR2
, outcome_in IN qu_outcome_xp.qu_outcome_rt
)
IS
l_placeholders qu_placeholder_tp.qu_placeholder_tc;
l_value maxvarchar2;
BEGIN
l_placeholders := qu_template_xp.fp_placeholders;
FOR indx IN l_placeholders.FIRST .. l_placeholders.LAST
LOOP
l_value := NULL;
CASE
WHEN l_placeholders ( indx ).name = 'fp.variable_name'
THEN
l_value := outcome_in.RESULT.attribute.argument_alias;
WHEN l_placeholders ( indx ).name = 'fp.datatype'
THEN
l_value := outcome_in.RESULT.attribute.datatype_declare;
WHEN l_placeholders ( indx ).name = 'fp.is_selectable'
THEN
l_value :=
CASE
WHEN qu_datatype_xp.is_selectable
( outcome_in.RESULT.data_type.universal_id
)
THEN 'TRUE'
ELSE 'FALSE'
END;
WHEN l_placeholders ( indx ).name = 'fp.is_cursor_variable'
THEN
l_value :=
CASE
WHEN qu_datatype_xp.is_ref_cursor
( outcome_in.RESULT.data_type.universal_id
)
THEN 'TRUE'
ELSE 'FALSE'
END;
WHEN l_placeholders ( indx ).name = 'fp.value'
THEN
IF qu_datatype_xp.is_scalar
( outcome_in.RESULT.data_type.universal_id
)
AND NOT is_really_null
( outcome_in.RESULT.attribute.external_value
)
AND outcome_in.RESULT.attribute.is_expression = c_yes
THEN
l_value :=
at_least_null ( outcome_in.RESULT.attribute.external_value
);
ELSE
l_value :=
at_least_null
( qu_substitution_xp.substituted_string
( outcome_in.substitutions
, outcome_in.RESULT.attribute.argument_alias
)
);
END IF;
WHEN l_placeholders ( indx ).name = 'fp.description'
THEN
-- Not currently used by any templates.
l_value :=
CASE
WHEN qu_datatype_xp.is_ref_cursor
( outcome_in.RESULT.data_type.universal_id
)
THEN 'Cursor variable'
ELSE '**SET BY DATATYPE**'
END;
WHEN l_placeholders ( indx ).name = 'fp.datatype_guid'
THEN
l_value :=
'''' || outcome_in.RESULT.data_type.universal_id || '''';
ELSE
-- If a placeholder is not handled here,
-- then we have bad code a coming!
qd_runtime.raise_error
( 'UNANTICIPATED-ERROR'
, 'No placeholder assignment logic for '
|| l_placeholders ( indx ).name
);
END CASE;
qu_replace.add_set ( context_in, l_placeholders ( indx ).name, l_value
);
END LOOP;
END set_standard_fp_placeholders;
PROCEDURE set_coll_placeholder (
context_in IN VARCHAR2
, NAME_IN IN VARCHAR2
, outcome_in IN qu_outcome_xp.qu_outcome_rt
)
IS
l_eqfunc maxvarchar2;
l_value maxvarchar2;
BEGIN
/*
When I add an item to this CASE statement must also update the list
in load_coll_placeholders.
*/
qd_runtime.assert ( is_coll_placeholder ( NAME_IN )
, 'The placeholder '
|| NAME_IN
|| ' is not defined as a collection placeholder!'
);
CASE
WHEN NAME_IN = 'return_equality_check'
THEN
-- Use the non-NULL value4 column value, first check result and
-- then go to control.
l_eqfunc :=
CASE
WHEN is_really_null ( outcome_in.RESULT.attribute.value4 )
THEN outcome_in.control.attribute.value4
ELSE outcome_in.RESULT.attribute.value4
END;
IF is_really_null ( l_eqfunc ) OR l_eqfunc IN ( '=', '''=''' )
THEN
l_value :=
'RETURN NOT ( NVL ( l_exp_collection ( exp_index_in ) =
l_fp_collection ( fp_index_in )
, FALSE
)
OR ( l_exp_collection ( exp_index_in ) IS NULL
AND l_fp_collection ( fp_index_in ) IS NULL
AND [qute.nulls_eq_is_true]
));';
ELSE
l_value :=
'RETURN NOT ( '
|| qu_all_objects.no_quotes ( l_eqfunc )
|| ' ( l_exp_collection ( exp_index_in )
, l_fp_collection ( fp_index_in )
, [qute.nulls_eq_is_true]
));';
END IF;
WHEN NAME_IN = 'match_index_values'
THEN
l_value :=
CASE
WHEN is_really_null ( outcome_in.control.attribute.value5 )
THEN 'FALSE'
ELSE outcome_in.control.attribute.value5
END;
WHEN NAME_IN = 'fp.start_index'
THEN
l_value := at_least_null ( outcome_in.RESULT.attribute.value2 );
WHEN NAME_IN = 'exp.start_index'
THEN
--qd_runtime.trace ('exp.start_index
val2','|'||outcome_in.control.attribute.value2||'|',true);
--qd_runtime.trace ('exp.start_index alnval2',at_least_null (
outcome_in.control.attribute.value2 ),true);
l_value := at_least_null ( outcome_in.control.attribute.value2 );
WHEN NAME_IN = 'fp.end_index'
THEN
l_value := at_least_null ( outcome_in.RESULT.attribute.value3 );
WHEN NAME_IN = 'exp.end_index'
THEN
l_value := at_least_null ( outcome_in.control.attribute.value3 );
WHEN NAME_IN = 'fp.index_type'
THEN
l_value :=
CASE
WHEN NVL ( outcome_in.RESULT.attribute.value1
, outcome_in.control.attribute.value1
) = c_string
THEN 'VARCHAR2(32767)'
ELSE 'PLS_INTEGER'
END;
WHEN NAME_IN = 'exp.index_type'
THEN
l_value :=
CASE
WHEN NVL ( outcome_in.control.attribute.value1
, outcome_in.RESULT.attribute.value1
) = c_string
THEN 'VARCHAR2(32767)'
ELSE 'PLS_INTEGER'
END;
WHEN NAME_IN = 'fp.collection_initialization'
THEN
l_value :=
CASE
WHEN outcome_in.RESULT.data_type.name IN
( 'NESTED TABLE', 'VARRAY' )
THEN ' := '
|| outcome_in.RESULT.attribute.datatype_declare
|| '()'
ELSE NULL
END;
WHEN NAME_IN = 'exp.collection_initialization'
THEN
l_value :=
CASE
WHEN outcome_in.control.data_type.name IN
( 'NESTED TABLE', 'VARRAY' )
THEN ' := '
|| outcome_in.control.attribute.datatype_declare
|| '()'
ELSE NULL
END;
WHEN NAME_IN = 'collections_against_instructions_comment'
THEN
CASE
WHEN qu_assertion_xp.is_dbms_output_assertion
( outcome_in.assertion.universal_id
)
THEN
l_value := '/* FINISH INSTRUCTIONS! */';
WHEN qu_datatype_xp.is_collection
( outcome_in.control.data_type.universal_id
)
AND qu_datatype_xp.is_collection
( outcome_in.RESULT.data_type.universal_id
)
THEN
l_value :=
'/*
Explanation of collection comparison logic:
This code compares the contents of two collections. The element datatype of
the
collections must be compatible. And if they are collections of scalars, you
will
need to create an "equals" function and provide the name of that function in
the definition of the outcome.
The "equals" function must have three arguments (the names are not
important,
but the order of these arguments is):
1. expected element: an argument that has the same datatype as an element
in
the one element/row of the expected value collection.
2. from program element: an argument that has the same datatype as an
element in
the one element/row of the from program collection.
3. a boolean flag that tells the "equals" function how to treat a "NULL =
NULL"
scenario, as equal or not equal.
*/';
WHEN qu_datatype_xp.is_collection
( outcome_in.control.data_type.universal_id
)
AND qu_datatype_xp.is_selectable
( outcome_in.RESULT.data_type.universal_id
)
THEN
l_value := '/* FINISH INSTRUCTIONS! */';
WHEN qu_datatype_xp.is_selectable
( outcome_in.control.data_type.universal_id
)
AND qu_datatype_xp.is_collection
( outcome_in.RESULT.data_type.universal_id
)
THEN
l_value := '/* FINISH INSTRUCTIONS! */';
ELSE
l_value := NULL;
END CASE;
ELSE
l_value := NULL;
END CASE;
qu_replace.add_set ( context_in, NAME_IN, l_value );
END set_coll_placeholder;
PROCEDURE set_all_coll_placeholders (
context_in IN VARCHAR2
, outcome_in IN qu_outcome_xp.qu_outcome_rt
)
IS
l_index qu_placeholder_tp.name_t := g_coll_placeholders.FIRST;
BEGIN
WHILE ( l_index IS NOT NULL )
LOOP
set_coll_placeholder ( context_in, l_index, outcome_in );
l_index := g_coll_placeholders.NEXT ( l_index );
END LOOP;
END set_all_coll_placeholders;
FUNCTION quoted_string ( string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN '''' || REPLACE ( string_in, '''', '''''' ) || '''';
END quoted_string;
FUNCTION get_placeholder_value (
outcome_in IN qu_outcome_xp.qu_outcome_rt
, NAME_IN IN VARCHAR2
)
RETURN VARCHAR2
IS
l_value maxvarchar2;
PROCEDURE fp_query_from_dataset ( quoted_in IN BOOLEAN DEFAULT FALSE )
IS
BEGIN
/*Templates using placeholder "fp.query_from_dataset"
selectable_against_ref_cursor
ref_cursor_against_ref_cursor
selectable_against_selectable
In each case, I need to produce a query that can be
inserted into the template.
*/
IF qu_datatype_xp.is_selectable
( outcome_in.RESULT.data_type.universal_id
)
THEN
IF outcome_in.RESULT.attribute.value1_is_expr = c_yes
OR outcome_in.RESULT.attribute.value2_is_expr = c_yes
THEN
-- Must rely on table functions to get and compare dataset.
l_value :=
qu_template_xp.tabfunc_pkg_name
( qu_outcome_xp.key_for_indicator
( outcome_in => outcome_in
, template_in =>
outcome_in.TEMPLATE.template_row
, override_ind_type_in =>
qu_template_xp.c_ind_exp_value
)
, subobject_name_in => qu_template_xp.c_fp_nt_name
, select_from_in => TRUE
);
ELSE
l_value :=
select_statement ( outcome_in
, qu_outcome_xp.c_result
, immediate_in => TRUE
);
END IF;
ELSIF qu_datatype_xp.is_ref_cursor
( outcome_in.RESULT.data_type.universal_id
)
THEN
-- Must work with the table function returning contents
-- of the ref cursor. The name of the function is always
-- derived from the expected/FP value.
l_value :=
qu_template_xp.tabfunc_pkg_name
( qu_outcome_xp.key_for_indicator
( outcome_in => outcome_in
, template_in =>
outcome_in.TEMPLATE.template_row
, override_ind_type_in =>
qu_template_xp.c_ind_exp_value
)
, subobject_name_in => qu_template_xp.c_fp_nt_name
, select_from_in => TRUE
);
ELSE
l_value := c_select_from_dual;
END IF;
IF quoted_in
THEN
l_value := quoted_string ( l_value );
END IF;
END fp_query_from_dataset;
PROCEDURE tf_package_name
IS
BEGIN
-- Must be coordinated with custom logic generated....
/* Templates using placeholder "tf_package_name" (table function
package name)
selectable_against_ref_cursor
ref_cursor_against_ref_cursor
ref_cursor_against_selectable*/
/* Use the expected value if expected is a dataset.
Otherwise, use FP. */
l_value :=
qu_template_xp.tabfunc_pkg_name
( qu_outcome_xp.key_for_indicator
( outcome_in => outcome_in
, template_in =>
outcome_in.TEMPLATE.template_row
, override_ind_type_in => CASE
WHEN qu_datatype_xp.is_dataset
( outcome_in.control.data_type.universal_id
)
THEN qu_template_xp.c_ind_exp_value
ELSE qu_template_xp.c_ind_fp_value
END
)
);
END tf_package_name;
PROCEDURE exp_query_from_dataset ( quoted_in IN BOOLEAN DEFAULT FALSE )
IS
BEGIN
/*Templates using placeholder "exp.query_from_dataset"
ref_cursor_against_selectable
selectable_against_selectable
*/
IF outcome_in.control.attribute.value1_is_expr = c_yes
OR outcome_in.control.attribute.value2_is_expr = c_yes
THEN
-- Must rely on table functions to get and compare dataset.
l_value :=
qu_template_xp.tabfunc_pkg_name
( qu_outcome_xp.key_for_indicator
( outcome_in => outcome_in
, template_in =>
outcome_in.TEMPLATE.template_row
, override_ind_type_in =>
qu_template_xp.c_ind_exp_value
)
, subobject_name_in => qu_template_xp.c_exp_nt_name
, select_from_in => TRUE
);
ELSE
l_value :=
select_statement ( outcome_in
, qu_outcome_xp.c_control
, immediate_in => TRUE
);
END IF;
IF quoted_in
THEN
l_value := quoted_string ( l_value );
END IF;
END exp_query_from_dataset;
BEGIN
CASE NAME_IN
WHEN 'fp.query_from_dataset'
THEN
fp_query_from_dataset;
WHEN 'fp.quoted_query_from_dataset'
THEN
fp_query_from_dataset ( quoted_in => TRUE );
WHEN 'exp.query_from_dataset'
THEN
exp_query_from_dataset;
WHEN 'exp.quoted_query_from_dataset'
THEN
exp_query_from_dataset ( quoted_in => TRUE );
WHEN 'tf_package_name'
THEN
tf_package_name;
ELSE
qd_runtime.raise_error
( 'UNANTICIPATED_ERROR'
, 'qu_engine.get_placeholder_value does not handle placeholder
"'
|| NAME_IN
|| '"'
);
END CASE;
RETURN l_value;
END get_placeholder_value;
PROCEDURE set_placeholder (
context_in IN VARCHAR2
, outcome_in IN qu_outcome_xp.qu_outcome_rt
, NAME_IN IN VARCHAR2
, override_value_in IN VARCHAR2 DEFAULT NULL
, use_override_in IN BOOLEAN DEFAULT FALSE
)
IS
BEGIN
IF use_override_in
THEN
qu_replace.add_set ( context_in, NAME_IN, override_value_in );
ELSE
qu_replace.add_set ( context_in
, NAME_IN
, get_placeholder_value ( outcome_in, NAME_IN )
);
END IF;
END set_placeholder;
FUNCTION sel_count_variable ( outcome_in IN qu_outcome_xp.qu_outcome_rt )
RETURN VARCHAR2
IS
BEGIN
/*RETURN c_qute_var_prefix
|| hash_value ( outcome_in.outcome.universal_id )
|| 'COUNT';*/
RETURN 'COUNT'
|| hash_value ( outcome_in.RESULT.attribute.argument_alias );
END sel_count_variable;
FUNCTION assertion_code_internal (
engine_type_in IN VARCHAR2
, outcome_in IN qu_outcome_xp.qu_outcome_rt
, start_indent_in IN PLS_INTEGER DEFAULT 12
)
RETURN VARCHAR2
IS
l_code maxvarchar2;
indx PLS_INTEGER;
PROCEDURE initialize
IS
BEGIN
qu_replace.RESET ( outcome_in.outcome.universal_id );
qu_replace.set_delims ( outcome_in.outcome.universal_id, '[', ']' );
END initialize;
PROCEDURE pl ( string_in IN VARCHAR2, indent_in IN PLS_INTEGER DEFAULT 3 )
IS
BEGIN
l_code :=
l_code
|| CHR ( 10 )
|| LPAD ( ' ', start_indent_in + indent_in )
|| string_in;
END pl;
PROCEDURE add_sub_templates
IS
l_subtemplates qu_template_tp.qu_template_tc;
BEGIN
l_subtemplates := qu_template_xp.all_subtemplates;
FOR indx IN 1 .. l_subtemplates.COUNT
LOOP
qu_replace.add_set ( outcome_in.outcome.universal_id
, l_subtemplates ( indx ).name
, l_subtemplates ( indx ).code
);
END LOOP;
END add_sub_templates;
PROCEDURE set_specific_placeholders
IS
l_placeholders qu_placeholder_tp.qu_placeholder_tc;
l_value maxvarchar2;
l_set_value BOOLEAN;
l_fp_ok BOOLEAN;
l_exp_ok BOOLEAN;
-- Used in many of the WHEN clauses below.
l_columns qu_describe.col_tabtype;
PROCEDURE prepare_local_values
IS
BEGIN
/* Templates using placeholder "prepare_local_values":
compare_two_values
But this template is also used to compare single value from
a dataset to a scalar. In this case (FP is a dataset),
we need to do some extra setup.
*/
IF qu_datatype_xp.is_dataset
( outcome_in.RESULT.data_type.universal_id
)
THEN
IF qu_datatype_xp.is_ref_cursor
( outcome_in.RESULT.data_type.universal_id
)
THEN
l_value := ' cv := [fp.variable_name];';
ELSE
l_value := ' OPEN cv FOR [fp.open_for_query_from_dataset];';
END IF;
l_value :=
l_value || CHR ( 10 )
|| 'FETCH cv INTO l_fp_value; CLOSE cv;';
ELSIF qu_assertion_xp.is_sqlrowcount_assertion
( outcome_in.assertion.universal_id
)
THEN
l_value :=
'l_fp_value := ' || qu_engine.c_sqlrowcount_varname || ';';
ELSIF qu_datatype_xp.is_scalar
( outcome_in.RESULT.data_type.universal_id
)
THEN
-- 1.1.2: if an expression, don't use the variable name.
IF outcome_in.RESULT.attribute.is_expression = c_yes
THEN
l_value := 'l_fp_value := [fp.value];';
ELSE
l_value := 'l_fp_value := [fp.variable_name];';
END IF;
END IF;
-- Need to truncate date value?
-- 1.1.2: BM 314 put the first two elements inside parens.
IF ( qu_datatype_xp.truncation_relevant
( outcome_in.control.data_type.universal_id
)
OR qu_datatype_xp.truncation_relevant
( outcome_in.RESULT.data_type.universal_id
)
)
AND ( outcome_in.RESULT.attribute.value1 = c_true
OR outcome_in.control.attribute.value1 = c_true
)
THEN
-- Relevant only for dates, etc.
l_value :=
l_value
|| CASE
WHEN l_value IS NOT NULL
THEN CHR ( 10 )
ELSE NULL
END
|| '-- Truncate values
l_fp_value := TRUNC ( l_fp_value);
l_exp_value := TRUNC ( l_exp_value );';
END IF;
END prepare_local_values;
BEGIN
/*
Single loop for ALL other placeholders:
Per placeholder, use CASE to set values based on datatype.
MUST BE UPDATED AS NEW PLACHOLDERS ARE ADDED!
*/
--qd_runtime.TRACE ( 'ph', outcome_in.TEMPLATE.template_row.name, TRUE
);
--qd_runtime.TRACE ( 'ph', outcome_in.TEMPLATE.placeholders.COUNT, TRUE
);
l_placeholders := outcome_in.TEMPLATE.placeholders;
l_fp_ok := FALSE;
l_exp_ok := FALSE;
indx := l_placeholders.FIRST;
WHILE ( indx IS NOT NULL )
LOOP
l_value := NULL;
l_set_value := TRUE;
CASE
WHEN l_placeholders ( indx ).name =
'collection_recipient_declaration'
THEN
-- Templates using placeholder
"collection_recipient_declaration": dataset_count
-- Declaration of collection that corresponds to dataset
query, plus
-- declaration of l_rows variable.
l_value :=
qu_outcome_xp.coll_recipient_declaration ( outcome_in );
WHEN l_placeholders ( indx ).name = 'eq_fields_check'
THEN
/* Templates using placeholder "eq_fields_check":
record_against_dataset
record_against_record*/
l_columns :=
qu_outcome_xp.columns_for_selectable
( outcome_in
, get_columns_in =>
TRUE
);
FOR indx IN 1 .. l_columns.COUNT
LOOP
l_value :=
l_value
|| CASE
WHEN indx = 1
THEN NULL
ELSE CHR ( 10 ) || 'AND '
END
|| '((rec1.'
|| l_columns ( indx ).column_name
|| ' = rec2.'
|| l_columns ( indx ).column_name
|| ') OR (rec1.'
|| l_columns ( indx ).column_name
|| ' IS NULL AND rec2.'
|| l_columns ( indx ).column_name
|| ' IS NULL))';
END LOOP;
WHEN l_placeholders ( indx ).name = 'exp.count_value'
THEN
-- Set to the same as exp.value unless the
-- fp is selectables and exp is null (which means
-- a before/after count in the dataset).
IF qu_datatype_xp.is_selectable
( outcome_in.RESULT.data_type.universal_id
)
AND outcome_in.control.data_type.universal_id IS NULL
THEN
l_value :=
at_least_null ( sel_count_variable ( outcome_in ));
ELSIF outcome_in.TEMPLATE.template_row.name =
qu_template_xp.c_selectable_count_compare_by
THEN
-- COUNT before/after relative (by a certain amount)
l_value :=
sel_count_variable ( outcome_in )
|| CASE outcome_in.OPERATOR.operator_symbol
WHEN '>'
THEN ' + '
WHEN '>='
THEN ' + '
WHEN '<'
THEN ' - '
WHEN '<='
THEN ' - '
END
|| at_least_null
( expected_value_string
( outcome_in
, outcome_in.substitutions
)
);
ELSE
l_value :=
at_least_null
( expected_value_string ( outcome_in
, outcome_in.substitutions
)
);
END IF;
WHEN l_placeholders ( indx ).name = 'fp.directory'
THEN
-- Templates using placeholder "fp.directory":
file_equal_file, file_exists
l_value :=
at_least_null ( outcome_in.RESULT.attribute.value2 );
WHEN l_placeholders ( indx ).name = 'fp.file_name'
THEN
-- Templates using placeholder "fp.file_name":
file_equal_file, file_exists
l_value :=
at_least_null ( outcome_in.RESULT.attribute.value1 );
WHEN l_placeholders ( indx ).name = 'exp.directory'
THEN
-- Templates using placeholder "exp.directory":
file_equal_file
l_value :=
at_least_null ( outcome_in.control.attribute.value2 );
WHEN l_placeholders ( indx ).name = 'exp.file_name'
THEN
-- Templates using placeholder "exp.file_name":
file_equal_file
l_value :=
at_least_null ( outcome_in.control.attribute.value1 );
WHEN l_placeholders ( indx ).name = 'fp.object_name'
THEN
-- Templates using placeholder "fp.object_name":
dbobject_exists
DECLARE
l_owner qu_attributes_tp.value1_t;
BEGIN
IF outcome_in.RESULT.attribute.value1_is_expr = c_yes
THEN
l_value := outcome_in.RESULT.attribute.value1;
ELSE
qu_all_objects.parse_object_name
( outcome_in.RESULT.attribute.value1
, l_owner
, l_value
, in_quotes_in => TRUE
);
END IF;
END;
WHEN l_placeholders ( indx ).name = 'fp.owner'
THEN
-- Templates using placeholder "fp.owner": dbobject_exists
DECLARE
l_dummy qu_attributes_tp.value1_t;
BEGIN
IF outcome_in.RESULT.attribute.value1_is_expr = c_yes
THEN
l_value := '''%''';
ELSE
qu_all_objects.parse_object_name
( outcome_in.RESULT.attribute.value1
, l_value
, l_dummy
, in_quotes_in => TRUE
);
-- 1.2 If null, then use current schema.
l_value := NVL ( l_value, 'USER' );
END IF;
END;
WHEN l_placeholders ( indx ).name IN
( 'fp.query_from_dataset'
, 'fp.quoted_query_from_dataset'
, 'exp.query_from_dataset'
, 'exp.quoted_query_from_dataset'
)
THEN
l_value :=
get_placeholder_value ( outcome_in
, l_placeholders ( indx ).name
);
WHEN l_placeholders ( indx ).name =
'fp.open_for_query_from_dataset'
THEN
/* Used by: dataset_count dataset_empty */
IF qu_datatype_xp.is_selectable
( outcome_in.RESULT.data_type.universal_id
)
THEN
l_value :=
select_statement ( outcome_in
, qu_outcome_xp.c_result
, immediate_in => FALSE
, with_select_list_in => TRUE
);
ELSE
l_value := c_select_from_dual;
END IF;
WHEN l_placeholders ( indx ).name =
'exp.open_for_query_from_dataset'
THEN
/*Templates using placeholder "exp.query_from_dataset"
record_against_dataset
ref_cursor_against_selectable
selectable_against_selectable
*/
IF qu_datatype_xp.is_selectable
( outcome_in.control.data_type.universal_id
)
THEN
l_value :=
select_statement ( outcome_in
, qu_outcome_xp.c_control
, immediate_in => FALSE
, with_select_list_in => TRUE
);
ELSE
l_value := c_select_from_dual;
END IF;
WHEN l_placeholders ( indx ).name = 'exp.selectable_setup'
THEN
/* Must generate setup code that populates the appropriate
nested table, to then use via the table function.
*/
/*
qd_runtime.TRACE
( 'is sel?'
, qu_datatype_xp.is_selectable
(
outcome_in.control.data_type.universal_id )
, TRUE
);
qd_runtime.TRACE
( 'is expr?'
,
outcome_in.control.attribute.value1_is_expr =
c_yes
OR
outcome_in.control.attribute.value2_is_expr =
c_yes
, TRUE
);
*/
IF qu_datatype_xp.is_selectable
( outcome_in.control.data_type.universal_id
)
AND ( outcome_in.control.attribute.value1_is_expr =
c_yes
OR outcome_in.control.attribute.value2_is_expr =
c_yes
)
THEN
l_value :=
' -- Move contents of expected dataset to a nested
table.
DECLARE temporary_cv SYS_REFCURSOR; BEGIN
OPEN temporary_cv FOR [exp.open_for_query_from_dataset];
[tf_package_name].nt_from_exp_cv := [tf_package_name].table_function (
temporary_cv );
END;';
ELSE
l_value := NULL;
END IF;
WHEN l_placeholders ( indx ).name = 'fp.selectable_setup'
THEN
/*Templates using placeholder:
selectable_against_selectable
selectable_against_ref_cursor
*/
IF qu_datatype_xp.is_selectable
( outcome_in.RESULT.data_type.universal_id
)
AND ( outcome_in.RESULT.attribute.value1_is_expr = c_yes
OR outcome_in.RESULT.attribute.value2_is_expr = c_yes
)
THEN
l_value :=
' -- Move contents of from program dataset to a nested
table.
DECLARE temporary_cv SYS_REFCURSOR; BEGIN
OPEN temporary_cv FOR [fp.open_for_query_from_dataset];
[tf_package_name].nt_from_fp_cv := [tf_package_name].table_function (
temporary_cv );
END;';
END IF;
WHEN l_placeholders ( indx ).name =
'fp.table_name_and_after_from_clause'
THEN
-- Templates using placeholder
"fp.table_name_and_after_from_clause":
-- dataset_count
l_value :=
select_statement ( outcome_in
, qu_outcome_xp.c_result
, immediate_in => FALSE
, with_select_list_in => FALSE
);
WHEN l_placeholders ( indx ).name =
'exp.table_name_and_after_from_clause'
THEN
l_value :=
select_statement ( outcome_in
, qu_outcome_xp.c_control
, immediate_in => FALSE
, with_select_list_in => FALSE
);
WHEN l_placeholders ( indx ).name = 'prepare_local_values'
THEN
prepare_local_values;
WHEN l_placeholders ( indx ).name = 'fp.to_string_function'
THEN
-- Templates using placeholder "to_string_function":
compare_two_values
-- Define the to_String function, which converts the value to
a string.
-- But if NOT a scalar (comparing single row query value, for
example),
-- fall back on the datatype of the expected value.
IF qu_datatype_xp.is_scalar
( outcome_in.RESULT.data_type.universal_id
)
THEN
l_value :=
qu_datatype_xp.to_string_function
( outcome_in.RESULT.data_type.universal_id
, 'fp_to_string'
);
ELSE
l_value :=
qu_datatype_xp.to_string_function
( outcome_in.control.data_type.universal_id
, 'fp_to_string'
);
END IF;
WHEN l_placeholders ( indx ).name = 'exp.to_string_function'
THEN
-- Templates using placeholder "to_string_function":
compare_two_values
-- Define the to_String function, which converts the value to
a string.
l_value :=
qu_datatype_xp.to_string_function
( outcome_in.control.data_type.universal_id
, 'exp_to_string'
);
WHEN l_placeholders ( indx ).name = 'query_from_record'
THEN
-- Templates using placeholder "query_from_record":
record_against_record
l_value :=
select_statement ( outcome_in
, qu_outcome_xp.c_control
, immediate_in => FALSE
);
WHEN l_placeholders ( indx ).name =
'record_recipient_declaration'
THEN
-- Templates using placeholder "record_recipient_declaration":
dataset_empty
-- Need a TYPE declaration of a record and variable named
l_row based on this.
l_columns :=
qu_outcome_xp.columns_for_selectable
( outcome_in
, get_columns_in =>
TRUE
);
-- Switch to qu_outcome_xp, with additional logic.
--qu_describe.columns_for_selectable
-- ( outcome_in.RESULT.attribute.value1
);
l_value := qu_describe.record_decl_from_columns ( l_columns );
l_value :=
l_value
|| CHR ( 10 )
|| 'l_row '
|| qu_describe.c_record_name
|| ';';
WHEN l_placeholders ( indx ).name = 'tf_package_name'
THEN
-- Must be coordinated with custom logic generated....
/* Templates using placeholder "tf_package_name" (table
function package name)
selectable_against_ref_cursor
ref_cursor_against_ref_cursor
ref_cursor_against_selectable*/
l_value :=
get_placeholder_value ( outcome_in, 'tf_package_name' );
WHEN l_placeholders ( indx ).name = 'exp.low_value'
THEN
l_value :=
at_least_null ( outcome_in.RESULT.attribute.value1 );
WHEN l_placeholders ( indx ).name = 'exp.high_value'
THEN
l_value :=
at_least_null ( outcome_in.RESULT.attribute.value2 );
WHEN is_coll_placeholder ( l_placeholders ( indx ).name )
THEN
set_coll_placeholder ( outcome_in.outcome.universal_id
, l_placeholders ( indx ).name
, outcome_in
);
l_set_value := FALSE;
ELSE
-- If a placeholder is not handled here,
-- then we have bad code a coming!
qd_runtime.raise_error
( 'UNANTICIPATED-ERROR'
, 'No placeholder assignment logic for '
|| l_placeholders ( indx ).name
);
END CASE;
/*
qd_runtime.TRACE ( 'set specific '
|| l_placeholders ( indx ).name
|| ' to:'
, l_value
, TRUE
);
*/
IF l_set_value
THEN
qu_replace.add_set ( outcome_in.outcome.universal_id
, l_placeholders ( indx ).name
, l_value
);
END IF;
l_set_value := TRUE;
indx := l_placeholders.NEXT ( indx );
END LOOP;
END set_specific_placeholders;
BEGIN
initialize;
add_sub_templates;
set_specific_placeholders;
set_qute_global_placeholders ( outcome_in.outcome.universal_id
, outcome_in
);
set_standard_exp_placeholders ( outcome_in.outcome.universal_id
, outcome_in
);
set_standard_fp_placeholders ( outcome_in.outcome.universal_id
, outcome_in );
qu_assertion_xp.set_placeholders ( outcome_in.assertion.universal_id
, outcome_in.outcome.universal_id
);
RETURN minimized_whitespace
( qu_outcome_xp.outcome_header ( outcome_in )
|| CHR ( 10 )
|| qu_replace.REPLACE
( outcome_in.outcome.universal_id
, outcome_in.TEMPLATE.template_row.code
/*
,
qu_template_xp.template_code_for_assertion
( assertion_guid_in =>
outcome_in.assertion.universal_id
, operator_guid_in =>
outcome_in.assertion.operator_guid
, fp_dt_guid_in =>
outcome_in.RESULT.data_type.universal_id
, exp_dt_guid_in =>
outcome_in.control.data_type.universal_id
)
--, show_replacements_in => TRUE*/
)
);
END assertion_code_internal;
FUNCTION assertion_code (
outcome_id_in IN qu_outcome_tp.universal_id_t
, engine_type_in IN qu_harness_tp.test_engine_type_t
, override_custom_in IN BOOLEAN DEFAULT FALSE
)
RETURN VARCHAR2
IS
l_outcome qu_outcome_xp.qu_outcome_rt;
BEGIN
-- If assertion type is RAISES, then have to jump back up to test case
-- and call special program because the assertion code is in the
-- exception section and not in the assertion section.
l_outcome :=
qu_outcome_xp.outcome_for_generation ( outcome_id_in
, include_inactive_in => TRUE
);
IF l_outcome.outcome.custom_assert_only = c_yes AND NOT override_custom_in
THEN
RETURN NULL;
ELSIF qu_assertion_xp.is_exception_assertion
( l_outcome.outcome.assertion_type_guid
)
THEN
-- Works with ALL outcomes....
DECLARE
l_outcomes qu_outcome_xp.qu_outcome_tt
:= qu_outcome_xp.qu_outcomes ( l_outcome.test_case.universal_id
, include_inactive_in => TRUE
);
BEGIN
RETURN exc_section_for_tc
( test_case_id_in =>
l_outcome.test_case.universal_id
, outcomes_in => l_outcomes
, start_indent_in => 3
);
END;
ELSE
RETURN assertion_code_internal ( engine_type_in
, l_outcome
, start_indent_in => 3
);
END IF;
END assertion_code;
FUNCTION is_declarable (
datatype_in IN qu_datatype_tp.qu_datatype_rt
, attribute_in IN qu_attributes_tp.qu_attributes_rt
)
RETURN BOOLEAN
IS
BEGIN
RETURN datatype_in.identifier_only = c_no
AND attribute_in.argument_alias IS NOT NULL
AND NVL ( attribute_in.no_local_declaration, c_no ) != c_yes;
END is_declarable;
FUNCTION need_in_declaration ( input_in IN qu_input_xp.qu_input_rt )
RETURN BOOLEAN
/*
Declare IN arguments if assign in setup is set to true.
Otherwise, values are applied directly in call to program.
*/
IS
l_declare BOOLEAN DEFAULT FALSE;
BEGIN
-- 1.1: assign in setup MEANS declare it!
-- AND input_in.is_expression = c_no
/*qd_runtime.TRACE ( 'need_in_declaration type for '
|| input_in.input.argument_alias
, input_in.test_element.element_type
, TRUE
);
qd_runtime.TRACE ( 'need_in_declaration ident only for '
|| input_in.input.argument_alias
, input_in.data_type.identifier_only
, TRUE
);
qd_runtime.TRACE ( 'need_in_declaration arg mode for '
|| input_in.input.argument_alias
, input_in.test_element.argument_mode
, TRUE
);
qd_runtime.TRACE ( 'need_in_declaration assign in setup for '
|| input_in.input.argument_alias
, input_in.input.assign_in_setup
, TRUE
);*/
l_declare :=
input_in.test_element.element_type = qu_test_element_xp.c_argument
AND input_in.data_type.identifier_only = c_no
AND ( input_in.test_element.argument_mode = qu_describe.c_in_out
OR input_in.input.assign_in_setup = c_yes
OR NOT qu_datatype_xp.is_scalar ( input_in.data_type.universal_id
)
);
-- Must have a variable name!
RETURN l_declare AND input_in.input.argument_alias IS NOT NULL;
END need_in_declaration;
--*** Need the test element name here to see if the FP var name
--*** has been changed.
FUNCTION need_fp_declaration ( outcome_in IN qu_outcome_xp.qu_outcome_rt )
RETURN BOOLEAN
IS
BEGIN
/*qd_runtime.TRACE ( outcome_in.result_argument_alias
, 'Check for declaration'
, TRUE
);
qd_runtime.TRACE ( 'is expression'
, outcome_in.result_is_expression
, TRUE
);
qd_runtime.TRACE ( 'ident only', outcome_in.result_identifier_only
, TRUE );
qd_runtime.TRACE ( 'no local decl'
, outcome_in.result_no_local_decl
, TRUE
);*/
/* Declare variable for FP element if...
- It is not identifier only (meaning, you cannot declare a variable of
this type.
- We have a variable name (argument alias)
- The user has not explicitly asked to "not declare"
- If not an expression or is not a scalar
*/
RETURN ( outcome_in.RESULT.attribute.is_expression = c_no
OR NOT qu_datatype_xp.is_scalar
( outcome_in.RESULT.data_type.universal_id
)
)
AND is_declarable ( outcome_in.RESULT.data_type
, outcome_in.RESULT.attribute
);
END need_fp_declaration;
FUNCTION need_exp_declaration ( outcome_in IN qu_outcome_xp.qu_outcome_rt )
RETURN BOOLEAN
IS
BEGIN
/*
qd_runtime.TRACE ( outcome_in.control.attribute.argument_alias
, outcome_in.control.data_type.identifier_only
, TRUE
);
qd_runtime.TRACE ( outcome_in.control.attribute.argument_alias
, outcome_in.control.attribute.no_local_declaration
, TRUE
);
--qd_runtime.trace (outcome_in.control.attribute.argument_alias,
--outcome_in.control.element_type , true);
*/
RETURN ( outcome_in.control.attribute.is_expression = c_no
OR NOT qu_datatype_xp.is_scalar
( outcome_in.control.data_type.universal_id
)
)
AND is_declarable ( outcome_in.control.data_type
, outcome_in.control.attribute
);
END need_exp_declaration;
FUNCTION program_invocation_internal (
unit_test_in IN qu_unit_test_tp.qu_unit_test_rt
, test_elements_in IN qu_test_element_tp.qu_test_element_tc
, testcase_in IN qu_test_case_tp.qu_test_case_rt
, outcomes_in IN qu_outcome_xp.qu_outcome_tt
, inputs_in IN qu_input_xp.qu_input_tt
, substitutions_in IN qu_substitution_tp.qu_substitution_tc
, look_up_substitutions_in IN BOOLEAN
, include_comments_in IN BOOLEAN
, start_indent_in IN PLS_INTEGER
, indent_first_line_in IN BOOLEAN
, in_anon_block_in IN BOOLEAN DEFAULT FALSE
)
-----------------------
-- LK 06/19/06
-- Version for CLOBs
-----------------------
-- RETURN VARCHAR2
RETURN CLOB
IS
-----------------------
-- LK 06/19/06
-- Version for CLOBs
-----------------------
-- l_code maxvarchar2;
l_code CLOB;
l_substitutions qu_substitution_tp.qu_substitution_tc;
l_exec_prog_name maxvarchar2 DEFAULT '*UNDEFINED*';
l_row PLS_INTEGER;
l_oc_index qu_outcome_tp.universal_id_t;
l_prev_indent PLS_INTEGER DEFAULT NULL;
PROCEDURE initialize
IS
l_harness qu_harness_tp.qu_harness_rt;
BEGIN
l_harness := qu_harness_qp.onerow ( unit_test_in.harness_guid );
-- If a packaged program, prefix the package name.
IF l_harness.program_type = 'PACKAGE'
THEN
l_exec_prog_name :=
l_harness.program_name || '.' || unit_test_in.program_name;
ELSE
l_exec_prog_name := l_harness.program_name;
END IF;
-- If the owner of the program is different from the current schema,
-- then append that too.
IF l_harness.program_owner != USER
THEN
l_exec_prog_name :=
l_harness.program_owner || '.' || l_exec_prog_name;
END IF;
IF substitutions_in.COUNT = 0 AND look_up_substitutions_in
THEN
l_substitutions :=
qu_substitution_xp.allrows_for_object
( owner_in =>
l_harness.program_owner
, object_name_in =>
l_harness.program_name
, object_type_in =>
l_harness.program_type
);
END IF;
END initialize;
FUNCTION substitute ( string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN qu_substitution_xp.substituted_string ( l_substitutions
, string_in
);
END substitute;
PROCEDURE pl ( string_in IN VARCHAR2, indent_in IN PLS_INTEGER
DEFAULT NULL )
IS
l_indent PLS_INTEGER;
BEGIN
IF indent_in IS NULL
THEN
l_indent := l_prev_indent;
ELSE
l_indent := indent_in;
END IF;
l_code := l_code || CHR ( 10 ) || LPAD ( ' ', l_indent ) || string_in;
l_prev_indent := l_indent;
END pl;
-----------------------
-- LK 06/19/06
-- Version for CLOBs
-----------------------
PROCEDURE pl ( string_in IN CLOB, indent_in IN PLS_INTEGER DEFAULT NULL )
IS
l_indent PLS_INTEGER;
BEGIN
IF indent_in IS NULL
THEN
l_indent := l_prev_indent;
ELSE
l_indent := indent_in;
END IF;
l_code := l_code || CHR ( 10 ) || LPAD ( ' ', l_indent ) || string_in;
l_prev_indent := l_indent;
END pl;
PROCEDURE plcust ( string_in IN VARCHAR2 )
IS
BEGIN
pl ( '/* Place all your custom '
|| string_in
|| ' code between these START and END comments. */'
);
END plcust;
PROCEDURE insert_named_notation
IS
l_first BOOLEAN DEFAULT TRUE;
l_row PLS_INTEGER;
l_use_varname BOOLEAN DEFAULT FALSE;
FUNCTION input_value_for_program ( te_guid_in IN VARCHAR2 )
RETURN VARCHAR2
IS
l_row PLS_INTEGER;
-- Get the input row for this test element.
FUNCTION input_row
RETURN PLS_INTEGER
IS
l_row PLS_INTEGER := inputs_in.FIRST;
l_last PLS_INTEGER := inputs_in.LAST;
BEGIN
WHILE ( l_row <= l_last
AND inputs_in ( l_row ).test_element.universal_id !=
te_guid_in
)
LOOP
l_row := l_row + 1;
END LOOP;
/*qd_runtime.assert
( l_row <= l_last
, 'No matching input row found for test element GUID '
|| te_guid_in
, error_name_in => 'UNANTICIPATED-ERROR'
);*/
-- No match. We have an IN argument test element
-- but no input. Just set input value to NULL.
RETURN CASE
WHEN l_row > l_last
THEN NULL
ELSE l_row
END;
END input_row;
BEGIN
l_row := input_row;
IF l_row IS NULL
THEN
RETURN 'NULL';
ELSE
l_use_varname :=
inputs_in ( l_row ).input.assign_in_setup = c_yes;
IF NOT l_use_varname
THEN
-- If datatype is identifier only then I must use the variable
-- name if it is not an expression.
l_use_varname :=
inputs_in ( l_row ).data_type.identifier_only = c_yes
AND inputs_in ( l_row ).input.is_expression = c_no;
END IF;
IF l_use_varname
THEN
RETURN at_least_null
( substitute ( inputs_in ( l_row
).input.argument_alias
)
);
ELSE
RETURN at_least_null ( inputs_in ( l_row
).input.external_value
);
END IF;
END IF;
END input_value_for_program;
BEGIN
qu_used.clear_used_list ( c_declared_list );
l_row := test_elements_in.FIRST;
WHILE ( l_row IS NOT NULL )
LOOP
IF test_elements_in ( l_row ).element_type =
qu_test_element_xp.c_argument
THEN
IF is_in_arg ( test_elements_in ( l_row ).argument_mode
, include_inout_in => FALSE
)
THEN
pl
( CASE
WHEN l_first
THEN NULL
ELSE ','
END
|| test_elements_in ( l_row ).name
|| ' => '
|| input_value_for_program
( test_elements_in ( l_row
).universal_id
)
, start_indent_in + 9
);
qu_used.mark_as_used ( c_declared_list
, test_elements_in ( l_row ).name
);
ELSIF is_out_arg ( test_elements_in ( l_row ).argument_mode )
THEN
pl
( CASE
WHEN l_first
THEN NULL
ELSE ','
END
|| test_elements_in ( l_row ).name
|| ' => '
|| qu_test_element_xp.prog_call_varname
( test_elements_in ( l_row
).name
)
, start_indent_in + 9
);
qu_used.mark_as_used ( c_declared_list
, test_elements_in ( l_row ).name
);
END IF;
l_first := FALSE;
END IF;
l_row := test_elements_in.NEXT ( l_row );
END LOOP;
qu_used.clear_used_list ( c_declared_list );
END insert_named_notation;
PROCEDURE pl_pre_execution
IS
BEGIN
IF include_comments_in
THEN
pl ( c_qute_start_comment
|| ' PRE-EXECUTION for TESTCASE '
|| testcase_in.universal_id
, start_indent_in + 3
);
plcust ( 'pre-execution' );
END IF;
pl ( testcase_in.pre_execution_code );
IF include_comments_in
THEN
pl ( c_qute_end_comment
|| ' PRE-EXECUTION for TESTCASE '
|| testcase_in.universal_id
);
END IF;
END pl_pre_execution;
PROCEDURE pl_post_execution
IS
BEGIN
IF include_comments_in
THEN
pl ( c_qute_start_comment
|| ' POST-EXECUTION for TESTCASE '
|| testcase_in.universal_id
, start_indent_in + 3
);
plcust ( 'post-execution' );
END IF;
pl ( testcase_in.post_execution_code );
IF include_comments_in
THEN
pl ( c_qute_end_comment
|| ' POST-EXECUTION for TESTCASE '
|| testcase_in.universal_id
);
END IF;
END pl_post_execution;
BEGIN
initialize;
IF NOT in_anon_block_in
THEN
pl ( 'PROCEDURE call_the_program IS'
, CASE
WHEN indent_first_line_in
THEN start_indent_in
ELSE 0
END
);
END IF;
pl ( 'BEGIN', start_indent_in );
IF NOT in_anon_block_in
THEN
pl_pre_execution;
pl ( '-- Capture start time.', start_indent_in + 3 );
pl ( c_start_time_varname || ' := DBMS_UTILITY.GET_TIME;'
, start_indent_in + 3
);
END IF;
-- IF testcase_in.alt_execution_code IS NOT NULL
IF clob_is_not_null ( testcase_in.alt_execution_code ) -- LK 05/10/06
THEN
IF include_comments_in
THEN
pl ( c_qute_start_comment
|| ' ALTERNATE EXECUTION for TESTCASE '
|| testcase_in.universal_id
, start_indent_in + 3
);
plcust ( 'program execution' );
END IF;
pl ( testcase_in.alt_execution_code );
IF include_comments_in
THEN
pl ( c_qute_end_comment
|| ' ALTERNATE EXECUTION for TESTCASE '
|| testcase_in.universal_id
);
END IF;
ELSE
qu_used.clear_used_list ( c_assigned_list );
IF unit_test_in.program_type = 'FUNCTION'
THEN
pl ( qu_test_element_xp.c_return_varname || ' :='
, start_indent_in + 3
);
END IF;
pl ( l_exec_prog_name || '(', start_indent_in + 3 );
insert_named_notation;
pl ( ');', start_indent_in + 3 );
-- Copy returned value to all outcome variables
-- based on the RETURN test element.
l_oc_index := outcomes_in.FIRST;
WHILE ( l_oc_index IS NOT NULL )
LOOP
IF outcomes_in ( l_oc_index ).RESULT.test_element.element_type =
qu_describe.c_function_return_name
AND outcomes_in ( l_oc_index ).RESULT.attribute.argument_alias !=
qu_test_element_xp.c_return_varname
THEN
-- Copy the value over -- but only once....
IF NOT qu_used.string_in_use
( c_assigned_list
, outcomes_in ( l_oc_index
).RESULT.attribute.argument_alias
)
THEN
pl
( '/* Copy value returned by function to all "from program"
variables based on the function''s RETURN clause. */'
, start_indent_in + 3
);
pl
( substitute
( outcomes_in ( l_oc_index
).RESULT.attribute.argument_alias
)
|| ' := '
|| qu_test_element_xp.c_return_varname
|| ';'
, start_indent_in + 3
);
qu_used.mark_as_used
( c_assigned_list
, outcomes_in ( l_oc_index
).RESULT.attribute.argument_alias
);
END IF;
END IF;
l_oc_index := outcomes_in.NEXT ( l_oc_index );
END LOOP;
END IF;
IF NOT in_anon_block_in
THEN
pl ( '-- Capture post-execution values.', start_indent_in + 3 );
pl ( c_sqlrowcount_varname || ' := SQL%ROWCOUNT;' );
pl ( c_end_time_varname || ' := DBMS_UTILITY.GET_TIME;' );
END IF;
pl_post_execution;
pl ( exc_section_for_tc ( testcase_in.universal_id
, outcomes_in
, start_indent_in
)
);
IF in_anon_block_in
THEN
-- Next are the assertions... pl ( 'END;' );
NULL;
ELSE
pl ( 'END call_the_program;', start_indent_in );
END IF;
pl ( ' ' );
RETURN LTRIM ( l_code, CHR ( 10 ));
END program_invocation_internal;
FUNCTION program_invocation (
unit_test_id_in IN qu_unit_test_tp.universal_id_t
, test_case_id_in IN qu_test_case_tp.universal_id_t
)
-----------------------
-- LK 06/19/06
-- Version for CLOBs
-----------------------
-- RETURN VARCHAR2
RETURN CLOB
IS
l_substitutions qu_substitution_tp.qu_substitution_tc;
BEGIN
RETURN program_invocation_internal
( unit_test_in => qu_unit_test_qp.onerow
( unit_test_id_in
)
, test_elements_in =>
qu_test_element_qp.ar_fk_test_id
( unit_test_id_in
)
, testcase_in => qu_test_case_qp.onerow
( test_case_id_in
)
, outcomes_in => qu_outcome_xp.qu_outcomes
( test_case_id_in
)
, inputs_in => qu_input_xp.qu_inputs
( test_case_id_in
)
, substitutions_in => l_substitutions
, look_up_substitutions_in => TRUE
, include_comments_in => FALSE
, start_indent_in => 3
, indent_first_line_in => TRUE
);
END program_invocation;
PROCEDURE gen_test_package (
-- l_code array needs to break up lines to fit for compilation!
harness_id_in IN qu_harness_tp.universal_id_t
, compile_in IN BOOLEAN
, spec_in IN BOOLEAN
, code_out OUT CLOB
, status_out OUT PLS_INTEGER
, include_cust_comments_in IN BOOLEAN DEFAULT TRUE
, terminate_with_slash_in IN BOOLEAN DEFAULT FALSE
, test_engine_type_in IN VARCHAR2 DEFAULT NULL
)
IS
l_harness qu_harness_tp.qu_harness_rt;
l_harness_customized BOOLEAN;
l_have_ext_test_code BOOLEAN DEFAULT FALSE;
l_ext_test_code qu_harness_tp.teardown_code_t;
-- Flags that reflect content of test package to be generated
/*maybe use this....
type content_flags_rt is record (
have_in_args boolean,
have_out_args boolean,
have_outcomes boolean,
have_in_args boolean,
);*/
l_have_in_args BOOLEAN;
l_have_out_args BOOLEAN;
l_have_setup BOOLEAN;
l_have_teardown BOOLEAN;
l_set_in_values BOOLEAN;
l_include_cust_comments BOOLEAN;
--
l_substitutions qu_substitution_tp.qu_substitution_tc;
g_testcode_lob CLOB;
l_status PLS_INTEGER;
l_obj_status maxvarchar2;
l_last_indent PLS_INTEGER := 3;
PROCEDURE add_to_ext_test_code ( string_in IN VARCHAR2 )
IS
BEGIN
l_ext_test_code := l_ext_test_code || CHR ( 10 ) || string_in;
l_have_ext_test_code := TRUE;
END add_to_ext_test_code;
PROCEDURE add_to_ext_test_code ( string_in IN CLOB )
IS
BEGIN
l_ext_test_code := l_ext_test_code || CHR ( 10 ) || string_in;
l_have_ext_test_code := TRUE;
END add_to_ext_test_code;
PROCEDURE save_ext_test_code
IS
BEGIN
IF l_have_ext_test_code
THEN
UPDATE qu_harness
SET teardown_code = 'BEGIN ' || l_ext_test_code || ' END;'
WHERE universal_id = l_harness.universal_id;
END IF;
END save_ext_test_code;
PROCEDURE initialize ( harness_out IN OUT qu_harness_tp.qu_harness_rt )
IS
BEGIN
g_testcode.DELETE;
DBMS_LOB.createtemporary ( g_testcode_lob, TRUE, DBMS_LOB.CALL );
--
harness_out := qu_harness_qp.onerow ( harness_id_in );
l_harness_customized := qu_harness_xp.is_customized ( harness_out );
IF test_engine_type_in IS NOT NULL
THEN
harness_out.test_engine_type := test_engine_type_in;
END IF;
-- Set engine type for use in generation.
set_current_harness_info
( run_harness_id_in => NULL
, dbms_output_only_in =>
harness_out.test_engine_type =
c_dbms_output
);
IF dbms_output_only
THEN
l_include_cust_comments := FALSE;
ELSE
l_include_cust_comments := include_cust_comments_in;
END IF;
-- Load substitutions
l_substitutions :=
qu_substitution_xp.allrows_for_object
( owner_in =>
l_harness.program_owner
, object_name_in =>
l_harness.program_name
, object_type_in =>
l_harness.program_type
);
END initialize;
FUNCTION substitute ( string_in IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN qu_substitution_xp.substituted_string ( l_substitutions
, string_in
);
END substitute;
PROCEDURE pl (
string_in IN VARCHAR2
, indent_in IN PLS_INTEGER DEFAULT NULL
, reuse_last_indent_in IN BOOLEAN DEFAULT TRUE
)
IS
c_array_max CONSTANT PLS_INTEGER DEFAULT 256;
l_string qu_engine.maxvarchar2;
PROCEDURE load_string_for_compilation ( string_in IN VARCHAR2 )
IS
l_string VARCHAR2 ( 256 );
l_start PLS_INTEGER := 1;
l_next_lf PLS_INTEGER;
c_length CONSTANT PLS_INTEGER := LENGTH ( string_in );
BEGIN
-- String cannot be longer than 256.
WHILE ( l_start <= c_length )
LOOP
l_next_lf := INSTR ( string_in, CHR ( 10 ), l_start );
IF l_next_lf > 0 AND l_next_lf < l_start + c_array_max
THEN
l_string :=
SUBSTR ( string_in, l_start, l_next_lf - l_start );
l_start := l_next_lf + 1;
ELSE
l_string := SUBSTR ( string_in, l_start, c_array_max );
l_start := l_start + c_array_max;
END IF;
g_testcode ( g_testcode.COUNT + 1 ) := l_string;
END LOOP;
END load_string_for_compilation;
BEGIN
IF reuse_last_indent_in AND indent_in IS NULL
THEN
l_string := LPAD ( ' ', l_last_indent ) || string_in;
ELSIF indent_in IS NOT NULL
THEN
l_string := LPAD ( ' ', indent_in ) || string_in;
l_last_indent := indent_in;
END IF;
DBMS_LOB.writeappend ( g_testcode_lob
, amount => NVL ( NVL ( LENGTH ( l_string )
, 1
)
+ 2
, 1
)
, buffer => NVL ( l_string, ' ' )
|| CHR ( 13 )
|| CHR ( 10 )
);
load_string_for_compilation ( l_string );
END pl;
-----------------------
-- LK 06/19/06
-- Version for CLOBs
-----------------------
PROCEDURE pl (
string_in IN CLOB
, indent_in IN PLS_INTEGER DEFAULT NULL
, reuse_last_indent_in IN BOOLEAN DEFAULT TRUE
)
IS
c_array_max CONSTANT PLS_INTEGER DEFAULT 256;
l_string CLOB;
l_amount PLS_INTEGER;
PROCEDURE load_string_for_compilation ( string_in IN CLOB )
IS
l_string VARCHAR2 ( 256 );
l_start PLS_INTEGER := 1;
l_next_lf PLS_INTEGER;
c_length CONSTANT PLS_INTEGER := LENGTH ( string_in );
BEGIN
-- String cannot be longer than 256.
WHILE ( l_start <= c_length )
LOOP
l_next_lf := INSTR ( string_in, CHR ( 10 ), l_start );
IF l_next_lf > 0 AND l_next_lf < l_start + c_array_max
THEN
l_string :=
SUBSTR ( string_in, l_start, l_next_lf - l_start );
l_start := l_next_lf + 1;
ELSE
l_string := SUBSTR ( string_in, l_start, c_array_max );
l_start := l_start + c_array_max;
END IF;
g_testcode ( g_testcode.COUNT + 1 ) := l_string;
END LOOP;
END load_string_for_compilation;
BEGIN
IF reuse_last_indent_in AND indent_in IS NULL
THEN
l_string := LPAD ( ' ', l_last_indent ) || string_in;
ELSIF indent_in IS NOT NULL
THEN
l_string := LPAD ( ' ', indent_in ) || string_in;
l_last_indent := indent_in;
END IF;
IF l_string IS NOT NULL
THEN
DBMS_LOB.append ( dest_lob => g_testcode_lob
, src_lob => l_string );
ELSE
DBMS_LOB.writeappend ( lob_loc => g_testcode_lob
, amount => 1
, buffer => ' '
);
END IF;
DBMS_LOB.writeappend ( lob_loc => g_testcode_lob
, amount => 2
, buffer => CHR ( 13 ) || CHR ( 10 )
);
load_string_for_compilation ( l_string );
END pl;
PROCEDURE plcust ( string_in IN VARCHAR2 )
IS
BEGIN
pl ( '/* Place all your custom '
|| string_in
|| ' code between these START and END comments. */'
);
END plcust;
PROCEDURE plnull ( indent_in IN PLS_INTEGER DEFAULT 0 )
IS
BEGIN
pl ( 'NULL;', indent_in );
END plnull;
PROCEDURE add_cust_info (
id_in IN VARCHAR2
, code_in IN CLOB
, level_in IN VARCHAR2
, type_in IN VARCHAR2
, desc_in IN VARCHAR2
)
IS
BEGIN
IF clob_is_not_null ( code_in )
OR l_include_cust_comments -- LK 05/10/06
THEN
pl ( c_qute_start_comment
|| ' '
|| type_in
|| ' for '
|| level_in
|| ' '
|| id_in
, 6
);
plcust ( desc_in );
pl ( code_in );
pl ( c_qute_end_comment
|| ' '
|| type_in
|| ' for '
|| level_in
|| ' '
|| id_in
);
END IF;
END add_cust_info;
PROCEDURE set_in_out_flags (
elements_in IN qu_test_element_tp.qu_test_element_tc
, in_flag OUT BOOLEAN
, out_flag OUT BOOLEAN
)
IS
l_row PLS_INTEGER;
BEGIN
l_row := elements_in.FIRST;
WHILE ( l_row IS NOT NULL )
LOOP
IF is_in_arg ( elements_in ( l_row ).argument_mode )
THEN
in_flag := TRUE;
END IF;
IF is_out_arg ( elements_in ( l_row ).argument_mode )
THEN
out_flag := TRUE;
END IF;
l_row := elements_in.NEXT ( l_row );
END LOOP;
END set_in_out_flags;
PROCEDURE compile_code
IS
cur BINARY_INTEGER := DBMS_SQL.open_cursor;
l_last PLS_INTEGER := g_testcode.LAST;
PROCEDURE cleanup
IS
BEGIN
IF DBMS_SQL.is_open ( cur )
THEN
DBMS_SQL.close_cursor ( cur );
END IF;
END cleanup;
BEGIN
IF l_last IS NOT NULL
THEN
IF terminate_with_slash_in
THEN
l_last := l_last - 1;
END IF;
DBMS_SQL.parse ( c => cur
, STATEMENT => g_testcode
, lb => g_testcode.FIRST
, ub => l_last
, lfflg => TRUE
, language_flag => DBMS_SQL.native
);
DBMS_SQL.close_cursor ( cur );
END IF;
cleanup;
EXCEPTION
WHEN OTHERS
THEN
cleanup;
END compile_code;
PROCEDURE generate_instructions
IS
BEGIN
pl ( '|' );
pl
( '| This package may be run from within any PL/SQL execution
environment.'
);
pl ( '| by executing the following statements:' );
pl ( '|' );
pl ( '| SET SERVEROUTPUT ON FORMAT WRAPPED SIZE 1000000' );
pl ( '|' );
pl ( '| BEGIN' );
pl ( '| ' || l_harness.program_name || '.run_all_tests;' );
pl ( '| END;' );
pl ( '| /' );
pl ( '|' );
pl
( '| Results will be displayed via DBMS_OUTPUT. This package
requires the'
);
pl
( '| presence of the qu_assert package. If you do not have Qute
installed,'
);
pl ( '| you can download just the qu_assert package from:' );
pl ( '|' );
pl ( '|
http://www.unit-test.com/download/zip' );
pl ( '|' );
pl
( '| Then use the following statements to install all needed
objects'
);
pl ( '| (assuming the program you want to test is already installed):'
);
pl ( '|' );
pl ( '| -- Assertion package' );
pl ( '| @pks' );
pl ( '| @pkb' );
pl ( '|' );
pl ( '| -- Test code ' );
pl ( '| @' || l_harness.name || '.pkg' );
pl ( '|' );
END generate_instructions;
PROCEDURE generate_header
IS
BEGIN
IF spec_in
THEN
-- 1.0.3 Add current user to header.
pl ( 'CREATE OR REPLACE PACKAGE '
|| l_harness.name
|| ' AUTHID CURRENT_USER'
, 0
);
ELSE
pl ( 'CREATE OR REPLACE PACKAGE BODY ' || l_harness.name, 0 );
END IF;
pl ( '/*' );
pl ( '| Unit Test Package for '
--|| l_harness.program_owner
--|| '.'
|| l_harness.program_name );
pl ( '|' );
pl
( '| Generated by Qute -- the Quick Unit Test Engine
(www.unit-test.com)'
);
pl ( '| Generated on ' || TO_CHAR ( SYSDATE, 'YYYY-MM-DD HH24:MI:SS'
));
IF dbms_output_only
THEN
generate_instructions;
ELSE
pl
( '| This package must be run from within the Qute graphical
interface.'
);
END IF;
pl ( '*/' );
pl ( 'IS' );
-- 1.1.3 Move declarations to avoid duplication.
IF NOT spec_in
THEN
-- Declare variables for elapsed time calculations.
pl ( '/* Global variables for timings and SQL status. */' );
pl ( c_start_time_varname || ' NUMBER;' );
pl ( c_end_time_varname || ' NUMBER;' );
pl ( c_sqlrowcount_varname || ' PLS_INTEGER; -- for SQL%ROWCOUNT' );
END IF;
IF spec_in
THEN
add_cust_info ( l_harness.universal_id
, l_harness.declarations
, 'HARNESS'
, 'DECLARATIONS'
, 'declaration'
);
END IF;
IF spec_in
THEN
-- Used by "simple test case" engine.
pl
( 'PROCEDURE qute#assert_null (outcome_guid_in IN VARCHAR2,
is_null_in IN BOOLEAN, check_type_in IN VARCHAR2, raise_exc_in IN BOOLEAN :=
FALSE);'
, 3
);
pl
( 'PROCEDURE qute#assert_this (outcome_guid_in IN VARCHAR2,
msg_in IN VARCHAR2, check_this_in IN BOOLEAN, null_ok_in IN BOOLEAN := FALSE,
raise_exc_in IN BOOLEAN := FALSE);'
, 3
);
pl
( 'PROCEDURE qute#report_result (result_guid_in IN VARCHAR2,
status_in IN VARCHAR2, description_in IN VARCHAR2);'
, 3
);
pl ( 'FUNCTION qute#error_info RETURN VARCHAR2;', 3 );
pl ( 'PROCEDURE ' || l_harness.prefix || 'setup;', 3 );
ELSE
-- Insert private modules for use by assertion logic.
-- pl ( minimized_whitespace ( c_qute#error_info_code ));
pl
( minimized_whitespace
( qu_template_xp.private_test_code
( l_harness.test_engine_type
)
)
);
pl ( ' ' );
pl ( 'PROCEDURE ' || l_harness.prefix || 'setup IS', 3 );
pl ( 'BEGIN' );
add_cust_info ( l_harness.universal_id
, l_harness.setup_code
, 'HARNESS'
, 'SETUP'
, 'initialization'
);
plnull ( 6 );
pl ( 'END ' || l_harness.prefix || 'setup;', 3 );
pl ( ' ' );
END IF;
IF spec_in
THEN
pl ( 'PROCEDURE ' || l_harness.prefix || 'teardown;', 3 );
ELSE
pl ( 'PROCEDURE ' || l_harness.prefix || 'teardown IS' );
pl ( 'BEGIN' );
add_cust_info ( l_harness.universal_id
, l_harness.teardown_code
, 'HARNESS'
, 'TEARDOWN'
, 'cleanup'
);
plnull ( 6 );
pl ( 'END ' || l_harness.prefix || 'teardown;', 3 );
END IF;
END generate_header;
PROCEDURE generate_assertions (
tc_in IN qu_test_case_tp.qu_test_case_rt
, outcomes_in IN qu_outcome_xp.qu_outcome_tt
)
IS
l_oc_index qu_outcome_tp.universal_id_t;
BEGIN
IF outcomes_in.COUNT > 0
OR clob_is_not_null ( tc_in.assertion_code ) -- LK 05/10/06
OR l_include_cust_comments
THEN
pl ( 'PROCEDURE check_out_args_and_return IS', 9 );
pl ( 'BEGIN' );
l_oc_index := outcomes_in.FIRST;
WHILE ( l_oc_index IS NOT NULL )
LOOP
IF outcomes_in ( l_oc_index ).outcome.custom_assert_only = c_yes
THEN
-- Skip it. This is done in the customized section.
NULL;
ELSIF qu_assertion_xp.is_exception_assertion
( outcomes_in ( l_oc_index
).assertion.universal_id
)
THEN
-- Handled elsewhere...
NULL;
ELSE
pl ( '/* Outcome name: '
|| outcomes_in ( l_oc_index ).outcome.name
|| ' */'
, 9
);
IF dbms_output_only
THEN
pl ( 'DBMS_OUTPUT.PUT_LINE ('''
|| c_output_prefix
|| ' Outcome "'
|| REPLACE ( outcomes_in ( l_oc_index ).outcome.name
, ''''
, ''''''
)
|| '"'');'
, 12
);
END IF;
pl ( assertion_code_internal ( l_harness.test_engine_type
, outcomes_in ( l_oc_index )
, start_indent_in => 12
)
, 0
);
pl ( ' ' );
END IF;
l_oc_index := outcomes_in.NEXT ( l_oc_index );
END LOOP;
add_cust_info ( tc_in.universal_id
, tc_in.assertion_code
, 'TESTCASE'
, 'ASSERTION'
, 'assertion'
);
plnull ( 12 );
pl ( 'END check_out_args_and_return;', 9 );
pl ( ' ' );
END IF;
END generate_assertions;
FUNCTION tc_is_simple ( test_case_in IN qu_test_case_tp.qu_test_case_rt )
RETURN BOOLEAN
IS
BEGIN
RETURN FALSE;
-- Turned off in 1.1.3 RETURN test_case_in.testing_status = c_simple;
END tc_is_simple;
PROCEDURE generate_tc_definitions (
unit_test_in IN qu_unit_test_tp.qu_unit_test_rt
, test_cases_in IN OUT qu_test_case_tp.qu_test_case_tc
, test_elements_in IN qu_test_element_tp.qu_test_element_tc
, return_te_in IN qu_test_element_tp.qu_test_element_rt
, harness_customized_in IN BOOLEAN
, ut_customized_in IN BOOLEAN
)
IS
-- l_tc qu_test_case_tp.qu_test_case_rt;
l_outcomes qu_outcome_xp.qu_outcome_tt;
l_inputs qu_input_xp.qu_input_tt;
l_tc_index PLS_INTEGER;
--
PROCEDURE gen_local_vars (
test_elements_in IN qu_test_element_tp.qu_test_element_tc
, inputs_in IN qu_input_xp.qu_input_tt
, outcomes_in IN qu_outcome_xp.qu_outcome_tt
, send_to_ext_code_in IN BOOLEAN DEFAULT FALSE
)
IS
l_int_index PLS_INTEGER;
l_oc_index qu_outcome_tp.universal_id_t;
PROCEDURE pl_int (
string_in IN VARCHAR2
, start_indent_in IN PLS_INTEGER DEFAULT NULL
)
IS
BEGIN
IF send_to_ext_code_in
THEN
add_to_ext_test_code ( string_in );
ELSE
pl ( string_in, start_indent_in );
END IF;
END pl_int;
PROCEDURE pl_and_mark_used (
varname_in IN VARCHAR2
, dt_in IN VARCHAR2
, pre_comment_in IN VARCHAR2 DEFAULT NULL
)
IS
BEGIN
IF NOT qu_used.string_in_use ( c_declared_list, varname_in )
THEN
IF pre_comment_in IS NOT NULL
THEN
pl_int ( pre_comment_in );
END IF;
pl_int ( substitute ( varname_in ) || ' ' || dt_in || ';' );
qu_used.mark_as_used ( c_declared_list, varname_in );
END IF;
END pl_and_mark_used;
BEGIN
IF send_to_ext_code_in
THEN
pl_int ( c_simple_tc_start || 'DECLARE' );
END IF;
qu_used.clear_used_list ( c_declared_list );
-- LK 05/08/06
-- Declare variables for selectable before/after if needed.
l_oc_index := l_outcomes.FIRST;
WHILE ( l_oc_index IS NOT NULL )
LOOP
IF qu_datatype_xp.is_selectable
( l_outcomes ( l_oc_index
).RESULT.data_type.universal_id
)
THEN
pl_and_mark_used
( sel_count_variable ( l_outcomes ( l_oc_index
)
)
, 'PLS_INTEGER'
);
END IF;
l_oc_index := l_outcomes.NEXT ( l_oc_index );
END LOOP;
-- Always declare return variable for function and each OUT
argument.
IF unit_test_in.program_type = 'FUNCTION'
THEN
pl_and_mark_used ( qu_test_element_xp.c_return_varname
, return_te_in.data_type_name
, '-- Return value of function'
);
END IF;
IF l_have_out_args
THEN
l_int_index := test_elements_in.FIRST;
WHILE ( l_int_index IS NOT NULL )
LOOP
IF test_elements_in ( l_int_index ).element_type =
qu_test_element_xp.c_argument
AND is_out_arg
( test_elements_in ( l_int_index
).argument_mode
)
THEN
pl_and_mark_used
( qu_test_element_xp.prog_call_varname
( test_elements_in ( l_int_index
).name
)
, substitute
( test_elements_in ( l_int_index
).data_type_name
)
);
END IF;
l_int_index := test_elements_in.NEXT ( l_int_index );
END LOOP;
END IF;
l_int_index := inputs_in.FIRST;
WHILE ( l_int_index IS NOT NULL )
LOOP
IF need_in_declaration ( inputs_in ( l_int_index ))
THEN
pl_and_mark_used
( inputs_in ( l_int_index ).input.argument_alias
, inputs_in ( l_int_index
).test_element.data_type_name
);
END IF;
l_int_index := inputs_in.NEXT ( l_int_index );
END LOOP;
l_oc_index := outcomes_in.FIRST;
WHILE ( l_oc_index IS NOT NULL )
LOOP
IF need_fp_declaration ( outcomes_in ( l_oc_index ))
THEN
pl_and_mark_used
( outcomes_in ( l_oc_index
).RESULT.attribute.argument_alias
, outcomes_in ( l_oc_index
).RESULT.attribute.datatype_declare
);
END IF;
IF need_exp_declaration ( outcomes_in ( l_oc_index ))
THEN
pl_and_mark_used
( outcomes_in ( l_oc_index
).control.attribute.argument_alias
, outcomes_in ( l_oc_index
).control.attribute.datatype_declare
);
END IF;
l_oc_index := outcomes_in.NEXT ( l_oc_index );
END LOOP;
qu_used.clear_used_list ( c_declared_list );
END gen_local_vars;
PROCEDURE generate_setup (
tc_in IN qu_test_case_tp.qu_test_case_rt
, inputs_in IN qu_input_xp.qu_input_tt
, have_setup_out IN OUT BOOLEAN
)
IS
PROCEDURE check_or_put (
action_in IN VARCHAR2
,
(Message over 64k, truncated.)