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

Skip to content

Commit 716369a

Browse files
authored
Merge pull request #226 from Pazus/enchance-reporting
Enhanced reporting to include dbms output and improve error reporting. Refactoring and code cleanup.
2 parents 9096940 + 30ba62e commit 716369a

46 files changed

Lines changed: 566 additions & 424 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

client_source/sqlplus/ut_run.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ set define &
111111
/*
112112
* Make SQLPlus parameters optional and pass parameters call to param_list variable
113113
*/
114-
@@define_params_variable.sql.tmp
114+
@define_params_variable.sql.tmp
115115

116116

117117

@@ -293,8 +293,8 @@ begin
293293
p(' v_reporter.reporter_id := '''||l_reporter_id||''';');
294294
p(' v_reporters_list.extend; v_reporters_list(v_reporters_list.last) := v_reporter;');
295295
end loop;
296+
close :l_run_params_cur;
296297
end if;
297-
close :l_run_params_cur;
298298
p( ' ut_runner.run( ut_varchar2_list('||:l_paths||'), v_reporters_list, a_color_console => '||:l_color_enabled||' );');
299299
p( 'end;');
300300
p( '/');

source/api/ut.pkb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ create or replace package body ut is
8484

8585
procedure fail(a_message in varchar2) is
8686
begin
87-
ut_assert_processor.report_error(a_message);
87+
ut_assert_processor.report_failure(a_message);
8888
end;
8989

9090
procedure run_autonomous(a_paths ut_varchar2_list, a_reporter ut_reporter_base, a_color_console integer) is

source/core/coverage/ut_coverage.pkb

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,57 +39,85 @@ create or replace package body ut_coverage is
3939
return l_result;
4040
end;
4141

42+
-- The source query has two important transformations done in it.
43+
-- the flag: to_be_skipped ='Y' is set for a line of code that is badly reported by DBMS_PROFILER as executed 0 times.
44+
-- This includes lines that are:
45+
-- - PACKAGE, PROCEDURE, FUNCTION definition line,
46+
-- - BEGIN, END of a block
47+
-- Another transformation is adjustment of line number for TRIGGER body.
48+
-- DBMS_PROFILER is reporting line numbers for triggers not as defined in DBA_SOURCE, its usign line numbers as defined in DBA_TRIGGERS
49+
-- the DBA_TRIGGERS does not contain the trigger specification lines, only lines that define the trigger body.
50+
-- the query adjusts the line numbers for triggers by finding first occurrence of begin|declare|compound in the trigger body line.
51+
-- The subquery is optimized by:
52+
-- - COALESCE function -> it will execute only for TRIGGERS
53+
-- - scalar subquery cache -> it will only execute once for one trigger source code.
4254
function get_sources_query return varchar2 is
4355
l_result varchar2(32767);
56+
l_full_name varchar2(100);
4457
begin
45-
l_result := 'insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)';
4658
if g_file_mappings is not null then
47-
l_result := 'insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
48-
select f.file_name, s.owner,s.name,s.line,s.text,';
59+
l_full_name := 'f.file_name';
4960
else
50-
l_result := 'insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
51-
select lower(s.owner||''.''||s.name) as file_name, s.owner,s.name,s.line,s.text,';
61+
l_full_name := 'lower(s.owner||''.''||s.name)';
5262
end if;
53-
l_result := l_result || q'[
54-
case
55-
when
56-
-- to avoid execution of regexp_like on every line
57-
-- first do a rough check for existence of search pattern keyword
58-
(lower(s.text) like '%procedure%'
59-
or lower(s.text) like '%function%'
60-
or lower(s.text) like '%begin%'
61-
or lower(s.text) like '%end%'
62-
or lower(s.text) like '%package%'
63-
) and
64-
regexp_like(
65-
s.text,
66-
'^\s*(((not)?\s*(overriding|final|instantiable)\s*)*(static|constructor|member)?\s*(procedure|function)|package(\s+body)|begin|end(\s+\S+)?\s*;)', 'i'
67-
)
68-
then 'Y'
69-
end as to_be_skipped
70-
from all_source s]';
63+
l_result := '
64+
insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
65+
select *
66+
from (
67+
select '||l_full_name||q'[,
68+
s.owner,
69+
s.name,
70+
s.line -
71+
coalesce(
72+
case when type!='TRIGGER' then 0 end,
73+
(select min(t.line) - 1
74+
from dba_source t
75+
where t.owner = s.owner and t.type = s.type and t.name = s.name
76+
and regexp_like( t.text, '\w*(begin|declare|compound).*','i'))
77+
) as line,
78+
s.text,
79+
case
80+
when
81+
-- to avoid execution of regexp_like on every line
82+
-- first do a rough check for existence of search pattern keyword
83+
(lower(s.text) like '%procedure%'
84+
or lower(s.text) like '%function%'
85+
or lower(s.text) like '%begin%'
86+
or lower(s.text) like '%end%'
87+
or lower(s.text) like '%package%'
88+
) and
89+
regexp_like(
90+
s.text,
91+
'^\s*(((not)?\s*(overriding|final|instantiable)\s*)*(static|constructor|member)?\s*(procedure|function)|package(\s+body)|begin|end(\s+\S+)?\s*;)', 'i'
92+
)
93+
then 'Y'
94+
end as to_be_skipped
95+
from all_source s]';
7196
if g_file_mappings is not null then
7297
l_result := l_result || '
73-
join table(:g_file_mappings) f
74-
on s.name = f.object_name
75-
and s.type = f.object_type
76-
and s.owner = f.object_owner
77-
where 1 = 1';
98+
join table(:g_file_mappings) f
99+
on s.name = f.object_name
100+
and s.type = f.object_type
101+
and s.owner = f.object_owner
102+
where 1 = 1';
78103
else
79104
l_result := l_result || '
80-
where s.owner in (select upper(t.column_value) from table(:l_schema_names) t)';
105+
where s.owner in (select upper(t.column_value) from table(:l_schema_names) t)';
81106
end if;
82107
l_result := l_result || q'[
83-
and s.type not in ('PACKAGE', 'TYPE')
84-
--Exclude calls to utPLSQL framework, Unit Test packages and objects from a_exclude_list parameter of coverage reporter
85-
and (s.owner, s.name) not in (select el.owner, el.name from table(:l_skipped_objects) el)]';
108+
and s.type not in ('PACKAGE', 'TYPE')
109+
--Exclude calls to utPLSQL framework, Unit Test packages and objects from a_exclude_list parameter of coverage reporter
110+
and (s.owner, s.name) not in (select el.owner, el.name from table(:l_skipped_objects) el)]';
86111
if g_include_list is null then
87112
l_result := l_result || '
88-
and :g_include_list is null';
113+
and :g_include_list is null';
89114
else
90115
l_result := l_result || '
91-
and (s.owner, s.name) in (select il.owner, il.name from table(:g_include_list) il)';
116+
and (s.owner, s.name) in (select il.owner, il.name from table(:g_include_list) il)';
92117
end if;
118+
l_result := l_result || '
119+
)
120+
where line > 0';
93121
return l_result;
94122
end;
95123
/**

source/core/types/ut_assert_result.tpb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,9 @@ create or replace type body ut_assert_result is
6262
if a_clob is not null and l_text is not null then
6363
l_text := chr(10) || l_text;
6464
end if;
65-
if l_text is not null then
66-
dbms_lob.writeappend(a_clob, length(l_text), l_text);
67-
end if;
65+
ut_utils.append_to_clob(a_clob, l_text);
6866
end;
6967
begin
70-
dbms_lob.createtemporary(l_result, true);
7168
if self.result != ut_utils.tr_success or self.error_message is not null then
7269
if self.message is not null then
7370
add_text_line(l_result, ' expectation description: ', self.message);

source/core/types/ut_executable.tpb

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,22 @@ create or replace type body ut_executable is
3333
return self.procedure_name is not null and self.object_name is not null;
3434
end;
3535

36-
member function is_valid return boolean is
37-
l_result boolean := true;
36+
member function is_valid(self in out nocopy ut_executable) return boolean is
37+
l_result boolean := false;
38+
l_message_part varchar2(4000) := 'Call params for ' || self.associated_event_name || ' are not valid: ';
3839
begin
3940

4041
if self.object_name is null then
41-
l_result := false;
42-
ut_assert_processor.report_error('Call params for ' || self.associated_event_name || ' are not valid: package is not defined');
43-
end if;
44-
45-
if self.procedure_name is null then
46-
l_result := false;
47-
ut_assert_processor.report_error('Call params for ' || self.associated_event_name || ' are not valid: procedure is not defined');
48-
end if;
49-
50-
if l_result and not ut_metadata.package_valid(self.owner_name, self.object_name) then
51-
l_result := false;
52-
ut_assert_processor.report_error('Call params for ' || self.associated_event_name ||
53-
' are not valid: package does not exist or is invalid: ' ||nvl(self.owner_name, '<missing schema name>')||'.'||
54-
nvl(self.object_name, '<missing package name>'));
55-
end if;
56-
57-
if l_result and not ut_metadata.procedure_exists(self.owner_name, self.object_name, self.procedure_name) then
58-
l_result := false;
59-
ut_assert_processor.report_error('Call params for ' || self.associated_event_name || ' are not valid: package missing ' ||
60-
' procedure ' || self.object_name || '.' ||
61-
nvl(self.procedure_name, '<missing procedure name>'));
42+
self.error_stack := l_message_part || 'package is not defined';
43+
elsif not ut_metadata.package_valid(self.owner_name, self.object_name) then
44+
self.error_stack := l_message_part || 'package does not exist or is invalid: ' ||upper(self.owner_name||'.'||self.object_name);
45+
elsif self.procedure_name is null then
46+
self.error_stack := l_message_part || 'procedure is not defined';
47+
elsif not ut_metadata.procedure_exists(self.owner_name, self.object_name, self.procedure_name) then
48+
self.error_stack := l_message_part || 'package missing procedure '
49+
|| upper(self.owner_name || '.' || self.object_name || '.' ||self.procedure_name);
50+
else
51+
l_result := true;
6252
end if;
6353

6454
return l_result;
@@ -85,28 +75,16 @@ create or replace type body ut_executable is
8575

8676
l_completed_without_errors boolean := true;
8777

88-
function process_errors_from_call(a_error_stack varchar2, a_error_backtrace varchar2) return boolean is
89-
l_errors_stack_trace varchar2(32767) := rtrim(a_error_stack||a_error_backtrace, chr(10));
90-
begin
91-
if l_errors_stack_trace is not null then
92-
ut_utils.debug_log('test method failed- ' ||l_errors_stack_trace );
93-
ut_assert_processor.report_error( l_errors_stack_trace );
94-
return false;
95-
else
96-
return true;
97-
end if;
98-
end;
99-
10078
procedure save_dbms_output is
10179
l_status number;
10280
l_line varchar2(32767);
10381
begin
10482
dbms_lob.createtemporary(self.serveroutput, true, dur => dbms_lob.session);
105-
83+
10684
loop
10785
dbms_output.get_line(line => l_line, status => l_status);
10886
exit when l_status = 1;
109-
87+
11088
dbms_lob.writeappend(lob_loc => self.serveroutput,
11189
amount => length(l_line),
11290
buffer => l_line);
@@ -153,16 +131,20 @@ create or replace type body ut_executable is
153131
dbms_sql.variable_value(l_cursor_number, 'a_error_stack', self.error_stack);
154132
dbms_sql.variable_value(l_cursor_number, 'a_error_backtrace', self.error_backtrace);
155133
dbms_sql.close_cursor(l_cursor_number);
156-
134+
157135
save_dbms_output;
158136

159-
l_completed_without_errors := process_errors_from_call(self.error_stack, self.error_backtrace);
137+
l_completed_without_errors := (self.error_stack||self.error_backtrace) is null;
160138

161139
a_listener.fire_after_event(self.associated_event_name, a_item);
162140
--listener - after call to executable
163141
end if;
164142
return l_completed_without_errors;
165143
end do_execute;
166144

145+
member function get_error_stack_trace return varchar2 is
146+
begin
147+
return rtrim(self.error_stack||self.error_backtrace, chr(10));
148+
end;
167149
end;
168150
/

source/core/types/ut_executable.tps

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ create or replace type ut_executable authid current_user as object(
2626
error_stack varchar2(4000),
2727
serveroutput clob,
2828
constructor function ut_executable( self in out nocopy ut_executable, a_context ut_suite_item, a_procedure_name varchar2, a_associated_event_name varchar2) return self as result,
29-
member function is_valid return boolean,
29+
member function is_valid(self in out nocopy ut_executable) return boolean,
3030
member function is_defined return boolean,
3131
member function form_name return varchar2,
3232
member procedure 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),
@@ -35,6 +35,7 @@ create or replace type ut_executable authid current_user as object(
3535
* returns true if executed without exceptions
3636
* returns false if exceptions were raised
3737
*/
38-
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
38+
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,
39+
member function get_error_stack_trace return varchar2
3940
) final
4041
/

source/core/types/ut_logical_suite.tpb

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ create or replace type body ut_logical_suite as
2626
return;
2727
end;
2828

29-
member function is_valid return boolean is
29+
member function is_valid(self in out nocopy ut_logical_suite) return boolean is
3030
begin
3131
return true;
3232
end;
@@ -58,14 +58,14 @@ create or replace type body ut_logical_suite as
5858
l_completed_without_errors boolean;
5959
begin
6060
ut_utils.debug_log('ut_logical_suite.execute');
61-
62-
a_listener.fire_before_event(ut_utils.gc_suite,self);
63-
self.start_time := current_timestamp;
6461

65-
if self.get_ignore_flag() then
66-
self.result := ut_utils.tr_ignore;
62+
a_listener.fire_before_event(ut_utils.gc_suite,self);
63+
self.start_time := current_timestamp;
64+
65+
if self.get_disabled_flag() then
66+
self.result := ut_utils.tr_disabled;
6767
self.end_time := self.start_time;
68-
ut_utils.debug_log('ut_logical_suite.execute - ignored');
68+
ut_utils.debug_log('ut_logical_suite.execute - disabled');
6969
else
7070

7171
self.start_time := current_timestamp;
@@ -79,7 +79,7 @@ create or replace type body ut_logical_suite as
7979
self.end_time := current_timestamp;
8080

8181
end if;
82-
82+
8383
a_listener.fire_after_event(ut_utils.gc_suite,self);
8484

8585
return l_completed_without_errors;
@@ -100,20 +100,30 @@ create or replace type body ut_logical_suite as
100100

101101
self.result := l_result;
102102
end;
103-
104-
overriding member procedure fail(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2) is
103+
104+
overriding member procedure mark_as_errored(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base, a_error_stack_trace varchar2) is
105105
begin
106106
ut_utils.debug_log('ut_logical_suite.fail');
107107
a_listener.fire_before_event(ut_utils.gc_suite, self);
108108
self.start_time := current_timestamp;
109109
for i in 1 .. self.items.count loop
110110
-- execute the item (test or suite)
111-
self.items(i).fail(a_listener,a_failure_msg);
111+
self.items(i).mark_as_errored(a_listener, a_error_stack_trace);
112112
end loop;
113113
self.calc_execution_result();
114114
self.end_time := self.start_time;
115115
a_listener.fire_after_event(ut_utils.gc_suite, self);
116-
end;
116+
end;
117+
118+
overriding member function get_error_stack_traces return ut_varchar2_list is
119+
begin
120+
return ut_varchar2_list();
121+
end;
122+
123+
overriding member function get_serveroutputs return clob is
124+
begin
125+
return null;
126+
end;
117127

118128
end;
119129
/

source/core/types/ut_logical_suite.tps

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ create or replace type ut_logical_suite under ut_suite_item (
2424
constructor function ut_logical_suite(
2525
self in out nocopy ut_logical_suite,a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_description varchar2 := null, a_path varchar2
2626
) return self as result,
27-
member function is_valid return boolean,
27+
member function is_valid(self in out nocopy ut_logical_suite) return boolean,
2828
/**
2929
* Finds the item in the suite by it's name and returns the item index
3030
*/
3131
member function item_index(a_name varchar2) return pls_integer,
3232
member procedure add_item(self in out nocopy ut_logical_suite, a_item ut_suite_item),
3333
overriding member function do_execute(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base) return boolean,
3434
overriding member procedure calc_execution_result(self in out nocopy ut_logical_suite),
35-
overriding member procedure fail(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base, a_failure_msg varchar2)
35+
overriding member procedure mark_as_errored(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base, a_error_stack_trace varchar2),
36+
overriding member function get_error_stack_traces return ut_varchar2_list,
37+
overriding member function get_serveroutputs return clob
3638
) not final
3739
/

source/core/types/ut_reporter_base.tpb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ create or replace type body ut_reporter_base is
2929
ut_output_buffer.send_line(self,a_text);
3030
end;
3131

32+
member procedure print_clob(self in out nocopy ut_reporter_base, a_clob clob) is
33+
l_lines ut_varchar2_list;
34+
begin
35+
if a_clob is not null and dbms_lob.getlength(a_clob) > 0 then
36+
l_lines := ut_utils.clob_to_table(a_clob);
37+
for i in 1 .. l_lines.count loop
38+
self.print_text(l_lines(i));
39+
end loop;
40+
end if;
41+
end;
42+
3243
-- run hooks
3344
member procedure before_calling_run(self in out nocopy ut_reporter_base, a_run in ut_run) is
3445
begin

source/core/types/ut_reporter_base.tps

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ create or replace type ut_reporter_base authid current_user as object(
2222

2323
member procedure print_text(self in out nocopy ut_reporter_base, a_text varchar2),
2424

25+
member procedure print_clob(self in out nocopy ut_reporter_base, a_clob clob),
26+
2527
-- run hooks
2628
member procedure before_calling_run(self in out nocopy ut_reporter_base, a_run in ut_run),
2729

0 commit comments

Comments
 (0)