Skip to content

Commit 8797c84

Browse files
committed
Reworked coverage, to accept file list with mappings or file list with mapping rules (regex).
Extended coverage to output file names mapped to objects, if file names are provided. Added support for include and exclude objects list.
1 parent d34ab05 commit 8797c84

20 files changed

Lines changed: 569 additions & 111 deletions

source/api/ut_runner.pkb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ create or replace package body ut_runner is
3030
else
3131
l_listener := ut_event_listener(a_reporters);
3232
end if;
33-
l_items_to_run := ut_run( ut_suite_manager.configure_execution_by_path(a_paths) );
33+
l_items_to_run := ut_run( ut_suite_manager.configure_execution_by_path(a_paths), a_paths );
3434
l_items_to_run.do_execute(l_listener);
3535

3636
ut_output_buffer.close(l_listener.reporters);

source/core/coverage/ut_coverage.pkb

Lines changed: 172 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,118 @@ create or replace package body ut_coverage is
1717
*/
1818

1919
g_skipped_objects ut_object_names;
20+
g_schema_names ut_varchar2_list;
21+
g_include_list ut_object_names;
22+
g_exclude_list ut_object_names;
23+
g_file_mappings ut_coverage_file_mappings;
24+
25+
26+
/**
27+
* Private functions
28+
*/
29+
function to_ut_object_list( a_names ut_varchar2_list) return ut_object_names is
30+
l_result ut_object_names;
31+
begin
32+
if a_names is not null then
33+
l_result := ut_object_names();
34+
for i in 1 .. a_names.count loop
35+
l_result.extend;
36+
l_result(l_result.last) := ut_object_name(a_names(i));
37+
end loop;
38+
end if;
39+
return l_result;
40+
end;
41+
42+
/**
43+
* Public functions
44+
*/
45+
function default_file_to_obj_type_map return ut_key_value_pairs is
46+
begin
47+
return ut_key_value_pairs(
48+
ut_key_value_pair('tpb', 'TYPE BODY'),
49+
ut_key_value_pair('pkb', 'PACKAGE BODY'),
50+
ut_key_value_pair('trg', 'TRIGGER')
51+
);
52+
end;
53+
54+
function build_file_mappings(
55+
a_file_paths ut_varchar2_list, a_file_to_object_type_mapping ut_key_value_pairs,
56+
a_regex_pattern varchar2, a_object_owner_subexpression positive, a_object_name_subexpression positive, a_object_type_subexpression positive
57+
) return ut_coverage_file_mappings is
58+
type tt_key_values is table of varchar2(4000) index by varchar2(4000);
59+
l_key_values tt_key_values;
60+
l_mappings ut_coverage_file_mappings;
61+
l_mapping ut_coverage_file_mapping;
62+
l_object_type_key varchar2(4000);
63+
l_object_type varchar2(4000);
64+
l_file_to_object_type_mapping ut_key_value_pairs;
65+
begin
66+
l_file_to_object_type_mapping := nvl(a_file_to_object_type_mapping, default_file_to_obj_type_map());
67+
for i in 1 .. l_file_to_object_type_mapping.count loop
68+
l_key_values(upper(l_file_to_object_type_mapping(i).key)) := l_file_to_object_type_mapping(i).value;
69+
end loop;
70+
if a_file_paths is not null then
71+
l_mappings := ut_coverage_file_mappings();
72+
for i in 1 .. a_file_paths.count loop
73+
l_object_type_key := upper(regexp_substr(a_file_paths(i), a_regex_pattern,1,1,'i',a_object_type_subexpression));
74+
if l_key_values.exists(l_object_type_key) then
75+
l_object_type := l_key_values(l_object_type_key);
76+
else
77+
l_object_type := null;
78+
end if;
79+
l_mapping := ut_coverage_file_mapping(
80+
file_name => a_file_paths(i),
81+
object_owner => nvl(
82+
upper(regexp_substr(a_file_paths(i), a_regex_pattern, 1, 1, 'i', a_object_owner_subexpression))
83+
, sys_context('USERENV', 'CURRENT_SCHEMA')
84+
),
85+
object_name => upper(regexp_substr(a_file_paths(i), a_regex_pattern, 1, 1, 'i', a_object_name_subexpression)),
86+
object_type => l_object_type
87+
);
88+
l_mappings.extend();
89+
l_mappings(l_mappings.last) := l_mapping;
90+
end loop;
91+
end if;
92+
return l_mappings;
93+
end;
2094

2195
function get_coverage_id return integer is
2296
begin
2397
return ut_coverage_helper.get_coverage_id;
2498
end;
2599

100+
function get_include_schema_names return ut_varchar2_list is
101+
begin
102+
return g_schema_names;
103+
end;
104+
105+
procedure set_include_schema_names(a_schema_names ut_varchar2_list) is
106+
begin
107+
g_schema_names := a_schema_names;
108+
end;
109+
110+
procedure init(
111+
a_schema_names ut_varchar2_list,
112+
a_include_object_list ut_varchar2_list,
113+
a_exclude_object_list ut_varchar2_list
114+
) is
115+
begin
116+
g_schema_names := a_schema_names;
117+
g_include_list := to_ut_object_list(a_include_object_list);
118+
g_exclude_list := to_ut_object_list(a_exclude_object_list);
119+
end;
120+
121+
procedure init(
122+
a_file_mappings ut_coverage_file_mappings,
123+
a_include_object_list ut_varchar2_list,
124+
a_exclude_object_list ut_varchar2_list
125+
) is
126+
begin
127+
g_include_list := to_ut_object_list(a_include_object_list);
128+
g_exclude_list := to_ut_object_list(a_exclude_object_list);
129+
g_file_mappings := a_file_mappings;
130+
end;
131+
26132
function coverage_start return integer is
27133
begin
28134
g_skipped_objects := ut_object_names();
@@ -32,7 +138,7 @@ create or replace package body ut_coverage is
32138
procedure coverage_start is
33139
l_coverage_id integer;
34140
begin
35-
l_coverage_id := coverage_start;
141+
l_coverage_id := coverage_start();
36142
end;
37143

38144
procedure coverage_start_develop is
@@ -61,16 +167,16 @@ create or replace package body ut_coverage is
61167
ut_coverage_helper.coverage_stop();
62168
end;
63169

64-
procedure skip_coverage_for(a_object ut_object_name) is
170+
procedure skip_coverage_for(a_owner varchar2, a_name varchar2) is
65171
begin
66172
if g_skipped_objects is null then
67173
g_skipped_objects := ut_object_names();
68174
end if;
69-
g_skipped_objects.extend;
70-
g_skipped_objects(g_skipped_objects.last) := a_object;
175+
g_skipped_objects.extend;
176+
g_skipped_objects(g_skipped_objects.last) := ut_object_name(a_owner, a_name);
71177
end;
72178

73-
function get_coverage_data(a_schema_names ut_varchar2_list) return t_coverage is
179+
function get_coverage_data return t_coverage is
74180

75181
pragma autonomous_transaction;
76182

@@ -88,6 +194,7 @@ create or replace package body ut_coverage is
88194
type t_source_lines is table of binary_integer;
89195
l_source_lines t_source_lines;
90196
line_no binary_integer;
197+
l_schema_names ut_varchar2_list := coalesce(g_schema_names,ut_varchar2_list(sys_context('USERENV','CURRENT_SCHEMA')));
91198
begin
92199

93200
if not ut_coverage_helper.is_develop_mode() then
@@ -97,37 +204,70 @@ create or replace package body ut_coverage is
97204
--prepare global temp table with sources
98205
delete from ut_coverage_sources_tmp;
99206

100-
insert into ut_coverage_sources_tmp(owner,name,line,text, to_be_skipped)
101-
select s.owner,s.name,s.line,s.text,
102-
case
103-
when
104-
-- to avoid execution of regexp_like on every line
105-
-- first do a rough check for existence of search pattern keyword
106-
(lower(s.text) like '%procedure%'
107-
or lower(s.text) like '%function%'
108-
or lower(s.text) like '%begin%'
109-
or lower(s.text) like '%end%'
110-
or lower(s.text) like '%package%'
111-
) and
112-
regexp_like(
113-
s.text,
114-
'^\s*(((not)?\s*(overriding|final|instantiable)\s*)*(constructor|member)?\s*(procedure|function)|package(\s+body)|begin|end(\s+\S+)?\s*;)', 'i'
115-
)
116-
then 'Y'
117-
end as to_be_skipped
118-
from all_source s
119-
where s.type not in ('PACKAGE', 'TYPE')
120-
and s.owner in (select t.column_value from table(a_schema_names) t)
121-
--Exclude calls to utPLSQL framework and Unit Test packages
122-
and not exists(select 1 from table(l_skipped_objects) l where s.owner = l.owner AND s.name = l.name);
207+
if g_file_mappings is not null then
208+
insert into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
209+
select f.file_name, s.owner,s.name,s.line,s.text,
210+
case
211+
when
212+
-- to avoid execution of regexp_like on every line
213+
-- first do a rough check for existence of search pattern keyword
214+
(lower(s.text) like '%procedure%'
215+
or lower(s.text) like '%function%'
216+
or lower(s.text) like '%begin%'
217+
or lower(s.text) like '%end%'
218+
or lower(s.text) like '%package%'
219+
) and
220+
regexp_like(
221+
s.text,
222+
'^\s*(((not)?\s*(overriding|final|instantiable)\s*)*(static|constructor|member)?\s*(procedure|function)|package(\s+body)|begin|end(\s+\S+)?\s*;)', 'i'
223+
)
224+
then 'Y'
225+
end as to_be_skipped
226+
from all_source s
227+
join table(g_file_mappings) f
228+
on s.name = f.object_name
229+
and s.type = f.object_type
230+
and s.owner = f.object_owner
231+
where s.type not in ('PACKAGE', 'TYPE')
232+
and (g_include_list is null or (s.owner, s.name) in (select il.owner, il.name from table(g_include_list) il))
233+
and (s.owner, s.name) not in (select el.owner, el.name from table(g_exclude_list) el)
234+
--Exclude calls to utPLSQL framework and Unit Test packages
235+
and (s.owner, s.name) not in (select so.owner, so.name from table(l_skipped_objects) so);
236+
else
237+
insert into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
238+
select lower(s.owner||'.'||s.name), s.owner,s.name,s.line,s.text,
239+
case
240+
when
241+
-- to avoid execution of regexp_like on every line
242+
-- first do a rough check for existence of search pattern keyword
243+
(lower(s.text) like '%procedure%'
244+
or lower(s.text) like '%function%'
245+
or lower(s.text) like '%begin%'
246+
or lower(s.text) like '%end%'
247+
or lower(s.text) like '%package%'
248+
) and
249+
regexp_like(
250+
s.text,
251+
'^\s*(((not)?\s*(overriding|final|instantiable)\s*)*(static|constructor|member)?\s*(procedure|function)|package(\s+body)|begin|end(\s+\S+)?\s*;)', 'i'
252+
)
253+
then 'Y'
254+
end as to_be_skipped
255+
from all_source s
256+
where s.type not in ('PACKAGE', 'TYPE')
257+
and s.owner in (select t.column_value from table(l_schema_names) t)
258+
and (g_include_list is null or (s.owner, s.name) in (select il.owner, il.name from table(g_include_list) il ) )
259+
and (s.owner, s.name) not in (select el.owner, el.name from table(g_exclude_list) el)
260+
--Exclude calls to utPLSQL framework and Unit Test packages
261+
and (s.owner, s.name) not in (select so.owner, so.name from table(l_skipped_objects) so);
262+
end if;
123263

124264
for src_object in (
125-
select o.owner, o.name, lower(o.owner||'.'||o.name) full_name, max(o.line) lines_count,
265+
select o.owner, o.name, o.full_name, max(o.line) lines_count,
126266
cast(
127267
collect(decode(to_be_skipped, 'Y', to_char(line))) as ut_varchar2_list
128268
) to_be_skipped_list
129269
from ut_coverage_sources_tmp o
130-
group by o.owner, o.name
270+
group by o.owner, o.name, o.full_name
131271
) loop
132272

133273
--get coverage data
@@ -145,6 +285,8 @@ create or replace package body ut_coverage is
145285

146286
if not l_result.objects.exists(src_object.full_name) then
147287
l_result.objects(src_object.full_name) := l_new_unit;
288+
l_result.objects(src_object.full_name).owner := src_object.owner;
289+
l_result.objects(src_object.full_name).name := src_object.name;
148290
end if;
149291
l_result.total_lines := l_result.total_lines + src_object.lines_count;
150292
l_result.objects(src_object.full_name).total_lines := src_object.lines_count;
@@ -179,45 +321,5 @@ create or replace package body ut_coverage is
179321
return l_result;
180322
end get_coverage_data;
181323

182-
function get_schema_names_from_run(a_run ut_run) return ut_varchar2_list is
183-
type t_schema_names is table of boolean index by varchar2(500);
184-
l_schema_names t_schema_names;
185-
l_result ut_varchar2_list;
186-
187-
l_schema_name varchar2(500);
188-
189-
procedure get_suite_item_schema_names(a_suite_item ut_logical_suite, a_schema_names in out nocopy t_schema_names) is
190-
begin
191-
if a_suite_item is of (ut_suite) then
192-
a_schema_names(a_suite_item.object_owner) := true;
193-
elsif a_suite_item.items is not null then
194-
for i in 1 .. a_suite_item.items.count loop
195-
if a_suite_item is of (ut_logical_suite) then
196-
get_suite_item_schema_names(treat( a_suite_item.items(i) as ut_logical_suite), a_schema_names);
197-
end if;
198-
end loop;
199-
end if;
200-
end;
201-
202-
begin
203-
if a_run is not null and a_run.items is not null then
204-
for i in 1 .. a_run.items.count loop
205-
if a_run.items(i) is of (ut_logical_suite) then
206-
get_suite_item_schema_names(treat( a_run.items(i) as ut_logical_suite), l_schema_names);
207-
end if;
208-
end loop;
209-
end if;
210-
if l_schema_names.count > 0 then
211-
l_result := ut_varchar2_list();
212-
l_schema_name := l_schema_names.first;
213-
loop
214-
exit when l_schema_name is null;
215-
l_result.extend;
216-
l_result(l_result.last) := l_schema_name;
217-
l_schema_name := l_schema_names.next(l_schema_name);
218-
end loop;
219-
end if;
220-
return l_result;
221-
end;
222324
end;
223325
/

source/core/coverage/ut_coverage.pks

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ create or replace package ut_coverage authid current_user is
2525
type tt_lines is table of t_line_executions index by binary_integer;
2626
--unit coverage information record
2727
type t_unit_coverage is record (
28+
owner varchar2(128),
29+
name varchar2(128),
2830
covered_lines binary_integer := 0,
2931
uncovered_lines binary_integer := 0,
3032
total_lines binary_integer := 0,
@@ -44,6 +46,33 @@ create or replace package ut_coverage authid current_user is
4446
objects tt_program_units
4547
);
4648

49+
function default_file_to_obj_type_map return ut_key_value_pairs;
50+
51+
function build_file_mappings(
52+
a_file_paths ut_varchar2_list,
53+
a_file_to_object_type_mapping ut_key_value_pairs,
54+
a_regex_pattern varchar2,
55+
a_object_owner_subexpression positive,
56+
a_object_name_subexpression positive,
57+
a_object_type_subexpression positive
58+
) return ut_coverage_file_mappings;
59+
60+
function get_include_schema_names return ut_varchar2_list;
61+
62+
procedure set_include_schema_names(a_schema_names ut_varchar2_list);
63+
64+
procedure init(
65+
a_schema_names ut_varchar2_list,
66+
a_include_object_list ut_varchar2_list,
67+
a_exclude_object_list ut_varchar2_list
68+
);
69+
70+
procedure init(
71+
a_file_mappings ut_coverage_file_mappings,
72+
a_include_object_list ut_varchar2_list,
73+
a_exclude_object_list ut_varchar2_list
74+
);
75+
4776
function get_coverage_id return integer;
4877

4978
function coverage_start return integer;
@@ -62,11 +91,9 @@ create or replace package ut_coverage authid current_user is
6291

6392
procedure coverage_flush;
6493

65-
procedure skip_coverage_for(a_object ut_object_name);
66-
67-
function get_coverage_data(a_schema_names ut_varchar2_list) return t_coverage;
94+
procedure skip_coverage_for(a_owner varchar2, a_name varchar2);
6895

69-
function get_schema_names_from_run(a_run ut_run) return ut_varchar2_list;
96+
function get_coverage_data return t_coverage;
7097

7198
end;
7299
/
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
create or replace type ut_coverage_file_mapping as object(
2+
file_name varchar2(4000),
3+
object_owner varchar2(4000),
4+
object_name varchar2(4000),
5+
object_type varchar2(4000)
6+
)
7+
/
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
create or replace type ut_coverage_file_mappings as table of ut_coverage_file_mapping
2+
/

source/core/coverage/ut_coverage_sources_tmp.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ create global temporary table ut_coverage_sources_tmp(
1212
See the License for the specific language governing permissions and
1313
limitations under the License.
1414
*/
15+
full_name varchar2(4000),
1516
owner varchar2(250),
1617
name varchar2(250),
1718
line number(38,0),

0 commit comments

Comments
 (0)