Skip to content

Commit df1aee3

Browse files
committed
Added Junit Windy Road version 1 reporter
Signed-off-by: lwasylow <lwasylow@gmail.com>
1 parent a62c9ce commit df1aee3

File tree

7 files changed

+316
-0
lines changed

7 files changed

+316
-0
lines changed

source/create_synonyms_and_grants_for_public.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ grant execute on &&ut3_owner..ut to public;
4949
grant execute on &&ut3_owner..ut_runner to public;
5050
grant execute on &&ut3_owner..ut_teamcity_reporter to public;
5151
grant execute on &&ut3_owner..ut_xunit_reporter to public;
52+
grant execute on &&ut3_owner..ut_junit_reporter to public;
5253
grant execute on &&ut3_owner..ut_documentation_reporter to public;
5354
grant execute on &&ut3_owner..ut_coverage_html_reporter to public;
5455
grant execute on &&ut3_owner..ut_coverage_sonar_reporter to public;
@@ -106,6 +107,7 @@ create public synonym ut for &&ut3_owner..ut;
106107
create public synonym ut_runner for &&ut3_owner..ut_runner;
107108
create public synonym ut_teamcity_reporter for &&ut3_owner..ut_teamcity_reporter;
108109
create public synonym ut_xunit_reporter for &&ut3_owner..ut_xunit_reporter;
110+
create public synonym ut_junit_reporter for &&ut3_owner..ut_junit_reporter;
109111
create public synonym ut_documentation_reporter for &&ut3_owner..ut_documentation_reporter;
110112
create public synonym ut_coverage_html_reporter for &&ut3_owner..ut_coverage_html_reporter;
111113
create public synonym ut_coverage_sonar_reporter for &&ut3_owner..ut_coverage_sonar_reporter;

source/create_synonyms_and_grants_for_user.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ grant execute on &&ut3_owner..ut to &ut3_user;
6969
grant execute on &&ut3_owner..ut_runner to &ut3_user;
7070
grant execute on &&ut3_owner..ut_teamcity_reporter to &ut3_user;
7171
grant execute on &&ut3_owner..ut_xunit_reporter to &ut3_user;
72+
grant execute on &&ut3_owner..ut_junit_reporter to &ut3_user;
7273
grant execute on &&ut3_owner..ut_documentation_reporter to &ut3_user;
7374
grant execute on &&ut3_owner..ut_coverage_html_reporter to &ut3_user;
7475
grant execute on &&ut3_owner..ut_coverage_sonar_reporter to &ut3_user;
@@ -125,6 +126,7 @@ create or replace synonym &ut3_user..ut for &&ut3_owner..ut;
125126
create or replace synonym &ut3_user..ut_runner for &&ut3_owner..ut_runner;
126127
create or replace synonym &ut3_user..ut_teamcity_reporter for &&ut3_owner..ut_teamcity_reporter;
127128
create or replace synonym &ut3_user..ut_xunit_reporter for &&ut3_owner..ut_xunit_reporter;
129+
create or replace synonym &ut3_user..ut_junit_reporter for &&ut3_owner..ut_junit_reporter;
128130
create or replace synonym &ut3_user..ut_documentation_reporter for &&ut3_owner..ut_documentation_reporter;
129131
create or replace synonym &ut3_user..ut_coverage_html_reporter for &&ut3_owner..ut_coverage_html_reporter;
130132
create or replace synonym &ut3_user..ut_coverage_sonar_reporter for &&ut3_owner..ut_coverage_sonar_reporter;

source/install.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ prompt Installing PLSQL profiler objects into &&ut3_owner schema
239239
@@install_component.sql 'reporters/ut_teamcity_reporter.tpb'
240240
@@install_component.sql 'reporters/ut_xunit_reporter.tps'
241241
@@install_component.sql 'reporters/ut_xunit_reporter.tpb'
242+
@@install_component.sql 'reporters/ut_junit_reporter.tps'
243+
@@install_component.sql 'reporters/ut_junit_reporter.tpb'
242244
@@install_component.sql 'reporters/ut_sonar_test_reporter.tps'
243245
@@install_component.sql 'reporters/ut_sonar_test_reporter.tpb'
244246

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
create or replace type body ut_junit_reporter is
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+
19+
constructor function ut_junit_reporter(
20+
self in out nocopy ut_junit_reporter,
21+
a_version in integer) return self as result is
22+
begin
23+
self.init($$plsql_unit);
24+
junit_version := a_version;
25+
return;
26+
end;
27+
28+
overriding member procedure after_calling_run(self in out nocopy ut_junit_reporter, a_run in ut_run) is
29+
begin
30+
if self.junit_version = 1 then
31+
junit_version_one(a_run);
32+
else
33+
junit_version_four(a_run);
34+
end if;
35+
end;
36+
37+
member procedure junit_version_four(self in out nocopy ut_junit_reporter,a_run in ut_run) is
38+
l_suite_id integer := 0;
39+
l_tests_count integer := a_run.results_count.disabled_count + a_run.results_count.success_count +
40+
a_run.results_count.failure_count + a_run.results_count.errored_count;
41+
function get_common_item_attributes(a_item ut_suite_item) return varchar2 is
42+
begin
43+
return ' skipped="' || a_item.results_count.disabled_count ||
44+
'" error="' || a_item.results_count.errored_count ||
45+
'"' || ' failure="' || a_item.results_count.failure_count ||
46+
'" name="' || dbms_xmlgen.convert(nvl(a_item.description, a_item.name)) || '"' ||
47+
' time="' || ut_utils.to_xml_number_format(a_item.execution_time()) || '" ';
48+
end;
49+
50+
function get_path(a_path_with_name varchar2, a_name varchar2) return varchar2 is
51+
begin
52+
return regexp_substr(a_path_with_name, '(.*)\.' ||a_name||'$',subexpression=>1);
53+
end;
54+
55+
procedure print_test_elements(a_test ut_test) is
56+
l_lines ut_varchar2_list;
57+
l_output clob;
58+
begin
59+
self.print_text('<testcase classname="' || dbms_xmlgen.convert(get_path(a_test.path, a_test.name)) || '" ' || ' assertions="' ||
60+
nvl(a_test.all_expectations.count,0) || '"' || get_common_item_attributes(a_test) || case when
61+
a_test.result != ut_utils.tr_success then
62+
' status="' || ut_utils.test_result_to_char(a_test.result) || '"' end || '>');
63+
if a_test.result = ut_utils.tr_disabled then
64+
self.print_text('<skipped/>');
65+
end if;
66+
if a_test.result = ut_utils.tr_error then
67+
self.print_text('<error>');
68+
self.print_text('<![CDATA[');
69+
self.print_clob(ut_utils.table_to_clob(a_test.get_error_stack_traces()));
70+
self.print_text(']]>');
71+
self.print_text('</error>');
72+
elsif a_test.result > ut_utils.tr_success then
73+
self.print_text('<failure>');
74+
self.print_text('<![CDATA[');
75+
for i in 1 .. a_test.failed_expectations.count loop
76+
l_lines := a_test.failed_expectations(i).get_result_lines();
77+
for j in 1 .. l_lines.count loop
78+
self.print_text(l_lines(j));
79+
end loop;
80+
self.print_text(a_test.failed_expectations(i).caller_info);
81+
end loop;
82+
self.print_text(']]>');
83+
self.print_text('</failure>');
84+
end if;
85+
-- TODO - decide if we need/want to use the <system-err/> tag too
86+
l_output := a_test.get_serveroutputs();
87+
if l_output is not null then
88+
self.print_text('<system-out>');
89+
self.print_text('<![CDATA[');
90+
self.print_clob(l_output);
91+
self.print_text(']]>');
92+
self.print_text('</system-out>');
93+
end if;
94+
self.print_text('</testcase>');
95+
end;
96+
97+
procedure print_suite_elements(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is
98+
l_tests_count integer := a_suite.results_count.disabled_count + a_suite.results_count.success_count +
99+
a_suite.results_count.failure_count + a_suite.results_count.errored_count;
100+
l_suite ut_suite;
101+
begin
102+
a_suite_id := a_suite_id + 1;
103+
self.print_text('<testsuite tests="' || l_tests_count || '"' || ' id="' || a_suite_id || '"' || ' package="' ||
104+
dbms_xmlgen.convert(a_suite.path) || '" ' || get_common_item_attributes(a_suite) || '>');
105+
if a_suite is of(ut_suite) then
106+
l_suite := treat(a_suite as ut_suite);
107+
108+
if l_suite.before_all.serveroutput is not null or l_suite.after_all.serveroutput is not null then
109+
self.print_text('<system-out>');
110+
self.print_text('<![CDATA[');
111+
self.print_clob(l_suite.get_serveroutputs());
112+
self.print_text(']]>');
113+
self.print_text('</system-out>');
114+
end if;
115+
116+
if l_suite.before_all.error_stack is not null or l_suite.after_all.error_stack is not null then
117+
self.print_text('<system-err>');
118+
self.print_text('<![CDATA[');
119+
self.print_text(trim(l_suite.before_all.error_stack) || trim(chr(10) || chr(10) || l_suite.after_all.error_stack));
120+
self.print_text(']]>');
121+
self.print_text('</system-err>');
122+
end if;
123+
end if;
124+
125+
for i in 1 .. a_suite.items.count loop
126+
if a_suite.items(i) is of(ut_test) then
127+
print_test_elements(treat(a_suite.items(i) as ut_test));
128+
elsif a_suite.items(i) is of(ut_logical_suite) then
129+
print_suite_elements(treat(a_suite.items(i) as ut_logical_suite), a_suite_id);
130+
end if;
131+
end loop;
132+
self.print_text('</testsuite>');
133+
end;
134+
begin
135+
l_suite_id := 0;
136+
self.print_text('<testsuites tests="' || l_tests_count || '"' || get_common_item_attributes(a_run) || '>');
137+
for i in 1 .. a_run.items.count loop
138+
print_suite_elements(treat(a_run.items(i) as ut_logical_suite), l_suite_id);
139+
end loop;
140+
self.print_text('</testsuites>');
141+
end;
142+
143+
member procedure junit_version_one(self in out nocopy ut_junit_reporter,a_run in ut_run) is
144+
l_suite_id integer := 0;
145+
l_tests_count integer := a_run.results_count.disabled_count + a_run.results_count.success_count +
146+
a_run.results_count.failure_count + a_run.results_count.errored_count;
147+
148+
function get_common_suite_attributes(a_item ut_suite_item) return varchar2 is
149+
begin
150+
return ' errors="' ||a_item.results_count.errored_count || '"' ||
151+
' failures="' || a_item.results_count.failure_count ||
152+
'" name="' || dbms_xmlgen.convert(nvl(a_item.description, a_item.name)) || '"' ||
153+
' time="' || ut_utils.to_xml_number_format(a_item.execution_time()) || '" '||
154+
' timestamp="' || to_char(sysdate,'RRRR-MM-DD"T"HH24:MI:SS') || '" '||
155+
' hostname="' || sys_context('USERENV','HOST') || '" ';
156+
end;
157+
158+
function get_common_testcase_attributes(a_item ut_suite_item) return varchar2 is
159+
begin
160+
return ' name="' || dbms_xmlgen.convert(nvl(a_item.description, a_item.name)) || '"' ||
161+
' time="' || ut_utils.to_xml_number_format(a_item.execution_time()) || '"';
162+
end;
163+
164+
function get_path(a_path_with_name varchar2, a_name varchar2) return varchar2 is
165+
begin
166+
return regexp_substr(a_path_with_name, '(.*)\.' ||a_name||'$',subexpression=>1);
167+
end;
168+
169+
procedure print_test_elements(a_test ut_test) is
170+
l_lines ut_varchar2_list;
171+
l_output clob;
172+
begin
173+
self.print_text('<testcase classname="' || dbms_xmlgen.convert(get_path(a_test.path, a_test.name)) || '" ' ||
174+
get_common_testcase_attributes(a_test) || '>');
175+
/*
176+
According to specs :
177+
- A failure is a test which the code has explicitly failed by using the mechanisms for that purpose.
178+
e.g., via an assertEquals
179+
- An errored test is one that had an unanticipated problem.
180+
e.g., an unchecked throwable; or a problem with the implementation of the test.
181+
*/
182+
183+
if a_test.result = ut_utils.tr_error then
184+
self.print_text('<error type="error" message="Error while executing '||a_test.name||'">');
185+
self.print_text('<![CDATA[');
186+
self.print_clob(ut_utils.table_to_clob(a_test.get_error_stack_traces()));
187+
self.print_text(']]>');
188+
self.print_text('</error>');
189+
-- Do not count error as failure
190+
elsif a_test.result = ut_utils.tr_failure then
191+
self.print_text('<failure type="failure" message="Test '||a_test.name||' failed">');
192+
self.print_text('<![CDATA[');
193+
for i in 1 .. a_test.failed_expectations.count loop
194+
l_lines := a_test.failed_expectations(i).get_result_lines();
195+
for j in 1 .. l_lines.count loop
196+
self.print_text(l_lines(j));
197+
end loop;
198+
self.print_text(a_test.failed_expectations(i).caller_info);
199+
end loop;
200+
self.print_text(']]>');
201+
self.print_text('</failure>');
202+
end if;
203+
204+
self.print_text('</testcase>');
205+
end;
206+
207+
procedure print_suite_elements(a_suite ut_logical_suite, a_suite_id in out nocopy integer) is
208+
l_tests_count integer := a_suite.results_count.disabled_count + a_suite.results_count.success_count +
209+
a_suite.results_count.failure_count + a_suite.results_count.errored_count;
210+
l_suite ut_suite;
211+
begin
212+
a_suite_id := a_suite_id + 1;
213+
self.print_text('<testsuite tests="' || l_tests_count || '"' || ' id="' || a_suite_id || '"' || ' package="' ||
214+
dbms_xmlgen.convert(a_suite.path) || '" ' || get_common_suite_attributes(a_suite) || '>');
215+
self.print_text('<properties/>');
216+
217+
for i in 1 .. a_suite.items.count loop
218+
if a_suite.items(i) is of(ut_test) then
219+
print_test_elements(treat(a_suite.items(i) as ut_test));
220+
elsif a_suite.items(i) is of(ut_logical_suite) then
221+
print_suite_elements(treat(a_suite.items(i) as ut_logical_suite), a_suite_id);
222+
end if;
223+
end loop;
224+
225+
if a_suite is of(ut_suite) then
226+
l_suite := treat(a_suite as ut_suite);
227+
228+
if l_suite.before_all.serveroutput is not null or l_suite.after_all.serveroutput is not null then
229+
self.print_text('<system-out>');
230+
self.print_text('<![CDATA[');
231+
self.print_clob(l_suite.get_serveroutputs());
232+
self.print_text(']]>');
233+
self.print_text('</system-out>');
234+
else
235+
self.print_text('<system-out/>');
236+
end if;
237+
238+
if l_suite.before_all.error_stack is not null or l_suite.after_all.error_stack is not null then
239+
self.print_text('<system-err>');
240+
self.print_text('<![CDATA[');
241+
self.print_text(trim(l_suite.before_all.error_stack) || trim(chr(10) || chr(10) || l_suite.after_all.error_stack));
242+
self.print_text(']]>');
243+
self.print_text('</system-err>');
244+
else
245+
self.print_text('<system-err/>');
246+
end if;
247+
end if;
248+
249+
self.print_text('</testsuite>');
250+
end;
251+
begin
252+
l_suite_id := 0;
253+
self.print_text('<testsuites>');
254+
for i in 1 .. a_run.items.count loop
255+
print_suite_elements(treat(a_run.items(i) as ut_logical_suite), l_suite_id);
256+
end loop;
257+
self.print_text('</testsuites>');
258+
end;
259+
260+
overriding member function get_description return varchar2 as
261+
begin
262+
return 'Provides outcomes in a format conforming with JUnit. Based on attribute a_version we can get output for version 4 or 1.
263+
Version 4 and above is defined in: https://gist.github.com/kuzuha/232902acab1344d6b578.
264+
Version 1 is based on windy road junit https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd.';
265+
end;
266+
267+
end;
268+
/
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
create or replace type ut_junit_reporter under ut_output_reporter_base(
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+
/**
19+
* The XUnit reporter.
20+
* Provides outcomes in a format conforming with JUnit4 as defined in:
21+
* https://gist.github.com/kuzuha/232902acab1344d6b578
22+
*/
23+
24+
junit_version integer,
25+
26+
constructor function ut_junit_reporter(
27+
self in out nocopy ut_junit_reporter,
28+
a_version in integer := 4)
29+
return self as result,
30+
31+
overriding member procedure after_calling_run(self in out nocopy ut_junit_reporter, a_run in ut_run),
32+
33+
member procedure junit_version_four(self in out nocopy ut_junit_reporter, a_run in ut_run),
34+
member procedure junit_version_one(self in out nocopy ut_junit_reporter, a_run in ut_run),
35+
36+
overriding member function get_description return varchar2
37+
)
38+
not final
39+

source/uninstall.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ drop type ut_teamcity_reporter force;
194194

195195
drop type ut_xunit_reporter force;
196196

197+
drop type ut_junit_reporter force;
198+
197199
drop type ut_event_listener force;
198200

199201
drop type ut_output_reporter_base force;

test/api/test_ut_runner.pkb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ end;';
286286
select 'UT3.UT_COVERAGE_SONAR_REPORTER', 'Y' from dual union all
287287
select 'UT3.UT_COVERALLS_REPORTER', 'Y' from dual union all
288288
select 'UT3.UT_DOCUMENTATION_REPORTER', 'Y' from dual union all
289+
select 'UT3.UT_JUNIT_REPORTER', 'Y' from dual union all
289290
select 'UT3.UT_SONAR_TEST_REPORTER', 'Y' from dual union all
290291
select 'UT3.UT_TEAMCITY_REPORTER', 'Y' from dual union all
291292
select 'UT3.UT_XUNIT_REPORTER', 'Y' from dual;

0 commit comments

Comments
 (0)