diff --git a/VERSION b/VERSION index 47673efd4..3cbc57657 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v3.0.4-develop +v3.1.0-develop diff --git a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql index 133b27f03..d512c0856 100644 --- a/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql +++ b/examples/developer_examples/RunExampleComplexSuiteWithCustomReporter.sql @@ -16,7 +16,8 @@ declare suite1 ut_logical_suite; suite2 ut_logical_suite; suite_complex ut_logical_suite; - listener ut_event_listener; + l_reporter ut_output_reporter_base; + l_listener ut_event_listener; l_run ut_run; begin suite1 := ut_logical_suite(a_object_owner=>null, a_object_name => null, a_name => null, a_description => 'Test Suite 1', a_path => null); @@ -44,10 +45,11 @@ begin suite_complex.items := ut_suite_items(suite1, suite2); -- provide a reporter to process results - listener := ut_event_listener(ut_reporters(ut_custom_reporter(a_tab_size => 2))); + l_reporter := ut_custom_reporter(a_tab_size => 2); + l_listener := ut_event_listener(ut_reporters(l_reporter)); l_run := ut_run(ut_suite_items(suite_complex)); - l_run.do_execute(listener); - ut_output_buffer.lines_to_dbms_output(listener.reporters(1).reporter_id,0); + l_run.do_execute(l_listener); + l_reporter.lines_to_dbms_output(); end; / diff --git a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql index aed1d8e84..d86c862c9 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql @@ -12,9 +12,11 @@ set echo off PROMPT Runs test report using composite reporter declare - suite ut_logical_suite; - listener ut_event_listener; - l_run ut_run; + suite ut_logical_suite; + l_doc_reporter ut_output_reporter_base := ut_documentation_reporter(); + l_tc_reporter ut_output_reporter_base := ut_teamcity_reporter(); + l_listener ut_event_listener := ut_event_listener(ut_reporters(l_doc_reporter, l_tc_reporter)); + l_run ut_run; begin suite := ut_logical_suite(a_object_owner=>null, a_object_name => 'ut_exampletest', a_name => null, a_description => 'Test Suite Name',a_path => null); @@ -36,11 +38,10 @@ begin ); -- provide a reporter to process results - listener := ut_event_listener(ut_reporters(ut_documentation_reporter, ut_teamcity_reporter)); l_run := ut_run(ut_suite_items(suite)); - l_run.do_execute(listener); - ut_output_buffer.lines_to_dbms_output(listener.reporters(1).reporter_id,0); - ut_output_buffer.lines_to_dbms_output(listener.reporters(2).reporter_id,0); + l_run.do_execute(l_listener); + l_doc_reporter.lines_to_dbms_output(0,0); + l_tc_reporter.lines_to_dbms_output(0,0); end; / diff --git a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql index 08a4f575e..6658228d4 100644 --- a/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql +++ b/examples/developer_examples/RunExampleTestSuiteWithCustomReporter.sql @@ -15,7 +15,8 @@ set echo off declare suite ut_logical_suite; - listener ut_event_listener; + l_reporter ut_output_reporter_base; + l_listener ut_event_listener; l_run ut_run; begin -- Install ut_custom_reporter first from example folder @@ -40,10 +41,11 @@ begin ); -- provide a reporter to process results tabbing each hierarcy level by tab_size - listener := ut_event_listener(ut_reporters(ut_custom_reporter(a_tab_size => 2))); + l_reporter := ut_custom_reporter(a_tab_size => 2); + l_listener := ut_event_listener(ut_reporters(l_reporter)); l_run := ut_run(ut_suite_items(suite)); - l_run.do_execute(listener); - ut_output_buffer.lines_to_dbms_output(listener.reporters(1).reporter_id,0); + l_run.do_execute(l_listener); + l_reporter.lines_to_dbms_output(0,0); end; / diff --git a/old_tests/RunAll.sql b/old_tests/RunAll.sql index f3978032b..7888a2fba 100644 --- a/old_tests/RunAll.sql +++ b/old_tests/RunAll.sql @@ -72,7 +72,8 @@ exec ut_coverage.coverage_start_develop(); @@lib/RunTest.sql ut_metadata/ut_metadata.form_name.TrimStandaloneProgramName.sql @@lib/RunTest.sql ut_output_buffer/get_lines.RecievesALineFromBufferTableAndDeletes.sql -@@lib/RunTest.sql ut_output_buffer/send_line.DoesNotSendLineIfNullReporterIdGiven.sql +@@lib/RunTest.sql ut_output_buffer/get_lines.WaitsForMoreDataToAppearForSpecifiedTime.sql +@@lib/RunTest.sql ut_output_buffer/get_lines.WaitsForTheDataToAppearForSpecifiedTime.sql @@lib/RunTest.sql ut_output_buffer/send_line.DoesNotSendLineIfNullTextGiven.sql @@lib/RunTest.sql ut_output_buffer/send_line.SendsALineIntoBufferTable.sql @@ -93,6 +94,7 @@ exec ut_coverage.coverage_start_develop(); @@lib/RunTest.sql ut/ut.run.AcceptsCoverageFileList.sql @@lib/RunTest.sql ut/ut.run.AcceptsCoverageFileListWithSutePaths.sql @@lib/RunTest.sql ut/ut.run.AcceptsSutePaths.sql +@@lib/RunTest.sql ut/ut.run.ExecutesSuccesfullyAnEmptySuite.sql @@lib/RunTest.sql ut/ut.run.FailsToExecuteAnInvalidPackageBody.sql @@lib/RunTest.sql ut/ut.run.function.AcceptsCoverageFileList.sql @@lib/RunTest.sql ut/ut.run.function.AcceptsCoverageFileListWithSutePaths.sql @@ -252,6 +254,7 @@ begin 'source/api/ut_runner.pkb', 'source/api/ut_runner.pks', 'source/core/coverage', + 'source/core/output_buffers', 'source/core/types', 'source/core/annotations/ut_annotation_manager.pkb', 'source/core/annotations/ut_annotation_manager.pks', @@ -263,12 +266,8 @@ begin 'source/core/ut_expectation_processor.pks', 'source/core/ut_file_mapper.pkb', 'source/core/ut_file_mapper.pks', - 'source/core/ut_message_id_seq.sql', 'source/core/ut_metadata.pkb', 'source/core/ut_metadata.pks', - 'source/core/ut_output_buffer.pkb', - 'source/core/ut_output_buffer.pks', - 'source/core/ut_output_buffer_tmp.sql', 'source/core/ut_suite_manager.pkb', 'source/core/ut_suite_manager.pks', 'source/core/ut_utils.pkb', @@ -281,6 +280,12 @@ begin 'source/core/coverage/ut_coverage_sources_tmp.sql', 'source/core/coverage/ut_coverage_reporter_base.tpb', 'source/core/coverage/ut_coverage_reporter_base.tps', + 'source/core/output_buffers/ut_message_id_seq.sql', + 'source/core/output_buffers/ut_output_buffer_base.tps', + 'source/core/output_buffers/ut_output_buffer_info_tmp.sql', + 'source/core/output_buffers/ut_output_buffer_tmp.sql', + 'source/core/output_buffers/ut_output_table_buffer.tpb', + 'source/core/output_buffers/ut_output_table_buffer.tps', 'source/core/types/ut_console_reporter_base.tpb', 'source/core/types/ut_console_reporter_base.tps', 'source/core/types/ut_coverage_options.tps', @@ -292,8 +297,9 @@ begin 'source/core/types/ut_expectation_result.tpb', 'source/core/types/ut_expectation_result.tps', 'source/core/types/ut_expectation_results.tps', - 'source/core/coverage/ut_file_mapping.tps', - 'source/core/coverage/ut_file_mappings.tps', + 'source/core/types/ut_file_mapping.tpb', + 'source/core/types/ut_file_mapping.tps', + 'source/core/types/ut_file_mappings.tps', 'source/core/types/ut_key_value_pair.tps', 'source/core/types/ut_key_value_pairs.tps', 'source/core/types/ut_logical_suite.tpb', @@ -301,6 +307,8 @@ begin 'source/core/types/ut_object_name.tpb', 'source/core/types/ut_object_name.tps', 'source/core/types/ut_object_names.tps', + 'source/core/types/ut_output_reporter_base.tpb', + 'source/core/types/ut_output_reporter_base.tps', 'source/core/types/ut_reporters.tps', 'source/core/types/ut_reporter_base.tpb', 'source/core/types/ut_reporter_base.tps', @@ -317,6 +325,7 @@ begin 'source/core/types/ut_test.tpb', 'source/core/types/ut_test.tps', 'source/core/types/ut_varchar2_list.tps', + 'source/core/types/ut_varchar2_rows.tps', 'source/expectations/data_values', 'source/expectations/matchers', 'source/expectations/ut_expectation.tpb', @@ -347,6 +356,8 @@ begin 'source/expectations/ut_expectation_varchar2.tps', 'source/expectations/ut_expectation_yminterval.tpb', 'source/expectations/ut_expectation_yminterval.tps', + 'source/expectations/data_values/ut_cursor_data.sql', + 'source/expectations/data_values/ut_data_value.tpb', 'source/expectations/data_values/ut_data_value.tps', 'source/expectations/data_values/ut_data_value_anydata.tpb', 'source/expectations/data_values/ut_data_value_anydata.tps', @@ -433,31 +444,34 @@ begin --run for the first time to gather coverage and timings on reporters too l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); - :html_reporter_id := l_reporter.reporter_id; l_reporter.after_calling_run(l_test_run); + l_reporter.finalize(); l_reporter := ut_coverage_sonar_reporter(); - :sonar_reporter_id := l_reporter.reporter_id; l_reporter.after_calling_run(l_test_run); + l_reporter.finalize(); l_reporter := ut_coveralls_reporter(); - :coveralls_reporter_id := l_reporter.reporter_id; l_reporter.after_calling_run(l_test_run); + l_reporter.finalize(); ut_coverage.coverage_stop_develop(); --run for the second time to get the coverage report l_reporter := ut_coverage_html_reporter(a_project_name => 'utPLSQL v3'); - :html_reporter_id := l_reporter.reporter_id; l_reporter.after_calling_run(l_test_run); + l_reporter.finalize(); + :html_reporter_id := l_reporter.get_reporter_id; l_reporter := ut_coverage_sonar_reporter(); - :sonar_reporter_id := l_reporter.reporter_id; l_reporter.after_calling_run(l_test_run); + l_reporter.finalize(); + :sonar_reporter_id := l_reporter.get_reporter_id; l_reporter := ut_coveralls_reporter(); - :coveralls_reporter_id := l_reporter.reporter_id; l_reporter.after_calling_run(l_test_run); + l_reporter.finalize(); + :coveralls_reporter_id := l_reporter.get_reporter_id; end; / @@ -467,23 +481,42 @@ set termout off set feedback off set arraysize 50 spool coverage.xml -exec ut_output_buffer.lines_to_dbms_output(:sonar_reporter_id); +declare + l_reporter ut_output_reporter_base := ut_coverage_sonar_reporter(); +begin + l_reporter.set_reporter_id(:sonar_reporter_id); + l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); +end; +/ spool off set termout on prompt Spooling outcomes to coverage.json set termout off spool coverage.json -select * from table(ut_output_buffer.get_lines(:coveralls_reporter_id)); +declare + l_reporter ut_output_reporter_base := ut_coveralls_reporter(); +begin + l_reporter.set_reporter_id(:coveralls_reporter_id); + l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); +end; +/ spool off set termout on prompt Spooling outcomes to coverage.html set termout off spool coverage.html -exec ut_output_buffer.lines_to_dbms_output(:html_reporter_id); +declare + l_reporter ut_output_reporter_base := ut_coverage_html_reporter(); +begin + l_reporter.set_reporter_id(:html_reporter_id); + l_reporter.lines_to_dbms_output(a_initial_timeout=>1, a_timeout_sec=>1); +end; +/ spool off +set termout on spool stats.log exec mystats_pkg.ms_stop(1000); spool off diff --git a/old_tests/helpers/utplsql_test_reporter.typ b/old_tests/helpers/utplsql_test_reporter.typ index 9f3d0839e..874777341 100644 --- a/old_tests/helpers/utplsql_test_reporter.typ +++ b/old_tests/helpers/utplsql_test_reporter.typ @@ -1,4 +1,4 @@ -create or replace type utplsql_test_reporter under ut_reporter_base( +create or replace type utplsql_test_reporter under ut_output_reporter_base( constructor function utplsql_test_reporter(self in out nocopy utplsql_test_reporter) return self as result, overriding member procedure after_calling_run(self in out nocopy utplsql_test_reporter, a_run in ut_run) ) diff --git a/old_tests/ut/ut.run.ExecutesSuccesfullyAnEmptySuite.sql b/old_tests/ut/ut.run.ExecutesSuccesfullyAnEmptySuite.sql new file mode 100644 index 000000000..f739d97c8 --- /dev/null +++ b/old_tests/ut/ut.run.ExecutesSuccesfullyAnEmptySuite.sql @@ -0,0 +1,30 @@ +set termout off +create or replace package empty_suite as + -- %suite + + procedure not_a_test; +end; +/ +create or replace package body empty_suite as + procedure not_a_test is begin null; end; +end; +/ +set termout on +declare + l_result integer; +begin + select * + into l_result + from table(ut.run('empty_suite',utplsql_test_reporter())); +--Assert + if l_result = ut_utils.tr_error then + :test_result := ut_utils.tr_success; + else + dbms_output.put_line('expected failure of ''empty_suite'' got: '''||ut_utils.test_result_to_char(l_result)||'''' ); + end if; +end; +/ + +set termout off +drop package empty_suite; +set termout on diff --git a/old_tests/ut_expectations/ut.expect.not_to_equal.anydata.GivesFailureWhenComparingTheSameData.sql b/old_tests/ut_expectations/ut.expect.not_to_equal.anydata.GivesFailureWhenComparingTheSameData.sql new file mode 100644 index 000000000..fd030a701 --- /dev/null +++ b/old_tests/ut_expectations/ut.expect.not_to_equal.anydata.GivesFailureWhenComparingTheSameData.sql @@ -0,0 +1,17 @@ +--Arrange +declare + l_expected department$ := department$('hr'); + l_actual department$ := department$('hr'); + l_result integer; +begin +--Act + ut.expect( anydata.convertObject(l_actual) ).not_to_equal( anydata.convertObject(l_expected) ); + l_result := ut_expectation_processor.get_status(); +--Assert + if l_result = ut_utils.tr_failure then + :test_result := ut_utils.tr_success; + else + dbms_output.put_line('expected: '''||ut_utils.tr_success||''', got: '''||l_result||'''' ); + end if; +end; +/ diff --git a/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNotBoolean.sql b/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNotBoolean.sql index f23e1b98a..b44f8ea92 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNotBoolean.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNotBoolean.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 ).to_( be_false() ); + ut.expect( 1 ).not_to( be_true() ); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_failure then diff --git a/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNull.sql b/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNull.sql index 982b42772..f1b23640a 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNull.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsNull.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 = null ).to_be_false(); + ut.expect( 1 = null ).not_to_be_true(); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_failure then diff --git a/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsTrue.sql b/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsTrue.sql index 088fb5f1d..377881c5b 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsTrue.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_false.GivesFailureWhenExpessionIsTrue.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 = 1 ).to_be_false(); + ut.expect( 1 = 1 ).not_to_be_true(); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_failure then diff --git a/old_tests/ut_expectations/ut.expect.to_be_false.GivesSuccessWhenExpessionIsFalse.sql b/old_tests/ut_expectations/ut.expect.to_be_false.GivesSuccessWhenExpessionIsFalse.sql index f7c5d5587..223d9aa5e 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_false.GivesSuccessWhenExpessionIsFalse.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_false.GivesSuccessWhenExpessionIsFalse.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 = 0 ).to_be_false(); + ut.expect( 1 = 0 ).not_to_be_true(); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_success then diff --git a/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsFalse.sql b/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsFalse.sql index 6a3b87185..36848cd8c 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsFalse.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsFalse.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 = 0 ).to_be_true(); + ut.expect( 1 = 0 ).not_to_be_false(); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_failure then diff --git a/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNotBoolean.sql b/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNotBoolean.sql index d94e46b13..a73cc94c5 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNotBoolean.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNotBoolean.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 ).to_( be_true() ); + ut.expect( 1 ).not_to( be_false() ); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_failure then diff --git a/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNull.sql b/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNull.sql index b0fc4e7b9..b8721b26e 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNull.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_true.GivesFailureWhenExpessionIsNull.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 = null ).to_be_true(); + ut.expect( 1 = null ).not_to_be_false(); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_failure then diff --git a/old_tests/ut_expectations/ut.expect.to_be_true.GivesSuccessWhenExpessionIsTrue.sql b/old_tests/ut_expectations/ut.expect.to_be_true.GivesSuccessWhenExpessionIsTrue.sql index d13c3d693..b86d9e14a 100644 --- a/old_tests/ut_expectations/ut.expect.to_be_true.GivesSuccessWhenExpessionIsTrue.sql +++ b/old_tests/ut_expectations/ut.expect.to_be_true.GivesSuccessWhenExpessionIsTrue.sql @@ -5,6 +5,7 @@ declare begin --Act ut.expect( 1 = 1 ).to_be_true(); + ut.expect( 1 = 1 ).not_to_be_false(); l_result := ut_expectation_processor.get_status(); --Assert if nvl(:test_result, ut_utils.tr_success) = ut_utils.tr_success and l_result = ut_utils.tr_success then diff --git a/old_tests/ut_output_buffer/get_lines.RecievesALineFromBufferTableAndDeletes.sql b/old_tests/ut_output_buffer/get_lines.RecievesALineFromBufferTableAndDeletes.sql index 94722ce7b..dfebf9d08 100644 --- a/old_tests/ut_output_buffer/get_lines.RecievesALineFromBufferTableAndDeletes.sql +++ b/old_tests/ut_output_buffer/get_lines.RecievesALineFromBufferTableAndDeletes.sql @@ -3,18 +3,17 @@ declare l_result varchar2(4000); l_remaining integer; l_expected varchar2(4000); - l_reporter ut_reporter_base := ut_documentation_reporter(); + l_output ut_output_buffer_base := ut_output_table_buffer(); begin ---Act + --Act l_expected := lpad('a text',4000,',a text'); - ut_output_buffer.send_line(l_reporter, l_expected); + l_output.send_line(l_expected); - select * into l_result from table(ut_output_buffer.get_lines(l_reporter.reporter_id,0)); + select * into l_result from table(l_output.get_lines(a_timeout_sec => 0)); + select count(1) into l_remaining from ut_output_buffer_tmp where output_id = l_output.output_id; + --Assert ut.expect(l_result).to_equal(l_expected); - - select count(1) into l_remaining from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; - ut.expect(l_remaining).to_equal(0); if ut_expectation_processor.get_status = ut_utils.tr_success then @@ -23,11 +22,11 @@ begin dbms_output.put_line(ut_expectation_processor.get_failed_expectations()(1).get_result_clob); end if; - delete from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; + delete from ut_output_buffer_tmp where output_id = l_output.output_id; commit; exception when others then - delete from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; + delete from ut_output_buffer_tmp where output_id = l_output.output_id; commit; raise; end; diff --git a/old_tests/ut_output_buffer/get_lines.WaitsForMoreDataToAppearForSpecifiedTime.sql b/old_tests/ut_output_buffer/get_lines.WaitsForMoreDataToAppearForSpecifiedTime.sql new file mode 100644 index 000000000..c51d9ffa7 --- /dev/null +++ b/old_tests/ut_output_buffer/get_lines.WaitsForMoreDataToAppearForSpecifiedTime.sql @@ -0,0 +1,24 @@ +--Arrange +declare + l_result integer; + l_dummy integer; + l_output ut_output_buffer_base := ut_output_table_buffer(); + l_start_time timestamp := systimestamp; + l_wait_seconds integer := 1; +begin + --Act + l_output.send_line(lpad('a text',4000,',a text')); + + select count(*) into l_dummy from table( l_output.get_lines( a_initial_timeout => 0, a_timeout_sec => l_wait_seconds )); + l_result := round(extract(second from (systimestamp - l_start_time))); + + --Assert + ut.expect(l_result).to_equal(l_wait_seconds); + + if ut_expectation_processor.get_status = ut_utils.tr_success then + :test_result := ut_utils.tr_success; + else + dbms_output.put_line(ut_expectation_processor.get_failed_expectations()(1).get_result_clob); + end if; +end; +/ diff --git a/old_tests/ut_output_buffer/get_lines.WaitsForTheDataToAppearForSpecifiedTime.sql b/old_tests/ut_output_buffer/get_lines.WaitsForTheDataToAppearForSpecifiedTime.sql index 94722ce7b..01e2b3d7b 100644 --- a/old_tests/ut_output_buffer/get_lines.WaitsForTheDataToAppearForSpecifiedTime.sql +++ b/old_tests/ut_output_buffer/get_lines.WaitsForTheDataToAppearForSpecifiedTime.sql @@ -1,34 +1,22 @@ --Arrange declare - l_result varchar2(4000); - l_remaining integer; - l_expected varchar2(4000); - l_reporter ut_reporter_base := ut_documentation_reporter(); + l_result integer; + l_dummy integer; + l_output ut_output_buffer_base := ut_output_table_buffer(); + l_start_time timestamp := systimestamp; + l_wait_seconds integer := 1; begin ---Act - l_expected := lpad('a text',4000,',a text'); - ut_output_buffer.send_line(l_reporter, l_expected); + --Act + select count(1) into l_dummy from table( l_output.get_lines( a_initial_timeout => l_wait_seconds, a_timeout_sec => 0 )); + l_result := round(extract(second from (systimestamp - l_start_time))); - select * into l_result from table(ut_output_buffer.get_lines(l_reporter.reporter_id,0)); - - ut.expect(l_result).to_equal(l_expected); - - select count(1) into l_remaining from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; - - ut.expect(l_remaining).to_equal(0); + --Assert + ut.expect(l_result).to_equal(l_wait_seconds); if ut_expectation_processor.get_status = ut_utils.tr_success then :test_result := ut_utils.tr_success; else dbms_output.put_line(ut_expectation_processor.get_failed_expectations()(1).get_result_clob); end if; - - delete from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; - commit; -exception - when others then - delete from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; - commit; - raise; end; / diff --git a/old_tests/ut_output_buffer/send_line.DoesNotSendLineIfNullReporterIdGiven.sql b/old_tests/ut_output_buffer/send_line.DoesNotSendLineIfNullReporterIdGiven.sql deleted file mode 100644 index 06e373cf3..000000000 --- a/old_tests/ut_output_buffer/send_line.DoesNotSendLineIfNullReporterIdGiven.sql +++ /dev/null @@ -1,19 +0,0 @@ ---Arrange -declare - l_result integer; -begin - delete from ut_output_buffer_tmp; - --Act - ut_output_buffer.send_line(null,'a text to send'); - - select count(1) into l_result from ut_output_buffer_tmp; - - ut.expect(l_result).to_equal(0); - if ut_expectation_processor.get_status = ut_utils.tr_success then - :test_result := ut_utils.tr_success; - else - dbms_output.put_line(ut_expectation_processor.get_failed_expectations()(1).get_result_clob); - end if; - -end; -/ diff --git a/old_tests/ut_output_buffer/send_line.DoesNotSendLineIfNullTextGiven.sql b/old_tests/ut_output_buffer/send_line.DoesNotSendLineIfNullTextGiven.sql index 32c0f4f3b..fe837fe8f 100644 --- a/old_tests/ut_output_buffer/send_line.DoesNotSendLineIfNullTextGiven.sql +++ b/old_tests/ut_output_buffer/send_line.DoesNotSendLineIfNullTextGiven.sql @@ -1,14 +1,15 @@ --Arrange declare l_result integer; - l_reporter ut_reporter_base := ut_documentation_reporter(); + l_output ut_output_buffer_base := ut_output_table_buffer(); begin delete from ut_output_buffer_tmp; --Act - ut_output_buffer.send_line(l_reporter,null); + l_output.send_line(null); select count(1) into l_result from ut_output_buffer_tmp; + --Assert ut.expect(l_result).to_equal(0); if ut_expectation_processor.get_status = ut_utils.tr_success then :test_result := ut_utils.tr_success; diff --git a/old_tests/ut_output_buffer/send_line.SendsALineIntoBufferTable.sql b/old_tests/ut_output_buffer/send_line.SendsALineIntoBufferTable.sql index 6da6cc77b..66b5c7a88 100644 --- a/old_tests/ut_output_buffer/send_line.SendsALineIntoBufferTable.sql +++ b/old_tests/ut_output_buffer/send_line.SendsALineIntoBufferTable.sql @@ -2,14 +2,15 @@ declare l_result varchar2(4000); l_expected varchar2(4000); - l_reporter ut_reporter_base := ut_documentation_reporter(); + l_output ut_output_buffer_base := ut_output_table_buffer(); begin ---Act + --Act l_expected := lpad('a text',4000,',a text'); - ut_output_buffer.send_line(l_reporter, l_expected); + l_output.send_line(l_expected); - select text into l_result from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; + select text into l_result from ut_output_buffer_tmp where output_id = l_output.output_id; + --Assert ut.expect(l_result).to_equal(l_expected); if ut_expectation_processor.get_status = ut_utils.tr_success then :test_result := ut_utils.tr_success; @@ -17,7 +18,7 @@ begin dbms_output.put_line(ut_expectation_processor.get_failed_expectations()(1).get_result_clob); end if; - delete from ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; + delete from ut_output_buffer_tmp where output_id = l_output.output_id; commit; end; / diff --git a/source/api/ut.pkb b/source/api/ut.pkb index bf0cd70b9..7ac52ba0c 100644 --- a/source/api/ut.pkb +++ b/source/api/ut.pkb @@ -140,13 +140,15 @@ create or replace package body ut is l_paths, l_reporter, a_color_console, a_coverage_schemes, a_source_file_mappings, a_test_file_mappings, a_include_objects, a_exclude_objects ); - l_lines := ut_output_buffer.get_lines_cursor(l_reporter.reporter_id); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); - end loop; - close l_lines; + if l_reporter is of (ut_output_reporter_base) then + l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + loop + fetch l_lines into l_line; + exit when l_lines%notfound; + pipe row(l_line); + end loop; + close l_lines; + end if; end; function run( @@ -163,13 +165,15 @@ create or replace package body ut is l_paths, l_reporter, a_color_console, a_coverage_schemes, a_source_files, a_test_files, a_include_objects, a_exclude_objects ); - l_lines := ut_output_buffer.get_lines_cursor(l_reporter.reporter_id); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); - end loop; - close l_lines; + if l_reporter is of (ut_output_reporter_base) then + l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + loop + fetch l_lines into l_line; + exit when l_lines%notfound; + pipe row(l_line); + end loop; + close l_lines; + end if; end; function run( @@ -185,13 +189,15 @@ create or replace package body ut is a_paths, l_reporter, a_color_console, a_coverage_schemes, a_source_file_mappings, a_test_file_mappings, a_include_objects, a_exclude_objects ); - l_lines := ut_output_buffer.get_lines_cursor(l_reporter.reporter_id); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); - end loop; - close l_lines; + if l_reporter is of (ut_output_reporter_base) then + l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + loop + fetch l_lines into l_line; + exit when l_lines%notfound; + pipe row(l_line); + end loop; + close l_lines; + end if; end; function run( @@ -207,13 +213,15 @@ create or replace package body ut is a_paths, l_reporter, a_color_console, a_coverage_schemes, a_source_files, a_test_files, a_include_objects, a_exclude_objects ); - l_lines := ut_output_buffer.get_lines_cursor(l_reporter.reporter_id); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); - end loop; - close l_lines; + if l_reporter is of (ut_output_reporter_base) then + l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + loop + fetch l_lines into l_line; + exit when l_lines%notfound; + pipe row(l_line); + end loop; + close l_lines; + end if; end; function run( @@ -230,13 +238,15 @@ create or replace package body ut is l_paths, l_reporter, a_color_console, a_coverage_schemes, a_source_file_mappings, a_test_file_mappings, a_include_objects, a_exclude_objects ); - l_lines := ut_output_buffer.get_lines_cursor(l_reporter.reporter_id); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); - end loop; - close l_lines; + if l_reporter is of (ut_output_reporter_base) then + l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + loop + fetch l_lines into l_line; + exit when l_lines%notfound; + pipe row(l_line); + end loop; + close l_lines; + end if; end; function run( @@ -253,13 +263,15 @@ create or replace package body ut is l_paths, l_reporter, a_color_console, a_coverage_schemes, a_source_files, a_test_files, a_include_objects, a_exclude_objects ); - l_lines := ut_output_buffer.get_lines_cursor(l_reporter.reporter_id); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - pipe row(l_line); - end loop; - close l_lines; + if l_reporter is of (ut_output_reporter_base) then + l_lines := treat(l_reporter as ut_output_reporter_base).get_lines_cursor(); + loop + fetch l_lines into l_line; + exit when l_lines%notfound; + pipe row(l_line); + end loop; + close l_lines; + end if; end; procedure run( @@ -273,7 +285,9 @@ create or replace package body ut is a_paths, l_reporter, ut_utils.boolean_to_int(a_color_console), a_coverage_schemes, a_source_file_mappings, a_test_file_mappings, a_include_objects, a_exclude_objects ); - ut_output_buffer.lines_to_dbms_output(l_reporter.reporter_id); + if l_reporter is of (ut_output_reporter_base) then + treat(l_reporter as ut_output_reporter_base).lines_to_dbms_output(); + end if; end; procedure run( @@ -287,7 +301,9 @@ create or replace package body ut is a_paths, l_reporter, ut_utils.boolean_to_int(a_color_console), a_coverage_schemes, a_source_files, a_test_files, a_include_objects, a_exclude_objects ); - ut_output_buffer.lines_to_dbms_output(l_reporter.reporter_id); + if l_reporter is of (ut_output_reporter_base) then + treat(l_reporter as ut_output_reporter_base).lines_to_dbms_output(); + end if; end; procedure run( diff --git a/source/api/ut_runner.pkb b/source/api/ut_runner.pkb index 0c4514e5e..6953baba8 100644 --- a/source/api/ut_runner.pkb +++ b/source/api/ut_runner.pkb @@ -33,10 +33,10 @@ create or replace package body ut_runner is return l_result; end; - procedure finish_run(a_reporters ut_reporters) is + procedure finish_run(l_listener in out ut_event_listener) is begin ut_utils.cleanup_temp_tables; - ut_output_buffer.close(a_reporters); + l_listener.fire_on_event(ut_utils.gc_finalize); ut_metadata.reset_source_definition_cache; ut_utils.read_cache_to_dbms_output(); ut_coverage_helper.cleanup_tmp_table(); @@ -73,7 +73,6 @@ create or replace package body ut_runner is l_listener ut_event_listener; begin begin - ut_output_buffer.cleanup_buffer(); ut_utils.save_dbms_output_to_cache(); ut_console_reporter_base.set_color_enabled(a_color_console); @@ -93,10 +92,10 @@ create or replace package body ut_runner is ); l_items_to_run.do_execute(l_listener); - finish_run(l_listener.reporters); + finish_run(l_listener); exception when others then - finish_run(l_listener.reporters); + finish_run(l_listener); dbms_output.put_line(dbms_utility.format_error_backtrace); dbms_output.put_line(dbms_utility.format_error_stack); raise; @@ -142,5 +141,38 @@ create or replace package body ut_runner is return; end; + function get_reporters_list return tt_reporters_info pipelined + AS + l_cursor sys_refcursor; + l_owner varchar2(128) := ut_utils.ut_owner(); + l_results tt_reporters_info; + c_bulk_limit constant integer := 10; + begin + open l_cursor for 'SELECT + owner || ''.'' || type_name, + CASE + WHEN sys_connect_by_path(owner + || ''.'' + || type_name,'','') LIKE ''%' || l_owner || ''' + || ''.UT_OUTPUT_REPORTER_BASE%'' THEN ''Y'' + ELSE ''N'' + END + is_output_reporter + FROM dba_types t + WHERE instantiable = ''YES'' + CONNECT BY supertype_name = PRIOR type_name AND supertype_owner = PRIOR owner + START WITH type_name = ''UT_REPORTER_BASE'' AND owner = '''|| l_owner || ''''; + loop + fetch l_cursor bulk collect into l_results limit c_bulk_limit; + for i in 1 .. l_results.count loop + pipe row (l_results(i)); + end loop; + exit when l_cursor%notfound; + end loop; + close l_cursor; + end; + + + end ut_runner; / diff --git a/source/api/ut_runner.pks b/source/api/ut_runner.pks index 79b015ad3..582f63073 100644 --- a/source/api/ut_runner.pks +++ b/source/api/ut_runner.pks @@ -99,6 +99,17 @@ create or replace package ut_runner authid current_user is */ function get_unit_test_info(a_owner varchar2, a_package_name varchar2 := null) return tt_annotations pipelined; + type t_reporter_rec is record ( + reporter_object_name varchar2(250), + is_output_reporter varchar2(1) --Y/N flag + ); + type tt_reporters_info is table of t_reporter_rec ; + + /** Returns a list of available reporters. Gives information about whether a reporter is an output reporter or not + * + * @return tt_reporters_info + */ + function get_reporters_list return tt_reporters_info pipelined; end ut_runner; / diff --git a/source/core/coverage/ut_coverage_reporter_base.tpb b/source/core/coverage/ut_coverage_reporter_base.tpb index 42b416850..cf8135ba5 100644 --- a/source/core/coverage/ut_coverage_reporter_base.tpb +++ b/source/core/coverage/ut_coverage_reporter_base.tpb @@ -18,7 +18,7 @@ create or replace type body ut_coverage_reporter_base is overriding final member procedure before_calling_run(self in out nocopy ut_coverage_reporter_base, a_run ut_run) as begin - (self as ut_reporter_base).before_calling_run(a_run); + (self as ut_output_reporter_base).before_calling_run(a_run); ut_coverage.coverage_start(); end; diff --git a/source/core/coverage/ut_coverage_reporter_base.tps b/source/core/coverage/ut_coverage_reporter_base.tps index 4b837dc79..b7ef2a68f 100644 --- a/source/core/coverage/ut_coverage_reporter_base.tps +++ b/source/core/coverage/ut_coverage_reporter_base.tps @@ -1,4 +1,4 @@ -create or replace type ut_coverage_reporter_base under ut_reporter_base( +create or replace type ut_coverage_reporter_base under ut_output_reporter_base( /* utPLSQL - Version 3 Copyright 2016 - 2017 utPLSQL Project diff --git a/source/core/output_buffers/ut_message_id_seq.sql b/source/core/output_buffers/ut_message_id_seq.sql new file mode 100644 index 000000000..3f0cd25c4 --- /dev/null +++ b/source/core/output_buffers/ut_message_id_seq.sql @@ -0,0 +1 @@ +create sequence ut_message_id_seq nocycle cache 100; diff --git a/source/core/output_buffers/ut_output_buffer_base.tps b/source/core/output_buffers/ut_output_buffer_base.tps new file mode 100644 index 000000000..320b4ed5c --- /dev/null +++ b/source/core/output_buffers/ut_output_buffer_base.tps @@ -0,0 +1,27 @@ +create or replace type ut_output_buffer_base authid definer as object( + /* + utPLSQL - Version 3 + Copyright 2016 - 2017 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + output_id raw(32), + member procedure init(self in out nocopy ut_output_buffer_base), + not instantiable member procedure close(self in ut_output_buffer_base), + not instantiable member procedure send_line(self in ut_output_buffer_base, a_text varchar2), + not instantiable member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, + not instantiable member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, + not instantiable member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout natural := null, a_timeout_sec natural := null) +) not final not instantiable +/ diff --git a/source/core/output_buffers/ut_output_buffer_info_tmp.sql b/source/core/output_buffers/ut_output_buffer_info_tmp.sql new file mode 100644 index 000000000..0cfe58ed2 --- /dev/null +++ b/source/core/output_buffers/ut_output_buffer_info_tmp.sql @@ -0,0 +1,63 @@ +create table ut_output_buffer_info_tmp$( + /* + utPLSQL - Version 3 + Copyright 2016 - 2017 utPLSQL Project + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + /* + * This table is not a global temporary table as it needs to allow cross-session data exchange + * It is used however as a temporary table with multiple writers. + * This is why it has very high initrans and has nologging + */ + output_id raw(32) not null, + start_date date not null, + constraint ut_output_buffer_info_tmp_pk primary key(output_id) +) organization index nologging initrans 10 +; + +-- This is needed to be EBR ready as editioning view can only be created by edition enabled user +declare + ex_nonedition_user exception; + ex_view_doesnt_exist exception; + pragma exception_init(ex_nonedition_user,-42314); + pragma exception_init(ex_view_doesnt_exist,-942); + v_view_source varchar2(32767); +begin + begin + execute immediate 'drop view ut_output_buffer_info_tmp'; + exception + when ex_view_doesnt_exist then + null; + end; + v_view_source := ' ut_output_buffer_info_tmp as +/* +utPLSQL - Version 3 +Copyright 2016 - 2017 utPLSQL Project +Licensed under the Apache License, Version 2.0 (the "License"): +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +select output_id + ,start_date + from ut_output_buffer_info_tmp$'; + + execute immediate 'create or replace editioning view '||v_view_source; +exception + when ex_nonedition_user then + execute immediate 'create or replace view '||v_view_source; +end; +/ diff --git a/source/core/ut_output_buffer_tmp.sql b/source/core/output_buffers/ut_output_buffer_tmp.sql similarity index 86% rename from source/core/ut_output_buffer_tmp.sql rename to source/core/output_buffers/ut_output_buffer_tmp.sql index 1a8b8b7ea..8d0def8a8 100644 --- a/source/core/ut_output_buffer_tmp.sql +++ b/source/core/output_buffers/ut_output_buffer_tmp.sql @@ -17,18 +17,16 @@ create table ut_output_buffer_tmp$( * It is used however as a temporary table with multiple writers. * This is why it has very high initrans and has nologging */ - reporter_id raw(32) not null, + output_id raw(32) not null, message_id number(38,0) not null, text varchar2(4000), is_finished number(1,0) default 0 not null, - start_date date not null, - constraint ut_output_buffer_tmp_pk primary key(reporter_id, message_id), - constraint ut_output_buffer_tmp_ck check(is_finished = 0 and text is not null or is_finished = 1 and text is null) -) nologging nomonitoring initrans 100 + constraint ut_output_buffer_tmp_pk primary key(output_id, message_id), + constraint ut_output_buffer_tmp_ck check(is_finished = 0 and text is not null or is_finished = 1 and text is null), + constraint ut_output_buffer_fk1 foreign key (output_id) references ut_output_buffer_info_tmp$(output_id) +) organization index overflow nologging initrans 100 ; -create index ut_output_buffer_tmp_i on ut_output_buffer_tmp$(start_date) initrans 100 nologging; - -- This is needed to be EBR ready as editioning view can only be created by edition enabled user declare ex_nonedition_user exception; @@ -57,11 +55,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -select reporter_id +select output_id ,message_id ,text ,is_finished - ,start_date from ut_output_buffer_tmp$'; execute immediate 'create or replace editioning view '||v_view_source; diff --git a/source/core/output_buffers/ut_output_table_buffer.tpb b/source/core/output_buffers/ut_output_table_buffer.tpb new file mode 100644 index 000000000..d7d9a0813 --- /dev/null +++ b/source/core/output_buffers/ut_output_table_buffer.tpb @@ -0,0 +1,159 @@ +create or replace type body ut_output_table_buffer is + /* + utPLSQL - Version 3 + Copyright 2016 - 2017 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_output_table_buffer(self in out nocopy ut_output_table_buffer, a_output_id raw := null) return self as result is + begin + self.output_id := coalesce(a_output_id, sys_guid()); + self.start_date := sysdate; + self.init(); + self.cleanup_buffer(); + return; + end; + + overriding member procedure init(self in out nocopy ut_output_table_buffer) is + pragma autonomous_transaction; + l_exists int; + begin + select count(*) into l_exists from ut_output_buffer_info_tmp where output_id = self.output_id; + if ( l_exists > 0 ) then + update ut_output_buffer_info_tmp set start_date = self.start_date where output_id = self.output_id; + else + insert into ut_output_buffer_info_tmp(output_id, start_date) values (self.output_id, self.start_date); + end if; + commit; + end; + + overriding member procedure close(self in ut_output_table_buffer) is + pragma autonomous_transaction; + begin + insert into ut_output_buffer_tmp(output_id, message_id, is_finished) + values (self.output_id, ut_message_id_seq.nextval, 1); + commit; + end; + + overriding member procedure send_line(self in ut_output_table_buffer, a_text varchar2) is + l_text_list ut_varchar2_rows; + pragma autonomous_transaction; + begin + if a_text is not null then + if length(a_text) > ut_utils.gc_max_storage_varchar2_len then + l_text_list := ut_utils.convert_collection(ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len)); + insert + into ut_output_buffer_tmp(output_id, message_id, text) + select self.output_id, ut_message_id_seq.nextval, t.column_value + from table(l_text_list) t; + else + insert into ut_output_buffer_tmp(output_id, message_id, text) + values (self.output_id, ut_message_id_seq.nextval, a_text); + end if; + commit; + end if; + end; + + overriding member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined is + l_buffer_data ut_varchar2_rows; + l_already_waited_for number(10,2) := 0; + l_finished boolean := false; + lc_init_wait_sec constant naturaln := coalesce(a_initial_timeout, 60 ); -- 1 minute + lc_max_wait_sec constant naturaln := coalesce(a_timeout_sec, 60 * 60); -- 1 hour + l_wait_for integer := lc_init_wait_sec; + lc_short_sleep_time constant number(1,1) := 0.1; --sleep for 100 ms between checks + lc_long_sleep_time constant number(1) := 1; --sleep for 1 s when waiting long + lc_long_wait_time constant number(1) := 1; --waiting more than 1 sec + l_sleep_time number(2,1) := lc_short_sleep_time; + function get_data_from_buffer return ut_varchar2_rows is + l_results ut_varchar2_rows; + pragma autonomous_transaction; + begin + delete from ( + select * + from ut_output_buffer_tmp where output_id = self.output_id order by message_id + ) + returning text bulk collect into l_results; + commit; + return l_results; + end; + + begin + loop + l_buffer_data := get_data_from_buffer(); + --nothing fetched from output, wait and try again + if l_buffer_data.count = 0 then + dbms_lock.sleep(l_sleep_time); + l_already_waited_for := l_already_waited_for + l_sleep_time; + if l_already_waited_for > lc_long_wait_time then + l_sleep_time := lc_long_sleep_time; + end if; + else + --reset wait time + -- we wait lc_max_wait_sec for new message + l_wait_for := lc_max_wait_sec; + l_already_waited_for := 0; + l_sleep_time := lc_short_sleep_time; + for i in 1 .. l_buffer_data.count loop + if l_buffer_data(i) is not null then + pipe row(l_buffer_data(i)); + else + l_finished := true; + exit; + end if; + end loop; + end if; + exit when l_already_waited_for >= l_wait_for or l_finished; + end loop; + return; + end; + + overriding member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor is + l_lines sys_refcursor; + begin + open l_lines for + select column_value as text + from table(self.get_lines(a_initial_timeout, a_timeout_sec)); + return l_lines; + end; + + overriding member procedure lines_to_dbms_output(self in ut_output_table_buffer, a_initial_timeout natural := null, a_timeout_sec natural := null) is + l_lines sys_refcursor; + l_line varchar2(32767); + begin + l_lines := self.get_lines_cursor(a_initial_timeout, a_timeout_sec); + loop + fetch l_lines into l_line; + exit when l_lines%notfound; + dbms_output.put_line(l_line); + end loop; + close l_lines; + end; + + member procedure cleanup_buffer(self in ut_output_table_buffer, a_retention_time_sec natural := null) is + gc_buffer_retention_sec constant naturaln := coalesce(a_retention_time_sec, 60 * 60 * 24); -- 24 hours + l_retention_days number := gc_buffer_retention_sec / (60 * 60 * 24); + l_max_retention_date date := sysdate - l_retention_days; + pragma autonomous_transaction; + begin + delete from ut_output_buffer_tmp t + where t.output_id + in (select i.output_id from ut_output_buffer_info_tmp i where i.start_date <= l_max_retention_date); + + delete from ut_output_buffer_info_tmp i where i.start_date <= l_max_retention_date; + commit; + end; + +end; +/ diff --git a/source/core/output_buffers/ut_output_table_buffer.tps b/source/core/output_buffers/ut_output_table_buffer.tps new file mode 100644 index 000000000..f052b0744 --- /dev/null +++ b/source/core/output_buffers/ut_output_table_buffer.tps @@ -0,0 +1,29 @@ +create or replace type ut_output_table_buffer under ut_output_buffer_base ( + /* + utPLSQL - Version 3 + Copyright 2016 - 2017 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + start_date date, + constructor function ut_output_table_buffer(self in out nocopy ut_output_table_buffer, a_output_id raw := null) return self as result, + overriding member procedure init(self in out nocopy ut_output_table_buffer), + overriding member procedure send_line(self in ut_output_table_buffer, a_text varchar2), + overriding member procedure close(self in ut_output_table_buffer), + overriding member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, + overriding member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, + overriding member procedure lines_to_dbms_output(self in ut_output_table_buffer, a_initial_timeout natural := null, a_timeout_sec natural := null), + member procedure cleanup_buffer(self in ut_output_table_buffer, a_retention_time_sec natural := null) +) not final +/ diff --git a/source/core/types/ut_console_reporter_base.tps b/source/core/types/ut_console_reporter_base.tps index 5fb4561c0..23882596a 100644 --- a/source/core/types/ut_console_reporter_base.tps +++ b/source/core/types/ut_console_reporter_base.tps @@ -1,4 +1,4 @@ -create or replace type ut_console_reporter_base under ut_reporter_base( +create or replace type ut_console_reporter_base under ut_output_reporter_base( /* utPLSQL - Version 3 Copyright 2016 - 2017 utPLSQL Project diff --git a/source/core/types/ut_event_listener.tpb b/source/core/types/ut_event_listener.tpb index 8e2fcb110..501c40689 100644 --- a/source/core/types/ut_event_listener.tpb +++ b/source/core/types/ut_event_listener.tpb @@ -24,15 +24,15 @@ create or replace type body ut_event_listener is overriding member procedure fire_before_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base) is begin - self.fire_event('before', a_event_name, a_item); + self.fire_on_event('before', a_event_name, a_item); end; overriding member procedure fire_after_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base) is begin - self.fire_event('after', a_event_name, a_item); + self.fire_on_event('after', a_event_name, a_item); end; - overriding member procedure fire_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) is + overriding member procedure fire_on_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) is begin for i in 1..self.reporters.count loop if a_event_timing = 'before' then @@ -56,8 +56,6 @@ create or replace type body ut_event_listener is self.reporters(i).before_calling_after_each(treat(a_item as ut_test)); elsif a_event_name = ut_utils.gc_after_all then self.reporters(i).before_calling_after_all(treat(a_item as ut_logical_suite)); - else - raise_application_error(ut_utils.gc_invalid_rep_event_name,'Invalid reporting event name - '|| nvl(a_event_name,'NULL')); end if; elsif a_event_timing = 'after' then if a_event_name = ut_utils.gc_run then @@ -80,15 +78,20 @@ create or replace type body ut_event_listener is self.reporters(i).after_calling_after_each(treat(a_item as ut_test)); elsif a_event_name = ut_utils.gc_after_all then self.reporters(i).after_calling_after_all(treat(a_item as ut_logical_suite)); - else - raise_application_error(ut_utils.gc_invalid_rep_event_name,'Invalid reporting event name - '|| nvl(a_event_name,'NULL')); end if; - else - raise_application_error(ut_utils.gc_invalid_rep_event_time,'Invalid reporting event time - '|| nvl(a_event_timing,'NULL')); end if; end loop; - end fire_event; + end fire_on_event; + + overriding member procedure fire_on_event(self in out nocopy ut_event_listener, a_event_name varchar2) is + begin + for i in 1..self.reporters.count loop + if a_event_name = ut_utils.gc_finalize then + self.reporters(i).finalize(); + end if; + end loop; + end fire_on_event; end; / diff --git a/source/core/types/ut_event_listener.tps b/source/core/types/ut_event_listener.tps index cba15602b..d9a063362 100644 --- a/source/core/types/ut_event_listener.tps +++ b/source/core/types/ut_event_listener.tps @@ -19,6 +19,7 @@ create or replace type ut_event_listener under ut_event_listener_base( constructor function ut_event_listener(self in out nocopy ut_event_listener, a_reporters ut_reporters) return self as result, overriding member procedure fire_before_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base), overriding member procedure fire_after_event(self in out nocopy ut_event_listener, a_event_name varchar2, a_item ut_suite_item_base), - overriding member procedure fire_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) + overriding member procedure fire_on_event(self in out nocopy ut_event_listener, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base), + overriding member procedure fire_on_event(self in out nocopy ut_event_listener, a_event_name varchar2) ) / diff --git a/source/core/types/ut_event_listener_base.tps b/source/core/types/ut_event_listener_base.tps index cb3d52904..d157b9458 100644 --- a/source/core/types/ut_event_listener_base.tps +++ b/source/core/types/ut_event_listener_base.tps @@ -18,6 +18,7 @@ create or replace type ut_event_listener_base authid current_user as object( name varchar2(250), member procedure fire_before_event(self in out nocopy ut_event_listener_base, a_event_name varchar2, a_item ut_suite_item_base), member procedure fire_after_event(self in out nocopy ut_event_listener_base, a_event_name varchar2, a_item ut_suite_item_base), - member procedure fire_event(self in out nocopy ut_event_listener_base, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base) + member procedure fire_on_event(self in out nocopy ut_event_listener_base, a_event_timing varchar2, a_event_name varchar2, a_item ut_suite_item_base), + member procedure fire_on_event(self in out nocopy ut_event_listener_base, a_event_name varchar2) ) not final not instantiable / diff --git a/source/core/types/ut_output_reporter_base.tpb b/source/core/types/ut_output_reporter_base.tpb new file mode 100644 index 000000000..c65d6c879 --- /dev/null +++ b/source/core/types/ut_output_reporter_base.tpb @@ -0,0 +1,83 @@ +create or replace type body ut_output_reporter_base is + /* + utPLSQL - Version 3 + Copyright 2016 - 2017 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_output_reporter_base(self in out nocopy ut_output_reporter_base) return self as result is + begin + return; + end; + + member procedure init(self in out nocopy ut_output_reporter_base, a_self_type varchar2, a_output_buffer ut_output_buffer_base := null) is + begin + (self as ut_reporter_base).init(a_self_type); + self.output_buffer := coalesce(a_output_buffer, ut_output_table_buffer()); + self.set_reporter_id(self.output_buffer.output_id); + end; + + overriding member procedure set_reporter_id(self in out nocopy ut_output_reporter_base, a_reporter_id raw) is + begin + self.id := a_reporter_id; + self.output_buffer.output_id := a_reporter_id; + end; + + overriding member procedure before_calling_run(self in out nocopy ut_output_reporter_base, a_run in ut_run) is + l_output_table_buffer ut_output_table_buffer; + begin + (self as ut_reporter_base).before_calling_run(a_run); + l_output_table_buffer := treat(self.output_buffer as ut_output_table_buffer); + end; + + member procedure print_text(self in out nocopy ut_output_reporter_base, a_text varchar2) is + begin + self.output_buffer.send_line(a_text); + end; + + final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural) return ut_varchar2_rows pipelined is + begin + for i in (select column_value from table(self.output_buffer.get_lines(a_initial_timeout, a_timeout_sec))) loop + pipe row (i.column_value); + end loop; + end; + + final member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural) return sys_refcursor is + begin + return self.output_buffer.get_lines_cursor(a_initial_timeout, a_timeout_sec); + end; + + final member procedure lines_to_dbms_output(self in ut_output_reporter_base, a_initial_timeout natural := null, a_timeout_sec natural) is + begin + self.output_buffer.lines_to_dbms_output(a_initial_timeout, a_timeout_sec); + end; + + member procedure print_clob(self in out nocopy ut_output_reporter_base, a_clob clob) is + l_lines ut_varchar2_list; + begin + if a_clob is not null and dbms_lob.getlength(a_clob) > 0 then + l_lines := ut_utils.clob_to_table(a_clob); + for i in 1 .. l_lines.count loop + self.print_text(l_lines(i)); + end loop; + end if; + end; + + overriding final member procedure finalize(self in out nocopy ut_output_reporter_base) is + begin + self.output_buffer.close(); + end; + +end; +/ diff --git a/source/core/types/ut_output_reporter_base.tps b/source/core/types/ut_output_reporter_base.tps new file mode 100644 index 000000000..8684bf78a --- /dev/null +++ b/source/core/types/ut_output_reporter_base.tps @@ -0,0 +1,34 @@ +create or replace type ut_output_reporter_base under ut_reporter_base( + /* + utPLSQL - Version 3 + Copyright 2016 - 2017 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + output_buffer ut_output_buffer_base, + constructor function ut_output_reporter_base(self in out nocopy ut_output_reporter_base) return self as result, + member procedure init(self in out nocopy ut_output_reporter_base, a_self_type varchar2, a_output_buffer ut_output_buffer_base := null), + overriding member procedure set_reporter_id(self in out nocopy ut_output_reporter_base, a_reporter_id raw), + overriding member procedure before_calling_run(self in out nocopy ut_output_reporter_base, a_run in ut_run), + + member procedure print_text(self in out nocopy ut_output_reporter_base, a_text varchar2), + + member procedure print_clob(self in out nocopy ut_output_reporter_base, a_clob clob), + + final member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_varchar2_rows pipelined, + final member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor, + final member procedure lines_to_dbms_output(self in ut_output_reporter_base, a_initial_timeout natural := null, a_timeout_sec natural := null), + overriding final member procedure finalize(self in out nocopy ut_output_reporter_base) +) +not final not instantiable +/ diff --git a/source/core/types/ut_reporter_base.tpb b/source/core/types/ut_reporter_base.tpb index 8b9ee105a..c5a48996a 100644 --- a/source/core/types/ut_reporter_base.tpb +++ b/source/core/types/ut_reporter_base.tpb @@ -19,25 +19,23 @@ create or replace type body ut_reporter_base is final member procedure init(self in out nocopy ut_reporter_base, a_self_type varchar2) is begin self.self_type := a_self_type; - self.reporter_id := sys_guid(); - self.start_date := sysdate(); + self.id := sys_guid(); return; end; - member procedure print_text(self in out nocopy ut_reporter_base, a_text varchar2) is + member procedure set_reporter_id(self in out nocopy ut_reporter_base, a_reporter_id raw) is begin - ut_output_buffer.send_line(self,a_text); + self.id := a_reporter_id; end; - member procedure print_clob(self in out nocopy ut_reporter_base, a_clob clob) is - l_lines ut_varchar2_list; + member function get_reporter_id return raw is begin - if a_clob is not null and dbms_lob.getlength(a_clob) > 0 then - l_lines := ut_utils.clob_to_table(a_clob); - for i in 1 .. l_lines.count loop - self.print_text(l_lines(i)); - end loop; - end if; + return self.id; + end; + + member function get_description return varchar2 is + begin + return 'No description available'; end; -- run hooks @@ -135,7 +133,7 @@ create or replace type body ut_reporter_base is -- run hooks continued member procedure after_calling_run (self in out nocopy ut_reporter_base, a_run in ut_run) is begin - ut_output_buffer.close(self); + null; end; end; diff --git a/source/core/types/ut_reporter_base.tps b/source/core/types/ut_reporter_base.tps index 4e9053ec6..a1ee6be25 100644 --- a/source/core/types/ut_reporter_base.tps +++ b/source/core/types/ut_reporter_base.tps @@ -15,14 +15,12 @@ create or replace type ut_reporter_base authid current_user as object( See the License for the specific language governing permissions and limitations under the License. */ - self_type varchar2(250), - reporter_id raw(32), - start_date date, + self_type varchar2(250), + id raw(32), final member procedure init(self in out nocopy ut_reporter_base, a_self_type varchar2), - - member procedure print_text(self in out nocopy ut_reporter_base, a_text varchar2), - - member procedure print_clob(self in out nocopy ut_reporter_base, a_clob clob), + member procedure set_reporter_id(self in out nocopy ut_reporter_base, a_reporter_id raw), + member function get_reporter_id return raw, + member function get_description return varchar2, -- run hooks member procedure before_calling_run(self in out nocopy ut_reporter_base, a_run in ut_run), @@ -60,7 +58,12 @@ create or replace type ut_reporter_base authid current_user as object( member procedure after_calling_suite(self in out nocopy ut_reporter_base, a_suite in ut_logical_suite), -- run hooks continued - member procedure after_calling_run (self in out nocopy ut_reporter_base, a_run in ut_run) + member procedure after_calling_run (self in out nocopy ut_reporter_base, a_run in ut_run), + + -- This method is executed when reporter is getting finalized + -- it differs from after_calling_run, as it is getting called, even when the run fails + -- This way, you may close all open outputs, files, connections etc. that need closing before the run finishes + not instantiable member procedure finalize(self in out nocopy ut_reporter_base) ) not final not instantiable diff --git a/source/core/types/ut_run.tpb b/source/core/types/ut_run.tpb index 611e4cab3..dac651bb1 100644 --- a/source/core/types/ut_run.tpb +++ b/source/core/types/ut_run.tpb @@ -72,6 +72,7 @@ create or replace type body ut_run as self.end_time := current_timestamp; a_listener.fire_after_event(ut_utils.gc_run, self); + a_listener.fire_on_event(ut_utils.gc_finalize); return l_completed_without_errors; end; diff --git a/source/core/ut_message_id_seq.sql b/source/core/ut_message_id_seq.sql deleted file mode 100644 index 6a8b11c5d..000000000 --- a/source/core/ut_message_id_seq.sql +++ /dev/null @@ -1 +0,0 @@ -create sequence ut_message_id_seq nocycle cache 20; diff --git a/source/core/ut_output_buffer.pkb b/source/core/ut_output_buffer.pkb deleted file mode 100644 index 5f957f2bd..000000000 --- a/source/core/ut_output_buffer.pkb +++ /dev/null @@ -1,128 +0,0 @@ -create or replace package body ut_output_buffer is - /* - utPLSQL - Version 3 - Copyright 2016 - 2017 utPLSQL Project - - Licensed under the Apache License, Version 2.0 (the "License"): - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - procedure send_line(a_reporter ut_reporter_base, a_text varchar2) is - l_text_list ut_varchar2_rows; - pragma autonomous_transaction; - begin - if a_reporter is not null and a_reporter.reporter_id is not null and a_reporter.start_date is not null and a_text is not null then - if length(a_text) > ut_utils.gc_max_storage_varchar2_len then - l_text_list := ut_utils.convert_collection(ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len)); - insert /*+ append */ - into ut_output_buffer_tmp(start_date, reporter_id, message_id, text) - select a_reporter.start_date, a_reporter.reporter_id, ut_message_id_seq.nextval, t.column_value - from table(l_text_list) t; - else - insert /*+ append */ into ut_output_buffer_tmp(start_date, reporter_id, message_id, text) - values (a_reporter.start_date, a_reporter.reporter_id, ut_message_id_seq.nextval, a_text); - end if; - commit; - end if; - end; - - procedure close(a_reporter ut_reporter_base) is - pragma autonomous_transaction; - begin - insert /*+ append */ into ut_output_buffer_tmp(start_date, reporter_id, message_id, is_finished) - values (a_reporter.start_date, a_reporter.reporter_id, ut_message_id_seq.nextval, 1); - commit; - end; - - procedure close(a_reporters ut_reporters) is - pragma autonomous_transaction; - begin - if a_reporters is not null then - forall i in 1 .. a_reporters.count - insert /*+ append */ into ut_output_buffer_tmp(start_date, reporter_id, message_id, is_finished) - values (a_reporters(i).start_date, a_reporters(i).reporter_id, ut_message_id_seq.nextval, 1); - end if; - commit; - end; - - function get_lines(a_reporter_id varchar2, a_timeout_sec naturaln := gc_max_wait_sec) return ut_varchar2_rows pipelined is - l_buffer_data ut_varchar2_rows; - l_wait_wait_time number(10,1) := 0; - l_finished boolean := false; - function get_data_from_buffer return ut_varchar2_rows is - l_results ut_varchar2_rows; - pragma autonomous_transaction; - begin - delete from ( - select * - from ut_output_buffer_tmp where reporter_id = a_reporter_id order by message_id - ) - returning text bulk collect into l_results; - commit; - return l_results; - end; - begin - loop - l_buffer_data := get_data_from_buffer(); - --nothing fetched from output, wait and try again - if l_buffer_data.count = 0 then - dbms_lock.sleep(gc_sleep_time); - l_wait_wait_time := l_wait_wait_time + gc_sleep_time; - else - for i in 1 .. l_buffer_data.count loop - if l_buffer_data(i) is not null then - pipe row(l_buffer_data(i)); - else - l_finished := true; - exit; - end if; - end loop; - end if; - exit when l_wait_wait_time >= a_timeout_sec or l_finished; - end loop; - return; - end; - - function get_lines_cursor(a_reporter_id varchar2, a_timeout_sec naturaln := gc_max_wait_sec) return sys_refcursor is - l_lines sys_refcursor; - begin - open l_lines for - select column_value as text - from table(ut_output_buffer.get_lines(a_reporter_id, a_timeout_sec)); - return l_lines; - end; - - procedure lines_to_dbms_output(a_reporter_id varchar2, a_timeout_sec naturaln := gc_max_wait_sec) is - l_lines sys_refcursor; - l_line varchar2(32767); - begin - l_lines := ut_output_buffer.get_lines_cursor(a_reporter_id, a_timeout_sec); - loop - fetch l_lines into l_line; - exit when l_lines%notfound; - dbms_output.put_line(l_line); - end loop; - close l_lines; - end; - - procedure cleanup_buffer(a_retention_time_sec naturaln := gc_buffer_retention_sec) is - l_retention_days number := a_retention_time_sec / (60 * 60 * 24); - l_max_retention_date date := sysdate - l_retention_days; - pragma autonomous_transaction; -- the cleanup should initiate transaction - begin - delete from ut_output_buffer_tmp t - where t.start_date <= l_max_retention_date; - commit; - end; - -end; -/ diff --git a/source/core/ut_output_buffer.pks b/source/core/ut_output_buffer.pks deleted file mode 100644 index fd66814a4..000000000 --- a/source/core/ut_output_buffer.pks +++ /dev/null @@ -1,38 +0,0 @@ -create or replace package ut_output_buffer authid definer is - /* - utPLSQL - Version 3 - Copyright 2016 - 2017 utPLSQL Project - - Licensed under the Apache License, Version 2.0 (the "License"): - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - gc_max_wait_sec constant naturaln := 60 * 60 * 4; -- 4 hours - gc_buffer_retention_sec constant naturaln := 60 * 60 * 24; -- 24 hours - gc_sleep_time constant number(1,1) := 0.1; --sleep for 100 ms between checks - - procedure send_line(a_reporter ut_reporter_base, a_text varchar2); - - procedure close(a_reporter ut_reporter_base); - - procedure close(a_reporters ut_reporters); - - function get_lines(a_reporter_id varchar2, a_timeout_sec naturaln := gc_max_wait_sec) return ut_varchar2_rows pipelined; - - function get_lines_cursor(a_reporter_id varchar2, a_timeout_sec naturaln := gc_max_wait_sec) return sys_refcursor; - - procedure lines_to_dbms_output(a_reporter_id varchar2, a_timeout_sec naturaln := gc_max_wait_sec); - - procedure cleanup_buffer(a_retention_time_sec naturaln := gc_buffer_retention_sec); - -end; -/ diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index 6b494592d..4b7db6689 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -34,6 +34,7 @@ create or replace package ut_utils authid definer is gc_after_test constant varchar2(10) := 'after_test'; gc_after_each constant varchar2(12) := 'after_each'; gc_after_all constant varchar2(12) := 'after_all'; + gc_finalize constant varchar2(12) := 'finalize'; /* Constants: Test Results */ tr_disabled constant number(1) := 0; -- test/suite was disabled diff --git a/source/create_synonyms_and_grants_for_public.sql b/source/create_synonyms_and_grants_for_public.sql index cf003c3b9..6ac4fcba5 100644 --- a/source/create_synonyms_and_grants_for_public.sql +++ b/source/create_synonyms_and_grants_for_public.sql @@ -59,10 +59,12 @@ grant execute on &&ut3_owner..ut_varchar2_list to public; grant execute on &&ut3_owner..ut_varchar2_rows to public; grant execute on &&ut3_owner..ut_integer_list to public; grant execute on &&ut3_owner..ut_reporter_base to public; +grant execute on &&ut3_owner..ut_output_reporter_base to public; grant execute on &&ut3_owner..ut_coverage to public; grant execute on &&ut3_owner..ut_coverage_options to public; grant execute on &&ut3_owner..ut_coverage_helper to public; -grant execute on &&ut3_owner..ut_output_buffer to public; +grant execute on &&ut3_owner..ut_output_buffer_base to public; +grant execute on &&ut3_owner..ut_output_table_buffer to public; grant execute on &&ut3_owner..ut_file_mappings to public; grant execute on &&ut3_owner..ut_file_mapping to public; grant execute on &&ut3_owner..ut_file_mapper to public; @@ -114,10 +116,12 @@ create public synonym ut_varchar2_list for &&ut3_owner..ut_varchar2_list; create public synonym ut_varchar2_rows for &&ut3_owner..ut_varchar2_rows; create public synonym ut_integer_list for &&ut3_owner..ut_integer_list; create public synonym ut_reporter_base for &&ut3_owner..ut_reporter_base; +create public synonym ut_output_reporter_base for &&ut3_owner..ut_output_reporter_base; create public synonym ut_coverage for &&ut3_owner..ut_coverage; create public synonym ut_coverage_options for &&ut3_owner..ut_coverage_options; create public synonym ut_coverage_helper for &&ut3_owner..ut_coverage_helper; -create public synonym ut_output_buffer for &&ut3_owner..ut_output_buffer; +create public synonym ut_output_buffer_base for &&ut3_owner..ut_output_buffer_base; +create public synonym ut_output_table_buffer for &&ut3_owner..ut_output_table_buffer; create public synonym ut_file_mappings for &&ut3_owner..ut_file_mappings; create public synonym ut_file_mapping for &&ut3_owner..ut_file_mapping; create public synonym ut_file_mapper for &&ut3_owner..ut_file_mapper; diff --git a/source/create_synonyms_and_grants_for_user.sql b/source/create_synonyms_and_grants_for_user.sql index 2ad2d226b..1ebdf7a4a 100644 --- a/source/create_synonyms_and_grants_for_user.sql +++ b/source/create_synonyms_and_grants_for_user.sql @@ -79,10 +79,12 @@ grant execute on &&ut3_owner..ut_varchar2_list to &ut3_user; grant execute on &&ut3_owner..ut_varchar2_rows to &ut3_user; grant execute on &&ut3_owner..ut_integer_list to &ut3_user; grant execute on &&ut3_owner..ut_reporter_base to &ut3_user; +grant execute on &&ut3_owner..ut_output_reporter_base to &ut3_user; grant execute on &&ut3_owner..ut_coverage to &ut3_user; grant execute on &&ut3_owner..ut_coverage_options to &ut3_user; grant execute on &&ut3_owner..ut_coverage_helper to &ut3_user; -grant execute on &&ut3_owner..ut_output_buffer to &ut3_user; +grant execute on &&ut3_owner..ut_output_buffer_base to &ut3_user; +grant execute on &&ut3_owner..ut_output_table_buffer to &ut3_user; grant execute on &&ut3_owner..ut_file_mappings to &ut3_user; grant execute on &&ut3_owner..ut_file_mapping to &ut3_user; grant execute on &&ut3_owner..ut_file_mapper to &ut3_user; @@ -133,10 +135,12 @@ create or replace synonym &ut3_user..ut_varchar2_list for &&ut3_owner..ut_varcha create or replace synonym &ut3_user..ut_varchar2_rows for &&ut3_owner..ut_varchar2_rows; create or replace synonym &ut3_user..ut_integer_list for &&ut3_owner..ut_integer_list; create or replace synonym &ut3_user..ut_reporter_base for &&ut3_owner..ut_reporter_base; +create or replace synonym &ut3_user..ut_output_reporter_base for &&ut3_owner..ut_output_reporter_base; create or replace synonym &ut3_user..ut_coverage for &&ut3_owner..ut_coverage; create or replace synonym &ut3_user..ut_coverage_options for &&ut3_owner..ut_coverage_options; create or replace synonym &ut3_user..ut_coverage_helper for &&ut3_owner..ut_coverage_helper; -create or replace synonym &ut3_user..ut_output_buffer for &&ut3_owner..ut_output_buffer; +create or replace synonym &ut3_user..ut_output_buffer_base for &&ut3_owner..ut_output_buffer_base; +create or replace synonym &ut3_user..ut_output_table_buffer for &&ut3_owner..ut_output_table_buffer; create or replace synonym &ut3_user..ut_file_mappings for &&ut3_owner..ut_file_mappings; create or replace synonym &ut3_user..ut_file_mapping for &&ut3_owner..ut_file_mapping; create or replace synonym &ut3_user..ut_file_mapper for &&ut3_owner..ut_file_mapper; diff --git a/source/install.sql b/source/install.sql index 0837fa0f4..69be9317c 100644 --- a/source/install.sql +++ b/source/install.sql @@ -71,12 +71,17 @@ alter session set current_schema = &&ut3_owner; @@install_component.sql 'core/types/ut_reporters.tps' @@install_component.sql 'core/types/ut_event_listener.tps' +--output buffer base api +@@install_component.sql 'core/output_buffers/ut_output_buffer_base.tps' --output buffer table -@@install_component.sql 'core/ut_output_buffer_tmp.sql' -@@install_component.sql 'core/ut_message_id_seq.sql' ---output buffer api -@@install_component.sql 'core/ut_output_buffer.pks' -@@install_component.sql 'core/ut_output_buffer.pkb' +@@install_component.sql 'core/output_buffers/ut_output_buffer_info_tmp.sql' +@@install_component.sql 'core/output_buffers/ut_output_buffer_tmp.sql' +@@install_component.sql 'core/output_buffers/ut_message_id_seq.sql' +--output buffer table api +@@install_component.sql 'core/output_buffers/ut_output_table_buffer.tps' +@@install_component.sql 'core/output_buffers/ut_output_table_buffer.tpb' + +@@install_component.sql 'core/types/ut_output_reporter_base.tps' --annoations @@install_component.sql 'core/annotations/ut_annotation.tps' @@ -132,6 +137,7 @@ prompt Installing PLSQL profiler objects into &&ut3_owner schema @@install_component.sql 'core/types/ut_event_listener.tpb' @@install_component.sql 'core/types/ut_expectation_result.tpb' @@install_component.sql 'core/types/ut_reporter_base.tpb' +@@install_component.sql 'core/types/ut_output_reporter_base.tpb' @@install_component.sql 'core/types/ut_file_mapping.tpb' @@install_component.sql 'core/types/ut_executable.tpb' @@install_component.sql 'core/types/ut_executable_test.tpb' diff --git a/source/reporters/ut_coverage_cobertura_reporter.tpb b/source/reporters/ut_coverage_cobertura_reporter.tpb index d8d7cf6b2..edd783ca6 100644 --- a/source/reporters/ut_coverage_cobertura_reporter.tpb +++ b/source/reporters/ut_coverage_cobertura_reporter.tpb @@ -133,5 +133,13 @@ create or replace type body ut_coverage_cobertura_reporter is (self as ut_reporter_base).after_calling_run(a_run); end; + overriding member function get_description return varchar2 as + begin + return 'Generates a Cobertura coverage report providing information on code coverage with line numbers.' || chr(10) || + 'Designed for Jenkins and TFS to report coverage. ' || chr(10) || + 'Cobertura Document Type Definition can be found: http://cobertura.sourceforge.net/xml/coverage-04.dtd.'|| chr(10) || + 'Sample file: https://github.com/leobalter/testing-examples/blob/master/solutions/3/report/cobertura-coverage.xml.'; + end; + end; / diff --git a/source/reporters/ut_coverage_cobertura_reporter.tps b/source/reporters/ut_coverage_cobertura_reporter.tps index 26f14c2ec..9b50a3922 100644 --- a/source/reporters/ut_coverage_cobertura_reporter.tps +++ b/source/reporters/ut_coverage_cobertura_reporter.tps @@ -20,7 +20,9 @@ create or replace type ut_coverage_cobertura_reporter under ut_coverage_reporter self in out nocopy ut_coverage_cobertura_reporter ) return self as result, - overriding member procedure after_calling_run(self in out nocopy ut_coverage_cobertura_reporter, a_run in ut_run) + overriding member procedure after_calling_run(self in out nocopy ut_coverage_cobertura_reporter, a_run in ut_run), + + overriding member function get_description return varchar2 ) / diff --git a/source/reporters/ut_coverage_html_reporter.tpb b/source/reporters/ut_coverage_html_reporter.tpb index 737b55f8a..4ebb0b2fd 100644 --- a/source/reporters/ut_coverage_html_reporter.tpb +++ b/source/reporters/ut_coverage_html_reporter.tpb @@ -37,8 +37,14 @@ create or replace type body ut_coverage_html_reporter is l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); self.print_clob( ut_coverage_report_html_helper.get_index( l_coverage_data, self.assets_path, self.project_name ) ); + end; + - (self as ut_reporter_base).after_calling_run(a_run); + overriding member function get_description return varchar2 as + begin + return 'Generates a HTML coverage report with summary and line by line information on code coverage.' || chr(10) || + 'Based on open-source simplecov-html coverage reporter for Ruby.' || chr(10) || + 'Includes source code in the report.'; end; end; diff --git a/source/reporters/ut_coverage_html_reporter.tps b/source/reporters/ut_coverage_html_reporter.tps index c522b915b..fccfb0e43 100644 --- a/source/reporters/ut_coverage_html_reporter.tps +++ b/source/reporters/ut_coverage_html_reporter.tps @@ -23,6 +23,8 @@ create or replace type ut_coverage_html_reporter under ut_coverage_reporter_base a_html_report_assets_path varchar2 := null ) return self as result, - overriding member procedure after_calling_run(self in out nocopy ut_coverage_html_reporter, a_run in ut_run) + overriding member procedure after_calling_run(self in out nocopy ut_coverage_html_reporter, a_run in ut_run), + + overriding member function get_description return varchar2 ) / diff --git a/source/reporters/ut_coverage_sonar_reporter.tpb b/source/reporters/ut_coverage_sonar_reporter.tpb index 7d67e45c3..48b04ffdd 100644 --- a/source/reporters/ut_coverage_sonar_reporter.tpb +++ b/source/reporters/ut_coverage_sonar_reporter.tpb @@ -86,8 +86,13 @@ create or replace type body ut_coverage_sonar_reporter is l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); self.print_clob( get_coverage_xml( l_coverage_data ) ); + end; - (self as ut_reporter_base).after_calling_run(a_run); + overriding member function get_description return varchar2 as + begin + return 'Generates a JSON coverage report providing information on code coverage with line numbers.' || chr(10) || + 'Designed for [SonarQube](https://about.sonarqube.com/) to report coverage.' || chr(10) || + 'JSON format returned conforms with the Sonar specification: https://docs.sonarqube.org/display/SONAR/Generic+Test+Data'; end; end; diff --git a/source/reporters/ut_coverage_sonar_reporter.tps b/source/reporters/ut_coverage_sonar_reporter.tps index 499906618..a013ad2fa 100644 --- a/source/reporters/ut_coverage_sonar_reporter.tps +++ b/source/reporters/ut_coverage_sonar_reporter.tps @@ -24,6 +24,8 @@ create or replace type ut_coverage_sonar_reporter under ut_coverage_reporter_bas self in out nocopy ut_coverage_sonar_reporter ) return self as result, - overriding member procedure after_calling_run(self in out nocopy ut_coverage_sonar_reporter, a_run in ut_run) + overriding member procedure after_calling_run(self in out nocopy ut_coverage_sonar_reporter, a_run in ut_run), + + overriding member function get_description return varchar2 ) / diff --git a/source/reporters/ut_coveralls_reporter.tpb b/source/reporters/ut_coveralls_reporter.tpb index e524ab700..c13084415 100644 --- a/source/reporters/ut_coveralls_reporter.tpb +++ b/source/reporters/ut_coveralls_reporter.tpb @@ -97,8 +97,13 @@ create or replace type body ut_coveralls_reporter is l_coverage_data := ut_coverage.get_coverage_data(a_run.coverage_options); self.print_clob( get_coverage_json( l_coverage_data ) ); + end; - (self as ut_reporter_base).after_calling_run(a_run); + overriding member function get_description return varchar2 as + begin + return 'Generates a JSON coverage report providing information on code coverage with line numbers.' || chr(10) || + 'Designed for [Coveralls](https://coveralls.io/).' || chr(10) || + 'JSON format conforms with specification: https://docs.coveralls.io/api-introduction'; end; end; diff --git a/source/reporters/ut_coveralls_reporter.tps b/source/reporters/ut_coveralls_reporter.tps index f5badb6b0..d62ec5058 100644 --- a/source/reporters/ut_coveralls_reporter.tps +++ b/source/reporters/ut_coveralls_reporter.tps @@ -24,6 +24,8 @@ create or replace type ut_coveralls_reporter under ut_coverage_reporter_base( self in out nocopy ut_coveralls_reporter ) return self as result, - overriding member procedure after_calling_run(self in out nocopy ut_coveralls_reporter, a_run in ut_run) + overriding member procedure after_calling_run(self in out nocopy ut_coveralls_reporter, a_run in ut_run), + + overriding member function get_description return varchar2 ) / diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index e5df13337..0b4ab377d 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -1,200 +1,205 @@ -create or replace type body ut_documentation_reporter is - /* - utPLSQL - Version 3 - Copyright 2016 - 2017 utPLSQL Project - - Licensed under the Apache License, Version 2.0 (the "License"): - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - constructor function ut_documentation_reporter(self in out nocopy ut_documentation_reporter) return self as result is - begin - self.init($$plsql_unit); - self.lvl := 0; - self.failed_test_running_count := 0; - return; - end; - - member function tab(self in ut_documentation_reporter) return varchar2 is - begin - return rpad(' ', self.lvl * 2); - end tab; - - overriding member procedure print_text(self in out nocopy ut_documentation_reporter, a_text varchar2) is - l_lines ut_varchar2_list; - begin - if a_text is not null then - l_lines := ut_utils.string_to_table(a_text); - for i in 1 .. l_lines.count loop - (self as ut_reporter_base).print_text(tab || l_lines(i)); - end loop; - end if; - end; - - overriding member procedure before_calling_suite(self in out nocopy ut_documentation_reporter, a_suite ut_logical_suite) as - begin - self.print_text(coalesce(a_suite.description, a_suite.name)); - lvl := lvl + 1; - end; - - overriding member procedure after_calling_test(self in out nocopy ut_documentation_reporter, a_test ut_test) as - l_message varchar2(4000); - - begin - l_message := coalesce(a_test.description, a_test.name)||' ['||round(a_test.execution_time,3)||' sec]'; - --if test failed, then add it to the failures list, print failure with number - if a_test.result = ut_utils.tr_disabled then - self.print_yellow_text(l_message || ' (DISABLED)'); - elsif a_test.result = ut_utils.tr_success then - self.print_green_text(l_message); - elsif a_test.result > ut_utils.tr_success then - failed_test_running_count := failed_test_running_count + 1; - self.print_red_text(l_message || ' (FAILED - ' || failed_test_running_count || ')'); - end if; - - -- reproduce the output from before/after procedures and the test - self.print_clob(a_test.get_serveroutputs); - end; - - overriding member procedure after_calling_before_all(self in out nocopy ut_documentation_reporter, a_suite in ut_logical_suite) is - begin - self.print_clob(treat(a_suite as ut_suite).before_all.serveroutput); - end; - - overriding member procedure after_calling_after_all(self in out nocopy ut_documentation_reporter, a_suite in ut_logical_suite) is - begin - self.print_clob(treat(a_suite as ut_suite).after_all.serveroutput); - end; - - overriding member procedure after_calling_suite(self in out nocopy ut_documentation_reporter, a_suite ut_logical_suite) as - begin - lvl := lvl - 1; - if lvl = 0 then - self.print_text(' '); - end if; - end; - - overriding member procedure after_calling_run(self in out nocopy ut_documentation_reporter, a_run in ut_run) as - l_summary_text varchar2(4000); - l_warning_index pls_integer := 0; - -- make all warning indexes uniformly indented - c_warnings_lpad constant integer := length(to_char(a_run.results_count.warnings_count)); - - procedure print_failure_for_expectation(a_expectation ut_expectation_result) is - l_lines ut_varchar2_list; - begin - l_lines := a_expectation.get_result_lines(); - for i in 1 .. l_lines.count loop - self.print_red_text(l_lines(i)); - end loop; - self.print_cyan_text(a_expectation.caller_info); - self.print_text(' '); - end; - - procedure print_failures_for_test(a_test ut_test, a_failure_no in out nocopy integer) is - begin - if a_test.result > ut_utils.tr_success then - a_failure_no := a_failure_no + 1; - self.print_text(lpad(a_failure_no, length(failed_test_running_count) + 2, ' ') || ') ' || - nvl(a_test.name, a_test.item.form_name)); - self.lvl := self.lvl + 3; - - self.print_red_text(ut_utils.table_to_clob(a_test.get_error_stack_traces())); - - for j in 1 .. a_test.failed_expectations.count loop - print_failure_for_expectation(a_test.failed_expectations(j)); - end loop; - - self.lvl := self.lvl - 3; - end if; - end; - - procedure print_failures_from_suite(a_suite ut_logical_suite, a_failure_no in out nocopy integer) is - begin - for i in 1 .. a_suite.items.count loop - if a_suite.items(i) is of(ut_logical_suite) then - print_failures_from_suite(treat(a_suite.items(i) as ut_logical_suite), a_failure_no); - elsif a_suite.items(i) is of(ut_test) then - print_failures_for_test(treat(a_suite.items(i) as ut_test), a_failure_no); - end if; - end loop; - end; - - procedure print_failures_details(a_run in ut_run) is - l_failure_no integer := 0; - begin - if a_run.results_count.failure_count > 0 or a_run.results_count.errored_count > 0 then - - self.print_text('Failures:'); - self.print_text(' '); - for i in 1 .. a_run.items.count loop - print_failures_from_suite(treat(a_run.items(i) as ut_logical_suite), l_failure_no); - end loop; - end if; - end; - - procedure print_item_warnings(a_item in ut_suite_item) is - l_items ut_suite_items; - begin - if a_item is of (ut_logical_suite) then - l_items := treat(a_item as ut_logical_suite).items; - for i in 1 .. l_items.count loop - if l_items(i) is of(ut_suite_item) then - print_item_warnings(l_items(i)); - end if; - end loop; - end if; - - if a_item.warnings is not null and a_item.warnings.count > 0 then - for i in 1 .. a_item.warnings.count loop - l_warning_index := l_warning_index + 1; - self.print_text(' ' || lpad(l_warning_index, c_warnings_lpad) || ') ' || a_item.path); - self.lvl := self.lvl + 3; - self.print_red_text(a_item.warnings(i)); - self.lvl := self.lvl - 3; - end loop; - self.print_text(' '); - end if; - end; - - procedure print_warnings(a_run in ut_run) is - begin - if a_run.results_count.warnings_count > 0 then - self.print_text(' '); - self.print_text('Warnings:'); - self.print_text(' '); - for i in 1 .. a_run.items.count loop - print_item_warnings(treat(a_run.items(i) as ut_suite_item)); - end loop; - end if; - end; - - begin - print_failures_details(a_run); - print_warnings(a_run); - self.print_text('Finished in ' || a_run.execution_time || ' seconds'); - - l_summary_text := - a_run.results_count.total_count || ' tests, ' - || a_run.results_count.failure_count || ' failed, ' || a_run.results_count.errored_count || ' errored, ' - || a_run.results_count.disabled_count ||' disabled, ' || a_run.results_count.warnings_count || ' warning(s)'; - if a_run.results_count.failure_count + a_run.results_count.errored_count + a_run.results_count.warnings_count > 0 then - self.print_red_text(l_summary_text); - else - self.print_green_text(l_summary_text); - end if; - self.print_text(' '); - (self as ut_reporter_base).after_calling_run(a_run); - end; - -end; -/ +create or replace type body ut_documentation_reporter is + /* + utPLSQL - Version 3 + Copyright 2016 - 2017 utPLSQL Project + + Licensed under the Apache License, Version 2.0 (the "License"): + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + constructor function ut_documentation_reporter(self in out nocopy ut_documentation_reporter) return self as result is + begin + self.init($$plsql_unit); + self.lvl := 0; + self.failed_test_running_count := 0; + return; + end; + + member function tab(self in ut_documentation_reporter) return varchar2 is + begin + return rpad(' ', self.lvl * 2); + end tab; + + overriding member procedure print_text(self in out nocopy ut_documentation_reporter, a_text varchar2) is + l_lines ut_varchar2_list; + begin + if a_text is not null then + l_lines := ut_utils.string_to_table(a_text); + for i in 1 .. l_lines.count loop + (self as ut_output_reporter_base).print_text(tab || l_lines(i)); + end loop; + end if; + end; + + overriding member procedure before_calling_suite(self in out nocopy ut_documentation_reporter, a_suite ut_logical_suite) as + begin + self.print_text(coalesce(a_suite.description, a_suite.name)); + lvl := lvl + 1; + end; + + overriding member procedure after_calling_test(self in out nocopy ut_documentation_reporter, a_test ut_test) as + l_message varchar2(4000); + + begin + l_message := coalesce(a_test.description, a_test.name)||' ['||round(a_test.execution_time,3)||' sec]'; + --if test failed, then add it to the failures list, print failure with number + if a_test.result = ut_utils.tr_disabled then + self.print_yellow_text(l_message || ' (DISABLED)'); + elsif a_test.result = ut_utils.tr_success then + self.print_green_text(l_message); + elsif a_test.result > ut_utils.tr_success then + failed_test_running_count := failed_test_running_count + 1; + self.print_red_text(l_message || ' (FAILED - ' || failed_test_running_count || ')'); + end if; + + -- reproduce the output from before/after procedures and the test + self.print_clob(a_test.get_serveroutputs); + end; + + overriding member procedure after_calling_before_all(self in out nocopy ut_documentation_reporter, a_suite in ut_logical_suite) is + begin + self.print_clob(treat(a_suite as ut_suite).before_all.serveroutput); + end; + + overriding member procedure after_calling_after_all(self in out nocopy ut_documentation_reporter, a_suite in ut_logical_suite) is + begin + self.print_clob(treat(a_suite as ut_suite).after_all.serveroutput); + end; + + overriding member procedure after_calling_suite(self in out nocopy ut_documentation_reporter, a_suite ut_logical_suite) as + begin + lvl := lvl - 1; + if lvl = 0 then + self.print_text(' '); + end if; + end; + + overriding member procedure after_calling_run(self in out nocopy ut_documentation_reporter, a_run in ut_run) as + l_summary_text varchar2(4000); + l_warning_index pls_integer := 0; + -- make all warning indexes uniformly indented + c_warnings_lpad constant integer := length(to_char(a_run.results_count.warnings_count)); + + procedure print_failure_for_expectation(a_expectation ut_expectation_result) is + l_lines ut_varchar2_list; + begin + l_lines := a_expectation.get_result_lines(); + for i in 1 .. l_lines.count loop + self.print_red_text(l_lines(i)); + end loop; + self.print_cyan_text(a_expectation.caller_info); + self.print_text(' '); + end; + + procedure print_failures_for_test(a_test ut_test, a_failure_no in out nocopy integer) is + begin + if a_test.result > ut_utils.tr_success then + a_failure_no := a_failure_no + 1; + self.print_text(lpad(a_failure_no, length(failed_test_running_count) + 2, ' ') || ') ' || + nvl(a_test.name, a_test.item.form_name)); + self.lvl := self.lvl + 3; + + self.print_red_text(ut_utils.table_to_clob(a_test.get_error_stack_traces())); + + for j in 1 .. a_test.failed_expectations.count loop + print_failure_for_expectation(a_test.failed_expectations(j)); + end loop; + + self.lvl := self.lvl - 3; + end if; + end; + + procedure print_failures_from_suite(a_suite ut_logical_suite, a_failure_no in out nocopy integer) is + begin + for i in 1 .. a_suite.items.count loop + if a_suite.items(i) is of(ut_logical_suite) then + print_failures_from_suite(treat(a_suite.items(i) as ut_logical_suite), a_failure_no); + elsif a_suite.items(i) is of(ut_test) then + print_failures_for_test(treat(a_suite.items(i) as ut_test), a_failure_no); + end if; + end loop; + end; + + procedure print_failures_details(a_run in ut_run) is + l_failure_no integer := 0; + begin + if a_run.results_count.failure_count > 0 or a_run.results_count.errored_count > 0 then + + self.print_text('Failures:'); + self.print_text(' '); + for i in 1 .. a_run.items.count loop + print_failures_from_suite(treat(a_run.items(i) as ut_logical_suite), l_failure_no); + end loop; + end if; + end; + + procedure print_item_warnings(a_item in ut_suite_item) is + l_items ut_suite_items; + begin + if a_item is of (ut_logical_suite) then + l_items := treat(a_item as ut_logical_suite).items; + for i in 1 .. l_items.count loop + if l_items(i) is of(ut_suite_item) then + print_item_warnings(l_items(i)); + end if; + end loop; + end if; + + if a_item.warnings is not null and a_item.warnings.count > 0 then + for i in 1 .. a_item.warnings.count loop + l_warning_index := l_warning_index + 1; + self.print_text(' ' || lpad(l_warning_index, c_warnings_lpad) || ') ' || a_item.path); + self.lvl := self.lvl + 3; + self.print_red_text(a_item.warnings(i)); + self.lvl := self.lvl - 3; + end loop; + self.print_text(' '); + end if; + end; + + procedure print_warnings(a_run in ut_run) is + begin + if a_run.results_count.warnings_count > 0 then + self.print_text(' '); + self.print_text('Warnings:'); + self.print_text(' '); + for i in 1 .. a_run.items.count loop + print_item_warnings(treat(a_run.items(i) as ut_suite_item)); + end loop; + end if; + end; + + begin + print_failures_details(a_run); + print_warnings(a_run); + self.print_text('Finished in ' || a_run.execution_time || ' seconds'); + + l_summary_text := + a_run.results_count.total_count || ' tests, ' + || a_run.results_count.failure_count || ' failed, ' || a_run.results_count.errored_count || ' errored, ' + || a_run.results_count.disabled_count ||' disabled, ' || a_run.results_count.warnings_count || ' warning(s)'; + if a_run.results_count.failure_count + a_run.results_count.errored_count + a_run.results_count.warnings_count > 0 then + self.print_red_text(l_summary_text); + else + self.print_green_text(l_summary_text); + end if; + self.print_text(' '); + (self as ut_reporter_base).after_calling_run(a_run); + end; + + overriding member function get_description return varchar2 as + begin + return 'A textual pretty-print of unit test results (usually use for console output)'; + end; + +end; +/ diff --git a/source/reporters/ut_documentation_reporter.tps b/source/reporters/ut_documentation_reporter.tps index 397be1ca0..152544452 100644 --- a/source/reporters/ut_documentation_reporter.tps +++ b/source/reporters/ut_documentation_reporter.tps @@ -26,7 +26,9 @@ create or replace type ut_documentation_reporter under ut_console_reporter_base( overriding member procedure after_calling_after_all (self in out nocopy ut_documentation_reporter, a_suite in ut_logical_suite), overriding member procedure after_calling_before_all (self in out nocopy ut_documentation_reporter, a_suite in ut_logical_suite), overriding member procedure after_calling_suite(self in out nocopy ut_documentation_reporter, a_suite ut_logical_suite), - overriding member procedure after_calling_run(self in out nocopy ut_documentation_reporter, a_run in ut_run) + overriding member procedure after_calling_run(self in out nocopy ut_documentation_reporter, a_run in ut_run), + + overriding member function get_description return varchar2 ) not final diff --git a/source/reporters/ut_sonar_test_reporter.tpb b/source/reporters/ut_sonar_test_reporter.tpb index 2302c8ab8..526ac4316 100644 --- a/source/reporters/ut_sonar_test_reporter.tpb +++ b/source/reporters/ut_sonar_test_reporter.tpb @@ -97,5 +97,12 @@ create or replace type body ut_sonar_test_reporter is self.print_text(''); end; + overriding member function get_description return varchar2 as + begin + return 'Generates a JSON report providing detailed information on test execution.' || chr(10) || + 'Designed for [SonarQube](https://about.sonarqube.com/) to report test execution.' || chr(10) || + 'JSON format returned conforms with the Sonar specification: https://docs.sonarqube.org/display/SONAR/Generic+Test+Data'; + end; + end; / diff --git a/source/reporters/ut_sonar_test_reporter.tps b/source/reporters/ut_sonar_test_reporter.tps index 4ffd04abb..f174d5abe 100644 --- a/source/reporters/ut_sonar_test_reporter.tps +++ b/source/reporters/ut_sonar_test_reporter.tps @@ -1,4 +1,4 @@ -create or replace type ut_sonar_test_reporter under ut_reporter_base( +create or replace type ut_sonar_test_reporter under ut_output_reporter_base( /* utPLSQL - Version 3 Copyright 2016 - 2017 utPLSQL Project @@ -20,7 +20,9 @@ create or replace type ut_sonar_test_reporter under ut_reporter_base( self in out nocopy ut_sonar_test_reporter ) return self as result, - overriding member procedure after_calling_run(self in out nocopy ut_sonar_test_reporter, a_run in ut_run) + overriding member procedure after_calling_run(self in out nocopy ut_sonar_test_reporter, a_run in ut_run), + + overriding member function get_description return varchar2 ) not final / diff --git a/source/reporters/ut_teamcity_reporter.tpb b/source/reporters/ut_teamcity_reporter.tpb index 49bc15d42..f19626de9 100644 --- a/source/reporters/ut_teamcity_reporter.tpb +++ b/source/reporters/ut_teamcity_reporter.tpb @@ -113,5 +113,11 @@ create or replace type body ut_teamcity_reporter is end; + overriding member function get_description return varchar2 as + begin + return 'Provides the TeamCity (a CI server by jetbrains) reporting-format that allows tracking of progress of a CI step/task as it executes.' || chr(10) || + 'https://confluence.jetbrains.com/display/TCD9/Build+Script+Interaction+with+TeamCity'; + end; + end; / diff --git a/source/reporters/ut_teamcity_reporter.tps b/source/reporters/ut_teamcity_reporter.tps index b7a71fcfb..71e0be8a1 100644 --- a/source/reporters/ut_teamcity_reporter.tps +++ b/source/reporters/ut_teamcity_reporter.tps @@ -1,4 +1,4 @@ -create or replace type ut_teamcity_reporter under ut_reporter_base( +create or replace type ut_teamcity_reporter under ut_output_reporter_base( /* utPLSQL - Version 3 Copyright 2016 - 2017 utPLSQL Project @@ -23,7 +23,9 @@ create or replace type ut_teamcity_reporter under ut_reporter_base( overriding member procedure before_calling_test(self in out nocopy ut_teamcity_reporter, a_test in ut_test), - overriding member procedure after_calling_test(self in out nocopy ut_teamcity_reporter, a_test in ut_test) + overriding member procedure after_calling_test(self in out nocopy ut_teamcity_reporter, a_test in ut_test), + + overriding member function get_description return varchar2 ) not final / diff --git a/source/reporters/ut_xunit_reporter.tpb b/source/reporters/ut_xunit_reporter.tpb index bc3dd0d5b..f50180bba 100644 --- a/source/reporters/ut_xunit_reporter.tpb +++ b/source/reporters/ut_xunit_reporter.tpb @@ -118,7 +118,6 @@ create or replace type body ut_xunit_reporter is print_suite_elements(treat(a_run.items(i) as ut_logical_suite), l_suite_id); end loop; self.print_text(''); - (self as ut_reporter_base).after_calling_run(a_run); end; member function get_common_item_attributes(a_item ut_suite_item) return varchar2 is @@ -130,5 +129,10 @@ create or replace type body ut_xunit_reporter is || '" time="' || ut_utils.to_xml_number_format(a_item.execution_time()) || '" '; end; + overriding member function get_description return varchar2 as + begin + return 'Provides outcomes in a format conforming with JUnit 4 and above as defined in: https://gist.github.com/kuzuha/232902acab1344d6b578'; + end; + end; / diff --git a/source/reporters/ut_xunit_reporter.tps b/source/reporters/ut_xunit_reporter.tps index 88c4d74ed..a9c3b7c31 100644 --- a/source/reporters/ut_xunit_reporter.tps +++ b/source/reporters/ut_xunit_reporter.tps @@ -1,4 +1,4 @@ -create or replace type ut_xunit_reporter under ut_reporter_base( +create or replace type ut_xunit_reporter under ut_output_reporter_base( /* utPLSQL - Version 3 Copyright 2016 - 2017 utPLSQL Project @@ -23,7 +23,9 @@ create or replace type ut_xunit_reporter under ut_reporter_base( constructor function ut_xunit_reporter(self in out nocopy ut_xunit_reporter) return self as result, overriding member procedure after_calling_run(self in out nocopy ut_xunit_reporter, a_run in ut_run), - member function get_common_item_attributes(a_item ut_suite_item) return varchar2 + member function get_common_item_attributes(a_item ut_suite_item) return varchar2, + + overriding member function get_description return varchar2 ) not final / diff --git a/source/uninstall.sql b/source/uninstall.sql index a5c5e0055..e155050b9 100644 --- a/source/uninstall.sql +++ b/source/uninstall.sql @@ -196,6 +196,8 @@ drop type ut_xunit_reporter force; drop type ut_event_listener force; +drop type ut_output_reporter_base force; + drop type ut_coverage_reporter_base force; drop type ut_reporters force; @@ -228,12 +230,18 @@ drop type ut_event_listener_base force; drop type ut_suite_item_base force; -drop package ut_output_buffer; +drop type ut_output_table_buffer force; + +drop type ut_output_buffer_base force; drop view ut_output_buffer_tmp; drop table ut_output_buffer_tmp$; +drop view ut_output_buffer_info_tmp; + +drop table ut_output_buffer_info_tmp$; + drop sequence ut_message_id_seq; drop type ut_results_counter force; diff --git a/test/api/test_ut_runner.pkb b/test/api/test_ut_runner.pkb index 6160b01f5..61f99e294 100644 --- a/test/api/test_ut_runner.pkb +++ b/test/api/test_ut_runner.pkb @@ -275,5 +275,25 @@ end;'; ut.expect(l_actual).to_equal(l_expected); end; + procedure test_get_reporters_list is + l_expected sys_refcursor; + l_actual sys_refcursor; + begin + --Arrange + open l_expected for + select 'UT3.UT_COVERAGE_COBERTURA_REPORTER' reporter_object_name, 'Y' is_output_reporter from dual union all + select 'UT3.UT_COVERAGE_HTML_REPORTER', 'Y' from dual union all + select 'UT3.UT_COVERAGE_SONAR_REPORTER', 'Y' from dual union all + select 'UT3.UT_COVERALLS_REPORTER', 'Y' from dual union all + select 'UT3.UT_DOCUMENTATION_REPORTER', 'Y' from dual union all + select 'UT3.UT_SONAR_TEST_REPORTER', 'Y' from dual union all + select 'UT3.UT_TEAMCITY_REPORTER', 'Y' from dual union all + select 'UT3.UT_XUNIT_REPORTER', 'Y' from dual; + --Act + open l_actual for select * from table(ut3.ut_runner.GET_REPORTERS_LIST()) order by 1; + --Assert + ut.expect(l_actual).to_equal(l_expected); + end; + end; / diff --git a/test/api/test_ut_runner.pks b/test/api/test_ut_runner.pks index 3b2c974c0..9f9d8dec4 100644 --- a/test/api/test_ut_runner.pks +++ b/test/api/test_ut_runner.pks @@ -48,5 +48,10 @@ create or replace package test_ut_runner is --%aftertest(cleanup_cache) procedure test_get_unit_test_info; + --%test(get_reporters_list returns a cursor containing all built-in reporters and information about output-reporter) + --%beforetest(setup_cache_objects) + --%aftertest(cleanup_cache) + procedure test_get_reporters_list; + end; / diff --git a/test/core/test_output_buffer.pkb b/test/core/test_output_buffer.pkb index f79dc25a4..7d60c5213 100644 --- a/test/core/test_output_buffer.pkb +++ b/test/core/test_output_buffer.pkb @@ -4,41 +4,29 @@ create or replace package body test_output_buffer is l_result varchar2(4000); l_remaining integer; l_expected varchar2(4000); - l_reporter ut3.ut_reporter_base :=ut3. ut_documentation_reporter(); + l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); begin --Act l_expected := lpad('a text',4000,',a text'); - ut3.ut_output_buffer.send_line(l_reporter, l_expected); + l_buffer.send_line(l_expected); - select * into l_result from table(ut3.ut_output_buffer.get_lines(l_reporter.reporter_id,0)); + select * into l_result from table(l_buffer.get_lines(0,0)); ut.expect(l_result).to_equal(l_expected); - select count(1) into l_remaining from ut3.ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; + select count(1) into l_remaining from ut3.ut_output_buffer_tmp where output_id = l_buffer.output_id; ut.expect(l_remaining).to_equal(0); end; - procedure test_doesnt_send_on_null_id is - l_cur sys_refcursor; - begin - delete from ut3.ut_output_buffer_tmp; - --Act - ut3.ut_output_buffer.send_line(null,'a text to send'); - - open l_cur for select * from ut3.ut_output_buffer_tmp; - - ut.expect(l_cur).to_be_empty; - end; - procedure test_doesnt_send_on_null_text is - l_cur sys_refcursor; + l_cur sys_refcursor; l_result integer; - l_reporter ut3.ut_reporter_base := ut3.ut_documentation_reporter(); + l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); begin delete from ut3.ut_output_buffer_tmp; --Act - ut3.ut_output_buffer.send_line(l_reporter,null); + l_buffer.send_line(null); open l_cur for select * from ut3.ut_output_buffer_tmp; ut.expect(l_cur).to_be_empty; @@ -47,30 +35,33 @@ create or replace package body test_output_buffer is procedure test_send_line is l_result varchar2(4000); c_expected constant varchar2(4000) := lpad('a text',4000,',a text'); - l_reporter ut3.ut_reporter_base := ut3.ut_documentation_reporter(); + l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); begin - ut3.ut_output_buffer.send_line(l_reporter, c_expected); + l_buffer.send_line(c_expected); - select text into l_result from ut3.ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; + select text into l_result from ut3.ut_output_buffer_tmp where output_id = l_buffer.output_id; ut.expect(l_result).to_equal(c_expected); end; procedure test_waiting_for_data is - l_result varchar2(4000); + l_result varchar2(4000); l_remaining integer; - l_expected varchar2(4000); - l_reporter ut3.ut_reporter_base := ut3.ut_documentation_reporter(); + l_expected varchar2(4000); + l_buffer ut3.ut_output_buffer_base := ut3.ut_output_table_buffer(); + l_start timestamp; + l_duration interval day to second; begin --Act l_expected := lpad('a text',4000,',a text'); - ut3.ut_output_buffer.send_line(l_reporter, l_expected); - - select * into l_result from table(ut3.ut_output_buffer.get_lines(l_reporter.reporter_id,0)); + l_buffer.send_line(l_expected); + l_start := systimestamp; + select * into l_result from table(l_buffer.get_lines(1,1)); + l_duration := systimestamp - l_start; ut.expect(l_result).to_equal(l_expected); - - select count(1) into l_remaining from ut3.ut_output_buffer_tmp where reporter_id = l_reporter.reporter_id; + ut.expect(l_duration).to_be_greater_than(interval '1' second); + select count(1) into l_remaining from ut3.ut_output_buffer_tmp where output_id = l_buffer.output_id; ut.expect(l_remaining).to_equal(0); diff --git a/test/core/test_output_buffer.pks b/test/core/test_output_buffer.pks index b17017134..6311d2275 100644 --- a/test/core/test_output_buffer.pks +++ b/test/core/test_output_buffer.pks @@ -6,9 +6,6 @@ create or replace package test_output_buffer is --%test(Recieves a line from buffer table and deletes) procedure test_recieve; - --%test(Does not send line if null reporter id given) - procedure test_doesnt_send_on_null_id; - --%test(Does not send line if null text given) procedure test_doesnt_send_on_null_text; diff --git a/tests/ut/ut.run.ExecutesSuccesfullyAnEmptySuite.sql b/tests/ut/ut.run.ExecutesSuccesfullyAnEmptySuite.sql new file mode 100644 index 000000000..f739d97c8 --- /dev/null +++ b/tests/ut/ut.run.ExecutesSuccesfullyAnEmptySuite.sql @@ -0,0 +1,30 @@ +set termout off +create or replace package empty_suite as + -- %suite + + procedure not_a_test; +end; +/ +create or replace package body empty_suite as + procedure not_a_test is begin null; end; +end; +/ +set termout on +declare + l_result integer; +begin + select * + into l_result + from table(ut.run('empty_suite',utplsql_test_reporter())); +--Assert + if l_result = ut_utils.tr_error then + :test_result := ut_utils.tr_success; + else + dbms_output.put_line('expected failure of ''empty_suite'' got: '''||ut_utils.test_result_to_char(l_result)||'''' ); + end if; +end; +/ + +set termout off +drop package empty_suite; +set termout on diff --git a/tests/ut_expectations/ut.expect.not_to_equal.anydata.GivesFailureWhenComparingTheSameData.sql b/tests/ut_expectations/ut.expect.not_to_equal.anydata.GivesFailureWhenComparingTheSameData.sql new file mode 100644 index 000000000..fd030a701 --- /dev/null +++ b/tests/ut_expectations/ut.expect.not_to_equal.anydata.GivesFailureWhenComparingTheSameData.sql @@ -0,0 +1,17 @@ +--Arrange +declare + l_expected department$ := department$('hr'); + l_actual department$ := department$('hr'); + l_result integer; +begin +--Act + ut.expect( anydata.convertObject(l_actual) ).not_to_equal( anydata.convertObject(l_expected) ); + l_result := ut_expectation_processor.get_status(); +--Assert + if l_result = ut_utils.tr_failure then + :test_result := ut_utils.tr_success; + else + dbms_output.put_line('expected: '''||ut_utils.tr_success||''', got: '''||l_result||'''' ); + end if; +end; +/ diff --git a/tests/ut_output_buffer/get_lines.WaitsForMoreDataToAppearForSpecifiedTime.sql b/tests/ut_output_buffer/get_lines.WaitsForMoreDataToAppearForSpecifiedTime.sql new file mode 100644 index 000000000..6c54e4330 --- /dev/null +++ b/tests/ut_output_buffer/get_lines.WaitsForMoreDataToAppearForSpecifiedTime.sql @@ -0,0 +1,24 @@ +--Arrange +declare + l_result integer; + l_dummy integer; + l_output ut_output_buffer_base := ut_output_table_buffer(); + l_start_time timestamp := systimestamp; + l_wait_seconds integer := 1; +begin + --Act + l_output.send_line(lpad('a text',4000,',a text')); + + select count(*) into l_dummy from table( l_output.get_lines( a_initial_timeout => 0, a_timeout_sec => l_wait_seconds )); + l_result := round(extract(second from (systimestamp - l_start_time))); + + --Assert + ut.expect(l_result).to_equal(l_wait_seconds); + + if ut_expectation_processor.get_status = ut_utils.tr_success then + :test_result := ut_utils.tr_success; + else + dbms_output.put_line(ut_expectation_processor.get_expectations_results()(1).get_result_clob); + end if; +end; +/