Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8e43a08

Browse files
committed
Moved validation of --%throws annotation values.
Now the validation is executed at runtime, when the tests is executed. This resolves issues related to the fact that some package constants may not exist or be valid at suite parse time. In such scenario, the annotations continued to be ignored despite the fact that package constants were valid at test runtime. With this change, tests can now have `--throws` annotations referencing constants that are undefined at compile time. Resolves #1033
1 parent 33f5152 commit 8e43a08

13 files changed

Lines changed: 390 additions & 388 deletions

source/core/types/ut_executable_test.tpb

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ create or replace type body ut_executable_test as
3131

3232
member procedure do_execute(
3333
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
34-
a_expected_error_codes in ut_integer_list
34+
a_expected_error_codes in ut_varchar2_rows
3535
) is
3636
l_completed_without_errors boolean;
3737
begin
@@ -40,10 +40,114 @@ create or replace type body ut_executable_test as
4040

4141
member function do_execute(
4242
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
43-
a_expected_error_codes in ut_integer_list
43+
a_expected_error_codes in ut_varchar2_rows
4444
) return boolean is
4545
l_expected_except_message varchar2(4000);
46+
l_expected_error_numbers ut_integer_list;
4647

48+
function build_exception_numbers_list(
49+
a_item in out nocopy ut_suite_item,
50+
a_expected_error_codes in ut_varchar2_rows
51+
) return ut_integer_list is
52+
l_exception_number integer;
53+
l_exception_number_list ut_integer_list := ut_integer_list();
54+
c_regexp_for_exception_no constant varchar2(30) := '^-?[[:digit:]]{1,5}$';
55+
56+
c_integer_exception constant varchar2(1) := 'I';
57+
c_named_exception constant varchar2(1) := 'N';
58+
59+
function is_valid_qualified_name (a_name varchar2) return boolean is
60+
l_name varchar2(500);
61+
begin
62+
l_name := dbms_assert.qualified_sql_name(a_name);
63+
return true;
64+
exception when others then
65+
return false;
66+
end;
67+
68+
function check_exception_type(a_exception_name in varchar2) return varchar2 is
69+
l_exception_type varchar2(50);
70+
begin
71+
--check if it is a predefined exception
72+
begin
73+
execute immediate 'begin null; exception when '||a_exception_name||' then null; end;';
74+
l_exception_type := c_named_exception;
75+
exception
76+
when others then
77+
if dbms_utility.format_error_stack() like '%PLS-00485%' then
78+
declare
79+
e_invalid_number exception;
80+
pragma exception_init ( e_invalid_number, -6502 );
81+
begin
82+
execute immediate 'declare x integer := '||a_exception_name||'; begin null; end;';
83+
l_exception_type := c_integer_exception;
84+
exception
85+
when others then
86+
null;
87+
end;
88+
end if;
89+
end;
90+
return l_exception_type;
91+
end;
92+
93+
function get_exception_number (a_exception_var in varchar2) return integer is
94+
l_exc_no integer;
95+
l_exc_type varchar2(50);
96+
function remap_no_data_found (a_number integer) return integer is
97+
begin
98+
return case a_number when 100 then -1403 else a_number end;
99+
end;
100+
begin
101+
l_exc_type := check_exception_type(a_exception_var);
102+
103+
execute immediate
104+
case l_exc_type
105+
when c_integer_exception then
106+
'declare l_exception number; begin :l_exception := '||a_exception_var||'; end;'
107+
when c_named_exception then
108+
'begin raise '||a_exception_var||'; exception when others then :l_exception := sqlcode; end;'
109+
else
110+
'begin :l_exception := null; end;'
111+
end
112+
using out l_exc_no;
113+
114+
return remap_no_data_found(l_exc_no);
115+
end;
116+
117+
begin
118+
if a_expected_error_codes is not empty then
119+
for i in 1 .. a_expected_error_codes.count loop
120+
/**
121+
* Check if its a valid qualified name and if so try to resolve name to an exception number
122+
*/
123+
if is_valid_qualified_name(a_expected_error_codes(i)) then
124+
l_exception_number := get_exception_number(a_expected_error_codes(i));
125+
elsif regexp_like(a_expected_error_codes(i), c_regexp_for_exception_no) then
126+
l_exception_number := a_expected_error_codes(i);
127+
end if;
128+
129+
if l_exception_number is null then
130+
a_item.put_warning(
131+
'Invalid parameter value "'||a_expected_error_codes(i)||'" for "--%throws" annotation. Parameter ignored.',
132+
self.procedure_name,
133+
a_item.line_no
134+
);
135+
elsif l_exception_number >= 0 then
136+
a_item.put_warning(
137+
'Invalid parameter value "'||a_expected_error_codes(i)||'" for "--%throws" annotation. Exception value must be a negative integer. Parameter ignored.',
138+
self.procedure_name,
139+
a_item.line_no
140+
);
141+
else
142+
l_exception_number_list.extend;
143+
l_exception_number_list(l_exception_number_list.last) := l_exception_number;
144+
end if;
145+
l_exception_number := null;
146+
end loop;
147+
end if;
148+
149+
return l_exception_number_list;
150+
end;
47151
function failed_expec_errnum_message(a_expected_error_codes in ut_integer_list) return varchar is
48152
l_actual_error_no integer;
49153
l_expected_error_codes varchar2(4000);
@@ -72,9 +176,9 @@ create or replace type body ut_executable_test as
72176
begin
73177
--Create a ut_executable object and call do_execute after that get the data to know the test's execution result
74178
self.do_execute(a_item);
75-
76-
if a_expected_error_codes is not null and a_expected_error_codes is not empty then
77-
l_expected_except_message := failed_expec_errnum_message(a_expected_error_codes);
179+
l_expected_error_numbers := build_exception_numbers_list(a_item, a_expected_error_codes);
180+
if l_expected_error_numbers is not null and l_expected_error_numbers is not empty then
181+
l_expected_except_message := failed_expec_errnum_message( l_expected_error_numbers );
78182

79183
if l_expected_except_message is not null then
80184
ut_expectation_processor.add_expectation_result(

source/core/types/ut_executable_test.tps

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ create or replace type ut_executable_test authid current_user under ut_executabl
2222

2323
member procedure do_execute(
2424
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
25-
a_expected_error_codes in ut_integer_list
25+
a_expected_error_codes in ut_varchar2_rows
2626
),
2727

2828
member function do_execute(
2929
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
30-
a_expected_error_codes in ut_integer_list
30+
a_expected_error_codes in ut_varchar2_rows
3131
) return boolean
3232

3333
) final;

source/core/types/ut_suite_cache_row.tps

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ create type ut_suite_cache_row as object (
3333
before_test_list ut_executables,
3434
after_each_list ut_executables,
3535
after_test_list ut_executables,
36-
expected_error_codes ut_integer_list,
36+
expected_error_codes ut_varchar2_rows,
3737
tags ut_varchar2_rows,
3838
item ut_executable_test
3939
)

source/core/types/ut_suite_item.tpb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ create or replace type body ut_suite_item as
9797
self.results_count.increase_warning_count;
9898
end;
9999

100+
member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2, a_procedure_name varchar2, a_line_no integer) is
101+
l_result varchar2(1000);
102+
begin
103+
l_result := self.object_owner || '.' || self.object_name ;
104+
if a_procedure_name is not null then
105+
l_result := l_result || '.' || a_procedure_name ;
106+
end if;
107+
put_warning( a_message || chr( 10 ) || 'at package "' || upper(l_result) || '", line ' || a_line_no );
108+
end;
109+
100110
member function get_transaction_invalidators return ut_varchar2_list is
101111
begin
102112
return transaction_invalidators;

source/core/types/ut_suite_item.tps

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ create or replace type ut_suite_item force under ut_event_item (
8484
not instantiable member procedure mark_as_errored(self in out nocopy ut_suite_item, a_error_stack_trace varchar2),
8585
not instantiable member function get_error_stack_traces return ut_varchar2_list,
8686
not instantiable member function get_serveroutputs return clob,
87-
member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2)
87+
member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2),
88+
member procedure put_warning(self in out nocopy ut_suite_item, a_message varchar2, a_procedure_name varchar2, a_line_no integer)
8889
)
8990
not final not instantiable
9091
/

source/core/types/ut_test.tpb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ create or replace type body ut_test as
1818

1919
constructor function ut_test(
2020
self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2,
21-
a_line_no integer, a_expected_error_codes ut_integer_list := null, a_tags ut_varchar2_rows := null
21+
a_line_no integer, a_expected_error_codes ut_varchar2_rows := null, a_tags ut_varchar2_rows := null
2222
) return self as result is
2323
begin
2424
self.self_type := $$plsql_unit;

source/core/types/ut_test.tps

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ create or replace type ut_test force under ut_suite_item (
5454
/**
5555
*Holds the expected error codes list when the user use the annotation throws
5656
*/
57-
expected_error_codes ut_integer_list,
57+
expected_error_codes ut_varchar2_rows,
5858
constructor function ut_test(
5959
self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2,
60-
a_line_no integer, a_expected_error_codes ut_integer_list := null, a_tags ut_varchar2_rows := null
60+
a_line_no integer, a_expected_error_codes ut_varchar2_rows := null, a_tags ut_varchar2_rows := null
6161
) return self as result,
6262
overriding member procedure mark_as_skipped(self in out nocopy ut_test),
6363
overriding member function do_execute(self in out nocopy ut_test) return boolean,

0 commit comments

Comments
 (0)