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

Skip to content

Commit 6fb7778

Browse files
authored
Merge pull request #564 from AlexisGaldamez/new_throws_annotation
New throws annotation
2 parents 953ef6a + 3cb7d76 commit 6fb7778

18 files changed

Lines changed: 521 additions & 25 deletions

source/core/types/ut_executable.tpb

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,10 @@ create or replace type body ut_executable is
6969
l_statement varchar2(4000);
7070
l_status number;
7171
l_cursor_number number;
72-
l_owner varchar2(200) := self.owner_name;
73-
l_object_name varchar2(200) := self.object_name;
74-
l_procedure_name varchar2(200) := self.procedure_name;
75-
7672
l_completed_without_errors boolean := true;
7773
l_start_transaction_id varchar2(250);
7874
l_end_transaction_id varchar2(250);
75+
7976
procedure save_dbms_output is
8077
l_status number;
8178
l_line varchar2(32767);
@@ -103,15 +100,15 @@ create or replace type body ut_executable is
103100
--listener - before call to executable
104101
a_listener.fire_before_event(self.associated_event_name, a_item);
105102

106-
ut_metadata.do_resolve(a_owner => l_owner, a_object => l_object_name, a_procedure_name => l_procedure_name);
103+
ut_metadata.do_resolve(a_owner => self.owner_name, a_object => self.object_name, a_procedure_name => self.procedure_name);
107104

108105
l_statement :=
109106
'declare' || chr(10) ||
110107
' l_error_stack varchar2(32767);' || chr(10) ||
111108
' l_error_backtrace varchar2(32767);' || chr(10) ||
112109
'begin' || chr(10) ||
113110
' begin' || chr(10) ||
114-
' ' || ut_metadata.form_name(l_owner, l_object_name, l_procedure_name) || ';' || chr(10) ||
111+
' ' || ut_metadata.form_name(self.owner_name, self.object_name, self.procedure_name) || ';' || chr(10) ||
115112
' exception' || chr(10) ||
116113
' when others then ' || chr(10) ||
117114
' l_error_stack := dbms_utility.format_error_stack;' || chr(10) ||

source/core/types/ut_executable.tps

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ create or replace type ut_executable authid current_user as object(
3737
*/
3838
member function do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base) return boolean,
3939
member function get_error_stack_trace return varchar2
40-
) final
40+
) not final
4141
/
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
create or replace type body ut_executable_test as
2+
constructor function ut_executable_test(
3+
self in out nocopy ut_executable_test, a_context ut_suite_item,
4+
a_procedure_name varchar2, a_associated_event_name varchar2
5+
) return self as result is
6+
begin
7+
self.associated_event_name := a_associated_event_name;
8+
self.owner_name := a_context.object_owner;
9+
self.object_name := a_context.object_name;
10+
self.procedure_name := a_procedure_name;
11+
return;
12+
end;
13+
14+
member procedure do_execute(
15+
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
16+
a_listener in out nocopy ut_event_listener_base, a_expected_error_codes in ut_varchar2_list := null
17+
) is
18+
l_completed_without_errors boolean;
19+
begin
20+
l_completed_without_errors := self.do_execute(a_item, a_listener, a_expected_error_codes);
21+
end do_execute;
22+
23+
member function do_execute(
24+
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
25+
a_listener in out nocopy ut_event_listener_base, a_expected_error_codes in ut_varchar2_list := null
26+
) return boolean is
27+
l_ut_executable ut_executable;
28+
l_expected_except_message varchar2(4000);
29+
30+
function failed_expec_errnum_message(a_error_stack in varchar2, a_expected_error_codes in ut_varchar2_list) return varchar is
31+
l_actual_error_no integer;
32+
l_expected_error_codes varchar2(4000);
33+
l_list_expect_error_codes ut_varchar2_list;
34+
l_fail_message varchar2(4000);
35+
begin
36+
--Convert the ut_varchar2_list to string to can construct the message
37+
l_expected_error_codes := ut_utils.table_to_clob(a_expected_error_codes, ',');
38+
39+
if a_error_stack is null then
40+
l_fail_message := 'Expected one of exceptions ('||l_expected_error_codes||') but nothing was raised.';
41+
else
42+
l_actual_error_no := regexp_substr(a_error_stack, '^ORA(-[0-9]+)', subexpression=>1);
43+
44+
if l_actual_error_no member of a_expected_error_codes then
45+
l_fail_message := null;
46+
else
47+
l_fail_message := 'Actual: '||l_actual_error_no||' was expected to be one of ('||l_expected_error_codes||')';
48+
end if;
49+
end if;
50+
51+
return l_fail_message;
52+
end;
53+
begin
54+
--Create a ut_executable object and call do_execute after that get the data to know the test's execution result
55+
l_ut_executable := treat(self as ut_executable);
56+
l_ut_executable.do_execute(a_item, a_listener);
57+
self.serveroutput := l_ut_executable.serveroutput;
58+
59+
if a_expected_error_codes is not null and a_expected_error_codes is not empty then
60+
l_expected_except_message := failed_expec_errnum_message(l_ut_executable.error_stack, a_expected_error_codes);
61+
62+
if l_expected_except_message is not null then
63+
ut_expectation_processor.add_expectation_result(
64+
ut_expectation_result(ut_utils.tr_failure, null, self.owner_name||'.'||self.object_name||'.'||self.procedure_name||' '||l_expected_except_message, false)
65+
);
66+
end if;
67+
else
68+
self.error_stack := l_ut_executable.error_stack;
69+
self.error_backtrace := l_ut_executable.error_backtrace;
70+
end if;
71+
72+
return (self.error_stack||self.error_backtrace) is null;
73+
end;
74+
end;
75+
/
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
create or replace type ut_executable_test authid current_user under ut_executable (
2+
/*
3+
utPLSQL - Version 3
4+
Copyright 2016 - 2017 utPLSQL Project
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"):
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
constructor function ut_executable_test(
19+
self in out nocopy ut_executable_test, a_context ut_suite_item,
20+
a_procedure_name varchar2, a_associated_event_name varchar2
21+
) return self as result,
22+
23+
member procedure do_execute(
24+
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
25+
a_listener in out nocopy ut_event_listener_base, a_expected_error_codes in ut_varchar2_list := null
26+
),
27+
28+
member function do_execute(
29+
self in out nocopy ut_executable_test, a_item in out nocopy ut_suite_item,
30+
a_listener in out nocopy ut_event_listener_base, a_expected_error_codes in ut_varchar2_list := null
31+
) return boolean
32+
33+
) final;
34+
/

source/core/types/ut_expectation_result.tpb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ create or replace type body ut_expectation_result is
1616
limitations under the License.
1717
*/
1818

19-
constructor function ut_expectation_result(self in out nocopy ut_expectation_result, a_status integer, a_description varchar2, a_message clob)
20-
return self as result is
19+
constructor function ut_expectation_result(
20+
self in out nocopy ut_expectation_result, a_status integer,
21+
a_description varchar2, a_message clob, a_include_caller_info boolean := true
22+
) return self as result is
2123
begin
2224
self.status := a_status;
2325
self.description := a_description;
2426
self.message := a_message;
25-
if self.status = ut_utils.tr_failure then
27+
if self.status = ut_utils.tr_failure and a_include_caller_info then
2628
self.caller_info := ut_expectation_processor.who_called_expectation(dbms_utility.format_call_stack());
2729
end if;
2830
return;

source/core/types/ut_expectation_result.tps

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ create or replace type ut_expectation_result authid current_user as object(
3333
* The information about the line of code that invoked the expectation
3434
*/
3535
caller_info varchar2(32767),
36-
constructor function ut_expectation_result(self in out nocopy ut_expectation_result, a_status integer, a_description varchar2, a_message clob)
37-
return self as result,
36+
constructor function ut_expectation_result(
37+
self in out nocopy ut_expectation_result, a_status integer,
38+
a_description varchar2, a_message clob, a_include_caller_info boolean := true
39+
) return self as result,
3840
member function get_result_clob(self in ut_expectation_result) return clob,
3941
member function get_result_lines(self in ut_expectation_result) return ut_varchar2_list,
4042
member function result return integer

source/core/types/ut_test.tpb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,20 @@ create or replace type body ut_test as
2020
self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2, a_description varchar2 := null,
2121
a_path varchar2 := null, a_rollback_type integer := null, a_disabled_flag boolean := false,
2222
a_before_each_proc_name varchar2 := null, a_before_test_proc_name varchar2 := null,
23-
a_after_test_proc_name varchar2 := null, a_after_each_proc_name varchar2 := null
23+
a_after_test_proc_name varchar2 := null, a_after_each_proc_name varchar2 := null,
24+
a_expected_error_codes ut_varchar2_list := null
2425
) return self as result is
2526
begin
2627
self.self_type := $$plsql_unit;
2728
self.init(a_object_owner, a_object_name, a_name, a_description, a_path, a_rollback_type, a_disabled_flag);
2829
self.before_each := ut_executable(self, a_before_each_proc_name, ut_utils.gc_before_each);
2930
self.before_test := ut_executable(self, a_before_test_proc_name, ut_utils.gc_before_test);
30-
self.item := ut_executable(self, a_name, ut_utils.gc_test_execute);
31+
self.item := ut_executable_test(self, a_name, ut_utils.gc_test_execute);
3132
self.after_test := ut_executable(self, a_after_test_proc_name, ut_utils.gc_after_test);
3233
self.after_each := ut_executable(self, a_after_each_proc_name, ut_utils.gc_after_each);
3334
self.all_expectations := ut_expectation_results();
3435
self.failed_expectations := ut_expectation_results();
36+
self.expected_error_codes := a_expected_error_codes;
3537
return;
3638
end;
3739

@@ -92,7 +94,7 @@ create or replace type body ut_test as
9294

9395
if l_completed_without_errors then
9496
-- execute the test
95-
self.item.do_execute(self, a_listener);
97+
self.item.do_execute(self, a_listener, self.expected_error_codes);
9698

9799
end if;
98100
-- perform cleanup regardless of the test or setup failure

source/core/types/ut_test.tps

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ create or replace type ut_test under ut_suite_item (
2828
/**
2929
* The Test procedure to be executed
3030
*/
31-
item ut_executable,
31+
item ut_executable_test,
3232
/**
3333
* The procedure to be invoked after invoking the test
3434
* Procedure exists within the same package as the test itself
@@ -55,11 +55,16 @@ create or replace type ut_test under ut_suite_item (
5555
* Will get populated on exceptions in before-all calls
5656
*/
5757
parent_error_stack_trace varchar2(4000),
58+
/**
59+
*Holds the expected error codes list when the user use the annotation throws
60+
*/
61+
expected_error_codes ut_varchar2_list,
5862
constructor function ut_test(
5963
self in out nocopy ut_test, a_object_owner varchar2 := null, a_object_name varchar2, a_name varchar2, a_description varchar2 := null,
6064
a_path varchar2 := null, a_rollback_type integer := null, a_disabled_flag boolean := false,
6165
a_before_each_proc_name varchar2 := null, a_before_test_proc_name varchar2 := null,
62-
a_after_test_proc_name varchar2 := null, a_after_each_proc_name varchar2 := null
66+
a_after_test_proc_name varchar2 := null, a_after_each_proc_name varchar2 := null,
67+
a_expected_error_codes ut_varchar2_list := null
6368
) return self as result,
6469
member function is_valid(self in out nocopy ut_test) return boolean,
6570
member procedure set_beforeeach(self in out nocopy ut_test, a_before_each_proc_name varchar2),

source/core/ut_suite_builder.pkb

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,27 @@ create or replace package body ut_suite_builder is
4141

4242
l_beforetest_procedure varchar2(250 char);
4343
l_aftertest_procedure varchar2(250 char);
44+
45+
l_expected_error_codes ut_varchar2_list;
46+
4447
l_rollback_type integer;
4548
l_displayname varchar2(4000);
4649
function is_last_annotation_for_proc(a_annotations ut_annotations, a_index binary_integer) return boolean is
4750
begin
4851
return a_index = a_annotations.count or a_annotations(a_index).subobject_name != nvl(a_annotations(a_index+1).subobject_name, ' ');
4952
end;
53+
54+
function exception_numbers_list(a_exception_numbers in varchar2) return ut_varchar2_list is
55+
l_exception_number_list ut_varchar2_list;
56+
l_regexp_for_excep_nums varchar2(30) := '^-?[[:digit:]]{1,5}$';
57+
begin
58+
/*the a_expected_error_codes is converted to a ut_varchar2_list after that is trimmed and filtered to left only valid exception numbers*/
59+
l_exception_number_list := ut_utils.string_to_table(a_exception_numbers, ',', 'Y');
60+
l_exception_number_list := ut_utils.trim_list_elements(l_exception_number_list);
61+
l_exception_number_list := ut_utils.filter_list(l_exception_number_list, l_regexp_for_excep_nums);
62+
63+
return l_exception_number_list;
64+
end;
5065
begin
5166
l_suite_rollback := ut_utils.gc_rollback_auto;
5267
for i in 1 .. a_object.annotations.count loop
@@ -71,7 +86,6 @@ create or replace package body ut_suite_builder is
7186
end if;
7287

7388
elsif l_is_suite then
74-
7589
l_proc_name := a_object.annotations(i).subobject_name;
7690

7791
if a_object.annotations(i).name = 'beforeeach' and l_default_setup_proc is null then
@@ -82,14 +96,14 @@ create or replace package body ut_suite_builder is
8296
l_suite_setup_proc := l_proc_name;
8397
elsif a_object.annotations(i).name = 'afterall' and l_suite_teardown_proc is null then
8498
l_suite_teardown_proc := l_proc_name;
85-
86-
8799
elsif a_object.annotations(i).name = 'disabled' then
88100
l_test_disabled := true;
89101
elsif a_object.annotations(i).name = 'beforetest' then
90102
l_beforetest_procedure := a_object.annotations(i).text;
91103
elsif a_object.annotations(i).name = 'aftertest' then
92104
l_aftertest_procedure := a_object.annotations(i).text;
105+
elsif a_object.annotations(i).name = 'throws' then
106+
l_expected_error_codes := exception_numbers_list(a_object.annotations(i).text);
93107
elsif a_object.annotations(i).name in ('displayname','test') then
94108
l_displayname := a_object.annotations(i).text;
95109
if a_object.annotations(i).name = 'test' then
@@ -113,13 +127,15 @@ create or replace package body ut_suite_builder is
113127
,a_rollback_type => coalesce(l_rollback_type, l_suite_rollback)
114128
,a_disabled_flag => l_test_disabled
115129
,a_before_test_proc_name => l_beforetest_procedure
116-
,a_after_test_proc_name => l_aftertest_procedure);
130+
,a_after_test_proc_name => l_aftertest_procedure
131+
,a_expected_error_codes => l_expected_error_codes);
117132

118133
l_is_test := false;
119134
l_test_disabled := false;
120135
l_aftertest_procedure := null;
121136
l_beforetest_procedure := null;
122137
l_rollback_type := null;
138+
l_expected_error_codes := null;
123139
end if;
124140

125141
end if;

source/core/ut_utils.pkb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,5 +492,43 @@ procedure append_to_clob(a_src_clob in out nocopy clob, a_clob_table t_clob_tab,
492492
return to_char(a_value, gc_number_format, 'NLS_NUMERIC_CHARACTERS=''. ''');
493493
end;
494494

495+
function trim_list_elements(a_list IN ut_varchar2_list, a_regexp_to_trim in varchar2 default '[:space:]') return ut_varchar2_list is
496+
l_trimmed_list ut_varchar2_list;
497+
l_index integer;
498+
begin
499+
if a_list is not null then
500+
l_trimmed_list := ut_varchar2_list();
501+
l_index := a_list.first;
502+
503+
while (l_index is not null) loop
504+
l_trimmed_list.extend;
505+
l_trimmed_list(l_trimmed_list.count) := regexp_replace(a_list(l_index), '(^['||a_regexp_to_trim||']*)|(['||a_regexp_to_trim||']*$)');
506+
l_index := a_list.next(l_index);
507+
end loop;
508+
end if;
509+
510+
return l_trimmed_list;
511+
end;
512+
513+
function filter_list(a_list IN ut_varchar2_list, a_regexp_filter in varchar2) return ut_varchar2_list is
514+
l_filtered_list ut_varchar2_list;
515+
l_index integer;
516+
begin
517+
if a_list is not null then
518+
l_filtered_list := ut_varchar2_list();
519+
l_index := a_list.first;
520+
521+
while (l_index is not null) loop
522+
if regexp_like(a_list(l_index), a_regexp_filter) then
523+
l_filtered_list.extend;
524+
l_filtered_list(l_filtered_list.count) := a_list(l_index);
525+
end if;
526+
l_index := a_list.next(l_index);
527+
end loop;
528+
end if;
529+
530+
return l_filtered_list;
531+
end;
532+
495533
end ut_utils;
496534
/

0 commit comments

Comments
 (0)