|
| 1 | +create or replace package body ut_coverage is |
| 2 | + /* |
| 3 | + utPLSQL - Version X.X.X.X |
| 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 | + |
| 19 | + g_skipped_objects ut_object_names; |
| 20 | + |
| 21 | + function get_coverage_id return integer is |
| 22 | + begin |
| 23 | + return ut_coverage_helper.get_coverage_id; |
| 24 | + end; |
| 25 | + |
| 26 | + function coverage_start return integer is |
| 27 | + begin |
| 28 | + g_skipped_objects := ut_object_names(); |
| 29 | + return ut_coverage_helper.coverage_start('utPLSQL Code coverage run '||ut_utils.to_string(systimestamp)); |
| 30 | + end; |
| 31 | + |
| 32 | + procedure coverage_start is |
| 33 | + l_coverage_id integer; |
| 34 | + begin |
| 35 | + l_coverage_id := coverage_start; |
| 36 | + end; |
| 37 | + |
| 38 | + procedure coverage_start_develop is |
| 39 | + begin |
| 40 | + g_skipped_objects := ut_object_names(); |
| 41 | + ut_coverage_helper.coverage_start_develop(); |
| 42 | + end; |
| 43 | + |
| 44 | + procedure coverage_flush is |
| 45 | + begin |
| 46 | + ut_coverage_helper.coverage_flush(); |
| 47 | + end; |
| 48 | + |
| 49 | + procedure coverage_pause is |
| 50 | + begin |
| 51 | + ut_coverage_helper.coverage_pause(); |
| 52 | + end; |
| 53 | + |
| 54 | + procedure coverage_resume is |
| 55 | + begin |
| 56 | + ut_coverage_helper.coverage_resume(); |
| 57 | + end; |
| 58 | + |
| 59 | + procedure coverage_stop is |
| 60 | + begin |
| 61 | + ut_coverage_helper.coverage_stop(); |
| 62 | + end; |
| 63 | + |
| 64 | + procedure skip_coverage_for(a_object ut_object_name) is |
| 65 | + begin |
| 66 | + if g_skipped_objects is null then |
| 67 | + g_skipped_objects := ut_object_names(); |
| 68 | + end if; |
| 69 | + g_skipped_objects.extend; |
| 70 | + g_skipped_objects(g_skipped_objects.last) := a_object; |
| 71 | + end; |
| 72 | + |
| 73 | + function get_coverage_data(a_schema_names ut_varchar2_list) return t_coverage is |
| 74 | + |
| 75 | + pragma autonomous_transaction; |
| 76 | + |
| 77 | + type t_coverage_row is record( |
| 78 | + name varchar2(500), |
| 79 | + line_number integer, |
| 80 | + total_occur number(38,0) |
| 81 | + ); |
| 82 | + type tt_coverage_rows is table of t_coverage_row; |
| 83 | + l_line_calls ut_coverage_helper.unit_line_calls; |
| 84 | + l_result t_coverage; |
| 85 | + l_new_unit t_unit_coverage; |
| 86 | + l_skipped_objects ut_object_names := ut_object_names(); |
| 87 | + |
| 88 | + type t_source_lines is table of binary_integer; |
| 89 | + l_source_lines t_source_lines; |
| 90 | + line_no binary_integer; |
| 91 | + begin |
| 92 | + |
| 93 | + if not ut_coverage_helper.is_develop_mode() then |
| 94 | + l_skipped_objects := ut_utils.get_utplsql_objects_list() multiset union set(g_skipped_objects); |
| 95 | + end if; |
| 96 | + |
| 97 | + --prepare global temp table with sources |
| 98 | + delete from ut_coverage_sources_tmp; |
| 99 | + |
| 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); |
| 123 | + |
| 124 | + for src_object in ( |
| 125 | + select o.owner, o.name, lower(o.owner||'.'||o.name) full_name, max(o.line) lines_count, |
| 126 | + cast( |
| 127 | + collect(decode(to_be_skipped, 'Y', to_char(line))) as ut_varchar2_list |
| 128 | + ) to_be_skipped_list |
| 129 | + from ut_coverage_sources_tmp o |
| 130 | + group by o.owner, o.name |
| 131 | + ) loop |
| 132 | + |
| 133 | + --get coverage data |
| 134 | + l_line_calls := ut_coverage_helper.get_raw_coverage_data( src_object.owner, src_object.name ); |
| 135 | + |
| 136 | + --if there is coverage, we need to filter out the garbage (badly indicated data from dbms_profiler) |
| 137 | + if l_line_calls.count > 0 then |
| 138 | + --remove lines that should not be indicted as meaningful |
| 139 | + for i in 1 .. src_object.to_be_skipped_list.count loop |
| 140 | + if src_object.to_be_skipped_list(i) is not null then |
| 141 | + l_line_calls.delete(src_object.to_be_skipped_list(i)); |
| 142 | + end if; |
| 143 | + end loop; |
| 144 | + end if; |
| 145 | + |
| 146 | + if not l_result.objects.exists(src_object.full_name) then |
| 147 | + l_result.objects(src_object.full_name) := l_new_unit; |
| 148 | + end if; |
| 149 | + l_result.total_lines := l_result.total_lines + src_object.lines_count; |
| 150 | + l_result.objects(src_object.full_name).total_lines := src_object.lines_count; |
| 151 | + --map to results |
| 152 | + line_no := l_line_calls.first; |
| 153 | + if line_no is null then |
| 154 | + l_result.uncovered_lines := l_result.uncovered_lines + src_object.lines_count; |
| 155 | + l_result.objects(src_object.full_name).uncovered_lines := src_object.lines_count; |
| 156 | + else |
| 157 | + loop |
| 158 | + exit when line_no is null; |
| 159 | + |
| 160 | + if l_line_calls(line_no) > 0 then |
| 161 | + l_result.covered_lines := l_result.covered_lines + 1; |
| 162 | + l_result.executions := l_result.executions + l_line_calls(line_no); |
| 163 | + l_result.objects(src_object.full_name).covered_lines := l_result.objects(src_object.full_name).covered_lines + 1; |
| 164 | + l_result.objects(src_object.full_name).executions := l_result.objects(src_object.full_name).executions + l_line_calls(line_no); |
| 165 | + elsif l_line_calls(line_no) = 0 then |
| 166 | + l_result.uncovered_lines := l_result.uncovered_lines + 1; |
| 167 | + l_result.objects(src_object.full_name).uncovered_lines := l_result.objects(src_object.full_name).uncovered_lines + 1; |
| 168 | + end if; |
| 169 | + l_result.objects(src_object.full_name).lines(line_no) := l_line_calls(line_no); |
| 170 | + |
| 171 | + line_no := l_line_calls.next(line_no); |
| 172 | + end loop; |
| 173 | + end if; |
| 174 | + |
| 175 | + |
| 176 | + end loop; |
| 177 | + |
| 178 | + commit; |
| 179 | + return l_result; |
| 180 | + end get_coverage_data; |
| 181 | + |
| 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; |
| 222 | +end; |
| 223 | +/ |
0 commit comments